1 /* $NetBSD: usbhidaction.c,v 1.3 2001/02/20 23:55:42 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson <lennart@augustsson.net>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 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. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <ctype.h> 43 #include <err.h> 44 #include <fcntl.h> 45 #include <unistd.h> 46 #include <sys/types.h> 47 #include <sys/ioctl.h> 48 #include <dev/usb/usb.h> 49 #include <dev/usb/usbhid.h> 50 #include <usb.h> 51 #include <util.h> 52 53 int verbose = 0; 54 55 struct command { 56 struct command *next; 57 int line; 58 59 struct hid_item item; 60 int value; 61 char anyvalue; 62 char *name; 63 char *action; 64 }; 65 struct command *commands; 66 67 #define SIZE 4000 68 69 void usage(void); 70 void parse_conf(const char *conf, report_desc_t repd, int ignore); 71 void docmd(struct command *cmd, int value, const char *hid, 72 int argc, char **argv); 73 74 int 75 main(int argc, char **argv) 76 { 77 const char *conf = NULL; 78 const char *hid = NULL; 79 int fd, ch, sz, n, val; 80 int demon, ignore; 81 report_desc_t repd; 82 char buf[100]; 83 struct command *cmd; 84 85 demon = 1; 86 ignore = 0; 87 while ((ch = getopt(argc, argv, "c:dif:v")) != -1) { 88 switch(ch) { 89 case 'c': 90 conf = optarg; 91 break; 92 case 'd': 93 demon ^= 1; 94 break; 95 case 'i': 96 ignore++; 97 break; 98 case 'f': 99 hid = optarg; 100 break; 101 case 'v': 102 demon = 0; 103 verbose++; 104 break; 105 case '?': 106 default: 107 usage(); 108 } 109 } 110 argc -= optind; 111 argv += optind; 112 113 if (conf == NULL || hid == NULL) 114 usage(); 115 116 hid_init(NULL); 117 118 fd = open(hid, O_RDWR); 119 if (fd < 0) 120 err(1, "%s", hid); 121 repd = hid_get_report_desc(fd); 122 if (repd == NULL) 123 err(1, "hid_get_report_desc() failed\n"); 124 125 parse_conf(conf, repd, ignore); 126 127 sz = hid_report_size(repd, hid_input, NULL); 128 hid_dispose_report_desc(repd); 129 130 if (verbose) 131 printf("report size %d\n", sz); 132 if (sz > sizeof buf) 133 errx(1, "report too large"); 134 135 if (demon) { 136 if (daemon(0, 0) < 0) 137 err(1, "daemon()"); 138 pidfile(NULL); 139 } 140 141 for(;;) { 142 n = read(fd, buf, sz); 143 if (verbose > 2) 144 printf("read %d bytes [%02x]\n", n, buf[0]); 145 if (n < 0) { 146 if (verbose) 147 err(1, "read"); 148 else 149 exit(1); 150 } 151 for (cmd = commands; cmd; cmd = cmd->next) { 152 val = hid_get_data(buf, &cmd->item); 153 if (cmd->value == val || cmd->anyvalue) 154 docmd(cmd, val, hid, argc, argv); 155 } 156 } 157 158 exit(0); 159 } 160 161 void 162 usage(void) 163 { 164 165 fprintf(stderr, "Usage: %s -c config_file [-d] -f hid_dev " 166 " [-v]\n", getprogname()); 167 exit(1); 168 } 169 170 static int 171 peek(FILE *f) 172 { 173 int c; 174 175 c = getc(f); 176 if (c != EOF) 177 ungetc(c, f); 178 return c; 179 } 180 181 void 182 parse_conf(const char *conf, report_desc_t repd, int ignore) 183 { 184 FILE *f; 185 char *p; 186 int line; 187 char buf[SIZE], name[SIZE], value[SIZE], action[SIZE]; 188 char usage[SIZE], coll[SIZE]; 189 struct command *cmd; 190 struct hid_data *d; 191 struct hid_item h; 192 193 f = fopen(conf, "r"); 194 if (f == NULL) 195 err(1, "%s", conf); 196 197 for (line = 1; ; line++) { 198 if (fgets(buf, sizeof buf, f) == NULL) 199 break; 200 if (buf[0] == '#' || buf[0] == '\n') 201 continue; 202 p = strchr(buf, '\n'); 203 while (p && isspace(peek(f))) { 204 if (fgets(p, sizeof buf - strlen(buf), f) == NULL) 205 break; 206 p = strchr(buf, '\n'); 207 } 208 if (p) 209 *p = 0; 210 if (sscanf(buf, "%s %s %[^\n]", name, value, action) != 3) { 211 errx(1, "config file `%s', line %d, syntax error: %s", 212 conf, line, buf); 213 } 214 215 cmd = malloc(sizeof *cmd); 216 if (cmd == NULL) 217 err(1, "malloc failed"); 218 cmd->next = commands; 219 commands = cmd; 220 cmd->line = line; 221 222 if (strcmp(value, "*") == 0) { 223 cmd->anyvalue = 1; 224 } else { 225 cmd->anyvalue = 0; 226 if (sscanf(value, "%d", &cmd->value) != 1) 227 errx(1, "config file `%s', line %d, " 228 "bad value: %s\n", conf, line, value); 229 } 230 231 coll[0] = 0; 232 for (d = hid_start_parse(repd, 1 << hid_input); 233 hid_get_item(d, &h); ) { 234 if (verbose > 2) 235 printf("kind=%d usage=%x\n", h.kind, h.usage); 236 if (h.flags & HIO_CONST) 237 continue; 238 switch (h.kind) { 239 case hid_input: 240 snprintf(usage, sizeof usage, "%s:%s", 241 hid_usage_page(HID_PAGE(h.usage)), 242 hid_usage_in_page(h.usage)); 243 if (verbose > 2) 244 printf("usage %s\n", usage); 245 if (strcasecmp(usage, name) == 0) 246 goto foundhid; 247 if (coll[0]) { 248 snprintf(usage, sizeof usage, 249 "%s.%s:%s", coll+1, 250 hid_usage_page(HID_PAGE(h.usage)), 251 hid_usage_in_page(h.usage)); 252 if (verbose > 2) 253 printf("usage %s\n", usage); 254 if (strcasecmp(usage, name) == 0) 255 goto foundhid; 256 } 257 break; 258 case hid_collection: 259 snprintf(coll + strlen(coll), 260 sizeof coll - strlen(coll), ".%s:%s", 261 hid_usage_page(HID_PAGE(h.usage)), 262 hid_usage_in_page(h.usage)); 263 break; 264 case hid_endcollection: 265 if (coll[0]) 266 *strrchr(coll, '.') = 0; 267 break; 268 default: 269 break; 270 } 271 } 272 if (ignore) { 273 if (verbose) 274 warnx("ignore item '%s'\n", name); 275 continue; 276 } 277 errx(1, "config file `%s', line %d, HID item not found: `%s'\n", 278 conf, line, name); 279 280 foundhid: 281 hid_end_parse(d); 282 cmd->item = h; 283 cmd->name = strdup(name); 284 cmd->action = strdup(action); 285 286 if (verbose) 287 printf("PARSE:%d %s, %d, '%s'\n", cmd->line, name, 288 cmd->value, cmd->action); 289 } 290 fclose(f); 291 } 292 293 void 294 docmd(struct command *cmd, int value, const char *hid, int argc, char **argv) 295 { 296 char cmdbuf[SIZE], *p, *q; 297 size_t len; 298 int n, r; 299 300 for (p = cmd->action, q = cmdbuf; *p && q < &cmdbuf[SIZE-1]; ) { 301 if (*p == '$') { 302 p++; 303 len = &cmdbuf[SIZE-1] - q; 304 if (isdigit(*p)) { 305 n = strtol(p, &p, 10) - 1; 306 if (n >= 0 && n < argc) { 307 strncpy(q, argv[n], len); 308 q += strlen(q); 309 } 310 } else if (*p == 'V') { 311 p++; 312 snprintf(q, len, "%d", value); 313 q += strlen(q); 314 } else if (*p == 'N') { 315 p++; 316 strncpy(q, cmd->name, len); 317 q += strlen(q); 318 } else if (*p == 'H') { 319 p++; 320 strncpy(q, hid, len); 321 q += strlen(q); 322 } else if (*p) { 323 *q++ = *p++; 324 } 325 } else { 326 *q++ = *p++; 327 } 328 } 329 *q = 0; 330 331 if (verbose) 332 printf("system '%s'\n", cmdbuf); 333 r = system(cmdbuf); 334 if (verbose > 1 && r) 335 printf("return code = 0x%x\n", r); 336 } 337