usbhidaction.c revision 1.1 1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <err.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/ioctl.h>
10 #include <dev/usb/usb.h>
11 #include <dev/usb/usbhid.h>
12 #include <usb.h>
13 #include <util.h>
14
15 int verbose = 0;
16
17 struct command {
18 struct command *next;
19 int line;
20
21 struct hid_item item;
22 int value;
23 char anyvalue;
24 char *name;
25 char *action;
26 };
27 struct command *commands;
28
29 #define SIZE 4000
30
31 void usage(void);
32 void parse_conf(const char *conf, report_desc_t repd, int ignore);
33 void docmd(struct command *cmd, int value, const char *hid,
34 int argc, char **argv);
35
36 int
37 main(int argc, char **argv)
38 {
39 const char *conf = NULL;
40 const char *hid = NULL;
41 int fd, ch, sz, n, val;
42 int demon, ignore;
43 report_desc_t repd;
44 char buf[100];
45 struct command *cmd;
46
47 demon = 1;
48 ignore = 0;
49 while ((ch = getopt(argc, argv, "c:dif:v")) != -1) {
50 switch(ch) {
51 case 'c':
52 conf = optarg;
53 break;
54 case 'd':
55 demon ^= 1;
56 break;
57 case 'i':
58 ignore++;
59 break;
60 case 'f':
61 hid = optarg;
62 break;
63 case 'v':
64 demon = 0;
65 verbose++;
66 break;
67 case '?':
68 default:
69 usage();
70 }
71 }
72 argc -= optind;
73 argv += optind;
74
75 if (conf == NULL || hid == NULL)
76 usage();
77
78 hid_init(NULL);
79
80 fd = open(hid, O_RDWR);
81 if (fd < 0)
82 err(1, "%s", hid);
83 repd = hid_get_report_desc(fd);
84 if (repd == NULL)
85 err(1, "hid_get_report_desc() failed\n");
86
87 parse_conf(conf, repd, ignore);
88
89 sz = hid_report_size(repd, hid_input, NULL);
90 hid_dispose_report_desc(repd);
91
92 if (verbose)
93 printf("report size %d\n", sz);
94 if (sz > sizeof buf)
95 errx(1, "report too large");
96
97 if (demon) {
98 if (daemon(0, 0) < 0)
99 err(1, "daemon()");
100 pidfile(NULL);
101 }
102
103 for(;;) {
104 n = read(fd, buf, sz);
105 if (verbose > 2)
106 printf("read %d bytes [%02x]\n", n, buf[0]);
107 if (n < 0) {
108 if (verbose)
109 err(1, "read");
110 else
111 exit(1);
112 }
113 for (cmd = commands; cmd; cmd = cmd->next) {
114 val = hid_get_data(buf, &cmd->item);
115 if (cmd->value == val || cmd->anyvalue)
116 docmd(cmd, val, hid, argc, argv);
117 }
118 }
119
120 exit(0);
121 }
122
123 void
124 usage(void)
125 {
126 extern char *__progname;
127
128 fprintf(stderr, "Usage: %s -c config_file [-d] -f hid_dev "
129 " [-v]\n", __progname);
130 exit(1);
131 }
132
133 static int
134 peek(FILE *f)
135 {
136 int c;
137
138 c = getc(f);
139 if (c != EOF)
140 ungetc(c, f);
141 return c;
142 }
143
144 void
145 parse_conf(const char *conf, report_desc_t repd, int ignore)
146 {
147 FILE *f;
148 char *p;
149 int line;
150 char buf[SIZE], name[SIZE], value[SIZE], action[SIZE];
151 char usage[SIZE], coll[SIZE];
152 struct command *cmd;
153 struct hid_data *d;
154 struct hid_item h;
155
156 f = fopen(conf, "r");
157 if (f == NULL)
158 err(1, "%s", conf);
159
160 for (line = 1; ; line++) {
161 if (fgets(buf, sizeof buf, f) == NULL)
162 break;
163 if (buf[0] == '#' || buf[0] == '\n')
164 continue;
165 p = strchr(buf, '\n');
166 while (p && isspace(peek(f))) {
167 if (fgets(p, sizeof buf - strlen(buf), f) == NULL)
168 break;
169 p = strchr(buf, '\n');
170 }
171 if (p)
172 *p = 0;
173 if (sscanf(buf, "%s %s %[^\n]", name, value, action) != 3) {
174 errx(1, "config file `%s', line %d, syntax error: %s",
175 conf, line, buf);
176 }
177
178 cmd = malloc(sizeof *cmd);
179 if (cmd == NULL)
180 err(1, "malloc failed");
181 cmd->next = commands;
182 commands = cmd;
183 cmd->line = line;
184
185 if (strcmp(value, "*") == 0) {
186 cmd->anyvalue = 1;
187 } else {
188 cmd->anyvalue = 0;
189 if (sscanf(value, "%d", &cmd->value) != 1)
190 errx(1, "config file `%s', line %d, "
191 "bad value: %s\n", conf, line, value);
192 }
193
194 coll[0] = 0;
195 for (d = hid_start_parse(repd, 1 << hid_input);
196 hid_get_item(d, &h); ) {
197 if (verbose > 2)
198 printf("kind=%d usage=%x\n", h.kind, h.usage);
199 if (h.flags & HIO_CONST)
200 continue;
201 switch (h.kind) {
202 case hid_input:
203 snprintf(usage, sizeof usage, "%s:%s",
204 hid_usage_page(HID_PAGE(h.usage)),
205 hid_usage_in_page(h.usage));
206 if (verbose > 2)
207 printf("usage %s\n", usage);
208 if (strcasecmp(usage, name) == 0)
209 goto foundhid;
210 if (coll[0]) {
211 snprintf(usage, sizeof usage,
212 "%s.%s:%s", coll+1,
213 hid_usage_page(HID_PAGE(h.usage)),
214 hid_usage_in_page(h.usage));
215 if (verbose > 2)
216 printf("usage %s\n", usage);
217 if (strcasecmp(usage, name) == 0)
218 goto foundhid;
219 }
220 break;
221 case hid_collection:
222 snprintf(coll + strlen(coll),
223 sizeof coll - strlen(coll), ".%s:%s",
224 hid_usage_page(HID_PAGE(h.usage)),
225 hid_usage_in_page(h.usage));
226 break;
227 case hid_endcollection:
228 if (coll[0])
229 *strrchr(coll, '.') = 0;
230 break;
231 default:
232 break;
233 }
234 }
235 if (ignore) {
236 if (verbose)
237 warnx("ignore item '%s'\n", name);
238 continue;
239 }
240 errx(1, "config file `%s', line %d, HID item not found: `%s'\n",
241 conf, line, name);
242
243 foundhid:
244 hid_end_parse(d);
245 cmd->item = h;
246 cmd->name = strdup(name);
247 cmd->action = strdup(action);
248
249 if (verbose)
250 printf("PARSE:%d %s, %d, '%s'\n", cmd->line, name,
251 cmd->value, cmd->action);
252 }
253 fclose(f);
254 }
255
256 void
257 docmd(struct command *cmd, int value, const char *hid, int argc, char **argv)
258 {
259 char cmdbuf[SIZE], *p, *q;
260 size_t len;
261 int n, r;
262
263 for (p = cmd->action, q = cmdbuf; *p && q < &cmdbuf[SIZE-1]; ) {
264 if (*p == '$') {
265 p++;
266 len = &cmdbuf[SIZE-1] - q;
267 if (isdigit(*p)) {
268 n = strtol(p, &p, 10) - 1;
269 if (n >= 0 && n < argc) {
270 strncpy(q, argv[n], len);
271 q += strlen(q);
272 }
273 } else if (*p == 'V') {
274 p++;
275 snprintf(q, len, "%d", value);
276 q += strlen(q);
277 } else if (*p == 'N') {
278 p++;
279 strncpy(q, cmd->name, len);
280 q += strlen(q);
281 } else if (*p == 'H') {
282 p++;
283 strncpy(q, hid, len);
284 q += strlen(q);
285 } else if (*p) {
286 *q++ = *p++;
287 }
288 } else {
289 *q++ = *p++;
290 }
291 }
292 *q = 0;
293
294 if (verbose)
295 printf("system '%s'\n", cmdbuf);
296 r = system(cmdbuf);
297 if (verbose > 1 && r)
298 printf("return code = 0x%x\n", r);
299 }
300