xref: /freebsd/usr.bin/usbhidctl/usbhid.c (revision 2a63c3be)
109d308a8SNick Hibma /*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
209d308a8SNick Hibma 
31de7b4b8SPedro F. Giffuni /*-
4b61a5730SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni  *
609d308a8SNick Hibma  * Copyright (c) 1998 The NetBSD Foundation, Inc.
709d308a8SNick Hibma  * All rights reserved.
809d308a8SNick Hibma  *
909d308a8SNick Hibma  * This code is derived from software contributed to The NetBSD Foundation
1009d308a8SNick Hibma  * by Lennart Augustsson (augustss@netbsd.org).
1109d308a8SNick Hibma  *
1209d308a8SNick Hibma  * Redistribution and use in source and binary forms, with or without
1309d308a8SNick Hibma  * modification, are permitted provided that the following conditions
1409d308a8SNick Hibma  * are met:
1509d308a8SNick Hibma  * 1. Redistributions of source code must retain the above copyright
1609d308a8SNick Hibma  *    notice, this list of conditions and the following disclaimer.
1709d308a8SNick Hibma  * 2. Redistributions in binary form must reproduce the above copyright
1809d308a8SNick Hibma  *    notice, this list of conditions and the following disclaimer in the
1909d308a8SNick Hibma  *    documentation and/or other materials provided with the distribution.
2009d308a8SNick Hibma  *
2109d308a8SNick Hibma  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2209d308a8SNick Hibma  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2309d308a8SNick Hibma  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2409d308a8SNick Hibma  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2509d308a8SNick Hibma  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2609d308a8SNick Hibma  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2709d308a8SNick Hibma  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2809d308a8SNick Hibma  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2909d308a8SNick Hibma  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3009d308a8SNick Hibma  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3109d308a8SNick Hibma  * POSSIBILITY OF SUCH DAMAGE.
3209d308a8SNick Hibma  */
3309d308a8SNick Hibma 
3409d308a8SNick Hibma #include <stdio.h>
3509d308a8SNick Hibma #include <stdlib.h>
3609d308a8SNick Hibma #include <string.h>
3709d308a8SNick Hibma #include <sys/types.h>
3809d308a8SNick Hibma #include <fcntl.h>
3909d308a8SNick Hibma #include <unistd.h>
4009d308a8SNick Hibma #include <err.h>
4109d308a8SNick Hibma #include <ctype.h>
4209d308a8SNick Hibma #include <errno.h>
43cf0e07e5SMatthew N. Dodd #include <usbhid.h>
44bf41796cSAndrew Thompson #include <dev/usb/usbhid.h>
4509d308a8SNick Hibma 
4669c5bce6SEd Schouten static struct variable {
477778ab7eSAlexander Motin 	char *name;
487778ab7eSAlexander Motin 	int instance;
497778ab7eSAlexander Motin 	int val;
507778ab7eSAlexander Motin 	struct hid_item h;
517778ab7eSAlexander Motin 	struct variable *next;
527778ab7eSAlexander Motin } *vars;
537778ab7eSAlexander Motin 
5469c5bce6SEd Schouten static int verbose = 0;
5569c5bce6SEd Schouten static int noname = 0;
5669c5bce6SEd Schouten static int hexdump = 0;
5769c5bce6SEd Schouten static int wflag = 0;
5869c5bce6SEd Schouten static int zflag = 0;
5909d308a8SNick Hibma 
60cccdaf50SAlfonso Gregory static void usage(void) __dead2;
617778ab7eSAlexander Motin static void dumpitem(const char *label, struct hid_item *h);
627778ab7eSAlexander Motin static void dumpitems(report_desc_t r);
637778ab7eSAlexander Motin static void prdata(u_char *buf, struct hid_item *h);
647778ab7eSAlexander Motin static void dumpdata(int f, report_desc_t r, int loop);
657778ab7eSAlexander Motin static void writedata(int f, report_desc_t r);
6609d308a8SNick Hibma 
677778ab7eSAlexander Motin static void
parceargs(report_desc_t r,int all,int nnames,char ** names)687778ab7eSAlexander Motin parceargs(report_desc_t r, int all, int nnames, char **names)
6909d308a8SNick Hibma {
707778ab7eSAlexander Motin 	struct hid_data *d;
717778ab7eSAlexander Motin 	struct hid_item h;
727778ab7eSAlexander Motin 	char colls[1000];
737778ab7eSAlexander Motin 	char hname[1000], *tmp1, *tmp2;
747778ab7eSAlexander Motin 	struct variable *var, **pnext;
757778ab7eSAlexander Motin 	int i, instance, cp, t;
7609d308a8SNick Hibma 
777778ab7eSAlexander Motin 	pnext = &vars;
787778ab7eSAlexander Motin 	if (all) {
797778ab7eSAlexander Motin 		if (wflag)
807778ab7eSAlexander Motin 			errx(1, "Must not specify -w to read variables");
817778ab7eSAlexander Motin 		cp = 0;
827778ab7eSAlexander Motin 		for (d = hid_start_parse(r,
837778ab7eSAlexander Motin 		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
847778ab7eSAlexander Motin 		    hid_get_item(d, &h); ) {
857778ab7eSAlexander Motin 			if (h.kind == hid_collection) {
867778ab7eSAlexander Motin 				cp += sprintf(&colls[cp], "%s%s:%s",
877778ab7eSAlexander Motin 				    cp != 0 ? "." : "",
887778ab7eSAlexander Motin 				    hid_usage_page(HID_PAGE(h.usage)),
897778ab7eSAlexander Motin 				    hid_usage_in_page(h.usage));
907778ab7eSAlexander Motin 			} else if (h.kind == hid_endcollection) {
917778ab7eSAlexander Motin 				tmp1 = strrchr(colls, '.');
927778ab7eSAlexander Motin 				if (tmp1 != NULL) {
937778ab7eSAlexander Motin 					cp -= strlen(tmp1);
947778ab7eSAlexander Motin 					tmp1[0] = 0;
957778ab7eSAlexander Motin 				} else {
967778ab7eSAlexander Motin 					cp = 0;
977778ab7eSAlexander Motin 					colls[0] = 0;
987778ab7eSAlexander Motin 				}
997778ab7eSAlexander Motin 			}
1007778ab7eSAlexander Motin 			if ((h.kind != hid_input && h.kind != hid_output &&
1017778ab7eSAlexander Motin 			    h.kind != hid_feature) || (h.flags & HIO_CONST))
1027778ab7eSAlexander Motin 				continue;
1037778ab7eSAlexander Motin 			var = malloc(sizeof(*var));
1047778ab7eSAlexander Motin 			memset(var, 0, sizeof(*var));
1057778ab7eSAlexander Motin 			asprintf(&var->name, "%s%s%s:%s",
1067778ab7eSAlexander Motin 			    colls, colls[0] != 0 ? "." : "",
1077778ab7eSAlexander Motin 			    hid_usage_page(HID_PAGE(h.usage)),
1087778ab7eSAlexander Motin 			    hid_usage_in_page(h.usage));
1097778ab7eSAlexander Motin 			var->h = h;
1107778ab7eSAlexander Motin 			*pnext = var;
1117778ab7eSAlexander Motin 			pnext = &var->next;
1127778ab7eSAlexander Motin 		}
1137778ab7eSAlexander Motin 		hid_end_parse(d);
1147778ab7eSAlexander Motin 		return;
1157778ab7eSAlexander Motin 	}
1167778ab7eSAlexander Motin 	for (i = 0; i < nnames; i++) {
1177778ab7eSAlexander Motin 		var = malloc(sizeof(*var));
1187778ab7eSAlexander Motin 		memset(var, 0, sizeof(*var));
1197778ab7eSAlexander Motin 		tmp1 = tmp2 = strdup(names[i]);
1207778ab7eSAlexander Motin 		strsep(&tmp2, "=");
1217778ab7eSAlexander Motin 		var->name = strsep(&tmp1, "#");
1227778ab7eSAlexander Motin 		if (tmp1 != NULL)
1237778ab7eSAlexander Motin 			var->instance = atoi(tmp1);
1247778ab7eSAlexander Motin 		if (tmp2 != NULL) {
1257778ab7eSAlexander Motin 			if (!wflag)
1267778ab7eSAlexander Motin 				errx(1, "Must specify -w to write variables");
1277778ab7eSAlexander Motin 			var->val = atoi(tmp2);
1287778ab7eSAlexander Motin 		} else
1297778ab7eSAlexander Motin 			if (wflag)
1307778ab7eSAlexander Motin 				errx(1, "Must not specify -w to read variables");
1317778ab7eSAlexander Motin 		*pnext = var;
1327778ab7eSAlexander Motin 		pnext = &var->next;
1337778ab7eSAlexander Motin 
1347778ab7eSAlexander Motin 		instance = 0;
1357778ab7eSAlexander Motin 		cp = 0;
1367778ab7eSAlexander Motin 		for (d = hid_start_parse(r,
1377778ab7eSAlexander Motin 		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
1387778ab7eSAlexander Motin 		    hid_get_item(d, &h); ) {
1397778ab7eSAlexander Motin 			if (h.kind == hid_collection) {
1407778ab7eSAlexander Motin 				cp += sprintf(&colls[cp], "%s%s:%s",
1417778ab7eSAlexander Motin 				    cp != 0 ? "." : "",
1427778ab7eSAlexander Motin 				    hid_usage_page(HID_PAGE(h.usage)),
1437778ab7eSAlexander Motin 				    hid_usage_in_page(h.usage));
1447778ab7eSAlexander Motin 			} else if (h.kind == hid_endcollection) {
1457778ab7eSAlexander Motin 				tmp1 = strrchr(colls, '.');
1467778ab7eSAlexander Motin 				if (tmp1 != NULL) {
1477778ab7eSAlexander Motin 					cp -= strlen(tmp1);
1487778ab7eSAlexander Motin 					tmp1[0] = 0;
1497778ab7eSAlexander Motin 				} else {
1507778ab7eSAlexander Motin 					cp = 0;
1517778ab7eSAlexander Motin 					colls[0] = 0;
1527778ab7eSAlexander Motin 				}
1537778ab7eSAlexander Motin 			}
1547778ab7eSAlexander Motin 			if ((h.kind != hid_input && h.kind != hid_output &&
1557778ab7eSAlexander Motin 			    h.kind != hid_feature) || (h.flags & HIO_CONST))
1567778ab7eSAlexander Motin 				continue;
1577778ab7eSAlexander Motin 			snprintf(hname, sizeof(hname), "%s%s%s:%s",
1587778ab7eSAlexander Motin 			    colls, colls[0] != 0 ? "." : "",
1597778ab7eSAlexander Motin 			    hid_usage_page(HID_PAGE(h.usage)),
1607778ab7eSAlexander Motin 			    hid_usage_in_page(h.usage));
1617778ab7eSAlexander Motin 			t = strlen(hname) - strlen(var->name);
1627778ab7eSAlexander Motin 			if (t > 0) {
1637778ab7eSAlexander Motin 				if (strcmp(hname + t, var->name) != 0)
1647778ab7eSAlexander Motin 					continue;
1657778ab7eSAlexander Motin 				if (hname[t - 1] != '.')
1667778ab7eSAlexander Motin 					continue;
1677778ab7eSAlexander Motin 			} else if (strcmp(hname, var->name) != 0)
1687778ab7eSAlexander Motin 				continue;
1697778ab7eSAlexander Motin 			if (var->instance != instance++)
1707778ab7eSAlexander Motin 				continue;
1717778ab7eSAlexander Motin 			var->h = h;
1727778ab7eSAlexander Motin 			break;
1737778ab7eSAlexander Motin 		}
1747778ab7eSAlexander Motin 		hid_end_parse(d);
1757778ab7eSAlexander Motin 		if (var->h.usage == 0)
1767778ab7eSAlexander Motin 			errx(1, "Unknown item '%s'", var->name);
1777778ab7eSAlexander Motin 	}
17809d308a8SNick Hibma }
17909d308a8SNick Hibma 
1807778ab7eSAlexander Motin static void
usage(void)18109d308a8SNick Hibma usage(void)
18209d308a8SNick Hibma {
18309d308a8SNick Hibma 
1849a2a66f1SGreg Lehey 	fprintf(stderr,
1859a2a66f1SGreg Lehey                 "usage: %s -f device "
186e39e854eSAlexander Motin                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] name ...\n",
1871946089bSXin LI                 getprogname());
1889a2a66f1SGreg Lehey 	fprintf(stderr,
1899a2a66f1SGreg Lehey                 "       %s -f device "
190e39e854eSAlexander Motin                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] -a\n",
1911946089bSXin LI                 getprogname());
1927778ab7eSAlexander Motin 	fprintf(stderr,
1937778ab7eSAlexander Motin                 "       %s -f device "
1947778ab7eSAlexander Motin                 "[-t tablefile] [-v] [-z] -w name=value\n",
1957778ab7eSAlexander Motin                 getprogname());
19609d308a8SNick Hibma 	exit(1);
19709d308a8SNick Hibma }
19809d308a8SNick Hibma 
1997778ab7eSAlexander Motin static void
dumpitem(const char * label,struct hid_item * h)2001a27f4f2SMark Murray dumpitem(const char *label, struct hid_item *h)
20109d308a8SNick Hibma {
20209d308a8SNick Hibma 	if ((h->flags & HIO_CONST) && !verbose)
20309d308a8SNick Hibma 		return;
2045c1d9710SHans Petter Selasky 	printf("%s rid=%d pos=%d size=%d count=%d page=%s usage=%s%s%s", label,
2055c1d9710SHans Petter Selasky 	       h->report_ID, h->pos, h->report_size, h->report_count,
20609d308a8SNick Hibma 	       hid_usage_page(HID_PAGE(h->usage)),
20709d308a8SNick Hibma 	       hid_usage_in_page(h->usage),
2081bee2ec7SAlexander Motin 	       h->flags & HIO_CONST ? " Const" : "",
2091bee2ec7SAlexander Motin 	       h->flags & HIO_VARIABLE ? "" : " Array");
21009d308a8SNick Hibma 	printf(", logical range %d..%d",
21109d308a8SNick Hibma 	       h->logical_minimum, h->logical_maximum);
21209d308a8SNick Hibma 	if (h->physical_minimum != h->physical_maximum)
21309d308a8SNick Hibma 		printf(", physical range %d..%d",
21409d308a8SNick Hibma 		       h->physical_minimum, h->physical_maximum);
21509d308a8SNick Hibma 	if (h->unit)
21609d308a8SNick Hibma 		printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
21709d308a8SNick Hibma 	printf("\n");
21809d308a8SNick Hibma }
21909d308a8SNick Hibma 
2201bee2ec7SAlexander Motin static const char *
hid_collection_type(int32_t type)2211bee2ec7SAlexander Motin hid_collection_type(int32_t type)
2221bee2ec7SAlexander Motin {
2231bee2ec7SAlexander Motin 	static char num[8];
2241bee2ec7SAlexander Motin 
2251bee2ec7SAlexander Motin 	switch (type) {
2261bee2ec7SAlexander Motin 	case 0: return ("Physical");
2271bee2ec7SAlexander Motin 	case 1: return ("Application");
2281bee2ec7SAlexander Motin 	case 2: return ("Logical");
2291bee2ec7SAlexander Motin 	case 3: return ("Report");
2301bee2ec7SAlexander Motin 	case 4: return ("Named_Array");
2311bee2ec7SAlexander Motin 	case 5: return ("Usage_Switch");
2321bee2ec7SAlexander Motin 	case 6: return ("Usage_Modifier");
2331bee2ec7SAlexander Motin 	}
2341bee2ec7SAlexander Motin 	snprintf(num, sizeof(num), "0x%02x", type);
2351bee2ec7SAlexander Motin 	return (num);
2361bee2ec7SAlexander Motin }
2371bee2ec7SAlexander Motin 
2387778ab7eSAlexander Motin static void
dumpitems(report_desc_t r)23909d308a8SNick Hibma dumpitems(report_desc_t r)
24009d308a8SNick Hibma {
24109d308a8SNick Hibma 	struct hid_data *d;
24209d308a8SNick Hibma 	struct hid_item h;
2431d10fe50SNick Hibma 	int size;
24409d308a8SNick Hibma 
2451bee2ec7SAlexander Motin 	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
24609d308a8SNick Hibma 		switch (h.kind) {
24709d308a8SNick Hibma 		case hid_collection:
2481bee2ec7SAlexander Motin 			printf("Collection type=%s page=%s usage=%s\n",
2491bee2ec7SAlexander Motin 			       hid_collection_type(h.collection),
25009d308a8SNick Hibma 			       hid_usage_page(HID_PAGE(h.usage)),
25109d308a8SNick Hibma 			       hid_usage_in_page(h.usage));
25209d308a8SNick Hibma 			break;
25309d308a8SNick Hibma 		case hid_endcollection:
25409d308a8SNick Hibma 			printf("End collection\n");
25509d308a8SNick Hibma 			break;
25609d308a8SNick Hibma 		case hid_input:
25709d308a8SNick Hibma 			dumpitem("Input  ", &h);
25809d308a8SNick Hibma 			break;
25909d308a8SNick Hibma 		case hid_output:
26009d308a8SNick Hibma 			dumpitem("Output ", &h);
26109d308a8SNick Hibma 			break;
26209d308a8SNick Hibma 		case hid_feature:
26309d308a8SNick Hibma 			dumpitem("Feature", &h);
26409d308a8SNick Hibma 			break;
26509d308a8SNick Hibma 		}
26609d308a8SNick Hibma 	}
26709d308a8SNick Hibma 	hid_end_parse(d);
2681bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_input, -1);
2691a2cdef4SNick Hibma 	printf("Total   input size %d bytes\n", size);
27009d308a8SNick Hibma 
2711bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_output, -1);
2721d10fe50SNick Hibma 	printf("Total  output size %d bytes\n", size);
27309d308a8SNick Hibma 
2741bee2ec7SAlexander Motin 	size = hid_report_size(r, hid_feature, -1);
2751d10fe50SNick Hibma 	printf("Total feature size %d bytes\n", size);
27609d308a8SNick Hibma }
27709d308a8SNick Hibma 
2787778ab7eSAlexander Motin static void
prdata(u_char * buf,struct hid_item * h)27909d308a8SNick Hibma prdata(u_char *buf, struct hid_item *h)
28009d308a8SNick Hibma {
28109d308a8SNick Hibma 	u_int data;
28209d308a8SNick Hibma 	int i, pos;
28309d308a8SNick Hibma 
28409d308a8SNick Hibma 	pos = h->pos;
28509d308a8SNick Hibma 	for (i = 0; i < h->report_count; i++) {
28609d308a8SNick Hibma 		data = hid_get_data(buf, h);
2871bee2ec7SAlexander Motin 		if (i > 0)
2881bee2ec7SAlexander Motin 			printf(" ");
28909d308a8SNick Hibma 		if (h->logical_minimum < 0)
29009d308a8SNick Hibma 			printf("%d", (int)data);
29109d308a8SNick Hibma 		else
29209d308a8SNick Hibma 			printf("%u", data);
2939a2a66f1SGreg Lehey                 if (hexdump)
2949a2a66f1SGreg Lehey 			printf(" [0x%x]", data);
2951bee2ec7SAlexander Motin 		h->pos += h->report_size;
29609d308a8SNick Hibma 	}
2971bee2ec7SAlexander Motin 	h->pos = pos;
29809d308a8SNick Hibma }
29909d308a8SNick Hibma 
3007778ab7eSAlexander Motin static void
dumpdata(int f,report_desc_t rd,int loop)30109d308a8SNick Hibma dumpdata(int f, report_desc_t rd, int loop)
30209d308a8SNick Hibma {
3037778ab7eSAlexander Motin 	struct variable *var;
3047778ab7eSAlexander Motin 	int dlen, havedata, i, match, r, rid, use_rid;
30509d308a8SNick Hibma 	u_char *dbuf;
3067778ab7eSAlexander Motin 	enum hid_kind kind;
30709d308a8SNick Hibma 
308e39e854eSAlexander Motin 	kind = zflag ? 3 : 0;
3097778ab7eSAlexander Motin 	rid = -1;
3107778ab7eSAlexander Motin 	use_rid = !!hid_get_report_id(f);
31109d308a8SNick Hibma 	do {
3127778ab7eSAlexander Motin 		if (kind < 3) {
3137778ab7eSAlexander Motin 			if (++rid >= 256) {
3147778ab7eSAlexander Motin 				rid = 0;
3157778ab7eSAlexander Motin 				kind++;
31609d308a8SNick Hibma 			}
3177778ab7eSAlexander Motin 			if (kind >= 3)
3187778ab7eSAlexander Motin 				rid = -1;
3197778ab7eSAlexander Motin 			for (var = vars; var; var = var->next) {
3207778ab7eSAlexander Motin 				if (rid == var->h.report_ID &&
3217778ab7eSAlexander Motin 				    kind == var->h.kind)
3227778ab7eSAlexander Motin 					break;
3237778ab7eSAlexander Motin 			}
3247778ab7eSAlexander Motin 			if (var == NULL)
3251bee2ec7SAlexander Motin 				continue;
3267778ab7eSAlexander Motin 		}
3277778ab7eSAlexander Motin 		dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid);
3287778ab7eSAlexander Motin 		if (dlen <= 0)
3297778ab7eSAlexander Motin 			continue;
3307778ab7eSAlexander Motin 		dbuf = malloc(dlen);
3317778ab7eSAlexander Motin 		memset(dbuf, 0, dlen);
3327778ab7eSAlexander Motin 		if (kind < 3) {
3337778ab7eSAlexander Motin 			dbuf[0] = rid;
3347778ab7eSAlexander Motin 			r = hid_get_report(f, kind, dbuf, dlen);
3357778ab7eSAlexander Motin 			if (r < 0)
3367778ab7eSAlexander Motin 				warn("hid_get_report(rid %d)", rid);
3377778ab7eSAlexander Motin 			havedata = !r && (rid == 0 || dbuf[0] == rid);
3387778ab7eSAlexander Motin 			if (rid != 0)
3397778ab7eSAlexander Motin 				dbuf[0] = rid;
3407778ab7eSAlexander Motin 		} else {
3417778ab7eSAlexander Motin 			r = read(f, dbuf, dlen);
3427778ab7eSAlexander Motin 			if (r < 1)
3437778ab7eSAlexander Motin 				err(1, "read error");
3447778ab7eSAlexander Motin 			havedata = 1;
3457778ab7eSAlexander Motin 		}
3467778ab7eSAlexander Motin 		if (verbose) {
3477778ab7eSAlexander Motin 			printf("Got %s report %d (%d bytes):",
3487778ab7eSAlexander Motin 			    kind == hid_output ? "output" :
3497778ab7eSAlexander Motin 			    kind == hid_feature ? "feature" : "input",
3507778ab7eSAlexander Motin 			    use_rid ? dbuf[0] : 0, dlen);
3517778ab7eSAlexander Motin 			if (havedata) {
3527778ab7eSAlexander Motin 				for (i = 0; i < dlen; i++)
3537778ab7eSAlexander Motin 					printf(" %02x", dbuf[i]);
3547778ab7eSAlexander Motin 			}
3557778ab7eSAlexander Motin 			printf("\n");
3567778ab7eSAlexander Motin 		}
3577778ab7eSAlexander Motin 		match = 0;
3587778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
3597778ab7eSAlexander Motin 			if ((kind < 3 ? kind : hid_input) != var->h.kind)
3607778ab7eSAlexander Motin 				continue;
3617778ab7eSAlexander Motin 			if (var->h.report_ID != 0 &&
3627778ab7eSAlexander Motin 			    dbuf[0] != var->h.report_ID)
3637778ab7eSAlexander Motin 				continue;
3647778ab7eSAlexander Motin 			match = 1;
36509d308a8SNick Hibma 			if (!noname)
3667778ab7eSAlexander Motin 				printf("%s=", var->name);
3677778ab7eSAlexander Motin 			if (havedata)
3687778ab7eSAlexander Motin 				prdata(dbuf, &var->h);
36909d308a8SNick Hibma 			printf("\n");
37009d308a8SNick Hibma 		}
3717778ab7eSAlexander Motin 		if (match)
37209d308a8SNick Hibma 			printf("\n");
37309d308a8SNick Hibma 		free(dbuf);
3747778ab7eSAlexander Motin 	} while (loop || kind < 3);
3757778ab7eSAlexander Motin }
3767778ab7eSAlexander Motin 
3777778ab7eSAlexander Motin static void
writedata(int f,report_desc_t rd)3787778ab7eSAlexander Motin writedata(int f, report_desc_t rd)
3797778ab7eSAlexander Motin {
3807778ab7eSAlexander Motin 	struct variable *var;
3817778ab7eSAlexander Motin 	int dlen, i, r, rid;
3827778ab7eSAlexander Motin 	u_char *dbuf;
3837778ab7eSAlexander Motin 	enum hid_kind kind;
3847778ab7eSAlexander Motin 
3857778ab7eSAlexander Motin 	kind = 0;
3867778ab7eSAlexander Motin 	rid = 0;
3877778ab7eSAlexander Motin 	for (kind = 0; kind < 3; kind ++) {
3887778ab7eSAlexander Motin 	    for (rid = 0; rid < 256; rid ++) {
3897778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
3907778ab7eSAlexander Motin 			if (rid == var->h.report_ID && kind == var->h.kind)
3917778ab7eSAlexander Motin 				break;
3927778ab7eSAlexander Motin 		}
3937778ab7eSAlexander Motin 		if (var == NULL)
3947778ab7eSAlexander Motin 			continue;
3957778ab7eSAlexander Motin 		dlen = hid_report_size(rd, kind, rid);
3967778ab7eSAlexander Motin 		if (dlen <= 0)
3977778ab7eSAlexander Motin 			continue;
3987778ab7eSAlexander Motin 		dbuf = malloc(dlen);
3997778ab7eSAlexander Motin 		memset(dbuf, 0, dlen);
4007778ab7eSAlexander Motin 		dbuf[0] = rid;
4017778ab7eSAlexander Motin 		if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) {
4027778ab7eSAlexander Motin 			if (verbose) {
4037778ab7eSAlexander Motin 				printf("Got %s report %d (%d bytes):",
4047778ab7eSAlexander Motin 				    kind == hid_input ? "input" :
4057778ab7eSAlexander Motin 				    kind == hid_output ? "output" : "feature",
4067778ab7eSAlexander Motin 				    rid, dlen);
4077778ab7eSAlexander Motin 				for (i = 0; i < dlen; i++)
4087778ab7eSAlexander Motin 					printf(" %02x", dbuf[i]);
4097778ab7eSAlexander Motin 				printf("\n");
4107778ab7eSAlexander Motin 			}
4117778ab7eSAlexander Motin 		} else if (!zflag) {
4127778ab7eSAlexander Motin 			warn("hid_get_report(rid %d)", rid);
4137778ab7eSAlexander Motin 			if (verbose) {
4147778ab7eSAlexander Motin 				printf("Can't get %s report %d (%d bytes). "
4157778ab7eSAlexander Motin 				    "Will be initialized with zeros.\n",
4167778ab7eSAlexander Motin 				    kind == hid_input ? "input" :
4177778ab7eSAlexander Motin 				    kind == hid_output ? "output" : "feature",
4187778ab7eSAlexander Motin 				    rid, dlen);
4197778ab7eSAlexander Motin 			}
4207778ab7eSAlexander Motin 		}
4217778ab7eSAlexander Motin 		for (var = vars; var; var = var->next) {
4227778ab7eSAlexander Motin 			if (rid != var->h.report_ID || kind != var->h.kind)
4237778ab7eSAlexander Motin 				continue;
4247778ab7eSAlexander Motin 			hid_set_data(dbuf, &var->h, var->val);
4257778ab7eSAlexander Motin 		}
4267778ab7eSAlexander Motin 		if (verbose) {
4277778ab7eSAlexander Motin 			printf("Setting %s report %d (%d bytes):",
4287778ab7eSAlexander Motin 			    kind == hid_output ? "output" :
4297778ab7eSAlexander Motin 			    kind == hid_feature ? "feature" : "input",
4307778ab7eSAlexander Motin 			    rid, dlen);
4317778ab7eSAlexander Motin 			for (i = 0; i < dlen; i++)
4327778ab7eSAlexander Motin 				printf(" %02x", dbuf[i]);
4337778ab7eSAlexander Motin 			printf("\n");
4347778ab7eSAlexander Motin 		}
4357778ab7eSAlexander Motin 		r = hid_set_report(f, kind, dbuf, dlen);
4367778ab7eSAlexander Motin 		if (r != 0)
4377778ab7eSAlexander Motin 			warn("hid_set_report(rid %d)", rid);
4387778ab7eSAlexander Motin 		free(dbuf);
4397778ab7eSAlexander Motin 	    }
4407778ab7eSAlexander Motin 	}
44109d308a8SNick Hibma }
44209d308a8SNick Hibma 
44309d308a8SNick Hibma int
main(int argc,char ** argv)44409d308a8SNick Hibma main(int argc, char **argv)
44509d308a8SNick Hibma {
44609d308a8SNick Hibma 	report_desc_t r;
4477778ab7eSAlexander Motin 	char *table = 0;
4487778ab7eSAlexander Motin 	char devnam[100], *dev = NULL;
4497778ab7eSAlexander Motin 	int f;
4507778ab7eSAlexander Motin 	int all = 0;
45109d308a8SNick Hibma 	int ch;
45209d308a8SNick Hibma 	int repdump = 0;
45309d308a8SNick Hibma 	int loop = 0;
45409d308a8SNick Hibma 
4557778ab7eSAlexander Motin 	while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) {
45609d308a8SNick Hibma 		switch(ch) {
45709d308a8SNick Hibma 		case 'a':
45809d308a8SNick Hibma 			all++;
45909d308a8SNick Hibma 			break;
46009d308a8SNick Hibma 		case 'f':
46109d308a8SNick Hibma 			dev = optarg;
46209d308a8SNick Hibma 			break;
46309d308a8SNick Hibma 		case 'l':
46409d308a8SNick Hibma 			loop ^= 1;
46509d308a8SNick Hibma 			break;
46609d308a8SNick Hibma 		case 'n':
46709d308a8SNick Hibma 			noname++;
46809d308a8SNick Hibma 			break;
46909d308a8SNick Hibma 		case 'r':
47009d308a8SNick Hibma 			repdump++;
47109d308a8SNick Hibma 			break;
47209d308a8SNick Hibma 		case 't':
47309d308a8SNick Hibma 			table = optarg;
47409d308a8SNick Hibma 			break;
47509d308a8SNick Hibma 		case 'v':
47609d308a8SNick Hibma 			verbose++;
47709d308a8SNick Hibma 			break;
4787778ab7eSAlexander Motin 		case 'w':
4797778ab7eSAlexander Motin 			wflag = 1;
4807778ab7eSAlexander Motin 			break;
4819a2a66f1SGreg Lehey 		case 'x':
482eb29cfddSGreg Lehey 			hexdump = 1;
4839a2a66f1SGreg Lehey 			break;
4847778ab7eSAlexander Motin 		case 'z':
4857778ab7eSAlexander Motin 			zflag = 1;
4867778ab7eSAlexander Motin 			break;
48709d308a8SNick Hibma 		case '?':
48809d308a8SNick Hibma 		default:
48909d308a8SNick Hibma 			usage();
49009d308a8SNick Hibma 		}
49109d308a8SNick Hibma 	}
49209d308a8SNick Hibma 	argc -= optind;
49309d308a8SNick Hibma 	argv += optind;
4947778ab7eSAlexander Motin 	if (dev == NULL)
49509d308a8SNick Hibma 		usage();
49609d308a8SNick Hibma 
4977778ab7eSAlexander Motin 	if (argc == 0 && !all && !repdump)
49809d308a8SNick Hibma 		usage();
49909d308a8SNick Hibma 
50009d308a8SNick Hibma 	if (dev[0] != '/') {
50109d308a8SNick Hibma 		if (isdigit(dev[0]))
5021a27f4f2SMark Murray 			snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
50309d308a8SNick Hibma 		else
5041a27f4f2SMark Murray 			snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
5051a27f4f2SMark Murray 		dev = devnam;
50609d308a8SNick Hibma 	}
50709d308a8SNick Hibma 
50809d308a8SNick Hibma 	hid_init(table);
50909d308a8SNick Hibma 
51009d308a8SNick Hibma 	f = open(dev, O_RDWR);
51109d308a8SNick Hibma 	if (f < 0)
51209d308a8SNick Hibma 		err(1, "%s", dev);
51309d308a8SNick Hibma 
51409d308a8SNick Hibma 	r = hid_get_report_desc(f);
51509d308a8SNick Hibma 	if (r == 0)
51609d308a8SNick Hibma 		errx(1, "USB_GET_REPORT_DESC");
51709d308a8SNick Hibma 
51809d308a8SNick Hibma 	if (repdump) {
51909d308a8SNick Hibma 		printf("Report descriptor:\n");
52009d308a8SNick Hibma 		dumpitems(r);
52109d308a8SNick Hibma 	}
5227778ab7eSAlexander Motin 	if (argc != 0 || all) {
5237778ab7eSAlexander Motin 		parceargs(r, all, argc, argv);
5247778ab7eSAlexander Motin 		if (wflag)
5257778ab7eSAlexander Motin 			writedata(f, r);
5267778ab7eSAlexander Motin 		else
52709d308a8SNick Hibma 			dumpdata(f, r, loop);
5287778ab7eSAlexander Motin 	}
52909d308a8SNick Hibma 
53009d308a8SNick Hibma 	hid_dispose_report_desc(r);
53109d308a8SNick Hibma 	exit(0);
53209d308a8SNick Hibma }
533