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