xref: /freebsd/usr.bin/usbhidctl/usbhid.c (revision 7778ab7e)
109d308a8SNick Hibma /*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
209d308a8SNick Hibma /*	$FreeBSD$ */
309d308a8SNick Hibma 
409d308a8SNick Hibma /*
509d308a8SNick Hibma  * Copyright (c) 1998 The NetBSD Foundation, Inc.
609d308a8SNick Hibma  * All rights reserved.
709d308a8SNick Hibma  *
809d308a8SNick Hibma  * This code is derived from software contributed to The NetBSD Foundation
909d308a8SNick Hibma  * by Lennart Augustsson (augustss@netbsd.org).
1009d308a8SNick Hibma  *
1109d308a8SNick Hibma  * Redistribution and use in source and binary forms, with or without
1209d308a8SNick Hibma  * modification, are permitted provided that the following conditions
1309d308a8SNick Hibma  * are met:
1409d308a8SNick Hibma  * 1. Redistributions of source code must retain the above copyright
1509d308a8SNick Hibma  *    notice, this list of conditions and the following disclaimer.
1609d308a8SNick Hibma  * 2. Redistributions in binary form must reproduce the above copyright
1709d308a8SNick Hibma  *    notice, this list of conditions and the following disclaimer in the
1809d308a8SNick Hibma  *    documentation and/or other materials provided with the distribution.
1909d308a8SNick Hibma  *
2009d308a8SNick Hibma  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2109d308a8SNick Hibma  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2209d308a8SNick Hibma  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2309d308a8SNick Hibma  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2409d308a8SNick Hibma  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2509d308a8SNick Hibma  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2609d308a8SNick Hibma  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2709d308a8SNick Hibma  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2809d308a8SNick Hibma  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2909d308a8SNick Hibma  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3009d308a8SNick Hibma  * POSSIBILITY OF SUCH DAMAGE.
3109d308a8SNick Hibma  */
3209d308a8SNick Hibma 
3309d308a8SNick Hibma #include <stdio.h>
3409d308a8SNick Hibma #include <stdlib.h>
3509d308a8SNick Hibma #include <string.h>
3609d308a8SNick Hibma #include <sys/types.h>
3709d308a8SNick Hibma #include <fcntl.h>
3809d308a8SNick Hibma #include <unistd.h>
3909d308a8SNick Hibma #include <err.h>
4009d308a8SNick Hibma #include <ctype.h>
4109d308a8SNick Hibma #include <errno.h>
42cf0e07e5SMatthew N. Dodd #include <usbhid.h>
43bf41796cSAndrew Thompson #include <dev/usb/usbhid.h>
4409d308a8SNick Hibma 
457778ab7eSAlexander Motin struct variable {
467778ab7eSAlexander Motin 	char *name;
477778ab7eSAlexander Motin 	int instance;
487778ab7eSAlexander Motin 	int val;
497778ab7eSAlexander Motin 	struct hid_item h;
507778ab7eSAlexander Motin 	struct variable *next;
517778ab7eSAlexander Motin } *vars;
527778ab7eSAlexander Motin 
5309d308a8SNick Hibma int verbose = 0;
5409d308a8SNick Hibma int noname = 0;
559a2a66f1SGreg Lehey int hexdump = 0;
567778ab7eSAlexander Motin int wflag = 0;
577778ab7eSAlexander Motin int zflag = 0;
5809d308a8SNick Hibma 
597778ab7eSAlexander Motin static void usage(void);
607778ab7eSAlexander Motin static void dumpitem(const char *label, struct hid_item *h);
617778ab7eSAlexander Motin static void dumpitems(report_desc_t r);
627778ab7eSAlexander Motin static void prdata(u_char *buf, struct hid_item *h);
637778ab7eSAlexander Motin static void dumpdata(int f, report_desc_t r, int loop);
647778ab7eSAlexander Motin static void writedata(int f, report_desc_t r);
6509d308a8SNick Hibma 
667778ab7eSAlexander Motin static void
677778ab7eSAlexander Motin parceargs(report_desc_t r, int all, int nnames, char **names)
6809d308a8SNick Hibma {
697778ab7eSAlexander Motin 	struct hid_data *d;
707778ab7eSAlexander Motin 	struct hid_item h;
717778ab7eSAlexander Motin 	char colls[1000];
727778ab7eSAlexander Motin 	char hname[1000], *tmp1, *tmp2;
737778ab7eSAlexander Motin 	struct variable *var, **pnext;
747778ab7eSAlexander Motin 	int i, instance, cp, t;
7509d308a8SNick Hibma 
767778ab7eSAlexander Motin 	pnext = &vars;
777778ab7eSAlexander Motin 	if (all) {
787778ab7eSAlexander Motin 		if (wflag)
797778ab7eSAlexander Motin 			errx(1, "Must not specify -w to read variables");
807778ab7eSAlexander Motin 		cp = 0;
817778ab7eSAlexander Motin 		for (d = hid_start_parse(r,
827778ab7eSAlexander Motin 		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
837778ab7eSAlexander Motin 		    hid_get_item(d, &h); ) {
847778ab7eSAlexander Motin 			if (h.kind == hid_collection) {
857778ab7eSAlexander Motin 				cp += sprintf(&colls[cp], "%s%s:%s",
867778ab7eSAlexander Motin 				    cp != 0 ? "." : "",
877778ab7eSAlexander Motin 				    hid_usage_page(HID_PAGE(h.usage)),
887778ab7eSAlexander Motin 				    hid_usage_in_page(h.usage));
897778ab7eSAlexander Motin 			} else if (h.kind == hid_endcollection) {
907778ab7eSAlexander Motin 				tmp1 = strrchr(colls, '.');
917778ab7eSAlexander Motin 				if (tmp1 != NULL) {
927778ab7eSAlexander Motin 					cp -= strlen(tmp1);
937778ab7eSAlexander Motin 					tmp1[0] = 0;
947778ab7eSAlexander Motin 				} else {
957778ab7eSAlexander Motin 					cp = 0;
967778ab7eSAlexander Motin 					colls[0] = 0;
977778ab7eSAlexander Motin 				}
987778ab7eSAlexander Motin 			}
997778ab7eSAlexander Motin 			if ((h.kind != hid_input && h.kind != hid_output &&
1007778ab7eSAlexander Motin 			    h.kind != hid_feature) || (h.flags & HIO_CONST))
1017778ab7eSAlexander Motin 				continue;
1027778ab7eSAlexander Motin 			var = malloc(sizeof(*var));
1037778ab7eSAlexander Motin 			memset(var, 0, sizeof(*var));
1047778ab7eSAlexander Motin 			asprintf(&var->name, "%s%s%s:%s",
1057778ab7eSAlexander Motin 			    colls, colls[0] != 0 ? "." : "",
1067778ab7eSAlexander Motin 			    hid_usage_page(HID_PAGE(h.usage)),
1077778ab7eSAlexander Motin 			    hid_usage_in_page(h.usage));
1087778ab7eSAlexander Motin 			var->h = h;
1097778ab7eSAlexander Motin 			*pnext = var;
1107778ab7eSAlexander Motin 			pnext = &var->next;
1117778ab7eSAlexander Motin 		}
1127778ab7eSAlexander Motin 		hid_end_parse(d);
1137778ab7eSAlexander Motin 		return;
1147778ab7eSAlexander Motin 	}
1157778ab7eSAlexander Motin 	for (i = 0; i < nnames; i++) {
1167778ab7eSAlexander Motin 		var = malloc(sizeof(*var));
1177778ab7eSAlexander Motin 		memset(var, 0, sizeof(*var));
1187778ab7eSAlexander Motin 		tmp1 = tmp2 = strdup(names[i]);
1197778ab7eSAlexander Motin 		strsep(&tmp2, "=");
1207778ab7eSAlexander Motin 		var->name = strsep(&tmp1, "#");
1217778ab7eSAlexander Motin 		if (tmp1 != NULL)
1227778ab7eSAlexander Motin 			var->instance = atoi(tmp1);
1237778ab7eSAlexander Motin 		if (tmp2 != NULL) {
1247778ab7eSAlexander Motin 			if (!wflag)
1257778ab7eSAlexander Motin 				errx(1, "Must specify -w to write variables");
1267778ab7eSAlexander Motin 			var->val = atoi(tmp2);
1277778ab7eSAlexander Motin 		} else
1287778ab7eSAlexander Motin 			if (wflag)
1297778ab7eSAlexander Motin 				errx(1, "Must not specify -w to read variables");
1307778ab7eSAlexander Motin 		*pnext = var;
1317778ab7eSAlexander Motin 		pnext = &var->next;
1327778ab7eSAlexander Motin 
1337778ab7eSAlexander Motin 		instance = 0;
1347778ab7eSAlexander Motin 		cp = 0;
1357778ab7eSAlexander Motin 		for (d = hid_start_parse(r,
1367778ab7eSAlexander Motin 		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
1377778ab7eSAlexander Motin 		    hid_get_item(d, &h); ) {
1387778ab7eSAlexander Motin 			if (h.kind == hid_collection) {
1397778ab7eSAlexander Motin 				cp += sprintf(&colls[cp], "%s%s:%s",
1407778ab7eSAlexander Motin 				    cp != 0 ? "." : "",
1417778ab7eSAlexander Motin 				    hid_usage_page(HID_PAGE(h.usage)),
1427778ab7eSAlexander Motin 				    hid_usage_in_page(h.usage));
1437778ab7eSAlexander Motin 			} else if (h.kind == hid_endcollection) {
1447778ab7eSAlexander Motin 				tmp1 = strrchr(colls, '.');
1457778ab7eSAlexander Motin 				if (tmp1 != NULL) {
1467778ab7eSAlexander Motin 					cp -= strlen(tmp1);
1477778ab7eSAlexander Motin 					tmp1[0] = 0;
1487778ab7eSAlexander Motin 				} else {
1497778ab7eSAlexander Motin 					cp = 0;
1507778ab7eSAlexander Motin 					colls[0] = 0;
1517778ab7eSAlexander Motin 				}
1527778ab7eSAlexander Motin 			}
1537778ab7eSAlexander Motin 			if ((h.kind != hid_input && h.kind != hid_output &&
1547778ab7eSAlexander Motin 			    h.kind != hid_feature) || (h.flags & HIO_CONST))
1557778ab7eSAlexander Motin 				continue;
1567778ab7eSAlexander Motin 			snprintf(hname, sizeof(hname), "%s%s%s:%s",
1577778ab7eSAlexander Motin 			    colls, colls[0] != 0 ? "." : "",
1587778ab7eSAlexander Motin 			    hid_usage_page(HID_PAGE(h.usage)),
1597778ab7eSAlexander Motin 			    hid_usage_in_page(h.usage));
1607778ab7eSAlexander Motin 			t = strlen(hname) - strlen(var->name);
1617778ab7eSAlexander Motin 			if (t > 0) {
1627778ab7eSAlexander Motin 				if (strcmp(hname + t, var->name) != 0)
1637778ab7eSAlexander Motin 					continue;
1647778ab7eSAlexander Motin 				if (hname[t - 1] != '.')
1657778ab7eSAlexander Motin 					continue;
1667778ab7eSAlexander Motin 			} else if (strcmp(hname, var->name) != 0)
1677778ab7eSAlexander Motin 				continue;
1687778ab7eSAlexander Motin 			if (var->instance != instance++)
1697778ab7eSAlexander Motin 				continue;
1707778ab7eSAlexander Motin 			var->h = h;
1717778ab7eSAlexander Motin 			break;
1727778ab7eSAlexander Motin 		}
1737778ab7eSAlexander Motin 		hid_end_parse(d);
1747778ab7eSAlexander Motin 		if (var->h.usage == 0)
1757778ab7eSAlexander Motin 			errx(1, "Unknown item '%s'", var->name);
1767778ab7eSAlexander Motin 	}
17709d308a8SNick Hibma }
17809d308a8SNick Hibma 
1797778ab7eSAlexander Motin static void
18009d308a8SNick Hibma usage(void)
18109d308a8SNick Hibma {
18209d308a8SNick Hibma 
1839a2a66f1SGreg Lehey 	fprintf(stderr,
1849a2a66f1SGreg Lehey                 "usage: %s -f device "
185eb29cfddSGreg Lehey                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n",
1861946089bSXin LI                 getprogname());
1879a2a66f1SGreg Lehey 	fprintf(stderr,
1889a2a66f1SGreg Lehey                 "       %s -f device "
189eb29cfddSGreg Lehey                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
1901946089bSXin LI                 getprogname());
1917778ab7eSAlexander Motin 	fprintf(stderr,
1927778ab7eSAlexander Motin                 "       %s -f device "
1937778ab7eSAlexander Motin                 "[-t tablefile] [-v] [-z] -w name=value\n",
1947778ab7eSAlexander Motin                 getprogname());
19509d308a8SNick Hibma 	exit(1);
19609d308a8SNick Hibma }
19709d308a8SNick Hibma 
1987778ab7eSAlexander Motin static void
1991a27f4f2SMark Murray dumpitem(const char *label, struct hid_item *h)
20009d308a8SNick Hibma {
20109d308a8SNick Hibma 	if ((h->flags & HIO_CONST) && !verbose)
20209d308a8SNick Hibma 		return;
2031bee2ec7SAlexander Motin 	printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
2041bee2ec7SAlexander Motin 	       h->report_ID, h->report_size, h->report_count,
20509d308a8SNick Hibma 	       hid_usage_page(HID_PAGE(h->usage)),
20609d308a8SNick Hibma 	       hid_usage_in_page(h->usage),
2071bee2ec7SAlexander Motin 	       h->flags & HIO_CONST ? " Const" : "",
2081bee2ec7SAlexander Motin 	       h->flags & HIO_VARIABLE ? "" : " Array");
20909d308a8SNick Hibma 	printf(", logical range %d..%d",
21009d308a8SNick Hibma 	       h->logical_minimum, h->logical_maximum);
21109d308a8SNick Hibma 	if (h->physical_minimum != h->physical_maximum)
21209d308a8SNick Hibma 		printf(", physical range %d..%d",
21309d308a8SNick Hibma 		       h->physical_minimum, h->physical_maximum);
21409d308a8SNick Hibma 	if (h->unit)
21509d308a8SNick Hibma 		printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
21609d308a8SNick Hibma 	printf("\n");
21709d308a8SNick Hibma }
21809d308a8SNick Hibma 
2191bee2ec7SAlexander Motin static const char *
2201bee2ec7SAlexander Motin hid_collection_type(int32_t type)
2211bee2ec7SAlexander Motin {
2221bee2ec7SAlexander Motin 	static char num[8];
2231bee2ec7SAlexander Motin 
2241bee2ec7SAlexander Motin 	switch (type) {
2251bee2ec7SAlexander Motin 	case 0: return ("Physical");
2261bee2ec7SAlexander Motin 	case 1: return ("Application");
2271bee2ec7SAlexander Motin 	case 2: return ("Logical");
2281bee2ec7SAlexander Motin 	case 3: return ("Report");
2291bee2ec7SAlexander Motin 	case 4: return ("Named_Array");
2301bee2ec7SAlexander Motin 	case 5: return ("Usage_Switch");
2311bee2ec7SAlexander Motin 	case 6: return ("Usage_Modifier");
2321bee2ec7SAlexander Motin 	}
2331bee2ec7SAlexander Motin 	snprintf(num, sizeof(num), "0x%02x", type);
2341bee2ec7SAlexander Motin 	return (num);
2351bee2ec7SAlexander Motin }
2361bee2ec7SAlexander Motin 
2377778ab7eSAlexander Motin static void
23809d308a8SNick Hibma dumpitems(report_desc_t r)
23909d308a8SNick Hibma {
24009d308a8SNick Hibma 	struct hid_data *d;
24109d308a8SNick Hibma 	struct hid_item h;
2421d10fe50SNick Hibma 	int size;
24309d308a8SNick Hibma 
2441bee2ec7SAlexander Motin 	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
24509d308a8SNick Hibma 		switch (h.kind) {
24609d308a8SNick Hibma 		case hid_collection:
2471bee2ec7SAlexander Motin 			printf("Collection type=%s page=%s usage=%s\n",
2481bee2ec7SAlexander Motin 			       hid_collection_type(h.collection),
24909d308a8SNick Hibma 			       hid_usage_page(HID_PAGE(h.usage)),
25009d308a8SNick Hibma 			       hid_usage_in_page(h.usage));
25109d308a8SNick Hibma 			break;
25209d308a8SNick Hibma 		case hid_endcollection:
25309d308a8SNick Hibma 			printf("End collection\n");
25409d308a8SNick Hibma 			break;
25509d308a8SNick Hibma 		case hid_input:
25609d308a8SNick Hibma 			dumpitem("Input  ", &h);
25709d308a8SNick Hibma 			break;
25809d308a8SNick Hibma 		case hid_output:
25909d308a8SNick Hibma 			dumpitem("Output ", &h);
26009d308a8SNick Hibma 			break;
26109d308a8SNick Hibma 		case hid_feature:
26209d308a8SNick Hibma 			dumpitem("Feature", &h);
26309d308a8SNick Hibma 			break;
26409d308a8SNick Hibma 		}
26509d308a8SNick Hibma 	}
26609d308a8SNick Hibma 	hid_end_parse(d);
2671bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_input, -1);
2681a2cdef4SNick Hibma 	printf("Total   input size %d bytes\n", size);
26909d308a8SNick Hibma 
2701bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_output, -1);
2711d10fe50SNick Hibma 	printf("Total  output size %d bytes\n", size);
27209d308a8SNick Hibma 
2731bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_feature, -1);
2741d10fe50SNick Hibma 	printf("Total feature size %d bytes\n", size);
27509d308a8SNick Hibma }
27609d308a8SNick Hibma 
2777778ab7eSAlexander Motin static void
27809d308a8SNick Hibma prdata(u_char *buf, struct hid_item *h)
27909d308a8SNick Hibma {
28009d308a8SNick Hibma 	u_int data;
28109d308a8SNick Hibma 	int i, pos;
28209d308a8SNick Hibma 
28309d308a8SNick Hibma 	pos = h->pos;
28409d308a8SNick Hibma 	for (i = 0; i < h->report_count; i++) {
28509d308a8SNick Hibma 		data = hid_get_data(buf, h);
2861bee2ec7SAlexander Motin 		if (i > 0)
2871bee2ec7SAlexander Motin 			printf(" ");
28809d308a8SNick Hibma 		if (h->logical_minimum < 0)
28909d308a8SNick Hibma 			printf("%d", (int)data);
29009d308a8SNick Hibma 		else
29109d308a8SNick Hibma 			printf("%u", data);
2929a2a66f1SGreg Lehey                 if (hexdump)
2939a2a66f1SGreg Lehey 			printf(" [0x%x]", data);
2941bee2ec7SAlexander Motin 		h->pos += h->report_size;
29509d308a8SNick Hibma 	}
2961bee2ec7SAlexander Motin 	h->pos = pos;
29709d308a8SNick Hibma }
29809d308a8SNick Hibma 
2997778ab7eSAlexander Motin static void
30009d308a8SNick Hibma dumpdata(int f, report_desc_t rd, int loop)
30109d308a8SNick Hibma {
3027778ab7eSAlexander Motin 	struct variable *var;
3037778ab7eSAlexander Motin 	int dlen, havedata, i, match, r, rid, use_rid;
30409d308a8SNick Hibma 	u_char *dbuf;
3057778ab7eSAlexander Motin 	enum hid_kind kind;
30609d308a8SNick Hibma 
3077778ab7eSAlexander Motin 	kind = 0;
3087778ab7eSAlexander Motin 	rid = -1;
3097778ab7eSAlexander Motin 	use_rid = !!hid_get_report_id(f);
31009d308a8SNick Hibma 	do {
3117778ab7eSAlexander Motin 		if (kind < 3) {
3127778ab7eSAlexander Motin 			if (++rid >= 256) {
3137778ab7eSAlexander Motin 				rid = 0;
3147778ab7eSAlexander Motin 				kind++;
31509d308a8SNick Hibma 			}
3167778ab7eSAlexander Motin 			if (kind >= 3)
3177778ab7eSAlexander Motin 				rid = -1;
3187778ab7eSAlexander Motin 			for (var = vars; var; var = var->next) {
3197778ab7eSAlexander Motin 				if (rid == var->h.report_ID &&
3207778ab7eSAlexander Motin 				    kind == var->h.kind)
3217778ab7eSAlexander Motin 					break;
3227778ab7eSAlexander Motin 			}
3237778ab7eSAlexander Motin 			if (var == NULL)
3241bee2ec7SAlexander Motin 				continue;
3257778ab7eSAlexander Motin 		}
3267778ab7eSAlexander Motin 		dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid);
3277778ab7eSAlexander Motin 		if (dlen <= 0)
3287778ab7eSAlexander Motin 			continue;
3297778ab7eSAlexander Motin 		dbuf = malloc(dlen);
3307778ab7eSAlexander Motin 		memset(dbuf, 0, dlen);
3317778ab7eSAlexander Motin 		if (kind < 3) {
3327778ab7eSAlexander Motin 			dbuf[0] = rid;
3337778ab7eSAlexander Motin 			r = hid_get_report(f, kind, dbuf, dlen);
3347778ab7eSAlexander Motin 			if (r < 0)
3357778ab7eSAlexander Motin 				warn("hid_get_report(rid %d)", rid);
3367778ab7eSAlexander Motin 			havedata = !r && (rid == 0 || dbuf[0] == rid);
3377778ab7eSAlexander Motin 			if (rid != 0)
3387778ab7eSAlexander Motin 				dbuf[0] = rid;
3397778ab7eSAlexander Motin 		} else {
3407778ab7eSAlexander Motin 			r = read(f, dbuf, dlen);
3417778ab7eSAlexander Motin 			if (r < 1)
3427778ab7eSAlexander Motin 				err(1, "read error");
3437778ab7eSAlexander Motin 			havedata = 1;
3447778ab7eSAlexander Motin 		}
3457778ab7eSAlexander Motin 		if (verbose) {
3467778ab7eSAlexander Motin 			printf("Got %s report %d (%d bytes):",
3477778ab7eSAlexander Motin 			    kind == hid_output ? "output" :
3487778ab7eSAlexander Motin 			    kind == hid_feature ? "feature" : "input",
3497778ab7eSAlexander Motin 			    use_rid ? dbuf[0] : 0, dlen);
3507778ab7eSAlexander Motin 			if (havedata) {
3517778ab7eSAlexander Motin 				for (i = 0; i < dlen; i++)
3527778ab7eSAlexander Motin 					printf(" %02x", dbuf[i]);
3537778ab7eSAlexander Motin 			}
3547778ab7eSAlexander Motin 			printf("\n");
3557778ab7eSAlexander Motin 		}
3567778ab7eSAlexander Motin 		match = 0;
3577778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
3587778ab7eSAlexander Motin 			if ((kind < 3 ? kind : hid_input) != var->h.kind)
3597778ab7eSAlexander Motin 				continue;
3607778ab7eSAlexander Motin 			if (var->h.report_ID != 0 &&
3617778ab7eSAlexander Motin 			    dbuf[0] != var->h.report_ID)
3627778ab7eSAlexander Motin 				continue;
3637778ab7eSAlexander Motin 			match = 1;
36409d308a8SNick Hibma 			if (!noname)
3657778ab7eSAlexander Motin 				printf("%s=", var->name);
3667778ab7eSAlexander Motin 			if (havedata)
3677778ab7eSAlexander Motin 				prdata(dbuf, &var->h);
36809d308a8SNick Hibma 			printf("\n");
36909d308a8SNick Hibma 		}
3707778ab7eSAlexander Motin 		if (match)
37109d308a8SNick Hibma 			printf("\n");
37209d308a8SNick Hibma 		free(dbuf);
3737778ab7eSAlexander Motin 	} while (loop || kind < 3);
3747778ab7eSAlexander Motin }
3757778ab7eSAlexander Motin 
3767778ab7eSAlexander Motin static void
3777778ab7eSAlexander Motin writedata(int f, report_desc_t rd)
3787778ab7eSAlexander Motin {
3797778ab7eSAlexander Motin 	struct variable *var;
3807778ab7eSAlexander Motin 	int dlen, i, r, rid;
3817778ab7eSAlexander Motin 	u_char *dbuf;
3827778ab7eSAlexander Motin 	enum hid_kind kind;
3837778ab7eSAlexander Motin 
3847778ab7eSAlexander Motin 	kind = 0;
3857778ab7eSAlexander Motin 	rid = 0;
3867778ab7eSAlexander Motin 	for (kind = 0; kind < 3; kind ++) {
3877778ab7eSAlexander Motin 	    for (rid = 0; rid < 256; rid ++) {
3887778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
3897778ab7eSAlexander Motin 			if (rid == var->h.report_ID && kind == var->h.kind)
3907778ab7eSAlexander Motin 				break;
3917778ab7eSAlexander Motin 		}
3927778ab7eSAlexander Motin 		if (var == NULL)
3937778ab7eSAlexander Motin 			continue;
3947778ab7eSAlexander Motin 		dlen = hid_report_size(rd, kind, rid);
3957778ab7eSAlexander Motin 		if (dlen <= 0)
3967778ab7eSAlexander Motin 			continue;
3977778ab7eSAlexander Motin 		dbuf = malloc(dlen);
3987778ab7eSAlexander Motin 		memset(dbuf, 0, dlen);
3997778ab7eSAlexander Motin 		dbuf[0] = rid;
4007778ab7eSAlexander Motin 		if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) {
4017778ab7eSAlexander Motin 			if (verbose) {
4027778ab7eSAlexander Motin 				printf("Got %s report %d (%d bytes):",
4037778ab7eSAlexander Motin 				    kind == hid_input ? "input" :
4047778ab7eSAlexander Motin 				    kind == hid_output ? "output" : "feature",
4057778ab7eSAlexander Motin 				    rid, dlen);
4067778ab7eSAlexander Motin 				for (i = 0; i < dlen; i++)
4077778ab7eSAlexander Motin 					printf(" %02x", dbuf[i]);
4087778ab7eSAlexander Motin 				printf("\n");
4097778ab7eSAlexander Motin 			}
4107778ab7eSAlexander Motin 		} else if (!zflag) {
4117778ab7eSAlexander Motin 			warn("hid_get_report(rid %d)", rid);
4127778ab7eSAlexander Motin 			if (verbose) {
4137778ab7eSAlexander Motin 				printf("Can't get %s report %d (%d bytes). "
4147778ab7eSAlexander Motin 				    "Will be initialized with zeros.\n",
4157778ab7eSAlexander Motin 				    kind == hid_input ? "input" :
4167778ab7eSAlexander Motin 				    kind == hid_output ? "output" : "feature",
4177778ab7eSAlexander Motin 				    rid, dlen);
4187778ab7eSAlexander Motin 			}
4197778ab7eSAlexander Motin 		}
4207778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
4217778ab7eSAlexander Motin 			if (rid != var->h.report_ID || kind != var->h.kind)
4227778ab7eSAlexander Motin 				continue;
4237778ab7eSAlexander Motin 			hid_set_data(dbuf, &var->h, var->val);
4247778ab7eSAlexander Motin 		}
4257778ab7eSAlexander Motin 		if (verbose) {
4267778ab7eSAlexander Motin 			printf("Setting %s report %d (%d bytes):",
4277778ab7eSAlexander Motin 			    kind == hid_output ? "output" :
4287778ab7eSAlexander Motin 			    kind == hid_feature ? "feature" : "input",
4297778ab7eSAlexander Motin 			    rid, dlen);
4307778ab7eSAlexander Motin 			for (i = 0; i < dlen; i++)
4317778ab7eSAlexander Motin 				printf(" %02x", dbuf[i]);
4327778ab7eSAlexander Motin 			printf("\n");
4337778ab7eSAlexander Motin 		}
4347778ab7eSAlexander Motin 		r = hid_set_report(f, kind, dbuf, dlen);
4357778ab7eSAlexander Motin 		if (r != 0)
4367778ab7eSAlexander Motin 			warn("hid_set_report(rid %d)", rid);
4377778ab7eSAlexander Motin 		free(dbuf);
4387778ab7eSAlexander Motin 	    }
4397778ab7eSAlexander Motin 	}
44009d308a8SNick Hibma }
44109d308a8SNick Hibma 
44209d308a8SNick Hibma int
44309d308a8SNick Hibma main(int argc, char **argv)
44409d308a8SNick Hibma {
44509d308a8SNick Hibma 	report_desc_t r;
4467778ab7eSAlexander Motin 	char *table = 0;
4477778ab7eSAlexander Motin 	char devnam[100], *dev = NULL;
4487778ab7eSAlexander Motin 	int f;
4497778ab7eSAlexander Motin 	int all = 0;
45009d308a8SNick Hibma 	int ch;
45109d308a8SNick Hibma 	int repdump = 0;
45209d308a8SNick Hibma 	int loop = 0;
45309d308a8SNick Hibma 
4547778ab7eSAlexander Motin 	while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) {
45509d308a8SNick Hibma 		switch(ch) {
45609d308a8SNick Hibma 		case 'a':
45709d308a8SNick Hibma 			all++;
45809d308a8SNick Hibma 			break;
45909d308a8SNick Hibma 		case 'f':
46009d308a8SNick Hibma 			dev = optarg;
46109d308a8SNick Hibma 			break;
46209d308a8SNick Hibma 		case 'l':
46309d308a8SNick Hibma 			loop ^= 1;
46409d308a8SNick Hibma 			break;
46509d308a8SNick Hibma 		case 'n':
46609d308a8SNick Hibma 			noname++;
46709d308a8SNick Hibma 			break;
46809d308a8SNick Hibma 		case 'r':
46909d308a8SNick Hibma 			repdump++;
47009d308a8SNick Hibma 			break;
47109d308a8SNick Hibma 		case 't':
47209d308a8SNick Hibma 			table = optarg;
47309d308a8SNick Hibma 			break;
47409d308a8SNick Hibma 		case 'v':
47509d308a8SNick Hibma 			verbose++;
47609d308a8SNick Hibma 			break;
4777778ab7eSAlexander Motin 		case 'w':
4787778ab7eSAlexander Motin 			wflag = 1;
4797778ab7eSAlexander Motin 			break;
4809a2a66f1SGreg Lehey 		case 'x':
481eb29cfddSGreg Lehey 			hexdump = 1;
4829a2a66f1SGreg Lehey 			break;
4837778ab7eSAlexander Motin 		case 'z':
4847778ab7eSAlexander Motin 			zflag = 1;
4857778ab7eSAlexander Motin 			break;
48609d308a8SNick Hibma 		case '?':
48709d308a8SNick Hibma 		default:
48809d308a8SNick Hibma 			usage();
48909d308a8SNick Hibma 		}
49009d308a8SNick Hibma 	}
49109d308a8SNick Hibma 	argc -= optind;
49209d308a8SNick Hibma 	argv += optind;
4937778ab7eSAlexander Motin 	if (dev == NULL)
49409d308a8SNick Hibma 		usage();
49509d308a8SNick Hibma 
4967778ab7eSAlexander Motin 	if (argc == 0 && !all && !repdump)
49709d308a8SNick Hibma 		usage();
49809d308a8SNick Hibma 
49909d308a8SNick Hibma 	if (dev[0] != '/') {
50009d308a8SNick Hibma 		if (isdigit(dev[0]))
5011a27f4f2SMark Murray 			snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
50209d308a8SNick Hibma 		else
5031a27f4f2SMark Murray 			snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
5041a27f4f2SMark Murray 		dev = devnam;
50509d308a8SNick Hibma 	}
50609d308a8SNick Hibma 
50709d308a8SNick Hibma 	hid_init(table);
50809d308a8SNick Hibma 
50909d308a8SNick Hibma 	f = open(dev, O_RDWR);
51009d308a8SNick Hibma 	if (f < 0)
51109d308a8SNick Hibma 		err(1, "%s", dev);
51209d308a8SNick Hibma 
51309d308a8SNick Hibma 	r = hid_get_report_desc(f);
51409d308a8SNick Hibma 	if (r == 0)
51509d308a8SNick Hibma 		errx(1, "USB_GET_REPORT_DESC");
51609d308a8SNick Hibma 
51709d308a8SNick Hibma 	if (repdump) {
51809d308a8SNick Hibma 		printf("Report descriptor:\n");
51909d308a8SNick Hibma 		dumpitems(r);
52009d308a8SNick Hibma 	}
5217778ab7eSAlexander Motin 	if (argc != 0 || all) {
5227778ab7eSAlexander Motin 		parceargs(r, all, argc, argv);
5237778ab7eSAlexander Motin 		if (wflag)
5247778ab7eSAlexander Motin 			writedata(f, r);
5257778ab7eSAlexander Motin 		else
52609d308a8SNick Hibma 			dumpdata(f, r, loop);
5277778ab7eSAlexander Motin 	}
52809d308a8SNick Hibma 
52909d308a8SNick Hibma 	hid_dispose_report_desc(r);
53009d308a8SNick Hibma 	exit(0);
53109d308a8SNick Hibma }
532