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