usbhid.c revision 67256
13515Sache/* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 23515Sache/* $FreeBSD: head/usr.bin/usbhidctl/usbhid.c 67256 2000-10-17 17:13:38Z n_hibma $ */ 33515Sache 43515Sache/* 53515Sache * Copyright (c) 1998 The NetBSD Foundation, Inc. 612983Sjkh * All rights reserved. 712983Sjkh * 83515Sache * This code is derived from software contributed to The NetBSD Foundation 93515Sache * by Lennart Augustsson (augustss@netbsd.org). 103515Sache * 113515Sache * Redistribution and use in source and binary forms, with or without 123515Sache * modification, are permitted provided that the following conditions 133515Sache * are met: 143515Sache * 1. Redistributions of source code must retain the above copyright 153515Sache * notice, this list of conditions and the following disclaimer. 163515Sache * 2. Redistributions in binary form must reproduce the above copyright 173515Sache * notice, this list of conditions and the following disclaimer in the 183515Sache * documentation and/or other materials provided with the distribution. 193515Sache * 3. All advertising materials mentioning features or use of this software 203515Sache * must display the following acknowledgement: 213515Sache * This product includes software developed by the NetBSD 223515Sache * Foundation, Inc. and its contributors. 233515Sache * 4. Neither the name of The NetBSD Foundation nor the names of its 243740Sache * contributors may be used to endorse or promote products derived 253515Sache * from this software without specific prior written permission. 263515Sache * 273515Sache * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2812983Sjkh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2912983Sjkh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 303515Sache * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3112983Sjkh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 323515Sache * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 333515Sache * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 343515Sache * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 353515Sache * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 363515Sache * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 373515Sache * POSSIBILITY OF SUCH DAMAGE. 383515Sache */ 3913135Sjkh 4013135Sjkh#include <stdio.h> 4115322Sjkh#include <stdlib.h> 423515Sache#include <string.h> 4315273Sjkh#include <sys/types.h> 4415322Sjkh#include <fcntl.h> 4515273Sjkh#include <sys/ioctl.h> 4615273Sjkh#include <unistd.h> 4715289Sjkh#include <err.h> 4815322Sjkh#include <ctype.h> 4915273Sjkh#include <errno.h> 5015273Sjkh#include <libusb.h> 5115273Sjkh#include <dev/usb/usb.h> 5215376Sjkh#include <dev/usb/usbhid.h> 5315273Sjkh 5415273Sjkhint verbose = 0; 5515273Sjkhint all = 0; 5615273Sjkhint noname = 0; 5715273Sjkh 5815322Sjkhchar **names; 5915273Sjkhint nnames; 6015322Sjkh 6115273Sjkhvoid prbits(int bits, char **strs, int n); 6215273Sjkhvoid usage(void); 6315322Sjkhvoid dumpitem(char *label, struct hid_item *h); 6415273Sjkhvoid dumpitems(report_desc_t r); 6515273Sjkhvoid rev(struct hid_item **p); 6615273Sjkhvoid prdata(u_char *buf, struct hid_item *h); 6715273Sjkhvoid dumpdata(int f, report_desc_t r, int loop); 6815273Sjkhint gotname(char *n); 6915273Sjkh 7015322Sjkhint 7115273Sjkhgotname(char *n) 7215322Sjkh{ 7315322Sjkh int i; 7415273Sjkh 7515273Sjkh for (i = 0; i < nnames; i++) 7615273Sjkh if (strcmp(names[i], n) == 0) 7715273Sjkh return 1; 7815273Sjkh return 0; 7915273Sjkh} 8015273Sjkh 8115273Sjkhvoid 8215273Sjkhprbits(int bits, char **strs, int n) 8315273Sjkh{ 8415273Sjkh int i; 8515273Sjkh 8615273Sjkh for(i = 0; i < n; i++, bits >>= 1) 8715273Sjkh if (strs[i*2]) 8812983Sjkh printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]); 8915273Sjkh} 9015273Sjkh 9115273Sjkhvoid 9215273Sjkhusage(void) 9315273Sjkh{ 9415273Sjkh extern char *__progname; 9512983Sjkh 9615273Sjkh fprintf(stderr, "Usage: %s -f device [-l] [-n] [-r] [-t tablefile] [-v] name ...\n", __progname); 9715273Sjkh fprintf(stderr, " %s -f device [-l] [-n] [-r] [-t tablefile] [-v] -a\n", __progname); 9815273Sjkh exit(1); 9915273Sjkh} 10015273Sjkh 10115273Sjkhvoid 10215273Sjkhdumpitem(char *label, struct hid_item *h) 1034565Sache{ 10415273Sjkh if ((h->flags & HIO_CONST) && !verbose) 10515273Sjkh return; 10615273Sjkh printf("%s size=%d count=%d page=%s usage=%s%s", label, 10715273Sjkh h->report_size, h->report_count, 10815273Sjkh hid_usage_page(HID_PAGE(h->usage)), 10915273Sjkh hid_usage_in_page(h->usage), 11015273Sjkh h->flags & HIO_CONST ? " Const" : ""); 11115273Sjkh printf(", logical range %d..%d", 11215273Sjkh h->logical_minimum, h->logical_maximum); 1134527Sache if (h->physical_minimum != h->physical_maximum) 1143515Sache printf(", physical range %d..%d", 11515273Sjkh h->physical_minimum, h->physical_maximum); 11615273Sjkh if (h->unit) 1173515Sache printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 11815273Sjkh printf("\n"); 11915273Sjkh} 12015273Sjkh 12115273Sjkhvoid 12215273Sjkhdumpitems(report_desc_t r) 12315273Sjkh{ 12415273Sjkh struct hid_data *d; 12515273Sjkh struct hid_item h; 12615273Sjkh int size; 12715273Sjkh 12815273Sjkh for (d = hid_start_parse(r, ~0); hid_get_item(d, &h); ) { 12915273Sjkh switch (h.kind) { 13015273Sjkh case hid_collection: 13115273Sjkh printf("Collection page=%s usage=%s\n", 13215273Sjkh hid_usage_page(HID_PAGE(h.usage)), 13315273Sjkh hid_usage_in_page(h.usage)); 13415273Sjkh break; 13515273Sjkh case hid_endcollection: 13615273Sjkh printf("End collection\n"); 13715273Sjkh break; 13815273Sjkh case hid_input: 13915273Sjkh dumpitem("Input ", &h); 14015273Sjkh break; 14115273Sjkh case hid_output: 14215273Sjkh dumpitem("Output ", &h); 14315273Sjkh break; 14415273Sjkh case hid_feature: 14515273Sjkh dumpitem("Feature", &h); 14615273Sjkh break; 14715273Sjkh } 14815273Sjkh } 14915273Sjkh hid_end_parse(d); 15015273Sjkh size = hid_report_size(r, 0, hid_input); 15115273Sjkh printf("Total input size %s%d bytes\n", size); 15215273Sjkh 15315273Sjkh size = hid_report_size(r, 0, hid_output); 15415273Sjkh printf("Total output size %d bytes\n", size); 15515273Sjkh 15615273Sjkh size = hid_report_size(r, 0, hid_feature); 15712983Sjkh printf("Total feature size %d bytes\n", size); 15815273Sjkh} 15915273Sjkh 16015273Sjkhvoid 16115273Sjkhrev(struct hid_item **p) 16212983Sjkh{ 16315273Sjkh struct hid_item *cur, *prev, *next; 16415273Sjkh 16515273Sjkh prev = 0; 16615273Sjkh cur = *p; 16715273Sjkh while(cur != 0) { 16815273Sjkh next = cur->next; 16915273Sjkh cur->next = prev; 17015273Sjkh prev = cur; 17115273Sjkh cur = next; 17215273Sjkh } 17315273Sjkh *p = prev; 17415273Sjkh} 17515273Sjkh 17615273Sjkhvoid 17715273Sjkhprdata(u_char *buf, struct hid_item *h) 17815273Sjkh{ 17915273Sjkh u_int data; 18015273Sjkh int i, pos; 18115273Sjkh 18215273Sjkh pos = h->pos; 18315273Sjkh for (i = 0; i < h->report_count; i++) { 18415273Sjkh data = hid_get_data(buf, h); 18515273Sjkh if (h->logical_minimum < 0) 18615273Sjkh printf("%d", (int)data); 18715273Sjkh else 18815273Sjkh printf("%u", data); 18915273Sjkh pos += h->report_size; 19015273Sjkh } 19115273Sjkh} 19215273Sjkh 19315273Sjkhvoid 19415273Sjkhdumpdata(int f, report_desc_t rd, int loop) 19515273Sjkh{ 19615273Sjkh struct hid_data *d; 19715273Sjkh struct hid_item h, *hids, *n; 19815273Sjkh int r, dlen; 19915273Sjkh u_char *dbuf; 20015273Sjkh static int one = 1; 20115273Sjkh u_int32_t colls[100]; 20215273Sjkh int sp = 0; 20315273Sjkh int report_id; 20415273Sjkh char namebuf[10000], *namep; 20515273Sjkh 20615289Sjkh hids = 0; 20715289Sjkh for (d = hid_start_parse(rd, 1<<hid_input); 20815289Sjkh hid_get_item(d, &h); ) { 20915289Sjkh if (h.kind == hid_collection) 21015289Sjkh colls[++sp] = h.usage; 21115289Sjkh else if (h.kind == hid_endcollection) 21215289Sjkh --sp; 21315289Sjkh if (h.kind != hid_input || (h.flags & HIO_CONST)) 21415273Sjkh continue; 21515289Sjkh h.next = hids; 21615273Sjkh h.collection = colls[sp]; 21715273Sjkh hids = malloc(sizeof *hids); 21815273Sjkh *hids = h; 21915273Sjkh } 22015273Sjkh hid_end_parse(d); 22115273Sjkh rev(&hids); 22215273Sjkh dlen = hid_report_size(rd, 0, hid_input); 22315273Sjkh dbuf = malloc(dlen); 22415273Sjkh if (!loop) 22515273Sjkh if (ioctl(f, USB_SET_IMMED, &one) < 0) { 22615290Sjkh if (errno == EOPNOTSUPP) 22715290Sjkh warnx("device does not support immediate mode, only changes reported."); 22815273Sjkh else 22915142Sjkh err(1, "USB_SET_IMMED"); 23015273Sjkh } 23115273Sjkh do { 23215273Sjkh r = read(f, dbuf, dlen); 23315273Sjkh if (r != dlen) { 23415289Sjkh err(1, "bad read %d != %d", r, dlen); 23512983Sjkh } 23615289Sjkh for (n = hids; n; n = n->next) { 23715273Sjkh namep = namebuf; 23815289Sjkh namep += sprintf(namep, "%s:%s.", 23915273Sjkh hid_usage_page(HID_PAGE(n->collection)), 24015273Sjkh hid_usage_in_page(n->collection)); 24115354Sjkh namep += sprintf(namep, "%s:%s", 24215273Sjkh hid_usage_page(HID_PAGE(n->usage)), 24315289Sjkh hid_usage_in_page(n->usage)); 24415273Sjkh if (all || gotname(namebuf)) { 24515290Sjkh if (!noname) 24615273Sjkh printf("%s=", namebuf); 24715273Sjkh prdata(dbuf + (report_id != 0), n); 24815273Sjkh printf("\n"); 24915273Sjkh } 25015273Sjkh } 25115273Sjkh if (loop) 25215273Sjkh printf("\n"); 25315273Sjkh } while (loop); 25415273Sjkh free(dbuf); 25515273Sjkh} 25615273Sjkh 25712983Sjkhint 25815273Sjkhmain(int argc, char **argv) 25915273Sjkh{ 26015273Sjkh int f; 26115273Sjkh report_desc_t r; 26215273Sjkh char devname[100], *dev = 0; 26315273Sjkh int ch; 26415273Sjkh int repdump = 0; 26515273Sjkh int loop = 0; 26615273Sjkh char *table = 0; 26715273Sjkh 26815273Sjkh while ((ch = getopt(argc, argv, "af:lnrt:v")) != -1) { 26915273Sjkh switch(ch) { 27015273Sjkh case 'a': 27115273Sjkh all++; 27215273Sjkh break; 27315273Sjkh case 'f': 27415273Sjkh dev = optarg; 27515273Sjkh break; 27615273Sjkh case 'l': 27715273Sjkh loop ^= 1; 27815273Sjkh break; 27915273Sjkh case 'n': 28015273Sjkh noname++; 28115273Sjkh break; 28215273Sjkh case 'r': 28315273Sjkh repdump++; 28415273Sjkh break; 28515273Sjkh case 't': 28615273Sjkh table = optarg; 28715273Sjkh break; 28815273Sjkh case 'v': 28915273Sjkh verbose++; 29015273Sjkh break; 29115273Sjkh case '?': 29215273Sjkh default: 29315273Sjkh usage(); 29415273Sjkh } 29515273Sjkh } 29615273Sjkh argc -= optind; 29715273Sjkh argv += optind; 29815273Sjkh if (dev == 0) 29915273Sjkh usage(); 30015273Sjkh names = argv; 30115273Sjkh nnames = argc; 30215273Sjkh 30315273Sjkh if (nnames == 0 && !all && !repdump) 30415273Sjkh usage(); 30515273Sjkh 30615273Sjkh if (dev[0] != '/') { 30715273Sjkh if (isdigit(dev[0])) 30815273Sjkh snprintf(devname, sizeof(devname), "/dev/uhid%s", dev); 30915273Sjkh else 31015273Sjkh snprintf(devname, sizeof(devname), "/dev/%s", dev); 31115273Sjkh dev = devname; 31215273Sjkh } 31315289Sjkh 31415289Sjkh hid_init(table); 31515289Sjkh 31612983Sjkh f = open(dev, O_RDWR); 31715289Sjkh if (f < 0) 31815289Sjkh err(1, "%s", dev); 31915380Sjkh 32015380Sjkh r = hid_get_report_desc(f); 32115380Sjkh if (r == 0) 32215380Sjkh errx(1, "USB_GET_REPORT_DESC"); 32315273Sjkh 32415354Sjkh if (repdump) { 32515323Sjkh printf("Report descriptor:\n"); 32615323Sjkh dumpitems(r); 32715289Sjkh } 32815289Sjkh if (nnames != 0 || all) 32915289Sjkh dumpdata(f, r, loop); 33015289Sjkh 33115273Sjkh hid_dispose_report_desc(r); 33215289Sjkh exit(0); 33315289Sjkh} 33415273Sjkh