usbhid.c revision 1.8 1 /* $NetBSD: usbhid.c,v 1.8 1999/04/21 17:41:08 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 (at) 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 <dev/usb/usb.h>
47 #include <dev/usb/usbhid.h>
48 #include <errno.h>
49
50 #include "hidsubr.h"
51
52 #define HIDTABLE "/usr/share/misc/usb_hid_usages"
53
54 #define USBDEV "/dev/uhid0"
55
56 int verbose = 0;
57 int all = 0;
58 int noname = 0;
59
60 char **names;
61 int nnames;
62
63 void prbits(int bits, char **strs, int n);
64 void usage(void);
65 void dumpitem(char *label, struct hid_item *h);
66 void dumpitems(u_char *buf, int len);
67 void rev(struct hid_item **p);
68 u_long getdata(u_char *buf, int hpos, int hsize, int sign);
69 void prdata(u_char *buf, struct hid_item *h);
70 void dumpdata(int f, u_char *buf, int len, int loop);
71 int gotname(char *n);
72
73 int
74 gotname(char *n)
75 {
76 int i;
77
78 for (i = 0; i < nnames; i++)
79 if (strcmp(names[i], n) == 0)
80 return 1;
81 return 0;
82 }
83
84 void
85 prbits(int bits, char **strs, int n)
86 {
87 int i;
88
89 for(i = 0; i < n; i++, bits >>= 1)
90 if (strs[i*2])
91 printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]);
92 }
93
94 void
95 usage(void)
96 {
97 extern char *__progname;
98
99 fprintf(stderr, "Usage: %s -f device [-l] [-n] [-r] [-t tablefile] [-v] name ...\n", __progname);
100 fprintf(stderr, " %s -f device [-l] [-n] [-r] [-t tablefile] [-v] -a\n", __progname);
101 exit(1);
102 }
103
104 void
105 dumpitem(char *label, struct hid_item *h)
106 {
107 if ((h->flags & HIO_CONST) && !verbose)
108 return;
109 printf("%s size=%d count=%d page=%s usage=%s%s", label,
110 h->report_size, h->report_count,
111 usage_page(HID_PAGE(h->usage)),
112 usage_in_page(h->usage),
113 h->flags & HIO_CONST ? " Const" : "");
114 printf(", logical range %d..%d",
115 h->logical_minimum, h->logical_maximum);
116 if (h->physical_minimum != h->physical_maximum)
117 printf(", physical range %d..%d",
118 h->physical_minimum, h->physical_maximum);
119 if (h->unit)
120 printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
121 printf("\n");
122 }
123
124 void
125 dumpitems(u_char *buf, int len)
126 {
127 struct hid_data *d;
128 struct hid_item h;
129 int report_id, size;
130
131 for (d = hid_start_parse(buf, len, ~0); hid_get_item(d, &h); ) {
132 switch (h.kind) {
133 case hid_collection:
134 printf("Collection page=%s usage=%s\n",
135 usage_page(HID_PAGE(h.usage)),
136 usage_in_page(h.usage));
137 break;
138 case hid_endcollection:
139 printf("End collection\n");
140 break;
141 case hid_input:
142 dumpitem("Input ", &h);
143 break;
144 case hid_output:
145 dumpitem("Output ", &h);
146 break;
147 case hid_feature:
148 dumpitem("Feature", &h);
149 break;
150 }
151 }
152 hid_end_parse(d);
153 size = hid_report_size(buf, len, hid_input, &report_id);
154 size -= report_id != 0;
155 printf("Total input size %s%d bytes\n",
156 report_id && size ? "1+" : "", size);
157
158 size = hid_report_size(buf, len, hid_output, &report_id);
159 size -= report_id != 0;
160 printf("Total output size %s%d bytes\n",
161 report_id && size ? "1+" : "", size);
162
163 size = hid_report_size(buf, len, hid_feature, &report_id);
164 size -= report_id != 0;
165 printf("Total feature size %s%d bytes\n",
166 report_id && size ? "1+" : "", size);
167 }
168
169 void
170 rev(struct hid_item **p)
171 {
172 struct hid_item *cur, *prev, *next;
173
174 prev = 0;
175 cur = *p;
176 while(cur != 0) {
177 next = cur->next;
178 cur->next = prev;
179 prev = cur;
180 cur = next;
181 }
182 *p = prev;
183 }
184
185 u_long
186 getdata(u_char *buf, int hpos, int hsize, int sign)
187 {
188 u_long data;
189 int i, size, s;
190
191 data = 0;
192 s = hpos/8;
193 for (i = hpos; i < hpos+hsize; i += 8)
194 data |= buf[i / 8] << ((i/8-s) * 8);
195 data >>= (hpos % 8);
196 data &= (1 << hsize) - 1;
197 size = 32 - hsize;
198 if (sign)
199 /* Need to sign extend */
200 data = ((long)data << size) >> size;
201 return data;
202 }
203
204 void
205 prdata(u_char *buf, struct hid_item *h)
206 {
207 u_long data;
208 int i, pos;
209
210 pos = h->pos;
211 for (i = 0; i < h->report_count; i++) {
212 data = getdata(buf, pos, h->report_size,
213 h->logical_minimum < 0);
214 if (h->logical_minimum < 0)
215 printf("%ld", (long)data);
216 else
217 printf("%lu", data);
218 pos += h->report_size;
219 }
220 }
221
222 void
223 dumpdata(int f, u_char *buf, int len, int loop)
224 {
225 struct hid_data *d;
226 struct hid_item h, *hids, *n;
227 int r, dlen;
228 u_char *dbuf;
229 static int one = 1;
230 u_int32_t colls[100];
231 int sp = 0;
232 int report_id;
233 char namebuf[10000], *namep;
234
235 hids = 0;
236 for (d = hid_start_parse(buf, len, 1<<hid_input);
237 hid_get_item(d, &h); ) {
238 if (h.kind == hid_collection)
239 colls[++sp] = h.usage;
240 else if (h.kind == hid_endcollection)
241 --sp;
242 if (h.kind != hid_input || (h.flags & HIO_CONST))
243 continue;
244 h.next = hids;
245 h.collection = colls[sp];
246 hids = malloc(sizeof *hids);
247 *hids = h;
248 }
249 hid_end_parse(d);
250 rev(&hids);
251 dlen = hid_report_size(buf, len, hid_input, &report_id);
252 dbuf = malloc(dlen);
253 if (!loop)
254 if (ioctl(f, USB_SET_IMMED, &one) < 0) {
255 if (errno == EOPNOTSUPP)
256 warnx("device does not support immediate mode, only changes reported.");
257 else
258 err(1, "USB_SET_IMMED");
259 }
260 do {
261 r = read(f, dbuf, dlen);
262 if (r != dlen) {
263 err(1, "bad read %d != %d", r, dlen);
264 }
265 for (n = hids; n; n = n->next) {
266 namep = namebuf;
267 namep += sprintf(namep, "%s:%s.",
268 usage_page(HID_PAGE(n->collection)),
269 usage_in_page(n->collection));
270 namep += sprintf(namep, "%s:%s",
271 usage_page(HID_PAGE(n->usage)),
272 usage_in_page(n->usage));
273 if (all || gotname(namebuf)) {
274 if (!noname)
275 printf("%s=", namebuf);
276 prdata(dbuf + (report_id != 0), n);
277 printf("\n");
278 }
279 }
280 if (loop)
281 printf("\n");
282 } while (loop);
283 free(dbuf);
284 }
285
286 int
287 main(int argc, char **argv)
288 {
289 int f, r;
290 char devname[100], *dev = 0;
291 int ch;
292 extern char *optarg;
293 extern int optind;
294 struct usb_ctl_report_desc rep;
295 int repdump = 0;
296 int loop = 0;
297 char *table = HIDTABLE;
298
299 while ((ch = getopt(argc, argv, "af:lnrt:v")) != -1) {
300 switch(ch) {
301 case 'a':
302 all++;
303 break;
304 case 'f':
305 dev = optarg;
306 break;
307 case 'l':
308 loop ^= 1;
309 break;
310 case 'n':
311 noname++;
312 break;
313 case 'r':
314 repdump++;
315 break;
316 case 't':
317 table = optarg;
318 break;
319 case 'v':
320 verbose++;
321 break;
322 case '?':
323 default:
324 usage();
325 }
326 }
327 argc -= optind;
328 argv += optind;
329 if (dev == 0)
330 usage();
331 names = argv;
332 nnames = argc;
333
334 if (nnames == 0 && !all && !repdump)
335 usage();
336
337 if (dev[0] != '/') {
338 if (isdigit(dev[0]))
339 sprintf(devname, "/dev/uhid%s", dev);
340 else
341 sprintf(devname, "/dev/%s", dev);
342 dev = devname;
343 }
344
345 init_hid(table);
346
347 f = open(dev, O_RDWR);
348 if (f < 0)
349 err(1, "%s", dev);
350
351 rep.size = 0;
352 r = ioctl(f, USB_GET_REPORT_DESC, &rep);
353 if (r)
354 errx(1, "USB_GET_REPORT_DESC");
355
356 if (repdump) {
357 printf("Report descriptor\n");
358 dumpitems(rep.data, rep.size);
359 }
360 if (nnames != 0 || all)
361 dumpdata(f, rep.data, rep.size, loop);
362
363 exit(0);
364 }
365