d9d960a974f59864f59a7452ad80713e9b5940aa
[dragonfly.git] / usr.bin / u4bhidctl / 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <err.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <usbhid.h>
43 #include <bus/usb/usbhid.h>
44
45 static struct variable {
46         char *name;
47         int instance;
48         int val;
49         struct hid_item h;
50         struct variable *next;
51 } *vars;
52
53 static int verbose = 0;
54 static int noname = 0;
55 static int hexdump = 0;
56 static int wflag = 0;
57 static int zflag = 0;
58
59 static void usage(void);
60 static void dumpitem(const char *label, struct hid_item *h);
61 static void dumpitems(report_desc_t r);
62 static void prdata(u_char *buf, struct hid_item *h);
63 static void dumpdata(int f, report_desc_t r, int loop);
64 static void writedata(int f, report_desc_t r);
65
66 static void
67 parceargs(report_desc_t r, int all, int nnames, char **names)
68 {
69         struct hid_data *d;
70         struct hid_item h;
71         char colls[1000];
72         char hname[1000], *tmp1, *tmp2;
73         struct variable *var, **pnext;
74         int i, instance, cp, t;
75
76         pnext = &vars;
77         if (all) {
78                 if (wflag)
79                         errx(1, "Must not specify -w to read variables");
80                 cp = 0;
81                 for (d = hid_start_parse(r,
82                     1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
83                     hid_get_item(d, &h); ) {
84                         if (h.kind == hid_collection) {
85                                 cp += sprintf(&colls[cp], "%s%s:%s",
86                                     cp != 0 ? "." : "",
87                                     hid_usage_page(HID_PAGE(h.usage)),
88                                     hid_usage_in_page(h.usage));
89                         } else if (h.kind == hid_endcollection) {
90                                 tmp1 = strrchr(colls, '.');
91                                 if (tmp1 != NULL) {
92                                         cp -= strlen(tmp1);
93                                         tmp1[0] = 0;
94                                 } else {
95                                         cp = 0;
96                                         colls[0] = 0;
97                                 }
98                         }
99                         if ((h.kind != hid_input && h.kind != hid_output &&
100                             h.kind != hid_feature) || (h.flags & HIO_CONST))
101                                 continue;
102                         var = malloc(sizeof(*var));
103                         memset(var, 0, sizeof(*var));
104                         asprintf(&var->name, "%s%s%s:%s",
105                             colls, colls[0] != 0 ? "." : "",
106                             hid_usage_page(HID_PAGE(h.usage)),
107                             hid_usage_in_page(h.usage));
108                         var->h = h;
109                         *pnext = var;
110                         pnext = &var->next;
111                 }
112                 hid_end_parse(d);
113                 return;
114         }
115         for (i = 0; i < nnames; i++) {
116                 var = malloc(sizeof(*var));
117                 memset(var, 0, sizeof(*var));
118                 tmp1 = tmp2 = strdup(names[i]);
119                 strsep(&tmp2, "=");
120                 var->name = strsep(&tmp1, "#");
121                 if (tmp1 != NULL)
122                         var->instance = atoi(tmp1);
123                 if (tmp2 != NULL) {
124                         if (!wflag)
125                                 errx(1, "Must specify -w to write variables");
126                         var->val = atoi(tmp2);
127                 } else
128                         if (wflag)
129                                 errx(1, "Must not specify -w to read variables");
130                 *pnext = var;
131                 pnext = &var->next;
132
133                 instance = 0;
134                 cp = 0;
135                 for (d = hid_start_parse(r,
136                     1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
137                     hid_get_item(d, &h); ) {
138                         if (h.kind == hid_collection) {
139                                 cp += sprintf(&colls[cp], "%s%s:%s",
140                                     cp != 0 ? "." : "",
141                                     hid_usage_page(HID_PAGE(h.usage)),
142                                     hid_usage_in_page(h.usage));
143                         } else if (h.kind == hid_endcollection) {
144                                 tmp1 = strrchr(colls, '.');
145                                 if (tmp1 != NULL) {
146                                         cp -= strlen(tmp1);
147                                         tmp1[0] = 0;
148                                 } else {
149                                         cp = 0;
150                                         colls[0] = 0;
151                                 }
152                         }
153                         if ((h.kind != hid_input && h.kind != hid_output &&
154                             h.kind != hid_feature) || (h.flags & HIO_CONST))
155                                 continue;
156                         snprintf(hname, sizeof(hname), "%s%s%s:%s",
157                             colls, colls[0] != 0 ? "." : "",
158                             hid_usage_page(HID_PAGE(h.usage)),
159                             hid_usage_in_page(h.usage));
160                         t = strlen(hname) - strlen(var->name);
161                         if (t > 0) {
162                                 if (strcmp(hname + t, var->name) != 0)
163                                         continue;
164                                 if (hname[t - 1] != '.')
165                                         continue;
166                         } else if (strcmp(hname, var->name) != 0)
167                                 continue;
168                         if (var->instance != instance++)
169                                 continue;
170                         var->h = h;
171                         break;
172                 }
173                 hid_end_parse(d);
174                 if (var->h.usage == 0)
175                         errx(1, "Unknown item '%s'", var->name);
176         }
177 }
178
179 static void
180 usage(void)
181 {
182
183         fprintf(stderr,
184                 "usage: %s -f device "
185                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n",
186                 getprogname());
187         fprintf(stderr,
188                 "       %s -f device "
189                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
190                 getprogname());
191         fprintf(stderr,
192                 "       %s -f device "
193                 "[-t tablefile] [-v] [-z] -w name=value\n",
194                 getprogname());
195         exit(1);
196 }
197
198 static void
199 dumpitem(const char *label, struct hid_item *h)
200 {
201         if ((h->flags & HIO_CONST) && !verbose)
202                 return;
203         printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
204                h->report_ID, h->report_size, h->report_count,
205                hid_usage_page(HID_PAGE(h->usage)),
206                hid_usage_in_page(h->usage),
207                h->flags & HIO_CONST ? " Const" : "",
208                h->flags & HIO_VARIABLE ? "" : " Array");
209         printf(", logical range %d..%d",
210                h->logical_minimum, h->logical_maximum);
211         if (h->physical_minimum != h->physical_maximum)
212                 printf(", physical range %d..%d",
213                        h->physical_minimum, h->physical_maximum);
214         if (h->unit)
215                 printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
216         printf("\n");
217 }
218
219 static const char *
220 hid_collection_type(int32_t type)
221 {
222         static char num[8];
223
224         switch (type) {
225         case 0: return ("Physical");
226         case 1: return ("Application");
227         case 2: return ("Logical");
228         case 3: return ("Report");
229         case 4: return ("Named_Array");
230         case 5: return ("Usage_Switch");
231         case 6: return ("Usage_Modifier");
232         }
233         snprintf(num, sizeof(num), "0x%02x", type);
234         return (num);
235 }
236
237 static void
238 dumpitems(report_desc_t r)
239 {
240         struct hid_data *d;
241         struct hid_item h;
242         int size;
243
244         for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
245                 switch (h.kind) {
246                 case hid_collection:
247                         printf("Collection type=%s page=%s usage=%s\n",
248                                hid_collection_type(h.collection),
249                                hid_usage_page(HID_PAGE(h.usage)),
250                                hid_usage_in_page(h.usage));
251                         break;
252                 case hid_endcollection:
253                         printf("End collection\n");
254                         break;
255                 case hid_input:
256                         dumpitem("Input  ", &h);
257                         break;
258                 case hid_output:
259                         dumpitem("Output ", &h);
260                         break;
261                 case hid_feature:
262                         dumpitem("Feature", &h);
263                         break;
264                 }
265         }
266         hid_end_parse(d);
267         size = hid_report_size(r, hid_input, -1);
268         printf("Total   input size %d bytes\n", size);
269
270         size = hid_report_size(r, hid_output, -1);
271         printf("Total  output size %d bytes\n", size);
272
273         size = hid_report_size(r, hid_feature, -1);
274         printf("Total feature size %d bytes\n", size);
275 }
276
277 static void
278 prdata(u_char *buf, struct hid_item *h)
279 {
280         u_int data;
281         int i, pos;
282
283         pos = h->pos;
284         for (i = 0; i < h->report_count; i++) {
285                 data = hid_get_data(buf, h);
286                 if (i > 0)
287                         printf(" ");
288                 if (h->logical_minimum < 0)
289                         printf("%d", (int)data);
290                 else
291                         printf("%u", data);
292                 if (hexdump)
293                         printf(" [0x%x]", data);
294                 h->pos += h->report_size;
295         }
296         h->pos = pos;
297 }
298
299 static void
300 dumpdata(int f, report_desc_t rd, int loop)
301 {
302         struct variable *var;
303         int dlen, havedata, i, match, r, rid, use_rid;
304         u_char *dbuf;
305         enum hid_kind kind;
306
307         kind = 0;
308         rid = -1;
309         use_rid = !!hid_get_report_id(f);
310         do {
311                 if (kind < 3) {
312                         if (++rid >= 256) {
313                                 rid = 0;
314                                 kind++;
315                         }
316                         if (kind >= 3)
317                                 rid = -1;
318                         for (var = vars; var; var = var->next) {
319                                 if (rid == var->h.report_ID &&
320                                     kind == var->h.kind)
321                                         break;
322                         }
323                         if (var == NULL)
324                                 continue;
325                 }
326                 dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid);
327                 if (dlen <= 0)
328                         continue;
329                 dbuf = malloc(dlen);
330                 memset(dbuf, 0, dlen);
331                 if (kind < 3) {
332                         dbuf[0] = rid;
333                         r = hid_get_report(f, kind, dbuf, dlen);
334                         if (r < 0)
335                                 warn("hid_get_report(rid %d)", rid);
336                         havedata = !r && (rid == 0 || dbuf[0] == rid);
337                         if (rid != 0)
338                                 dbuf[0] = rid;
339                 } else {
340                         r = read(f, dbuf, dlen);
341                         if (r < 1)
342                                 err(1, "read error");
343                         havedata = 1;
344                 }
345                 if (verbose) {
346                         printf("Got %s report %d (%d bytes):",
347                             kind == hid_output ? "output" :
348                             kind == hid_feature ? "feature" : "input",
349                             use_rid ? dbuf[0] : 0, dlen);
350                         if (havedata) {
351                                 for (i = 0; i < dlen; i++)
352                                         printf(" %02x", dbuf[i]);
353                         }
354                         printf("\n");
355                 }
356                 match = 0;
357                 for (var = vars; var; var = var->next) {
358                         if ((kind < 3 ? kind : hid_input) != var->h.kind)
359                                 continue;
360                         if (var->h.report_ID != 0 &&
361                             dbuf[0] != var->h.report_ID)
362                                 continue;
363                         match = 1;
364                         if (!noname)
365                                 printf("%s=", var->name);
366                         if (havedata)
367                                 prdata(dbuf, &var->h);
368                         printf("\n");
369                 }
370                 if (match)
371                         printf("\n");
372                 free(dbuf);
373         } while (loop || kind < 3);
374 }
375
376 static void
377 writedata(int f, report_desc_t rd)
378 {
379         struct variable *var;
380         int dlen, i, r, rid;
381         u_char *dbuf;
382         enum hid_kind kind;
383
384         kind = 0;
385         rid = 0;
386         for (kind = 0; kind < 3; kind ++) {
387             for (rid = 0; rid < 256; rid ++) {
388                 for (var = vars; var; var = var->next) {
389                         if (rid == var->h.report_ID && kind == var->h.kind)
390                                 break;
391                 }
392                 if (var == NULL)
393                         continue;
394                 dlen = hid_report_size(rd, kind, rid);
395                 if (dlen <= 0)
396                         continue;
397                 dbuf = malloc(dlen);
398                 memset(dbuf, 0, dlen);
399                 dbuf[0] = rid;
400                 if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) {
401                         if (verbose) {
402                                 printf("Got %s report %d (%d bytes):",
403                                     kind == hid_input ? "input" :
404                                     kind == hid_output ? "output" : "feature",
405                                     rid, dlen);
406                                 for (i = 0; i < dlen; i++)
407                                         printf(" %02x", dbuf[i]);
408                                 printf("\n");
409                         }
410                 } else if (!zflag) {
411                         warn("hid_get_report(rid %d)", rid);
412                         if (verbose) {
413                                 printf("Can't get %s report %d (%d bytes). "
414                                     "Will be initialized with zeros.\n",
415                                     kind == hid_input ? "input" :
416                                     kind == hid_output ? "output" : "feature",
417                                     rid, dlen);
418                         }
419                 }
420                 for (var = vars; var; var = var->next) {
421                         if (rid != var->h.report_ID || kind != var->h.kind)
422                                 continue;
423                         hid_set_data(dbuf, &var->h, var->val);
424                 }
425                 if (verbose) {
426                         printf("Setting %s report %d (%d bytes):",
427                             kind == hid_output ? "output" :
428                             kind == hid_feature ? "feature" : "input",
429                             rid, dlen);
430                         for (i = 0; i < dlen; i++)
431                                 printf(" %02x", dbuf[i]);
432                         printf("\n");
433                 }
434                 r = hid_set_report(f, kind, dbuf, dlen);
435                 if (r != 0)
436                         warn("hid_set_report(rid %d)", rid);
437                 free(dbuf);
438             }
439         }
440 }
441
442 int
443 main(int argc, char **argv)
444 {
445         report_desc_t r;
446         char *table = 0;
447         char devnam[100], *dev = NULL;
448         int f;
449         int all = 0;
450         int ch;
451         int repdump = 0;
452         int loop = 0;
453
454         while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) {
455                 switch(ch) {
456                 case 'a':
457                         all++;
458                         break;
459                 case 'f':
460                         dev = optarg;
461                         break;
462                 case 'l':
463                         loop ^= 1;
464                         break;
465                 case 'n':
466                         noname++;
467                         break;
468                 case 'r':
469                         repdump++;
470                         break;
471                 case 't':
472                         table = optarg;
473                         break;
474                 case 'v':
475                         verbose++;
476                         break;
477                 case 'w':
478                         wflag = 1;
479                         break;
480                 case 'x':
481                         hexdump = 1;
482                         break;
483                 case 'z':
484                         zflag = 1;
485                         break;
486                 case '?':
487                 default:
488                         usage();
489                 }
490         }
491         argc -= optind;
492         argv += optind;
493         if (dev == NULL)
494                 usage();
495
496         if (argc == 0 && !all && !repdump)
497                 usage();
498
499         if (dev[0] != '/') {
500                 if (isdigit(dev[0]))
501                         snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
502                 else
503                         snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
504                 dev = devnam;
505         }
506
507         hid_init(table);
508
509         f = open(dev, O_RDWR);
510         if (f < 0)
511                 err(1, "%s", dev);
512
513         r = hid_get_report_desc(f);
514         if (r == 0)
515                 errx(1, "USB_GET_REPORT_DESC");
516
517         if (repdump) {
518                 printf("Report descriptor:\n");
519                 dumpitems(r);
520         }
521         if (argc != 0 || all) {
522                 parceargs(r, all, argc, argv);
523                 if (wflag)
524                         writedata(f, r);
525                 else
526                         dumpdata(f, r, loop);
527         }
528
529         hid_dispose_report_desc(r);
530         exit(0);
531 }