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