usbhid.c revision 225839
115103Sphk/* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 215103Sphk/* $FreeBSD: head/usr.bin/usbhidctl/usbhid.c 225839 2011-09-28 14:52:25Z mav $ */ 315103Sphk 415103Sphk/* 515103Sphk * Copyright (c) 1998 The NetBSD Foundation, Inc. 615103Sphk * All rights reserved. 715103Sphk * 815103Sphk * This code is derived from software contributed to The NetBSD Foundation 915103Sphk * by Lennart Augustsson (augustss@netbsd.org). 1015103Sphk * 1115103Sphk * Redistribution and use in source and binary forms, with or without 1215103Sphk * modification, are permitted provided that the following conditions 1315103Sphk * are met: 1415103Sphk * 1. Redistributions of source code must retain the above copyright 1515103Sphk * notice, this list of conditions and the following disclaimer. 1615103Sphk * 2. Redistributions in binary form must reproduce the above copyright 1715103Sphk * notice, this list of conditions and the following disclaimer in the 1815103Sphk * documentation and/or other materials provided with the distribution. 1915103Sphk * 2015103Sphk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2115103Sphk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2215103Sphk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2315103Sphk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2415103Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2515103Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2615103Sphk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2715103Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2815103Sphk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2915103Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3015103Sphk * POSSIBILITY OF SUCH DAMAGE. 3115103Sphk */ 3215103Sphk 3315103Sphk#include <stdio.h> 3415103Sphk#include <stdlib.h> 3515103Sphk#include <string.h> 3615103Sphk#include <sys/types.h> 3715103Sphk#include <fcntl.h> 3815103Sphk#include <unistd.h> 3915103Sphk#include <err.h> 4050477Speter#include <ctype.h> 4115103Sphk#include <errno.h> 4215103Sphk#include <usbhid.h> 4386190Srwatson#include <dev/usb/usbhid.h> 4484611Srwatson 4515103Sphkstruct variable { 4615103Sphk char *name; 4715103Sphk int instance; 4815103Sphk int val; 4915103Sphk struct hid_item h; 5087275Srwatson struct variable *next; 5187275Srwatson} *vars; 5246155Sphk 5376078Sjhbint verbose = 0; 54105046Smikeint noname = 0; 5528918Skatoint hexdump = 0; 5615103Sphkint wflag = 0; 5715103Sphkint zflag = 0; 5815103Sphk 5915103Sphkstatic void usage(void); 6015103Sphkstatic void dumpitem(const char *label, struct hid_item *h); 6115103Sphkstatic void dumpitems(report_desc_t r); 6223382Sbdestatic void prdata(u_char *buf, struct hid_item *h); 6315103Sphkstatic void dumpdata(int f, report_desc_t r, int loop); 6415103Sphkstatic void writedata(int f, report_desc_t r); 6515103Sphk 6615103Sphkstatic void 6715103Sphkparceargs(report_desc_t r, int all, int nnames, char **names) 6848891Sphk{ 6948891Sphk struct hid_data *d; 7015103Sphk struct hid_item h; 7115103Sphk char colls[1000]; 7215103Sphk char hname[1000], *tmp1, *tmp2; 7315103Sphk struct variable *var, **pnext; 7415103Sphk int i, instance, cp, t; 7515103Sphk 7634925Sdufault pnext = &vars; 7734925Sdufault if (all) { 7834029Sdufault if (wflag) 7950465Smarcel errx(1, "Must not specify -w to read variables"); 8050465Smarcel cp = 0; 8189414Sarr for (d = hid_start_parse(r, 8289414Sarr 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 8386190Srwatson hid_get_item(d, &h); ) { 8486190Srwatson if (h.kind == hid_collection) { 8586190Srwatson cp += sprintf(&colls[cp], "%s%s:%s", 8686190Srwatson cp != 0 ? "." : "", 8750465Smarcel hid_usage_page(HID_PAGE(h.usage)), 8886189Srwatson hid_usage_in_page(h.usage)); 8988019Sluigi } else if (h.kind == hid_endcollection) { 9015103Sphk tmp1 = strrchr(colls, '.'); 9186189Srwatson if (tmp1 != NULL) { 9246381Sbillf cp -= strlen(tmp1); 9315103Sphk tmp1[0] = 0; 9486189Srwatson } else { 9546381Sbillf cp = 0; 9615103Sphk colls[0] = 0; 9786189Srwatson } 9846381Sbillf } 9915103Sphk if ((h.kind != hid_input && h.kind != hid_output && 10015103Sphk h.kind != hid_feature) || (h.flags & HIO_CONST)) 10186189Srwatson continue; 10246381Sbillf var = malloc(sizeof(*var)); 10315103Sphk memset(var, 0, sizeof(*var)); 10486189Srwatson asprintf(&var->name, "%s%s%s:%s", 10546381Sbillf colls, colls[0] != 0 ? "." : "", 10615103Sphk hid_usage_page(HID_PAGE(h.usage)), 10786189Srwatson hid_usage_in_page(h.usage)); 10846381Sbillf var->h = h; 10915103Sphk *pnext = var; 11086189Srwatson pnext = &var->next; 11180418Speter } 11280418Speter hid_end_parse(d); 11386189Srwatson return; 11446381Sbillf } 11515103Sphk for (i = 0; i < nnames; i++) { 11686189Srwatson var = malloc(sizeof(*var)); 117105046Smike memset(var, 0, sizeof(*var)); 11815103Sphk tmp1 = tmp2 = strdup(names[i]); 11986189Srwatson strsep(&tmp2, "="); 12046381Sbillf var->name = strsep(&tmp1, "#"); 12115103Sphk if (tmp1 != NULL) 12286189Srwatson var->instance = atoi(tmp1); 12346381Sbillf if (tmp2 != NULL) { 12415103Sphk if (!wflag) 12515103Sphk errx(1, "Must specify -w to write variables"); 12686189Srwatson var->val = atoi(tmp2); 12746381Sbillf } else 12815103Sphk if (wflag) 12986189Srwatson errx(1, "Must not specify -w to read variables"); 13046381Sbillf *pnext = var; 13115103Sphk pnext = &var->next; 13215103Sphk 13315103Sphk instance = 0; 13415103Sphk cp = 0; 13586189Srwatson for (d = hid_start_parse(r, 13646381Sbillf 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 13715103Sphk hid_get_item(d, &h); ) { 13831990Sgpalmer if (h.kind == hid_collection) { 13986189Srwatson cp += sprintf(&colls[cp], "%s%s:%s", 14046381Sbillf cp != 0 ? "." : "", 14131990Sgpalmer hid_usage_page(HID_PAGE(h.usage)), 14286189Srwatson hid_usage_in_page(h.usage)); 14346381Sbillf } else if (h.kind == hid_endcollection) { 14431990Sgpalmer tmp1 = strrchr(colls, '.'); 14515103Sphk if (tmp1 != NULL) { 14686189Srwatson cp -= strlen(tmp1); 14746381Sbillf tmp1[0] = 0; 14815103Sphk } else { 14986189Srwatson cp = 0; 15046381Sbillf colls[0] = 0; 15115103Sphk } 152106605Stmm } 153106605Stmm if ((h.kind != hid_input && h.kind != hid_output && 154106605Stmm h.kind != hid_feature) || (h.flags & HIO_CONST)) 155106605Stmm continue; 156106605Stmm snprintf(hname, sizeof(hname), "%s%s%s:%s", 157106605Stmm colls, colls[0] != 0 ? "." : "", 158106605Stmm hid_usage_page(HID_PAGE(h.usage)), 159106605Stmm hid_usage_in_page(h.usage)); 160106605Stmm t = strlen(hname) - strlen(var->name); 161106605Stmm if (t > 0) { 162106605Stmm if (strcmp(hname + t, var->name) != 0) 163106605Stmm continue; 164106605Stmm if (hname[t - 1] != '.') 165106605Stmm continue; 166106605Stmm } else if (strcmp(hname, var->name) != 0) 167106605Stmm continue; 168106605Stmm if (var->instance != instance++) 169106605Stmm continue; 170106605Stmm var->h = h; 171106605Stmm break; 172106605Stmm } 173106605Stmm hid_end_parse(d); 174106605Stmm if (var->h.usage == 0) 175106605Stmm errx(1, "Unknown item '%s'", var->name); 176106605Stmm } 177106605Stmm} 17828885Skato 17928885Skatostatic void 18046381Sbillfusage(void) 18128885Skato{ 18215103Sphk 18315103Sphk fprintf(stderr, 18446155Sphk "usage: %s -f device " 18562573Sphk "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n", 18646155Sphk getprogname()); 18787072Srwatson fprintf(stderr, 18887275Srwatson " %s -f device " 18946155Sphk "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n", 19015103Sphk getprogname()); 19191406Sjhb fprintf(stderr, 19287072Srwatson " %s -f device " 19357163Srwatson "[-t tablefile] [-v] [-z] -w name=value\n", 19486190Srwatson getprogname()); 19587275Srwatson exit(1); 19687275Srwatson} 19787275Srwatson 19887275Srwatsonstatic void 19987275Srwatsondumpitem(const char *label, struct hid_item *h) 20087275Srwatson{ 20187275Srwatson if ((h->flags & HIO_CONST) && !verbose) 20287275Srwatson return; 20387275Srwatson printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label, 20487275Srwatson h->report_ID, h->report_size, h->report_count, 20587072Srwatson hid_usage_page(HID_PAGE(h->usage)), 20687275Srwatson hid_usage_in_page(h->usage), 20787275Srwatson h->flags & HIO_CONST ? " Const" : "", 20887275Srwatson h->flags & HIO_VARIABLE ? "" : " Array"); 20987275Srwatson printf(", logical range %d..%d", 21087275Srwatson h->logical_minimum, h->logical_maximum); 21187275Srwatson if (h->physical_minimum != h->physical_maximum) 21287275Srwatson printf(", physical range %d..%d", 21387275Srwatson h->physical_minimum, h->physical_maximum); 21487275Srwatson if (h->unit) 21587275Srwatson printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 21657111Srwatson printf("\n"); 21786189Srwatson} 21846155Sphk 21946155Sphkstatic const char * 22046155Sphkhid_collection_type(int32_t type) 22146155Sphk{ 22286189Srwatson static char num[8]; 22346155Sphk 22446381Sbillf switch (type) { 22546155Sphk case 0: return ("Physical"); 22686190Srwatson case 1: return ("Application"); 22784611Srwatson case 2: return ("Logical"); 22887072Srwatson case 3: return ("Report"); 22984611Srwatson case 4: return ("Named_Array"); 23084611Srwatson case 5: return ("Usage_Switch"); 23186190Srwatson case 6: return ("Usage_Modifier"); 23284611Srwatson } 23315103Sphk snprintf(num, sizeof(num), "0x%02x", type); 23493686Sarr return (num); 23515103Sphk} 23693686Sarr 23793686Sarrstatic void 23893686Sarrdumpitems(report_desc_t r) 23915103Sphk{ 24062573Sphk struct hid_data *d; 24115103Sphk struct hid_item h; 24286145Srwatson int size; 24386140Srwatson 24415103Sphk for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { 24591406Sjhb switch (h.kind) { 24686145Srwatson case hid_collection: 24786140Srwatson printf("Collection type=%s page=%s usage=%s\n", 24886140Srwatson hid_collection_type(h.collection), 24986140Srwatson hid_usage_page(HID_PAGE(h.usage)), 25086140Srwatson hid_usage_in_page(h.usage)); 25187275Srwatson break; 25287275Srwatson case hid_endcollection: 25386145Srwatson printf("End collection\n"); 25487275Srwatson break; 25587275Srwatson case hid_input: 25686140Srwatson dumpitem("Input ", &h); 25786140Srwatson break; 25886140Srwatson case hid_output: 25986140Srwatson dumpitem("Output ", &h); 26086140Srwatson break; 26186140Srwatson case hid_feature: 26286140Srwatson dumpitem("Feature", &h); 26386140Srwatson break; 26486145Srwatson } 26587275Srwatson } 26687072Srwatson hid_end_parse(d); 26787275Srwatson size = hid_report_size(r, hid_input, -1); 26887275Srwatson printf("Total input size %d bytes\n", size); 26986140Srwatson 27087275Srwatson size = hid_report_size(r, hid_output, -1); 27186145Srwatson printf("Total output size %d bytes\n", size); 27287275Srwatson 27386140Srwatson size = hid_report_size(r, hid_feature, -1); 27493686Sarr printf("Total feature size %d bytes\n", size); 27587072Srwatson} 27693686Sarr 27793686Sarrstatic void 27886140Srwatsonprdata(u_char *buf, struct hid_item *h) 27993686Sarr{ 28086140Srwatson u_int data; 28193686Sarr int i, pos; 28286140Srwatson 28386140Srwatson pos = h->pos; 28415103Sphk for (i = 0; i < h->report_count; i++) { 28515103Sphk data = hid_get_data(buf, h); 28683990Srwatson if (i > 0) 28783990Srwatson printf(" "); 28883990Srwatson if (h->logical_minimum < 0) 28961370Srwatson printf("%d", (int)data); 29015103Sphk else 29117281Swollman printf("%u", data); 29246381Sbillf if (hexdump) 29315103Sphk printf(" [0x%x]", data); 29486190Srwatson h->pos += h->report_size; 29578609Spirzyk } 29615103Sphk h->pos = pos; 29715103Sphk} 29815103Sphk 29986189Srwatsonstatic void 30015103Sphkdumpdata(int f, report_desc_t rd, int loop) 30115103Sphk{ 30286189Srwatson struct variable *var; 30346381Sbillf int dlen, havedata, i, match, r, rid, use_rid; 30486189Srwatson u_char *dbuf; 30546381Sbillf enum hid_kind kind; 30686189Srwatson 30746381Sbillf kind = 0; 30886189Srwatson rid = -1; 30946381Sbillf use_rid = !!hid_get_report_id(f); 31086189Srwatson do { 31146381Sbillf if (kind < 3) { 31286189Srwatson if (++rid >= 256) { 31346381Sbillf rid = 0; 31418540Sbde kind++; 31586189Srwatson } 31646381Sbillf if (kind >= 3) 31786189Srwatson rid = -1; 31846381Sbillf for (var = vars; var; var = var->next) { 31986189Srwatson if (rid == var->h.report_ID && 32086189Srwatson kind == var->h.kind) 32146381Sbillf break; 32286189Srwatson } 32346381Sbillf if (var == NULL) 32486189Srwatson continue; 32546381Sbillf } 32686189Srwatson dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid); 32746381Sbillf if (dlen <= 0) 32886189Srwatson continue; 32946381Sbillf dbuf = malloc(dlen); 33086189Srwatson memset(dbuf, 0, dlen); 33146381Sbillf if (kind < 3) { 33286189Srwatson dbuf[0] = rid; 33346381Sbillf r = hid_get_report(f, kind, dbuf, dlen); 33486189Srwatson if (r < 0) 33546381Sbillf warn("hid_get_report(rid %d)", rid); 33686189Srwatson havedata = !r && (rid == 0 || dbuf[0] == rid); 33746381Sbillf if (rid != 0) 33886189Srwatson dbuf[0] = rid; 33946381Sbillf } else { 34086189Srwatson r = read(f, dbuf, dlen); 34146381Sbillf if (r < 1) 34248891Sphk err(1, "read error"); 34348891Sphk havedata = 1; 34486189Srwatson } 34548891Sphk if (verbose) { 34648891Sphk printf("Got %s report %d (%d bytes):", 34786189Srwatson kind == hid_output ? "output" : 34848891Sphk kind == hid_feature ? "feature" : "input", 34948927Sphk use_rid ? dbuf[0] : 0, dlen); 35049535Sphk if (havedata) { 351104043Sphk for (i = 0; i < dlen; i++) 352104043Sphk printf(" %02x", dbuf[i]); 35358926Sphk } 35460041Sphk printf("\n"); 35558926Sphk } 35658926Sphk match = 0; 35758926Sphk for (var = vars; var; var = var->next) { 35858926Sphk if ((kind < 3 ? kind : hid_input) != var->h.kind) 35958926Sphk continue; 36072376Sjake if (var->h.report_ID != 0 && 36172376Sjake dbuf[0] != var->h.report_ID) 36272376Sjake continue; 36372376Sjake 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 376static void 377writedata(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 442int 443main(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