1 /* $NetBSD: usbhidaction.c,v 1.23 2008/04/28 20:24:15 martin Exp $ */
4 * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson <lennart@augustsson.net>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: usbhidaction.c,v 1.23 2008/04/28 20:24:15 martin Exp $");
45 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <dev/usb/usb.h>
48 #include <dev/usb/usbhid.h>
54 static int verbose
= 0;
55 static int isdemon
= 0;
56 static int reparse
= 0;
68 static struct command
*commands
;
72 static void usage(void) __dead
;
73 static struct command
*parse_conf(const char *, report_desc_t
, int, int);
74 static void docmd(struct command
*, int, const char *, int, char **);
75 static void freecommands(struct command
*);
85 main(int argc
, char **argv
)
87 const char *conf
= NULL
;
88 const char *dev
= NULL
;
89 int fd
, ch
, sz
, n
, val
, i
;
93 char devnamebuf
[PATH_MAX
];
96 const char *table
= NULL
;
99 (void)setlinebuf(stdout
);
103 while ((ch
= getopt(argc
, argv
, "c:df:it:v")) != -1) {
132 if (conf
== NULL
|| dev
== NULL
)
138 (void)snprintf(devnamebuf
, sizeof(devnamebuf
), "/dev/%s%s",
139 isdigit((unsigned char)dev
[0]) ? "uhid" : "", dev
);
143 if (demon
&& conf
[0] != '/')
144 errx(1, "config file must have an absolute path, %s", conf
);
146 fd
= open(dev
, O_RDWR
);
150 /* Avoid passing the device file descriptor to executed commands */
151 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
152 err(1, "fcntl(F_SETFD, FD_CLOEXEC)");
154 if (ioctl(fd
, USB_GET_REPORT_ID
, &reportid
) < 0)
156 repd
= hid_get_report_desc(fd
);
158 err(1, "hid_get_report_desc() failed");
160 commands
= parse_conf(conf
, repd
, reportid
, ignore
);
162 sz
= hid_report_size(repd
, hid_input
, reportid
);
165 (void)printf("report size %d\n", sz
);
166 if (sz
> (int)sizeof(buf
))
167 errx(1, "report too large");
169 (void)signal(SIGHUP
, sighup
);
172 if (daemon(0, 0) < 0)
179 n
= read(fd
, buf
, (size_t)sz
);
181 (void)printf("read %d bytes:", n
);
182 for (i
= 0; i
< n
; i
++)
183 (void)printf(" %02x", buf
[i
]);
197 for (cmd
= commands
; cmd
; cmd
= cmd
->next
) {
198 val
= hid_get_data(buf
, &cmd
->item
);
199 if (cmd
->value
== val
|| cmd
->anyvalue
)
200 docmd(cmd
, val
, dev
, argc
, argv
);
203 struct command
*cmds
=
204 parse_conf(conf
, repd
, reportid
, ignore
);
206 freecommands(commands
);
218 (void)fprintf(stderr
, "usage: %s -c config_file [-d] -f hid_dev "
219 "[-i] [-t table] [-v]\n", getprogname());
234 static struct command
*
235 parse_conf(const char *conf
, report_desc_t repd
, int reportid
, int ignore
)
240 char buf
[SIZE
], name
[SIZE
], value
[SIZE
], action
[SIZE
];
241 char usagestr
[SIZE
], coll
[SIZE
];
242 struct command
*cmd
, *cmds
;
245 int u
, lo
, hi
, range
;
247 f
= fopen(conf
, "r");
252 for (line
= 1; ; line
++) {
253 if (fgets(buf
, sizeof buf
, f
) == NULL
)
255 if (buf
[0] == '#' || buf
[0] == '\n')
257 p
= strchr(buf
, '\n');
258 while (p
&& isspace(peek(f
))) {
259 if (fgets(p
, (int)(sizeof buf
- strlen(buf
)), f
)
262 p
= strchr(buf
, '\n');
266 /* XXX SIZE == 4000 */
267 if (sscanf(buf
, "%3999s %3999s %[^\n]", name
, value
, action
) != 3) {
269 syslog(LOG_WARNING
, "config file `%s', line %d"
270 ", syntax error: %s", conf
, line
, buf
);
275 errx(1, "config file `%s', line %d,"
276 ", syntax error: %s", conf
, line
, buf
);
280 cmd
= malloc(sizeof *cmd
);
282 err(1, "malloc failed");
287 if (strcmp(value
, "*") == 0) {
291 if (sscanf(value
, "%d", &cmd
->value
) != 1) {
294 "config file `%s', line %d, "
301 errx(1, "config file `%s', line %d, "
309 for (d
= hid_start_parse(repd
, 1 << hid_input
, reportid
);
310 hid_get_item(d
, &h
); ) {
312 (void)printf("kind=%d usage=%x flags=%x\n",
313 h
.kind
, h
.usage
, h
.flags
);
316 if (h
.flags
& HIO_CONST
)
318 if (h
.usage_minimum
!= 0 ||
319 h
.usage_maximum
!= 0) {
320 lo
= h
.usage_minimum
;
321 hi
= h
.usage_maximum
;
328 for (u
= lo
; u
<= hi
; u
++) {
329 (void)snprintf(usagestr
,
332 hid_usage_page((int)HID_PAGE(u
)),
333 hid_usage_in_page((u_int
)u
));
335 (void)printf("usage %s\n",
337 if (!strcasecmp(usagestr
, name
))
340 (void)snprintf(usagestr
,
342 "%s.%s:%s", coll
+ 1,
343 hid_usage_page((int)HID_PAGE(u
)),
344 hid_usage_in_page((u_int
)u
));
349 if (!strcasecmp(usagestr
, name
))
355 (void)snprintf(coll
+ strlen(coll
),
356 sizeof coll
- strlen(coll
), ".%s:%s",
357 hid_usage_page((int)HID_PAGE(h
.usage
)),
358 hid_usage_in_page(h
.usage
));
360 (void)printf("coll '%s'\n", coll
);
362 case hid_endcollection
:
364 *strrchr(coll
, '.') = 0;
372 warnx("ignore item '%s'", name
);
376 syslog(LOG_WARNING
, "config file `%s', line %d, HID "
377 "item not found: `%s'", conf
, line
, name
);
382 errx(1, "config file `%s', line %d, HID item "
383 "not found: `%s'", conf
, line
, name
);
389 cmd
->name
= strdup(name
);
390 cmd
->action
= strdup(action
);
399 (void)printf("PARSE:%d %s, %d, '%s'\n", cmd
->line
, name
,
400 cmd
->value
, cmd
->action
);
407 docmd(struct command
*cmd
, int value
, const char *hid
, int argc
, char **argv
)
409 char cmdbuf
[SIZE
], *p
, *q
;
413 for (p
= cmd
->action
, q
= cmdbuf
; *p
&& q
< &cmdbuf
[SIZE
-1]; ) {
416 len
= &cmdbuf
[SIZE
-1] - q
;
417 if (isdigit((unsigned char)*p
)) {
418 n
= strtol(p
, &p
, 10) - 1;
419 if (n
>= 0 && n
< argc
) {
420 (void)strncpy(q
, argv
[n
], len
);
423 } else if (*p
== 'V') {
425 (void)snprintf(q
, len
, "%d", value
);
427 } else if (*p
== 'N') {
429 (void)strncpy(q
, cmd
->name
, len
);
431 } else if (*p
== 'H') {
433 (void)strncpy(q
, hid
, len
);
445 (void)printf("system '%s'\n", cmdbuf
);
447 if (verbose
> 1 && r
)
448 (void)printf("return code = 0x%x\n", r
);
452 freecommands(struct command
*cmd
)
454 struct command
*next
;