1 /* $NetBSD: usbhid.c,v 1.12 1999/05/16 19:42:03 augustss Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (augustss@netbsd.org). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <sys/types.h> 42 #include <fcntl.h> 43 #include <unistd.h> 44 #include <err.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <usb.h> 48 #include <dev/usb/usb.h> 49 #include <dev/usb/usbhid.h> 50 51 int verbose = 0; 52 int all = 0; 53 int noname = 0; 54 55 char **names; 56 int nnames; 57 58 void prbits(int bits, char **strs, int n); 59 void usage(void); 60 void dumpitem(char *label, struct hid_item *h); 61 void dumpitems(report_desc_t r); 62 void rev(struct hid_item **p); 63 void prdata(u_char *buf, struct hid_item *h); 64 void dumpdata(int f, report_desc_t r, int loop); 65 int gotname(char *n); 66 67 int 68 gotname(char *n) 69 { 70 int i; 71 72 for (i = 0; i < nnames; i++) 73 if (strcmp(names[i], n) == 0) 74 return 1; 75 return 0; 76 } 77 78 void 79 prbits(int bits, char **strs, int n) 80 { 81 int i; 82 83 for(i = 0; i < n; i++, bits >>= 1) 84 if (strs[i*2]) 85 printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]); 86 } 87 88 void 89 usage(void) 90 { 91 extern char *__progname; 92 93 fprintf(stderr, "Usage: %s -f device [-l] [-n] [-r] [-t tablefile] [-v] name ...\n", __progname); 94 fprintf(stderr, " %s -f device [-l] [-n] [-r] [-t tablefile] [-v] -a\n", __progname); 95 exit(1); 96 } 97 98 void 99 dumpitem(char *label, struct hid_item *h) 100 { 101 if ((h->flags & HIO_CONST) && !verbose) 102 return; 103 printf("%s size=%d count=%d page=%s usage=%s%s", label, 104 h->report_size, h->report_count, 105 hid_usage_page(HID_PAGE(h->usage)), 106 hid_usage_in_page(h->usage), 107 h->flags & HIO_CONST ? " Const" : ""); 108 printf(", logical range %d..%d", 109 h->logical_minimum, h->logical_maximum); 110 if (h->physical_minimum != h->physical_maximum) 111 printf(", physical range %d..%d", 112 h->physical_minimum, h->physical_maximum); 113 if (h->unit) 114 printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 115 printf("\n"); 116 } 117 118 void 119 dumpitems(report_desc_t r) 120 { 121 struct hid_data *d; 122 struct hid_item h; 123 int report_id, size; 124 125 for (d = hid_start_parse(r, ~0); hid_get_item(d, &h); ) { 126 switch (h.kind) { 127 case hid_collection: 128 printf("Collection page=%s usage=%s\n", 129 hid_usage_page(HID_PAGE(h.usage)), 130 hid_usage_in_page(h.usage)); 131 break; 132 case hid_endcollection: 133 printf("End collection\n"); 134 break; 135 case hid_input: 136 dumpitem("Input ", &h); 137 break; 138 case hid_output: 139 dumpitem("Output ", &h); 140 break; 141 case hid_feature: 142 dumpitem("Feature", &h); 143 break; 144 } 145 } 146 hid_end_parse(d); 147 size = hid_report_size(r, hid_input, &report_id); 148 size -= report_id != 0; 149 printf("Total input size %s%d bytes\n", 150 report_id && size ? "1+" : "", size); 151 152 size = hid_report_size(r, hid_output, &report_id); 153 size -= report_id != 0; 154 printf("Total output size %s%d bytes\n", 155 report_id && size ? "1+" : "", size); 156 157 size = hid_report_size(r, hid_feature, &report_id); 158 size -= report_id != 0; 159 printf("Total feature size %s%d bytes\n", 160 report_id && size ? "1+" : "", size); 161 } 162 163 void 164 rev(struct hid_item **p) 165 { 166 struct hid_item *cur, *prev, *next; 167 168 prev = 0; 169 cur = *p; 170 while(cur != 0) { 171 next = cur->next; 172 cur->next = prev; 173 prev = cur; 174 cur = next; 175 } 176 *p = prev; 177 } 178 179 void 180 prdata(u_char *buf, struct hid_item *h) 181 { 182 u_int data; 183 int i, pos; 184 185 pos = h->pos; 186 for (i = 0; i < h->report_count; i++) { 187 data = hid_get_data(buf, h); 188 if (h->logical_minimum < 0) 189 printf("%d", (int)data); 190 else 191 printf("%u", data); 192 pos += h->report_size; 193 } 194 } 195 196 void 197 dumpdata(int f, report_desc_t rd, int loop) 198 { 199 struct hid_data *d; 200 struct hid_item h, *hids, *n; 201 int r, dlen; 202 u_char *dbuf; 203 static int one = 1; 204 u_int32_t colls[100]; 205 int sp = 0; 206 int report_id; 207 char namebuf[10000], *namep; 208 209 hids = 0; 210 for (d = hid_start_parse(rd, 1<<hid_input); 211 hid_get_item(d, &h); ) { 212 if (h.kind == hid_collection) 213 colls[++sp] = h.usage; 214 else if (h.kind == hid_endcollection) 215 --sp; 216 if (h.kind != hid_input || (h.flags & HIO_CONST)) 217 continue; 218 h.next = hids; 219 h.collection = colls[sp]; 220 hids = malloc(sizeof *hids); 221 *hids = h; 222 } 223 hid_end_parse(d); 224 rev(&hids); 225 dlen = hid_report_size(rd, hid_input, &report_id); 226 dbuf = malloc(dlen); 227 if (!loop) 228 if (ioctl(f, USB_SET_IMMED, &one) < 0) { 229 if (errno == EOPNOTSUPP) 230 warnx("device does not support immediate mode, only changes reported."); 231 else 232 err(1, "USB_SET_IMMED"); 233 } 234 do { 235 r = read(f, dbuf, dlen); 236 if (r != dlen) { 237 err(1, "bad read %d != %d", r, dlen); 238 } 239 for (n = hids; n; n = n->next) { 240 namep = namebuf; 241 namep += sprintf(namep, "%s:%s.", 242 hid_usage_page(HID_PAGE(n->collection)), 243 hid_usage_in_page(n->collection)); 244 namep += sprintf(namep, "%s:%s", 245 hid_usage_page(HID_PAGE(n->usage)), 246 hid_usage_in_page(n->usage)); 247 if (all || gotname(namebuf)) { 248 if (!noname) 249 printf("%s=", namebuf); 250 prdata(dbuf + (report_id != 0), n); 251 printf("\n"); 252 } 253 } 254 if (loop) 255 printf("\n"); 256 } while (loop); 257 free(dbuf); 258 } 259 260 int 261 main(int argc, char **argv) 262 { 263 int f; 264 report_desc_t r; 265 char devname[100], *dev = 0; 266 int ch; 267 extern char *optarg; 268 extern int optind; 269 int repdump = 0; 270 int loop = 0; 271 char *table = 0; 272 273 while ((ch = getopt(argc, argv, "af:lnrt:v")) != -1) { 274 switch(ch) { 275 case 'a': 276 all++; 277 break; 278 case 'f': 279 dev = optarg; 280 break; 281 case 'l': 282 loop ^= 1; 283 break; 284 case 'n': 285 noname++; 286 break; 287 case 'r': 288 repdump++; 289 break; 290 case 't': 291 table = optarg; 292 break; 293 case 'v': 294 verbose++; 295 break; 296 case '?': 297 default: 298 usage(); 299 } 300 } 301 argc -= optind; 302 argv += optind; 303 if (dev == 0) 304 usage(); 305 names = argv; 306 nnames = argc; 307 308 if (nnames == 0 && !all && !repdump) 309 usage(); 310 311 if (dev[0] != '/') { 312 if (isdigit(dev[0])) 313 sprintf(devname, "/dev/uhid%s", dev); 314 else 315 sprintf(devname, "/dev/%s", dev); 316 dev = devname; 317 } 318 319 hid_init(table); 320 321 f = open(dev, O_RDWR); 322 if (f < 0) 323 err(1, "%s", dev); 324 325 r = hid_get_report_desc(f); 326 if (r == 0) 327 errx(1, "USB_GET_REPORT_DESC"); 328 329 if (repdump) { 330 printf("Report descriptor:\n"); 331 dumpitems(r); 332 } 333 if (nnames != 0 || all) 334 dumpdata(f, r, loop); 335 336 hid_dispose_report_desc(r); 337 exit(0); 338 } 339