usbhid.c revision 188945
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 188945 2009-02-23 18:36:54Z thompsa $ */ 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 <unistd.h> 4662642Sn_hibma#include <err.h> 4762642Sn_hibma#include <ctype.h> 4862642Sn_hibma#include <errno.h> 49113273Smdodd#include <usbhid.h> 50188945Sthompsa#include <dev/usb/usbhid.h> 5162642Sn_hibma 5262642Sn_hibmaint verbose = 0; 5362642Sn_hibmaint all = 0; 5462642Sn_hibmaint noname = 0; 55164531Sgrogint hexdump = 0; 56113273Smdoddstatic int reportid; 5762642Sn_hibma 5862642Sn_hibmachar **names; 5962642Sn_hibmaint nnames; 6062642Sn_hibma 6162642Sn_hibmavoid prbits(int bits, char **strs, int n); 6262642Sn_hibmavoid usage(void); 6387699Smarkmvoid dumpitem(const char *label, struct hid_item *h); 6462642Sn_hibmavoid dumpitems(report_desc_t r); 6562642Sn_hibmavoid rev(struct hid_item **p); 6662642Sn_hibmavoid prdata(u_char *buf, struct hid_item *h); 6762642Sn_hibmavoid dumpdata(int f, report_desc_t r, int loop); 6862642Sn_hibmaint gotname(char *n); 6962642Sn_hibma 7062642Sn_hibmaint 7162642Sn_hibmagotname(char *n) 7262642Sn_hibma{ 7362642Sn_hibma int i; 7462642Sn_hibma 7562642Sn_hibma for (i = 0; i < nnames; i++) 7662642Sn_hibma if (strcmp(names[i], n) == 0) 7762642Sn_hibma return 1; 7862642Sn_hibma return 0; 7962642Sn_hibma} 8062642Sn_hibma 8162642Sn_hibmavoid 8262642Sn_hibmaprbits(int bits, char **strs, int n) 8362642Sn_hibma{ 8462642Sn_hibma int i; 8562642Sn_hibma 8662642Sn_hibma for(i = 0; i < n; i++, bits >>= 1) 8762642Sn_hibma if (strs[i*2]) 8862642Sn_hibma printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]); 8962642Sn_hibma} 9062642Sn_hibma 9162642Sn_hibmavoid 9262642Sn_hibmausage(void) 9362642Sn_hibma{ 9462642Sn_hibma extern char *__progname; 9562642Sn_hibma 96164531Sgrog fprintf(stderr, 97164531Sgrog "usage: %s -f device " 98164544Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n", 99164531Sgrog __progname); 100164531Sgrog fprintf(stderr, 101164531Sgrog " %s -f device " 102164544Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n", 103164531Sgrog __progname); 10462642Sn_hibma exit(1); 10562642Sn_hibma} 10662642Sn_hibma 10762642Sn_hibmavoid 10887699Smarkmdumpitem(const char *label, struct hid_item *h) 10962642Sn_hibma{ 11062642Sn_hibma if ((h->flags & HIO_CONST) && !verbose) 11162642Sn_hibma return; 11262642Sn_hibma printf("%s size=%d count=%d page=%s usage=%s%s", label, 113164531Sgrog h->report_size, h->report_count, 114164531Sgrog hid_usage_page(HID_PAGE(h->usage)), 11562642Sn_hibma hid_usage_in_page(h->usage), 11662642Sn_hibma h->flags & HIO_CONST ? " Const" : ""); 11762642Sn_hibma printf(", logical range %d..%d", 11862642Sn_hibma h->logical_minimum, h->logical_maximum); 11962642Sn_hibma if (h->physical_minimum != h->physical_maximum) 12062642Sn_hibma printf(", physical range %d..%d", 12162642Sn_hibma h->physical_minimum, h->physical_maximum); 12262642Sn_hibma if (h->unit) 12362642Sn_hibma printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 12462642Sn_hibma printf("\n"); 12562642Sn_hibma} 12662642Sn_hibma 12762642Sn_hibmavoid 12862642Sn_hibmadumpitems(report_desc_t r) 12962642Sn_hibma{ 13062642Sn_hibma struct hid_data *d; 13162642Sn_hibma struct hid_item h; 13267256Sn_hibma int size; 13362642Sn_hibma 134113273Smdodd for (d = hid_start_parse(r, ~0, reportid); hid_get_item(d, &h); ) { 13562642Sn_hibma switch (h.kind) { 13662642Sn_hibma case hid_collection: 13762642Sn_hibma printf("Collection page=%s usage=%s\n", 138164531Sgrog hid_usage_page(HID_PAGE(h.usage)), 13962642Sn_hibma hid_usage_in_page(h.usage)); 14062642Sn_hibma break; 14162642Sn_hibma case hid_endcollection: 14262642Sn_hibma printf("End collection\n"); 14362642Sn_hibma break; 14462642Sn_hibma case hid_input: 14562642Sn_hibma dumpitem("Input ", &h); 14662642Sn_hibma break; 14762642Sn_hibma case hid_output: 14862642Sn_hibma dumpitem("Output ", &h); 14962642Sn_hibma break; 15062642Sn_hibma case hid_feature: 15162642Sn_hibma dumpitem("Feature", &h); 15262642Sn_hibma break; 15362642Sn_hibma } 15462642Sn_hibma } 15562642Sn_hibma hid_end_parse(d); 156174826Simp size = hid_report_size(r, hid_input, 0); 15775606Sn_hibma printf("Total input size %d bytes\n", size); 15862642Sn_hibma 159174826Simp size = hid_report_size(r, hid_output, 0); 16067256Sn_hibma printf("Total output size %d bytes\n", size); 16167256Sn_hibma 162174826Simp size = hid_report_size(r, hid_feature, 0); 16367256Sn_hibma printf("Total feature size %d bytes\n", size); 16462642Sn_hibma} 16562642Sn_hibma 16662642Sn_hibmavoid 16762642Sn_hibmarev(struct hid_item **p) 16862642Sn_hibma{ 16962642Sn_hibma struct hid_item *cur, *prev, *next; 17062642Sn_hibma 17162642Sn_hibma prev = 0; 17262642Sn_hibma cur = *p; 17362642Sn_hibma while(cur != 0) { 17462642Sn_hibma next = cur->next; 17562642Sn_hibma cur->next = prev; 17662642Sn_hibma prev = cur; 17762642Sn_hibma cur = next; 17862642Sn_hibma } 17962642Sn_hibma *p = prev; 18062642Sn_hibma} 18162642Sn_hibma 18262642Sn_hibmavoid 18362642Sn_hibmaprdata(u_char *buf, struct hid_item *h) 18462642Sn_hibma{ 18562642Sn_hibma u_int data; 18662642Sn_hibma int i, pos; 18762642Sn_hibma 18862642Sn_hibma pos = h->pos; 18962642Sn_hibma for (i = 0; i < h->report_count; i++) { 19062642Sn_hibma data = hid_get_data(buf, h); 19162642Sn_hibma if (h->logical_minimum < 0) 19262642Sn_hibma printf("%d", (int)data); 19362642Sn_hibma else 19462642Sn_hibma printf("%u", data); 195164531Sgrog if (hexdump) 196164531Sgrog printf(" [0x%x]", data); 19762642Sn_hibma pos += h->report_size; 19862642Sn_hibma } 19962642Sn_hibma} 20062642Sn_hibma 20162642Sn_hibmavoid 20262642Sn_hibmadumpdata(int f, report_desc_t rd, int loop) 20362642Sn_hibma{ 20462642Sn_hibma struct hid_data *d; 20562642Sn_hibma struct hid_item h, *hids, *n; 20662642Sn_hibma int r, dlen; 20762642Sn_hibma u_char *dbuf; 20862642Sn_hibma u_int32_t colls[100]; 20962642Sn_hibma int sp = 0; 21062642Sn_hibma char namebuf[10000], *namep; 21162642Sn_hibma 21262642Sn_hibma hids = 0; 213164531Sgrog for (d = hid_start_parse(rd, 1<<hid_input, reportid); 21462642Sn_hibma hid_get_item(d, &h); ) { 21562642Sn_hibma if (h.kind == hid_collection) 21662642Sn_hibma colls[++sp] = h.usage; 21762642Sn_hibma else if (h.kind == hid_endcollection) 21862642Sn_hibma --sp; 21962642Sn_hibma if (h.kind != hid_input || (h.flags & HIO_CONST)) 22062642Sn_hibma continue; 22162642Sn_hibma h.next = hids; 22262642Sn_hibma h.collection = colls[sp]; 22362642Sn_hibma hids = malloc(sizeof *hids); 22462642Sn_hibma *hids = h; 22562642Sn_hibma } 22662642Sn_hibma hid_end_parse(d); 22762642Sn_hibma rev(&hids); 228174826Simp dlen = hid_report_size(rd, hid_input, 0); 22962642Sn_hibma dbuf = malloc(dlen); 23062642Sn_hibma if (!loop) 231187994Salfred if (hid_set_immed(f, 1) < 0) { 23262642Sn_hibma if (errno == EOPNOTSUPP) 23362642Sn_hibma warnx("device does not support immediate mode, only changes reported."); 23462642Sn_hibma else 23562642Sn_hibma err(1, "USB_SET_IMMED"); 23662642Sn_hibma } 23762642Sn_hibma do { 23862642Sn_hibma r = read(f, dbuf, dlen); 23962642Sn_hibma if (r != dlen) { 24062642Sn_hibma err(1, "bad read %d != %d", r, dlen); 24162642Sn_hibma } 24262642Sn_hibma for (n = hids; n; n = n->next) { 24362642Sn_hibma namep = namebuf; 24462642Sn_hibma namep += sprintf(namep, "%s:%s.", 24562642Sn_hibma hid_usage_page(HID_PAGE(n->collection)), 24662642Sn_hibma hid_usage_in_page(n->collection)); 24762642Sn_hibma namep += sprintf(namep, "%s:%s", 24862642Sn_hibma hid_usage_page(HID_PAGE(n->usage)), 24962642Sn_hibma hid_usage_in_page(n->usage)); 25062642Sn_hibma if (all || gotname(namebuf)) { 25162642Sn_hibma if (!noname) 25262642Sn_hibma printf("%s=", namebuf); 253115317Smdodd prdata(dbuf + (reportid != 0), n); 25462642Sn_hibma printf("\n"); 25562642Sn_hibma } 25662642Sn_hibma } 25762642Sn_hibma if (loop) 25862642Sn_hibma printf("\n"); 25962642Sn_hibma } while (loop); 26062642Sn_hibma free(dbuf); 26162642Sn_hibma} 26262642Sn_hibma 26362642Sn_hibmaint 26462642Sn_hibmamain(int argc, char **argv) 26562642Sn_hibma{ 26662642Sn_hibma int f; 26762642Sn_hibma report_desc_t r; 26887699Smarkm char devnam[100], *dev = 0; 26962642Sn_hibma int ch; 27062642Sn_hibma int repdump = 0; 27162642Sn_hibma int loop = 0; 27262642Sn_hibma char *table = 0; 27362642Sn_hibma 274164531Sgrog while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) { 27562642Sn_hibma switch(ch) { 27662642Sn_hibma case 'a': 27762642Sn_hibma all++; 27862642Sn_hibma break; 27962642Sn_hibma case 'f': 28062642Sn_hibma dev = optarg; 28162642Sn_hibma break; 28262642Sn_hibma case 'l': 28362642Sn_hibma loop ^= 1; 28462642Sn_hibma break; 28562642Sn_hibma case 'n': 28662642Sn_hibma noname++; 28762642Sn_hibma break; 28862642Sn_hibma case 'r': 28962642Sn_hibma repdump++; 29062642Sn_hibma break; 29162642Sn_hibma case 't': 29262642Sn_hibma table = optarg; 29362642Sn_hibma break; 29462642Sn_hibma case 'v': 29562642Sn_hibma verbose++; 29662642Sn_hibma break; 297164531Sgrog case 'x': 298164544Sgrog hexdump = 1; 299164531Sgrog break; 30062642Sn_hibma case '?': 30162642Sn_hibma default: 30262642Sn_hibma usage(); 30362642Sn_hibma } 30462642Sn_hibma } 30562642Sn_hibma argc -= optind; 30662642Sn_hibma argv += optind; 30762642Sn_hibma if (dev == 0) 30862642Sn_hibma usage(); 30962642Sn_hibma names = argv; 31062642Sn_hibma nnames = argc; 31162642Sn_hibma 31262642Sn_hibma if (nnames == 0 && !all && !repdump) 31362642Sn_hibma usage(); 31462642Sn_hibma 31562642Sn_hibma if (dev[0] != '/') { 31662642Sn_hibma if (isdigit(dev[0])) 31787699Smarkm snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 31862642Sn_hibma else 31987699Smarkm snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 32087699Smarkm dev = devnam; 32162642Sn_hibma } 32262642Sn_hibma 32362642Sn_hibma hid_init(table); 32462642Sn_hibma 32562642Sn_hibma f = open(dev, O_RDWR); 32662642Sn_hibma if (f < 0) 32762642Sn_hibma err(1, "%s", dev); 32862642Sn_hibma 32962642Sn_hibma r = hid_get_report_desc(f); 330164531Sgrog if (r == 0) 33162642Sn_hibma errx(1, "USB_GET_REPORT_DESC"); 332164531Sgrog 33362642Sn_hibma if (repdump) { 33462642Sn_hibma printf("Report descriptor:\n"); 33562642Sn_hibma dumpitems(r); 33662642Sn_hibma } 33762642Sn_hibma if (nnames != 0 || all) 33862642Sn_hibma dumpdata(f, r, loop); 33962642Sn_hibma 34062642Sn_hibma hid_dispose_report_desc(r); 34162642Sn_hibma exit(0); 34262642Sn_hibma} 343