1 /* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 2 /* $FreeBSD$ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (augustss@netbsd.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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. 19 * 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. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/types.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #include <err.h> 40 #include <ctype.h> 41 #include <errno.h> 42 #include <usbhid.h> 43 #include <dev/usb/usbhid.h> 44 45 static struct variable { 46 char *name; 47 int instance; 48 int val; 49 struct hid_item h; 50 struct variable *next; 51 } *vars; 52 53 static int verbose = 0; 54 static int noname = 0; 55 static int hexdump = 0; 56 static int wflag = 0; 57 static int zflag = 0; 58 59 static void usage(void); 60 static void dumpitem(const char *label, struct hid_item *h); 61 static void dumpitems(report_desc_t r); 62 static void prdata(u_char *buf, struct hid_item *h); 63 static void dumpdata(int f, report_desc_t r, int loop); 64 static void writedata(int f, report_desc_t r); 65 66 static void 67 parceargs(report_desc_t r, int all, int nnames, char **names) 68 { 69 struct hid_data *d; 70 struct hid_item h; 71 char colls[1000]; 72 char hname[1000], *tmp1, *tmp2; 73 struct variable *var, **pnext; 74 int i, instance, cp, t; 75 76 pnext = &vars; 77 if (all) { 78 if (wflag) 79 errx(1, "Must not specify -w to read variables"); 80 cp = 0; 81 for (d = hid_start_parse(r, 82 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 83 hid_get_item(d, &h); ) { 84 if (h.kind == hid_collection) { 85 cp += sprintf(&colls[cp], "%s%s:%s", 86 cp != 0 ? "." : "", 87 hid_usage_page(HID_PAGE(h.usage)), 88 hid_usage_in_page(h.usage)); 89 } else if (h.kind == hid_endcollection) { 90 tmp1 = strrchr(colls, '.'); 91 if (tmp1 != NULL) { 92 cp -= strlen(tmp1); 93 tmp1[0] = 0; 94 } else { 95 cp = 0; 96 colls[0] = 0; 97 } 98 } 99 if ((h.kind != hid_input && h.kind != hid_output && 100 h.kind != hid_feature) || (h.flags & HIO_CONST)) 101 continue; 102 var = malloc(sizeof(*var)); 103 memset(var, 0, sizeof(*var)); 104 asprintf(&var->name, "%s%s%s:%s", 105 colls, colls[0] != 0 ? "." : "", 106 hid_usage_page(HID_PAGE(h.usage)), 107 hid_usage_in_page(h.usage)); 108 var->h = h; 109 *pnext = var; 110 pnext = &var->next; 111 } 112 hid_end_parse(d); 113 return; 114 } 115 for (i = 0; i < nnames; i++) { 116 var = malloc(sizeof(*var)); 117 memset(var, 0, sizeof(*var)); 118 tmp1 = tmp2 = strdup(names[i]); 119 strsep(&tmp2, "="); 120 var->name = strsep(&tmp1, "#"); 121 if (tmp1 != NULL) 122 var->instance = atoi(tmp1); 123 if (tmp2 != NULL) { 124 if (!wflag) 125 errx(1, "Must specify -w to write variables"); 126 var->val = atoi(tmp2); 127 } else 128 if (wflag) 129 errx(1, "Must not specify -w to read variables"); 130 *pnext = var; 131 pnext = &var->next; 132 133 instance = 0; 134 cp = 0; 135 for (d = hid_start_parse(r, 136 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 137 hid_get_item(d, &h); ) { 138 if (h.kind == hid_collection) { 139 cp += sprintf(&colls[cp], "%s%s:%s", 140 cp != 0 ? "." : "", 141 hid_usage_page(HID_PAGE(h.usage)), 142 hid_usage_in_page(h.usage)); 143 } else if (h.kind == hid_endcollection) { 144 tmp1 = strrchr(colls, '.'); 145 if (tmp1 != NULL) { 146 cp -= strlen(tmp1); 147 tmp1[0] = 0; 148 } else { 149 cp = 0; 150 colls[0] = 0; 151 } 152 } 153 if ((h.kind != hid_input && h.kind != hid_output && 154 h.kind != hid_feature) || (h.flags & HIO_CONST)) 155 continue; 156 snprintf(hname, sizeof(hname), "%s%s%s:%s", 157 colls, colls[0] != 0 ? "." : "", 158 hid_usage_page(HID_PAGE(h.usage)), 159 hid_usage_in_page(h.usage)); 160 t = strlen(hname) - strlen(var->name); 161 if (t > 0) { 162 if (strcmp(hname + t, var->name) != 0) 163 continue; 164 if (hname[t - 1] != '.') 165 continue; 166 } else if (strcmp(hname, var->name) != 0) 167 continue; 168 if (var->instance != instance++) 169 continue; 170 var->h = h; 171 break; 172 } 173 hid_end_parse(d); 174 if (var->h.usage == 0) 175 errx(1, "Unknown item '%s'", var->name); 176 } 177 } 178 179 static void 180 usage(void) 181 { 182 183 fprintf(stderr, 184 "usage: %s -f device " 185 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] name ...\n", 186 getprogname()); 187 fprintf(stderr, 188 " %s -f device " 189 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] -a\n", 190 getprogname()); 191 fprintf(stderr, 192 " %s -f device " 193 "[-t tablefile] [-v] [-z] -w name=value\n", 194 getprogname()); 195 exit(1); 196 } 197 198 static void 199 dumpitem(const char *label, struct hid_item *h) 200 { 201 if ((h->flags & HIO_CONST) && !verbose) 202 return; 203 printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label, 204 h->report_ID, h->report_size, h->report_count, 205 hid_usage_page(HID_PAGE(h->usage)), 206 hid_usage_in_page(h->usage), 207 h->flags & HIO_CONST ? " Const" : "", 208 h->flags & HIO_VARIABLE ? "" : " Array"); 209 printf(", logical range %d..%d", 210 h->logical_minimum, h->logical_maximum); 211 if (h->physical_minimum != h->physical_maximum) 212 printf(", physical range %d..%d", 213 h->physical_minimum, h->physical_maximum); 214 if (h->unit) 215 printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 216 printf("\n"); 217 } 218 219 static const char * 220 hid_collection_type(int32_t type) 221 { 222 static char num[8]; 223 224 switch (type) { 225 case 0: return ("Physical"); 226 case 1: return ("Application"); 227 case 2: return ("Logical"); 228 case 3: return ("Report"); 229 case 4: return ("Named_Array"); 230 case 5: return ("Usage_Switch"); 231 case 6: return ("Usage_Modifier"); 232 } 233 snprintf(num, sizeof(num), "0x%02x", type); 234 return (num); 235 } 236 237 static void 238 dumpitems(report_desc_t r) 239 { 240 struct hid_data *d; 241 struct hid_item h; 242 int size; 243 244 for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { 245 switch (h.kind) { 246 case hid_collection: 247 printf("Collection type=%s page=%s usage=%s\n", 248 hid_collection_type(h.collection), 249 hid_usage_page(HID_PAGE(h.usage)), 250 hid_usage_in_page(h.usage)); 251 break; 252 case hid_endcollection: 253 printf("End collection\n"); 254 break; 255 case hid_input: 256 dumpitem("Input ", &h); 257 break; 258 case hid_output: 259 dumpitem("Output ", &h); 260 break; 261 case hid_feature: 262 dumpitem("Feature", &h); 263 break; 264 } 265 } 266 hid_end_parse(d); 267 size = hid_report_size(r, hid_input, -1); 268 printf("Total input size %d bytes\n", size); 269 270 size = hid_report_size(r, hid_output, -1); 271 printf("Total output size %d bytes\n", size); 272 273 size = hid_report_size(r, hid_feature, -1); 274 printf("Total feature size %d bytes\n", size); 275 } 276 277 static void 278 prdata(u_char *buf, struct hid_item *h) 279 { 280 u_int data; 281 int i, pos; 282 283 pos = h->pos; 284 for (i = 0; i < h->report_count; i++) { 285 data = hid_get_data(buf, h); 286 if (i > 0) 287 printf(" "); 288 if (h->logical_minimum < 0) 289 printf("%d", (int)data); 290 else 291 printf("%u", data); 292 if (hexdump) 293 printf(" [0x%x]", data); 294 h->pos += h->report_size; 295 } 296 h->pos = pos; 297 } 298 299 static void 300 dumpdata(int f, report_desc_t rd, int loop) 301 { 302 struct variable *var; 303 int dlen, havedata, i, match, r, rid, use_rid; 304 u_char *dbuf; 305 enum hid_kind kind; 306 307 kind = zflag ? 3 : 0; 308 rid = -1; 309 use_rid = !!hid_get_report_id(f); 310 do { 311 if (kind < 3) { 312 if (++rid >= 256) { 313 rid = 0; 314 kind++; 315 } 316 if (kind >= 3) 317 rid = -1; 318 for (var = vars; var; var = var->next) { 319 if (rid == var->h.report_ID && 320 kind == var->h.kind) 321 break; 322 } 323 if (var == NULL) 324 continue; 325 } 326 dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid); 327 if (dlen <= 0) 328 continue; 329 dbuf = malloc(dlen); 330 memset(dbuf, 0, dlen); 331 if (kind < 3) { 332 dbuf[0] = rid; 333 r = hid_get_report(f, kind, dbuf, dlen); 334 if (r < 0) 335 warn("hid_get_report(rid %d)", rid); 336 havedata = !r && (rid == 0 || dbuf[0] == rid); 337 if (rid != 0) 338 dbuf[0] = rid; 339 } else { 340 r = read(f, dbuf, dlen); 341 if (r < 1) 342 err(1, "read error"); 343 havedata = 1; 344 } 345 if (verbose) { 346 printf("Got %s report %d (%d bytes):", 347 kind == hid_output ? "output" : 348 kind == hid_feature ? "feature" : "input", 349 use_rid ? dbuf[0] : 0, dlen); 350 if (havedata) { 351 for (i = 0; i < dlen; i++) 352 printf(" %02x", dbuf[i]); 353 } 354 printf("\n"); 355 } 356 match = 0; 357 for (var = vars; var; var = var->next) { 358 if ((kind < 3 ? kind : hid_input) != var->h.kind) 359 continue; 360 if (var->h.report_ID != 0 && 361 dbuf[0] != var->h.report_ID) 362 continue; 363 match = 1; 364 if (!noname) 365 printf("%s=", var->name); 366 if (havedata) 367 prdata(dbuf, &var->h); 368 printf("\n"); 369 } 370 if (match) 371 printf("\n"); 372 free(dbuf); 373 } while (loop || kind < 3); 374 } 375 376 static void 377 writedata(int f, report_desc_t rd) 378 { 379 struct variable *var; 380 int dlen, i, r, rid; 381 u_char *dbuf; 382 enum hid_kind kind; 383 384 kind = 0; 385 rid = 0; 386 for (kind = 0; kind < 3; kind ++) { 387 for (rid = 0; rid < 256; rid ++) { 388 for (var = vars; var; var = var->next) { 389 if (rid == var->h.report_ID && kind == var->h.kind) 390 break; 391 } 392 if (var == NULL) 393 continue; 394 dlen = hid_report_size(rd, kind, rid); 395 if (dlen <= 0) 396 continue; 397 dbuf = malloc(dlen); 398 memset(dbuf, 0, dlen); 399 dbuf[0] = rid; 400 if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) { 401 if (verbose) { 402 printf("Got %s report %d (%d bytes):", 403 kind == hid_input ? "input" : 404 kind == hid_output ? "output" : "feature", 405 rid, dlen); 406 for (i = 0; i < dlen; i++) 407 printf(" %02x", dbuf[i]); 408 printf("\n"); 409 } 410 } else if (!zflag) { 411 warn("hid_get_report(rid %d)", rid); 412 if (verbose) { 413 printf("Can't get %s report %d (%d bytes). " 414 "Will be initialized with zeros.\n", 415 kind == hid_input ? "input" : 416 kind == hid_output ? "output" : "feature", 417 rid, dlen); 418 } 419 } 420 for (var = vars; var; var = var->next) { 421 if (rid != var->h.report_ID || kind != var->h.kind) 422 continue; 423 hid_set_data(dbuf, &var->h, var->val); 424 } 425 if (verbose) { 426 printf("Setting %s report %d (%d bytes):", 427 kind == hid_output ? "output" : 428 kind == hid_feature ? "feature" : "input", 429 rid, dlen); 430 for (i = 0; i < dlen; i++) 431 printf(" %02x", dbuf[i]); 432 printf("\n"); 433 } 434 r = hid_set_report(f, kind, dbuf, dlen); 435 if (r != 0) 436 warn("hid_set_report(rid %d)", rid); 437 free(dbuf); 438 } 439 } 440 } 441 442 int 443 main(int argc, char **argv) 444 { 445 report_desc_t r; 446 char *table = 0; 447 char devnam[100], *dev = NULL; 448 int f; 449 int all = 0; 450 int ch; 451 int repdump = 0; 452 int loop = 0; 453 454 while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) { 455 switch(ch) { 456 case 'a': 457 all++; 458 break; 459 case 'f': 460 dev = optarg; 461 break; 462 case 'l': 463 loop ^= 1; 464 break; 465 case 'n': 466 noname++; 467 break; 468 case 'r': 469 repdump++; 470 break; 471 case 't': 472 table = optarg; 473 break; 474 case 'v': 475 verbose++; 476 break; 477 case 'w': 478 wflag = 1; 479 break; 480 case 'x': 481 hexdump = 1; 482 break; 483 case 'z': 484 zflag = 1; 485 break; 486 case '?': 487 default: 488 usage(); 489 } 490 } 491 argc -= optind; 492 argv += optind; 493 if (dev == NULL) 494 usage(); 495 496 if (argc == 0 && !all && !repdump) 497 usage(); 498 499 if (dev[0] != '/') { 500 if (isdigit(dev[0])) 501 snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 502 else 503 snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 504 dev = devnam; 505 } 506 507 hid_init(table); 508 509 f = open(dev, O_RDWR); 510 if (f < 0) 511 err(1, "%s", dev); 512 513 r = hid_get_report_desc(f); 514 if (r == 0) 515 errx(1, "USB_GET_REPORT_DESC"); 516 517 if (repdump) { 518 printf("Report descriptor:\n"); 519 dumpitems(r); 520 } 521 if (argc != 0 || all) { 522 parceargs(r, all, argc, argv); 523 if (wflag) 524 writedata(f, r); 525 else 526 dumpdata(f, r, loop); 527 } 528 529 hid_dispose_report_desc(r); 530 exit(0); 531 } 532