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