1 /* $NetBSD: usbhidaction.c,v 1.8 2002/06/11 06:06:21 itojun Exp $ */
2 /* $FreeBSD: head/usr.bin/usbhidaction/usbhidaction.c 227195 2011-11-06 08:18:23Z ed $ */
5 * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson <lennart@augustsson.net>.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
41 #include <sys/types.h>
42 #include <bus/u4b/usbhid.h>
49 static int verbose
= 0;
50 static int isdemon
= 0;
51 static int reparse
= 1;
52 static const char * pidfile
= "/var/run/usbaction.pid";
67 static struct command
*commands
;
72 struct command
*parse_conf(const char *, report_desc_t
, int, int);
73 void docmd(struct command
*, int, const char *, int, char **);
74 void freecommands(struct command
*);
77 sighup(int sig __unused
)
83 main(int argc
, char **argv
)
85 const char *conf
= NULL
;
86 const char *dev
= NULL
;
87 const char *table
= NULL
;
88 int fd
, fp
, ch
, n
, val
, i
;
90 int demon
, ignore
, dieearly
;
93 char devnamebuf
[PATH_MAX
];
100 while ((ch
= getopt(argc
, argv
, "c:def:ip:r:t:v")) != -1) {
121 reportid
= atoi(optarg
);
138 if (conf
== NULL
|| dev
== NULL
)
144 snprintf(devnamebuf
, sizeof(devnamebuf
), "/dev/%s%s",
145 isdigit(dev
[0]) ? "uhid" : "", dev
);
149 fd
= open(dev
, O_RDWR
);
152 repd
= hid_get_report_desc(fd
);
154 err(1, "hid_get_report_desc() failed");
156 commands
= parse_conf(conf
, repd
, reportid
, ignore
);
158 sz
= (size_t)hid_report_size(repd
, hid_input
, -1);
161 printf("report size %zu\n", sz
);
163 errx(1, "report too large");
165 (void)signal(SIGHUP
, sighup
);
168 fp
= open(pidfile
, O_WRONLY
|O_CREAT
, S_IRUSR
|S_IRGRP
|S_IROTH
);
170 sz1
= snprintf(buf
, sizeof buf
, "%ld\n",
172 if (sz1
> sizeof buf
)
177 err(1, "%s", pidfile
);
178 if (daemon(0, 0) < 0)
184 n
= read(fd
, buf
, sz
);
186 printf("read %d bytes:", n
);
187 for (i
= 0; i
< n
; i
++)
188 printf(" %02x", buf
[i
]);
202 for (cmd
= commands
; cmd
; cmd
= cmd
->next
) {
203 if (cmd
->item
.report_ID
!= 0 &&
204 buf
[0] != cmd
->item
.report_ID
)
206 if (cmd
->item
.flags
& HIO_VARIABLE
)
207 val
= hid_get_data(buf
, &cmd
->item
);
209 uint32_t pos
= cmd
->item
.pos
;
210 for (i
= 0; i
< cmd
->item
.report_count
; i
++) {
211 val
= hid_get_data(buf
, &cmd
->item
);
212 if (val
== cmd
->value
)
214 cmd
->item
.pos
+= cmd
->item
.report_size
;
217 val
= (i
< cmd
->item
.report_count
) ?
220 if (cmd
->value
!= val
&& cmd
->anyvalue
== 0)
222 if ((cmd
->debounce
== 0) ||
223 ((cmd
->debounce
== 1) && ((cmd
->lastseen
== -1) ||
224 (cmd
->lastseen
!= val
)))) {
225 docmd(cmd
, val
, dev
, argc
, argv
);
228 if ((cmd
->debounce
> 1) &&
229 ((cmd
->lastused
== -1) ||
230 (abs(cmd
->lastused
- val
) >= cmd
->debounce
))) {
231 docmd(cmd
, val
, dev
, argc
, argv
);
243 struct command
*cmds
=
244 parse_conf(conf
, repd
, reportid
, ignore
);
246 freecommands(commands
);
260 fprintf(stderr
, "Usage: %s [-deiv] -c config_file -f hid_dev "
261 "[-p pidfile] [-t tablefile]\n", getprogname());
277 parse_conf(const char *conf
, report_desc_t repd
, int reportid
, int ignore
)
282 char buf
[SIZE
], name
[SIZE
], value
[SIZE
], debounce
[SIZE
], action
[SIZE
];
283 char usbuf
[SIZE
], coll
[SIZE
], *tmp
;
284 struct command
*cmd
, *cmds
;
287 int inst
, cinst
, u
, lo
, hi
, range
, t
;
289 f
= fopen(conf
, "r");
294 for (line
= 1; ; line
++) {
295 if (fgets(buf
, sizeof buf
, f
) == NULL
)
297 if (buf
[0] == '#' || buf
[0] == '\n')
299 p
= strchr(buf
, '\n');
300 while (p
&& isspace(peek(f
))) {
301 if (fgets(p
, sizeof buf
- strlen(buf
), f
) == NULL
)
303 p
= strchr(buf
, '\n');
307 if (sscanf(buf
, "%s %s %s %[^\n]",
308 name
, value
, debounce
, action
) != 4) {
310 syslog(LOG_WARNING
, "config file `%s', line %d"
311 ", syntax error: %s", conf
, line
, buf
);
315 errx(1, "config file `%s', line %d,"
316 ", syntax error: %s", conf
, line
, buf
);
319 tmp
= strchr(name
, '#');
322 inst
= atoi(tmp
+ 1);
326 cmd
= malloc(sizeof *cmd
);
328 err(1, "malloc failed");
333 if (strcmp(value
, "*") == 0) {
337 if (sscanf(value
, "%d", &cmd
->value
) != 1) {
340 "config file `%s', line %d, "
341 "bad value: %s (should be * or a number)\n",
346 errx(1, "config file `%s', line %d, "
347 "bad value: %s (should be * or a number)\n",
353 if (sscanf(debounce
, "%d", &cmd
->debounce
) != 1) {
356 "config file `%s', line %d, "
357 "bad value: %s (should be a number >= 0)\n",
358 conf
, line
, debounce
);
362 errx(1, "config file `%s', line %d, "
363 "bad value: %s (should be a number >= 0)\n",
364 conf
, line
, debounce
);
370 for (d
= hid_start_parse(repd
, 1 << hid_input
, reportid
);
371 hid_get_item(d
, &h
); ) {
373 printf("kind=%d usage=%x\n", h
.kind
, h
.usage
);
374 if (h
.flags
& HIO_CONST
)
378 if (h
.usage_minimum
!= 0 ||
379 h
.usage_maximum
!= 0) {
380 lo
= h
.usage_minimum
;
381 hi
= h
.usage_maximum
;
388 for (u
= lo
; u
<= hi
; u
++) {
390 snprintf(usbuf
, sizeof usbuf
,
392 hid_usage_page(HID_PAGE(u
)),
393 hid_usage_in_page(u
));
395 snprintf(usbuf
, sizeof usbuf
,
397 hid_usage_page(HID_PAGE(u
)),
398 hid_usage_in_page(u
));
401 printf("usage %s\n", usbuf
);
402 t
= strlen(usbuf
) - strlen(name
);
404 if (strcmp(usbuf
+ t
, name
))
406 if (usbuf
[t
- 1] != '.')
408 } else if (strcmp(usbuf
, name
))
415 snprintf(coll
+ strlen(coll
),
416 sizeof coll
- strlen(coll
), ".%s:%s",
417 hid_usage_page(HID_PAGE(h
.usage
)),
418 hid_usage_in_page(h
.usage
));
420 case hid_endcollection
:
422 *strrchr(coll
, '.') = 0;
430 warnx("ignore item '%s'", name
);
434 syslog(LOG_WARNING
, "config file `%s', line %d, HID "
435 "item not found: `%s'\n", conf
, line
, name
);
439 errx(1, "config file `%s', line %d, HID item "
440 "not found: `%s'\n", conf
, line
, name
);
448 cmd
->name
= strdup(name
);
449 cmd
->action
= strdup(action
);
458 printf("PARSE:%d %s, %d, '%s'\n", cmd
->line
, name
,
459 cmd
->value
, cmd
->action
);
466 docmd(struct command
*cmd
, int value
, const char *hid
, int argc
, char **argv
)
468 char cmdbuf
[SIZE
], *p
, *q
;
472 for (p
= cmd
->action
, q
= cmdbuf
; *p
&& q
< &cmdbuf
[SIZE
-1]; ) {
475 len
= &cmdbuf
[SIZE
-1] - q
;
477 n
= strtol(p
, &p
, 10) - 1;
478 if (n
>= 0 && n
< argc
) {
479 strncpy(q
, argv
[n
], len
);
482 } else if (*p
== 'V') {
484 snprintf(q
, len
, "%d", value
);
486 } else if (*p
== 'N') {
488 strncpy(q
, cmd
->name
, len
);
490 } else if (*p
== 'H') {
492 strncpy(q
, hid
, len
);
504 printf("system '%s'\n", cmdbuf
);
506 if (verbose
> 1 && r
)
507 printf("return code = 0x%x\n", r
);
511 freecommands(struct command
*cmd
)
513 struct command
*next
;