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