]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - usr.bin/usbhidctl/usbhid.c
MFC r219038: Document the input line length limit.
[FreeBSD/stable/8.git] / usr.bin / usbhidctl / usbhid.c
1 /*      $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */
2 /*      $FreeBSD$ */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@netbsd.org).
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <err.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <usbhid.h>
50 #include <dev/usb/usbhid.h>
51
52 int verbose = 0;
53 int all = 0;
54 int noname = 0;
55 int hexdump = 0;
56
57 char **names;
58 int nnames;
59
60 void prbits(int bits, char **strs, int n);
61 void usage(void);
62 void dumpitem(const char *label, struct hid_item *h);
63 void dumpitems(report_desc_t r);
64 void rev(struct hid_item **p);
65 void prdata(u_char *buf, struct hid_item *h);
66 void dumpdata(int f, report_desc_t r, 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
94         fprintf(stderr,
95                 "usage: %s -f device "
96                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n",
97                 getprogname());
98         fprintf(stderr,
99                 "       %s -f device "
100                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
101                 getprogname());
102         exit(1);
103 }
104
105 void
106 dumpitem(const char *label, struct hid_item *h)
107 {
108         if ((h->flags & HIO_CONST) && !verbose)
109                 return;
110         printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
111                h->report_ID, h->report_size, h->report_count,
112                hid_usage_page(HID_PAGE(h->usage)),
113                hid_usage_in_page(h->usage),
114                h->flags & HIO_CONST ? " Const" : "",
115                h->flags & HIO_VARIABLE ? "" : " Array");
116         printf(", logical range %d..%d",
117                h->logical_minimum, h->logical_maximum);
118         if (h->physical_minimum != h->physical_maximum)
119                 printf(", physical range %d..%d",
120                        h->physical_minimum, h->physical_maximum);
121         if (h->unit)
122                 printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
123         printf("\n");
124 }
125
126 static const char *
127 hid_collection_type(int32_t type)
128 {
129         static char num[8];
130
131         switch (type) {
132         case 0: return ("Physical");
133         case 1: return ("Application");
134         case 2: return ("Logical");
135         case 3: return ("Report");
136         case 4: return ("Named_Array");
137         case 5: return ("Usage_Switch");
138         case 6: return ("Usage_Modifier");
139         }
140         snprintf(num, sizeof(num), "0x%02x", type);
141         return (num);
142 }
143
144 void
145 dumpitems(report_desc_t r)
146 {
147         struct hid_data *d;
148         struct hid_item h;
149         int size;
150
151         for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
152                 switch (h.kind) {
153                 case hid_collection:
154                         printf("Collection type=%s page=%s usage=%s\n",
155                                hid_collection_type(h.collection),
156                                hid_usage_page(HID_PAGE(h.usage)),
157                                hid_usage_in_page(h.usage));
158                         break;
159                 case hid_endcollection:
160                         printf("End collection\n");
161                         break;
162                 case hid_input:
163                         dumpitem("Input  ", &h);
164                         break;
165                 case hid_output:
166                         dumpitem("Output ", &h);
167                         break;
168                 case hid_feature:
169                         dumpitem("Feature", &h);
170                         break;
171                 }
172         }
173         hid_end_parse(d);
174         size = hid_report_size(r, hid_input, -1);
175         printf("Total   input size %d bytes\n", size);
176
177         size = hid_report_size(r, hid_output, -1);
178         printf("Total  output size %d bytes\n", size);
179
180         size = hid_report_size(r, hid_feature, -1);
181         printf("Total feature size %d bytes\n", size);
182 }
183
184 void
185 rev(struct hid_item **p)
186 {
187         struct hid_item *cur, *prev, *next;
188
189         prev = 0;
190         cur = *p;
191         while(cur != 0) {
192                 next = cur->next;
193                 cur->next = prev;
194                 prev = cur;
195                 cur = next;
196         }
197         *p = prev;
198 }
199
200 void
201 prdata(u_char *buf, struct hid_item *h)
202 {
203         u_int data;
204         int i, pos;
205
206         pos = h->pos;
207         for (i = 0; i < h->report_count; i++) {
208                 data = hid_get_data(buf, h);
209                 if (i > 0)
210                         printf(" ");
211                 if (h->logical_minimum < 0)
212                         printf("%d", (int)data);
213                 else
214                         printf("%u", data);
215                 if (hexdump)
216                         printf(" [0x%x]", data);
217                 h->pos += h->report_size;
218         }
219         h->pos = pos;
220 }
221
222 void
223 dumpdata(int f, report_desc_t rd, int loop)
224 {
225         struct hid_data *d;
226         struct hid_item h, *hids, *n;
227         int r, dlen;
228         u_char *dbuf;
229         u_int32_t colls[100];
230         int sp = 0;
231         char namebuf[10000], *namep;
232
233         hids = 0;
234         for (d = hid_start_parse(rd, 1<<hid_input, -1);
235              hid_get_item(d, &h); ) {
236                 if (h.kind == hid_collection)
237                         colls[++sp] = h.usage;
238                 else if (h.kind == hid_endcollection)
239                         --sp;
240                 if (h.kind != hid_input || (h.flags & HIO_CONST))
241                         continue;
242                 h.next = hids;
243                 h.collection = colls[sp];
244                 hids = malloc(sizeof *hids);
245                 *hids = h;
246         }
247         hid_end_parse(d);
248         rev(&hids);
249         dlen = hid_report_size(rd, hid_input, -1);
250         dbuf = malloc(dlen);
251         if (!loop)
252                 if (hid_set_immed(f, 1) < 0) {
253                         if (errno == EOPNOTSUPP)
254                                 warnx("device does not support immediate mode, only changes reported.");
255                         else
256                                 err(1, "USB_SET_IMMED");
257                 }
258         do {
259                 r = read(f, dbuf, dlen);
260                 if (r < 1) {
261                         err(1, "read error");
262                 }
263                 for (n = hids; n; n = n->next) {
264                         if (n->report_ID != 0 && dbuf[0] != n->report_ID)
265                                 continue;
266                         namep = namebuf;
267                         namep += sprintf(namep, "%s:%s.",
268                                          hid_usage_page(HID_PAGE(n->collection)),
269                                          hid_usage_in_page(n->collection));
270                         namep += sprintf(namep, "%s:%s",
271                                          hid_usage_page(HID_PAGE(n->usage)),
272                                          hid_usage_in_page(n->usage));
273                         if (all || gotname(namebuf)) {
274                                 if (!noname)
275                                         printf("%s=", namebuf);
276                                 prdata(dbuf, 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;
290         report_desc_t r;
291         char devnam[100], *dev = 0;
292         int ch;
293         int repdump = 0;
294         int loop = 0;
295         char *table = 0;
296
297         while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) {
298                 switch(ch) {
299                 case 'a':
300                         all++;
301                         break;
302                 case 'f':
303                         dev = optarg;
304                         break;
305                 case 'l':
306                         loop ^= 1;
307                         break;
308                 case 'n':
309                         noname++;
310                         break;
311                 case 'r':
312                         repdump++;
313                         break;
314                 case 't':
315                         table = optarg;
316                         break;
317                 case 'v':
318                         verbose++;
319                         break;
320                 case 'x':
321                         hexdump = 1;
322                         break;
323                 case '?':
324                 default:
325                         usage();
326                 }
327         }
328         argc -= optind;
329         argv += optind;
330         if (dev == 0)
331                 usage();
332         names = argv;
333         nnames = argc;
334
335         if (nnames == 0 && !all && !repdump)
336                 usage();
337
338         if (dev[0] != '/') {
339                 if (isdigit(dev[0]))
340                         snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
341                 else
342                         snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
343                 dev = devnam;
344         }
345
346         hid_init(table);
347
348         f = open(dev, O_RDWR);
349         if (f < 0)
350                 err(1, "%s", dev);
351
352         r = hid_get_report_desc(f);
353         if (r == 0)
354                 errx(1, "USB_GET_REPORT_DESC");
355
356         if (repdump) {
357                 printf("Report descriptor:\n");
358                 dumpitems(r);
359         }
360         if (nnames != 0 || all)
361                 dumpdata(f, r, loop);
362
363         hid_dispose_report_desc(r);
364         exit(0);
365 }