usbhid.c revision 164531
162642Sn_hibma/* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 262642Sn_hibma/* $FreeBSD: head/usr.bin/usbhidctl/usbhid.c 164531 2006-11-23 00:20:54Z grog $ */ 362642Sn_hibma 462642Sn_hibma/* 562642Sn_hibma * Copyright (c) 1998 The NetBSD Foundation, Inc. 662642Sn_hibma * All rights reserved. 762642Sn_hibma * 862642Sn_hibma * This code is derived from software contributed to The NetBSD Foundation 962642Sn_hibma * by Lennart Augustsson (augustss@netbsd.org). 1062642Sn_hibma * 1162642Sn_hibma * Redistribution and use in source and binary forms, with or without 1262642Sn_hibma * modification, are permitted provided that the following conditions 1362642Sn_hibma * are met: 1462642Sn_hibma * 1. Redistributions of source code must retain the above copyright 1562642Sn_hibma * notice, this list of conditions and the following disclaimer. 1662642Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright 1762642Sn_hibma * notice, this list of conditions and the following disclaimer in the 1862642Sn_hibma * documentation and/or other materials provided with the distribution. 1962642Sn_hibma * 3. All advertising materials mentioning features or use of this software 2062642Sn_hibma * must display the following acknowledgement: 2162642Sn_hibma * This product includes software developed by the NetBSD 2262642Sn_hibma * Foundation, Inc. and its contributors. 2362642Sn_hibma * 4. Neither the name of The NetBSD Foundation nor the names of its 2462642Sn_hibma * contributors may be used to endorse or promote products derived 2562642Sn_hibma * from this software without specific prior written permission. 2662642Sn_hibma * 2762642Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2862642Sn_hibma * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2962642Sn_hibma * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3062642Sn_hibma * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3162642Sn_hibma * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3262642Sn_hibma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3362642Sn_hibma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3462642Sn_hibma * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3562642Sn_hibma * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3662642Sn_hibma * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3762642Sn_hibma * POSSIBILITY OF SUCH DAMAGE. 3862642Sn_hibma */ 3962642Sn_hibma 4062642Sn_hibma#include <stdio.h> 4162642Sn_hibma#include <stdlib.h> 4262642Sn_hibma#include <string.h> 4362642Sn_hibma#include <sys/types.h> 4462642Sn_hibma#include <fcntl.h> 4562642Sn_hibma#include <sys/ioctl.h> 4662642Sn_hibma#include <unistd.h> 4762642Sn_hibma#include <err.h> 4862642Sn_hibma#include <ctype.h> 4962642Sn_hibma#include <errno.h> 50113273Smdodd#include <usbhid.h> 5162642Sn_hibma#include <dev/usb/usb.h> 5262642Sn_hibma#include <dev/usb/usbhid.h> 5362642Sn_hibma 5462642Sn_hibmaint verbose = 0; 5562642Sn_hibmaint all = 0; 5662642Sn_hibmaint noname = 0; 57164531Sgrogint hexdump = 0; 58113273Smdoddstatic int reportid; 5962642Sn_hibma 6062642Sn_hibmachar **names; 6162642Sn_hibmaint nnames; 6262642Sn_hibma 6362642Sn_hibmavoid prbits(int bits, char **strs, int n); 6462642Sn_hibmavoid usage(void); 6587699Smarkmvoid dumpitem(const char *label, struct hid_item *h); 6662642Sn_hibmavoid dumpitems(report_desc_t r); 6762642Sn_hibmavoid rev(struct hid_item **p); 6862642Sn_hibmavoid prdata(u_char *buf, struct hid_item *h); 6962642Sn_hibmavoid dumpdata(int f, report_desc_t r, int loop); 7062642Sn_hibmaint gotname(char *n); 7162642Sn_hibma 7262642Sn_hibmaint 7362642Sn_hibmagotname(char *n) 7462642Sn_hibma{ 7562642Sn_hibma int i; 7662642Sn_hibma 7762642Sn_hibma for (i = 0; i < nnames; i++) 7862642Sn_hibma if (strcmp(names[i], n) == 0) 7962642Sn_hibma return 1; 8062642Sn_hibma return 0; 8162642Sn_hibma} 8262642Sn_hibma 8362642Sn_hibmavoid 8462642Sn_hibmaprbits(int bits, char **strs, int n) 8562642Sn_hibma{ 8662642Sn_hibma int i; 8762642Sn_hibma 8862642Sn_hibma for(i = 0; i < n; i++, bits >>= 1) 8962642Sn_hibma if (strs[i*2]) 9062642Sn_hibma printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]); 9162642Sn_hibma} 9262642Sn_hibma 9362642Sn_hibmavoid 9462642Sn_hibmausage(void) 9562642Sn_hibma{ 9662642Sn_hibma extern char *__progname; 9762642Sn_hibma 98164531Sgrog fprintf(stderr, 99164531Sgrog "usage: %s -f device " 100164531Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [x] name ...\n", 101164531Sgrog __progname); 102164531Sgrog fprintf(stderr, 103164531Sgrog " %s -f device " 104164531Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [x] -a\n", 105164531Sgrog __progname); 10662642Sn_hibma exit(1); 10762642Sn_hibma} 10862642Sn_hibma 10962642Sn_hibmavoid 11087699Smarkmdumpitem(const char *label, struct hid_item *h) 11162642Sn_hibma{ 11262642Sn_hibma if ((h->flags & HIO_CONST) && !verbose) 11362642Sn_hibma return; 11462642Sn_hibma printf("%s size=%d count=%d page=%s usage=%s%s", label, 115164531Sgrog h->report_size, h->report_count, 116164531Sgrog hid_usage_page(HID_PAGE(h->usage)), 11762642Sn_hibma hid_usage_in_page(h->usage), 11862642Sn_hibma h->flags & HIO_CONST ? " Const" : ""); 11962642Sn_hibma printf(", logical range %d..%d", 12062642Sn_hibma h->logical_minimum, h->logical_maximum); 12162642Sn_hibma if (h->physical_minimum != h->physical_maximum) 12262642Sn_hibma printf(", physical range %d..%d", 12362642Sn_hibma h->physical_minimum, h->physical_maximum); 12462642Sn_hibma if (h->unit) 12562642Sn_hibma printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 12662642Sn_hibma printf("\n"); 12762642Sn_hibma} 12862642Sn_hibma 12962642Sn_hibmavoid 13062642Sn_hibmadumpitems(report_desc_t r) 13162642Sn_hibma{ 13262642Sn_hibma struct hid_data *d; 13362642Sn_hibma struct hid_item h; 13467256Sn_hibma int size; 13562642Sn_hibma 136113273Smdodd for (d = hid_start_parse(r, ~0, reportid); hid_get_item(d, &h); ) { 13762642Sn_hibma switch (h.kind) { 13862642Sn_hibma case hid_collection: 13962642Sn_hibma printf("Collection page=%s usage=%s\n", 140164531Sgrog hid_usage_page(HID_PAGE(h.usage)), 14162642Sn_hibma hid_usage_in_page(h.usage)); 14262642Sn_hibma break; 14362642Sn_hibma case hid_endcollection: 14462642Sn_hibma printf("End collection\n"); 14562642Sn_hibma break; 14662642Sn_hibma case hid_input: 14762642Sn_hibma dumpitem("Input ", &h); 14862642Sn_hibma break; 14962642Sn_hibma case hid_output: 15062642Sn_hibma dumpitem("Output ", &h); 15162642Sn_hibma break; 15262642Sn_hibma case hid_feature: 15362642Sn_hibma dumpitem("Feature", &h); 15462642Sn_hibma break; 15562642Sn_hibma } 15662642Sn_hibma } 15762642Sn_hibma hid_end_parse(d); 15867256Sn_hibma size = hid_report_size(r, 0, hid_input); 15975606Sn_hibma printf("Total input size %d bytes\n", size); 16062642Sn_hibma 16167256Sn_hibma size = hid_report_size(r, 0, hid_output); 16267256Sn_hibma printf("Total output size %d bytes\n", size); 16367256Sn_hibma 16467256Sn_hibma size = hid_report_size(r, 0, hid_feature); 16567256Sn_hibma printf("Total feature size %d bytes\n", size); 16662642Sn_hibma} 16762642Sn_hibma 16862642Sn_hibmavoid 16962642Sn_hibmarev(struct hid_item **p) 17062642Sn_hibma{ 17162642Sn_hibma struct hid_item *cur, *prev, *next; 17262642Sn_hibma 17362642Sn_hibma prev = 0; 17462642Sn_hibma cur = *p; 17562642Sn_hibma while(cur != 0) { 17662642Sn_hibma next = cur->next; 17762642Sn_hibma cur->next = prev; 17862642Sn_hibma prev = cur; 17962642Sn_hibma cur = next; 18062642Sn_hibma } 18162642Sn_hibma *p = prev; 18262642Sn_hibma} 18362642Sn_hibma 18462642Sn_hibmavoid 18562642Sn_hibmaprdata(u_char *buf, struct hid_item *h) 18662642Sn_hibma{ 18762642Sn_hibma u_int data; 18862642Sn_hibma int i, pos; 18962642Sn_hibma 19062642Sn_hibma pos = h->pos; 19162642Sn_hibma for (i = 0; i < h->report_count; i++) { 19262642Sn_hibma data = hid_get_data(buf, h); 19362642Sn_hibma if (h->logical_minimum < 0) 19462642Sn_hibma printf("%d", (int)data); 19562642Sn_hibma else 19662642Sn_hibma printf("%u", data); 197164531Sgrog if (hexdump) 198164531Sgrog printf(" [0x%x]", data); 19962642Sn_hibma pos += h->report_size; 20062642Sn_hibma } 20162642Sn_hibma} 20262642Sn_hibma 20362642Sn_hibmavoid 20462642Sn_hibmadumpdata(int f, report_desc_t rd, int loop) 20562642Sn_hibma{ 20662642Sn_hibma struct hid_data *d; 20762642Sn_hibma struct hid_item h, *hids, *n; 20862642Sn_hibma int r, dlen; 20962642Sn_hibma u_char *dbuf; 21062642Sn_hibma static int one = 1; 21162642Sn_hibma u_int32_t colls[100]; 21262642Sn_hibma int sp = 0; 21362642Sn_hibma char namebuf[10000], *namep; 21462642Sn_hibma 21562642Sn_hibma hids = 0; 216164531Sgrog for (d = hid_start_parse(rd, 1<<hid_input, reportid); 21762642Sn_hibma hid_get_item(d, &h); ) { 21862642Sn_hibma if (h.kind == hid_collection) 21962642Sn_hibma colls[++sp] = h.usage; 22062642Sn_hibma else if (h.kind == hid_endcollection) 22162642Sn_hibma --sp; 22262642Sn_hibma if (h.kind != hid_input || (h.flags & HIO_CONST)) 22362642Sn_hibma continue; 22462642Sn_hibma h.next = hids; 22562642Sn_hibma h.collection = colls[sp]; 22662642Sn_hibma hids = malloc(sizeof *hids); 22762642Sn_hibma *hids = h; 22862642Sn_hibma } 22962642Sn_hibma hid_end_parse(d); 23062642Sn_hibma rev(&hids); 23167256Sn_hibma dlen = hid_report_size(rd, 0, hid_input); 23262642Sn_hibma dbuf = malloc(dlen); 23362642Sn_hibma if (!loop) 23462642Sn_hibma if (ioctl(f, USB_SET_IMMED, &one) < 0) { 23562642Sn_hibma if (errno == EOPNOTSUPP) 23662642Sn_hibma warnx("device does not support immediate mode, only changes reported."); 23762642Sn_hibma else 23862642Sn_hibma err(1, "USB_SET_IMMED"); 23962642Sn_hibma } 24062642Sn_hibma do { 24162642Sn_hibma r = read(f, dbuf, dlen); 24262642Sn_hibma if (r != dlen) { 24362642Sn_hibma err(1, "bad read %d != %d", r, dlen); 24462642Sn_hibma } 24562642Sn_hibma for (n = hids; n; n = n->next) { 24662642Sn_hibma namep = namebuf; 24762642Sn_hibma namep += sprintf(namep, "%s:%s.", 24862642Sn_hibma hid_usage_page(HID_PAGE(n->collection)), 24962642Sn_hibma hid_usage_in_page(n->collection)); 25062642Sn_hibma namep += sprintf(namep, "%s:%s", 25162642Sn_hibma hid_usage_page(HID_PAGE(n->usage)), 25262642Sn_hibma hid_usage_in_page(n->usage)); 25362642Sn_hibma if (all || gotname(namebuf)) { 25462642Sn_hibma if (!noname) 25562642Sn_hibma printf("%s=", namebuf); 256115317Smdodd prdata(dbuf + (reportid != 0), n); 25762642Sn_hibma printf("\n"); 25862642Sn_hibma } 25962642Sn_hibma } 26062642Sn_hibma if (loop) 26162642Sn_hibma printf("\n"); 26262642Sn_hibma } while (loop); 26362642Sn_hibma free(dbuf); 26462642Sn_hibma} 26562642Sn_hibma 26662642Sn_hibmaint 26762642Sn_hibmamain(int argc, char **argv) 26862642Sn_hibma{ 26962642Sn_hibma int f; 27062642Sn_hibma report_desc_t r; 27187699Smarkm char devnam[100], *dev = 0; 27262642Sn_hibma int ch; 27362642Sn_hibma int repdump = 0; 27462642Sn_hibma int loop = 0; 27562642Sn_hibma char *table = 0; 27662642Sn_hibma 277164531Sgrog while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) { 27862642Sn_hibma switch(ch) { 27962642Sn_hibma case 'a': 28062642Sn_hibma all++; 28162642Sn_hibma break; 28262642Sn_hibma case 'f': 28362642Sn_hibma dev = optarg; 28462642Sn_hibma break; 28562642Sn_hibma case 'l': 28662642Sn_hibma loop ^= 1; 28762642Sn_hibma break; 28862642Sn_hibma case 'n': 28962642Sn_hibma noname++; 29062642Sn_hibma break; 29162642Sn_hibma case 'r': 29262642Sn_hibma repdump++; 29362642Sn_hibma break; 29462642Sn_hibma case 't': 29562642Sn_hibma table = optarg; 29662642Sn_hibma break; 29762642Sn_hibma case 'v': 29862642Sn_hibma verbose++; 29962642Sn_hibma break; 300164531Sgrog case 'x': 301164531Sgrog hexdump ^= 1; 302164531Sgrog break; 30362642Sn_hibma case '?': 30462642Sn_hibma default: 30562642Sn_hibma usage(); 30662642Sn_hibma } 30762642Sn_hibma } 30862642Sn_hibma argc -= optind; 30962642Sn_hibma argv += optind; 31062642Sn_hibma if (dev == 0) 31162642Sn_hibma usage(); 31262642Sn_hibma names = argv; 31362642Sn_hibma nnames = argc; 31462642Sn_hibma 31562642Sn_hibma if (nnames == 0 && !all && !repdump) 31662642Sn_hibma usage(); 31762642Sn_hibma 31862642Sn_hibma if (dev[0] != '/') { 31962642Sn_hibma if (isdigit(dev[0])) 32087699Smarkm snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 32162642Sn_hibma else 32287699Smarkm snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 32387699Smarkm dev = devnam; 32462642Sn_hibma } 32562642Sn_hibma 32662642Sn_hibma hid_init(table); 32762642Sn_hibma 32862642Sn_hibma f = open(dev, O_RDWR); 32962642Sn_hibma if (f < 0) 33062642Sn_hibma err(1, "%s", dev); 33162642Sn_hibma 33262642Sn_hibma r = hid_get_report_desc(f); 333164531Sgrog if (r == 0) 33462642Sn_hibma errx(1, "USB_GET_REPORT_DESC"); 335164531Sgrog 33662642Sn_hibma if (repdump) { 33762642Sn_hibma printf("Report descriptor:\n"); 33862642Sn_hibma dumpitems(r); 33962642Sn_hibma } 34062642Sn_hibma if (nnames != 0 || all) 34162642Sn_hibma dumpdata(f, r, loop); 34262642Sn_hibma 34362642Sn_hibma hid_dispose_report_desc(r); 34462642Sn_hibma exit(0); 34562642Sn_hibma} 346