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