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