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