usbhid.c revision 1.4 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