usbhid.c revision 224511
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 224511 2011-07-30 13:22:44Z mav $ */ 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 * 2062642Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2162642Sn_hibma * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2262642Sn_hibma * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2362642Sn_hibma * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2462642Sn_hibma * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2562642Sn_hibma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2662642Sn_hibma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2762642Sn_hibma * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2862642Sn_hibma * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2962642Sn_hibma * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3062642Sn_hibma * POSSIBILITY OF SUCH DAMAGE. 3162642Sn_hibma */ 3262642Sn_hibma 3362642Sn_hibma#include <stdio.h> 3462642Sn_hibma#include <stdlib.h> 3562642Sn_hibma#include <string.h> 3662642Sn_hibma#include <sys/types.h> 3762642Sn_hibma#include <fcntl.h> 3862642Sn_hibma#include <unistd.h> 3962642Sn_hibma#include <err.h> 4062642Sn_hibma#include <ctype.h> 4162642Sn_hibma#include <errno.h> 42113273Smdodd#include <usbhid.h> 43188945Sthompsa#include <dev/usb/usbhid.h> 4462642Sn_hibma 4562642Sn_hibmaint verbose = 0; 4662642Sn_hibmaint all = 0; 4762642Sn_hibmaint noname = 0; 48164531Sgrogint hexdump = 0; 4962642Sn_hibma 5062642Sn_hibmachar **names; 5162642Sn_hibmaint nnames; 5262642Sn_hibma 5362642Sn_hibmavoid prbits(int bits, char **strs, int n); 5462642Sn_hibmavoid usage(void); 5587699Smarkmvoid dumpitem(const char *label, struct hid_item *h); 5662642Sn_hibmavoid dumpitems(report_desc_t r); 5762642Sn_hibmavoid rev(struct hid_item **p); 5862642Sn_hibmavoid prdata(u_char *buf, struct hid_item *h); 5962642Sn_hibmavoid dumpdata(int f, report_desc_t r, int loop); 6062642Sn_hibmaint gotname(char *n); 6162642Sn_hibma 6262642Sn_hibmaint 6362642Sn_hibmagotname(char *n) 6462642Sn_hibma{ 6562642Sn_hibma int i; 6662642Sn_hibma 6762642Sn_hibma for (i = 0; i < nnames; i++) 6862642Sn_hibma if (strcmp(names[i], n) == 0) 6962642Sn_hibma return 1; 7062642Sn_hibma return 0; 7162642Sn_hibma} 7262642Sn_hibma 7362642Sn_hibmavoid 7462642Sn_hibmaprbits(int bits, char **strs, int n) 7562642Sn_hibma{ 7662642Sn_hibma int i; 7762642Sn_hibma 7862642Sn_hibma for(i = 0; i < n; i++, bits >>= 1) 7962642Sn_hibma if (strs[i*2]) 8062642Sn_hibma printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]); 8162642Sn_hibma} 8262642Sn_hibma 8362642Sn_hibmavoid 8462642Sn_hibmausage(void) 8562642Sn_hibma{ 8662642Sn_hibma 87164531Sgrog fprintf(stderr, 88164531Sgrog "usage: %s -f device " 89164544Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n", 90194789Sdelphij getprogname()); 91164531Sgrog fprintf(stderr, 92164531Sgrog " %s -f device " 93164544Sgrog "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n", 94194789Sdelphij getprogname()); 9562642Sn_hibma exit(1); 9662642Sn_hibma} 9762642Sn_hibma 9862642Sn_hibmavoid 9987699Smarkmdumpitem(const char *label, struct hid_item *h) 10062642Sn_hibma{ 10162642Sn_hibma if ((h->flags & HIO_CONST) && !verbose) 10262642Sn_hibma return; 103224511Smav printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label, 104224511Smav h->report_ID, h->report_size, h->report_count, 105164531Sgrog hid_usage_page(HID_PAGE(h->usage)), 10662642Sn_hibma hid_usage_in_page(h->usage), 107224511Smav h->flags & HIO_CONST ? " Const" : "", 108224511Smav h->flags & HIO_VARIABLE ? "" : " Array"); 10962642Sn_hibma printf(", logical range %d..%d", 11062642Sn_hibma h->logical_minimum, h->logical_maximum); 11162642Sn_hibma if (h->physical_minimum != h->physical_maximum) 11262642Sn_hibma printf(", physical range %d..%d", 11362642Sn_hibma h->physical_minimum, h->physical_maximum); 11462642Sn_hibma if (h->unit) 11562642Sn_hibma printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 11662642Sn_hibma printf("\n"); 11762642Sn_hibma} 11862642Sn_hibma 119224511Smavstatic const char * 120224511Smavhid_collection_type(int32_t type) 121224511Smav{ 122224511Smav static char num[8]; 123224511Smav 124224511Smav switch (type) { 125224511Smav case 0: return ("Physical"); 126224511Smav case 1: return ("Application"); 127224511Smav case 2: return ("Logical"); 128224511Smav case 3: return ("Report"); 129224511Smav case 4: return ("Named_Array"); 130224511Smav case 5: return ("Usage_Switch"); 131224511Smav case 6: return ("Usage_Modifier"); 132224511Smav } 133224511Smav snprintf(num, sizeof(num), "0x%02x", type); 134224511Smav return (num); 135224511Smav} 136224511Smav 13762642Sn_hibmavoid 13862642Sn_hibmadumpitems(report_desc_t r) 13962642Sn_hibma{ 14062642Sn_hibma struct hid_data *d; 14162642Sn_hibma struct hid_item h; 14267256Sn_hibma int size; 14362642Sn_hibma 144224511Smav for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { 14562642Sn_hibma switch (h.kind) { 14662642Sn_hibma case hid_collection: 147224511Smav printf("Collection type=%s page=%s usage=%s\n", 148224511Smav hid_collection_type(h.collection), 149164531Sgrog hid_usage_page(HID_PAGE(h.usage)), 15062642Sn_hibma hid_usage_in_page(h.usage)); 15162642Sn_hibma break; 15262642Sn_hibma case hid_endcollection: 15362642Sn_hibma printf("End collection\n"); 15462642Sn_hibma break; 15562642Sn_hibma case hid_input: 15662642Sn_hibma dumpitem("Input ", &h); 15762642Sn_hibma break; 15862642Sn_hibma case hid_output: 15962642Sn_hibma dumpitem("Output ", &h); 16062642Sn_hibma break; 16162642Sn_hibma case hid_feature: 16262642Sn_hibma dumpitem("Feature", &h); 16362642Sn_hibma break; 16462642Sn_hibma } 16562642Sn_hibma } 16662642Sn_hibma hid_end_parse(d); 167224511Smav size = hid_report_size(r, hid_input, -1); 16875606Sn_hibma printf("Total input size %d bytes\n", size); 16962642Sn_hibma 170224511Smav size = hid_report_size(r, hid_output, -1); 17167256Sn_hibma printf("Total output size %d bytes\n", size); 17267256Sn_hibma 173224511Smav size = hid_report_size(r, hid_feature, -1); 17467256Sn_hibma printf("Total feature size %d bytes\n", size); 17562642Sn_hibma} 17662642Sn_hibma 17762642Sn_hibmavoid 17862642Sn_hibmarev(struct hid_item **p) 17962642Sn_hibma{ 18062642Sn_hibma struct hid_item *cur, *prev, *next; 18162642Sn_hibma 18262642Sn_hibma prev = 0; 18362642Sn_hibma cur = *p; 18462642Sn_hibma while(cur != 0) { 18562642Sn_hibma next = cur->next; 18662642Sn_hibma cur->next = prev; 18762642Sn_hibma prev = cur; 18862642Sn_hibma cur = next; 18962642Sn_hibma } 19062642Sn_hibma *p = prev; 19162642Sn_hibma} 19262642Sn_hibma 19362642Sn_hibmavoid 19462642Sn_hibmaprdata(u_char *buf, struct hid_item *h) 19562642Sn_hibma{ 19662642Sn_hibma u_int data; 19762642Sn_hibma int i, pos; 19862642Sn_hibma 19962642Sn_hibma pos = h->pos; 20062642Sn_hibma for (i = 0; i < h->report_count; i++) { 20162642Sn_hibma data = hid_get_data(buf, h); 202224511Smav if (i > 0) 203224511Smav printf(" "); 20462642Sn_hibma if (h->logical_minimum < 0) 20562642Sn_hibma printf("%d", (int)data); 20662642Sn_hibma else 20762642Sn_hibma printf("%u", data); 208164531Sgrog if (hexdump) 209164531Sgrog printf(" [0x%x]", data); 210224511Smav h->pos += h->report_size; 21162642Sn_hibma } 212224511Smav h->pos = pos; 21362642Sn_hibma} 21462642Sn_hibma 21562642Sn_hibmavoid 21662642Sn_hibmadumpdata(int f, report_desc_t rd, int loop) 21762642Sn_hibma{ 21862642Sn_hibma struct hid_data *d; 21962642Sn_hibma struct hid_item h, *hids, *n; 22062642Sn_hibma int r, dlen; 22162642Sn_hibma u_char *dbuf; 22262642Sn_hibma u_int32_t colls[100]; 22362642Sn_hibma int sp = 0; 22462642Sn_hibma char namebuf[10000], *namep; 22562642Sn_hibma 22662642Sn_hibma hids = 0; 227224511Smav for (d = hid_start_parse(rd, 1<<hid_input, -1); 22862642Sn_hibma hid_get_item(d, &h); ) { 22962642Sn_hibma if (h.kind == hid_collection) 23062642Sn_hibma colls[++sp] = h.usage; 23162642Sn_hibma else if (h.kind == hid_endcollection) 23262642Sn_hibma --sp; 23362642Sn_hibma if (h.kind != hid_input || (h.flags & HIO_CONST)) 23462642Sn_hibma continue; 23562642Sn_hibma h.next = hids; 23662642Sn_hibma h.collection = colls[sp]; 23762642Sn_hibma hids = malloc(sizeof *hids); 23862642Sn_hibma *hids = h; 23962642Sn_hibma } 24062642Sn_hibma hid_end_parse(d); 24162642Sn_hibma rev(&hids); 242224511Smav dlen = hid_report_size(rd, hid_input, -1); 24362642Sn_hibma dbuf = malloc(dlen); 24462642Sn_hibma if (!loop) 245187994Salfred if (hid_set_immed(f, 1) < 0) { 24662642Sn_hibma if (errno == EOPNOTSUPP) 24762642Sn_hibma warnx("device does not support immediate mode, only changes reported."); 24862642Sn_hibma else 24962642Sn_hibma err(1, "USB_SET_IMMED"); 25062642Sn_hibma } 25162642Sn_hibma do { 25262642Sn_hibma r = read(f, dbuf, dlen); 253224511Smav if (r < 1) { 254224511Smav err(1, "read error"); 25562642Sn_hibma } 25662642Sn_hibma for (n = hids; n; n = n->next) { 257224511Smav if (n->report_ID != 0 && dbuf[0] != n->report_ID) 258224511Smav continue; 25962642Sn_hibma namep = namebuf; 26062642Sn_hibma namep += sprintf(namep, "%s:%s.", 26162642Sn_hibma hid_usage_page(HID_PAGE(n->collection)), 26262642Sn_hibma hid_usage_in_page(n->collection)); 26362642Sn_hibma namep += sprintf(namep, "%s:%s", 26462642Sn_hibma hid_usage_page(HID_PAGE(n->usage)), 26562642Sn_hibma hid_usage_in_page(n->usage)); 26662642Sn_hibma if (all || gotname(namebuf)) { 26762642Sn_hibma if (!noname) 26862642Sn_hibma printf("%s=", namebuf); 269224511Smav prdata(dbuf, n); 27062642Sn_hibma printf("\n"); 27162642Sn_hibma } 27262642Sn_hibma } 27362642Sn_hibma if (loop) 27462642Sn_hibma printf("\n"); 27562642Sn_hibma } while (loop); 27662642Sn_hibma free(dbuf); 27762642Sn_hibma} 27862642Sn_hibma 27962642Sn_hibmaint 28062642Sn_hibmamain(int argc, char **argv) 28162642Sn_hibma{ 28262642Sn_hibma int f; 28362642Sn_hibma report_desc_t r; 28487699Smarkm char devnam[100], *dev = 0; 28562642Sn_hibma int ch; 28662642Sn_hibma int repdump = 0; 28762642Sn_hibma int loop = 0; 28862642Sn_hibma char *table = 0; 28962642Sn_hibma 290164531Sgrog while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) { 29162642Sn_hibma switch(ch) { 29262642Sn_hibma case 'a': 29362642Sn_hibma all++; 29462642Sn_hibma break; 29562642Sn_hibma case 'f': 29662642Sn_hibma dev = optarg; 29762642Sn_hibma break; 29862642Sn_hibma case 'l': 29962642Sn_hibma loop ^= 1; 30062642Sn_hibma break; 30162642Sn_hibma case 'n': 30262642Sn_hibma noname++; 30362642Sn_hibma break; 30462642Sn_hibma case 'r': 30562642Sn_hibma repdump++; 30662642Sn_hibma break; 30762642Sn_hibma case 't': 30862642Sn_hibma table = optarg; 30962642Sn_hibma break; 31062642Sn_hibma case 'v': 31162642Sn_hibma verbose++; 31262642Sn_hibma break; 313164531Sgrog case 'x': 314164544Sgrog hexdump = 1; 315164531Sgrog break; 31662642Sn_hibma case '?': 31762642Sn_hibma default: 31862642Sn_hibma usage(); 31962642Sn_hibma } 32062642Sn_hibma } 32162642Sn_hibma argc -= optind; 32262642Sn_hibma argv += optind; 32362642Sn_hibma if (dev == 0) 32462642Sn_hibma usage(); 32562642Sn_hibma names = argv; 32662642Sn_hibma nnames = argc; 32762642Sn_hibma 32862642Sn_hibma if (nnames == 0 && !all && !repdump) 32962642Sn_hibma usage(); 33062642Sn_hibma 33162642Sn_hibma if (dev[0] != '/') { 33262642Sn_hibma if (isdigit(dev[0])) 33387699Smarkm snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 33462642Sn_hibma else 33587699Smarkm snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 33687699Smarkm dev = devnam; 33762642Sn_hibma } 33862642Sn_hibma 33962642Sn_hibma hid_init(table); 34062642Sn_hibma 34162642Sn_hibma f = open(dev, O_RDWR); 34262642Sn_hibma if (f < 0) 34362642Sn_hibma err(1, "%s", dev); 34462642Sn_hibma 34562642Sn_hibma r = hid_get_report_desc(f); 346164531Sgrog if (r == 0) 34762642Sn_hibma errx(1, "USB_GET_REPORT_DESC"); 348164531Sgrog 34962642Sn_hibma if (repdump) { 35062642Sn_hibma printf("Report descriptor:\n"); 35162642Sn_hibma dumpitems(r); 35262642Sn_hibma } 35362642Sn_hibma if (nnames != 0 || all) 35462642Sn_hibma dumpdata(f, r, loop); 35562642Sn_hibma 35662642Sn_hibma hid_dispose_report_desc(r); 35762642Sn_hibma exit(0); 35862642Sn_hibma} 359