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