-
Notifications
You must be signed in to change notification settings - Fork 3
/
hid.c
133 lines (108 loc) · 3.08 KB
/
hid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <syslog.h>
#include <linux/types.h>
#include <linux/hiddev.h>
#include <usb.h>
#include <ccan/array_size/array_size.h>
#include "lib.h"
#include "quickcall.h"
static void set_leds(struct quickcall *qc, int red, int green, int blue)
{
int rc;
struct hiddev_usage_ref ref = {
.report_type = HID_REPORT_TYPE_FEATURE,
.report_id = HID_REPORT_ID_UNKNOWN,
.usage_code = QUICKCALL_USAGE_LEDS,
};
struct hiddev_report_info ri = {
.report_type = HID_REPORT_TYPE_FEATURE,
.report_id = HID_REPORT_ID_FIRST,
};
ref.value = red | (green << 2) | (blue << 4);
rc = ioctl(qc->hidfd, HIDIOCSUSAGE, &ref);
if (rc)
log_printf(LOG_ERR, "Error on HIDIOCSUSAGE (fd=%d): %s\n",
qc->hidfd, strerror(errno));
rc = ioctl(qc->hidfd, HIDIOCSREPORT, &ri);
if (rc)
log_printf(LOG_ERR, "Error on HIDIOCSREPORT (fd=%d): %s\n",
qc->hidfd, strerror(errno));
}
static void update_leds(struct quickcall *qc)
{
set_leds(qc, qc->mutestate * QUICKCALL_LED_ON,
!qc->mutestate * QUICKCALL_LED_ON, 0);
}
static void mute_btn(struct quickcall *qc, struct hiddev_event *ev, void *data)
{
if (!ev->value)
return;
qc->mutestate = !qc->mutestate;
update_leds(qc);
quickcall_update_mute(qc);
}
static void volume_btn(struct quickcall *qc, struct hiddev_event *ev, void *data)
{
int delta = (int)data;
quickcall_update_volume(qc, delta);
}
static struct button_info {
unsigned usage;
char mask;
void (*fn)(struct quickcall *qc, struct hiddev_event *ev,
void *data);
void *data;
const char *name;
} button_table[] = {
{QUICKCALL_USAGE_CALL, 0x01, NULL, NULL, "CALL"},
{QUICKCALL_USAGE_MUTE, 0x02, mute_btn, NULL, "MUTE"},
{QUICKCALL_USAGE_HANGUP, 0x04, NULL, NULL, "HANGUP"},
{QUICKCALL_USAGE_MIC, 0x08, NULL, NULL, "MIC SOCKET"},
{QUICKCALL_USAGE_HEADPHONE, 0x10, NULL, NULL, "HEADPHONE SOCKET"},
{QUICKCALL_USAGE_RIGHT, 0x20, volume_btn, (void *)(+1), "RIGHT"},
{QUICKCALL_USAGE_LEFT, 0x40, volume_btn, (void *)(-1), "LEFT"},
{QUICKCALL_USAGE_MYSTERY, 0x80,NULL, NULL, "MYSTERY"},
};
static void process_event(struct quickcall *qc, struct hiddev_event *ev)
{
int i;
for (i = 0; i < ARRAY_SIZE(button_table); i++) {
struct button_info *btn = &button_table[i];
if (btn->usage == ev->hid) {
signed int oldval = !!(qc->hidstate & btn->mask);
if (oldval != ev->value) {
if (ev->value)
debug("%s pressed\n", btn->name);
else
debug("%s released\n", btn->name);
qc->hidstate ^= btn->mask;
if (btn->fn)
btn->fn(qc, ev, btn->data);
}
return;
}
}
debug("Received unknown usage 0x%08x (%d)\n", ev->hid, ev->value);
}
void quickcall_hidpoll(struct quickcall *qc)
{
struct hiddev_event ev;
int rc;
update_leds(qc);
while (1) {
rc = read(qc->hidfd, &ev, sizeof(ev));
if (rc < 0)
log_printf(LOG_ERR, "Error reading from %s: %s\n",
qc->hiddev, strerror(errno));
else if (rc == 0)
return; /* EOF */
else if (rc != sizeof(ev))
log_printf(LOG_ERR, "Short read from %s\n", qc->hiddev);
process_event(qc, &ev);
}
}