usbhid.c revision 224511
162642Sn_hibma/*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
262642Sn_hibma/*	$FreeBSD: head/usr.bin/usbhidctl/usbhid.c 224511 2011-07-30 13:22:44Z mav $ */
362642Sn_hibma
462642Sn_hibma/*
562642Sn_hibma * Copyright (c) 1998 The NetBSD Foundation, Inc.
662642Sn_hibma * All rights reserved.
762642Sn_hibma *
862642Sn_hibma * This code is derived from software contributed to The NetBSD Foundation
962642Sn_hibma * by Lennart Augustsson (augustss@netbsd.org).
1062642Sn_hibma *
1162642Sn_hibma * Redistribution and use in source and binary forms, with or without
1262642Sn_hibma * modification, are permitted provided that the following conditions
1362642Sn_hibma * are met:
1462642Sn_hibma * 1. Redistributions of source code must retain the above copyright
1562642Sn_hibma *    notice, this list of conditions and the following disclaimer.
1662642Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright
1762642Sn_hibma *    notice, this list of conditions and the following disclaimer in the
1862642Sn_hibma *    documentation and/or other materials provided with the distribution.
1962642Sn_hibma *
2062642Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2162642Sn_hibma * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2262642Sn_hibma * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2362642Sn_hibma * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2462642Sn_hibma * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2562642Sn_hibma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2662642Sn_hibma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2762642Sn_hibma * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2862642Sn_hibma * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2962642Sn_hibma * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3062642Sn_hibma * POSSIBILITY OF SUCH DAMAGE.
3162642Sn_hibma */
3262642Sn_hibma
3362642Sn_hibma#include <stdio.h>
3462642Sn_hibma#include <stdlib.h>
3562642Sn_hibma#include <string.h>
3662642Sn_hibma#include <sys/types.h>
3762642Sn_hibma#include <fcntl.h>
3862642Sn_hibma#include <unistd.h>
3962642Sn_hibma#include <err.h>
4062642Sn_hibma#include <ctype.h>
4162642Sn_hibma#include <errno.h>
42113273Smdodd#include <usbhid.h>
43188945Sthompsa#include <dev/usb/usbhid.h>
4462642Sn_hibma
4562642Sn_hibmaint verbose = 0;
4662642Sn_hibmaint all = 0;
4762642Sn_hibmaint noname = 0;
48164531Sgrogint hexdump = 0;
4962642Sn_hibma
5062642Sn_hibmachar **names;
5162642Sn_hibmaint nnames;
5262642Sn_hibma
5362642Sn_hibmavoid prbits(int bits, char **strs, int n);
5462642Sn_hibmavoid usage(void);
5587699Smarkmvoid dumpitem(const char *label, struct hid_item *h);
5662642Sn_hibmavoid dumpitems(report_desc_t r);
5762642Sn_hibmavoid rev(struct hid_item **p);
5862642Sn_hibmavoid prdata(u_char *buf, struct hid_item *h);
5962642Sn_hibmavoid dumpdata(int f, report_desc_t r, int loop);
6062642Sn_hibmaint gotname(char *n);
6162642Sn_hibma
6262642Sn_hibmaint
6362642Sn_hibmagotname(char *n)
6462642Sn_hibma{
6562642Sn_hibma	int i;
6662642Sn_hibma
6762642Sn_hibma	for (i = 0; i < nnames; i++)
6862642Sn_hibma		if (strcmp(names[i], n) == 0)
6962642Sn_hibma			return 1;
7062642Sn_hibma	return 0;
7162642Sn_hibma}
7262642Sn_hibma
7362642Sn_hibmavoid
7462642Sn_hibmaprbits(int bits, char **strs, int n)
7562642Sn_hibma{
7662642Sn_hibma	int i;
7762642Sn_hibma
7862642Sn_hibma	for(i = 0; i < n; i++, bits >>= 1)
7962642Sn_hibma		if (strs[i*2])
8062642Sn_hibma			printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]);
8162642Sn_hibma}
8262642Sn_hibma
8362642Sn_hibmavoid
8462642Sn_hibmausage(void)
8562642Sn_hibma{
8662642Sn_hibma
87164531Sgrog	fprintf(stderr,
88164531Sgrog                "usage: %s -f device "
89164544Sgrog                "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n",
90194789Sdelphij                getprogname());
91164531Sgrog	fprintf(stderr,
92164531Sgrog                "       %s -f device "
93164544Sgrog                "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
94194789Sdelphij                getprogname());
9562642Sn_hibma	exit(1);
9662642Sn_hibma}
9762642Sn_hibma
9862642Sn_hibmavoid
9987699Smarkmdumpitem(const char *label, struct hid_item *h)
10062642Sn_hibma{
10162642Sn_hibma	if ((h->flags & HIO_CONST) && !verbose)
10262642Sn_hibma		return;
103224511Smav	printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
104224511Smav	       h->report_ID, h->report_size, h->report_count,
105164531Sgrog	       hid_usage_page(HID_PAGE(h->usage)),
10662642Sn_hibma	       hid_usage_in_page(h->usage),
107224511Smav	       h->flags & HIO_CONST ? " Const" : "",
108224511Smav	       h->flags & HIO_VARIABLE ? "" : " Array");
10962642Sn_hibma	printf(", logical range %d..%d",
11062642Sn_hibma	       h->logical_minimum, h->logical_maximum);
11162642Sn_hibma	if (h->physical_minimum != h->physical_maximum)
11262642Sn_hibma		printf(", physical range %d..%d",
11362642Sn_hibma		       h->physical_minimum, h->physical_maximum);
11462642Sn_hibma	if (h->unit)
11562642Sn_hibma		printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
11662642Sn_hibma	printf("\n");
11762642Sn_hibma}
11862642Sn_hibma
119224511Smavstatic const char *
120224511Smavhid_collection_type(int32_t type)
121224511Smav{
122224511Smav	static char num[8];
123224511Smav
124224511Smav	switch (type) {
125224511Smav	case 0: return ("Physical");
126224511Smav	case 1: return ("Application");
127224511Smav	case 2: return ("Logical");
128224511Smav	case 3: return ("Report");
129224511Smav	case 4: return ("Named_Array");
130224511Smav	case 5: return ("Usage_Switch");
131224511Smav	case 6: return ("Usage_Modifier");
132224511Smav	}
133224511Smav	snprintf(num, sizeof(num), "0x%02x", type);
134224511Smav	return (num);
135224511Smav}
136224511Smav
13762642Sn_hibmavoid
13862642Sn_hibmadumpitems(report_desc_t r)
13962642Sn_hibma{
14062642Sn_hibma	struct hid_data *d;
14162642Sn_hibma	struct hid_item h;
14267256Sn_hibma	int size;
14362642Sn_hibma
144224511Smav	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
14562642Sn_hibma		switch (h.kind) {
14662642Sn_hibma		case hid_collection:
147224511Smav			printf("Collection type=%s page=%s usage=%s\n",
148224511Smav			       hid_collection_type(h.collection),
149164531Sgrog			       hid_usage_page(HID_PAGE(h.usage)),
15062642Sn_hibma			       hid_usage_in_page(h.usage));
15162642Sn_hibma			break;
15262642Sn_hibma		case hid_endcollection:
15362642Sn_hibma			printf("End collection\n");
15462642Sn_hibma			break;
15562642Sn_hibma		case hid_input:
15662642Sn_hibma			dumpitem("Input  ", &h);
15762642Sn_hibma			break;
15862642Sn_hibma		case hid_output:
15962642Sn_hibma			dumpitem("Output ", &h);
16062642Sn_hibma			break;
16162642Sn_hibma		case hid_feature:
16262642Sn_hibma			dumpitem("Feature", &h);
16362642Sn_hibma			break;
16462642Sn_hibma		}
16562642Sn_hibma	}
16662642Sn_hibma	hid_end_parse(d);
167224511Smav	size = hid_report_size(r, hid_input, -1);
16875606Sn_hibma	printf("Total   input size %d bytes\n", size);
16962642Sn_hibma
170224511Smav	size = hid_report_size(r, hid_output, -1);
17167256Sn_hibma	printf("Total  output size %d bytes\n", size);
17267256Sn_hibma
173224511Smav	size = hid_report_size(r, hid_feature, -1);
17467256Sn_hibma	printf("Total feature size %d bytes\n", size);
17562642Sn_hibma}
17662642Sn_hibma
17762642Sn_hibmavoid
17862642Sn_hibmarev(struct hid_item **p)
17962642Sn_hibma{
18062642Sn_hibma	struct hid_item *cur, *prev, *next;
18162642Sn_hibma
18262642Sn_hibma	prev = 0;
18362642Sn_hibma	cur = *p;
18462642Sn_hibma	while(cur != 0) {
18562642Sn_hibma		next = cur->next;
18662642Sn_hibma		cur->next = prev;
18762642Sn_hibma		prev = cur;
18862642Sn_hibma		cur = next;
18962642Sn_hibma	}
19062642Sn_hibma	*p = prev;
19162642Sn_hibma}
19262642Sn_hibma
19362642Sn_hibmavoid
19462642Sn_hibmaprdata(u_char *buf, struct hid_item *h)
19562642Sn_hibma{
19662642Sn_hibma	u_int data;
19762642Sn_hibma	int i, pos;
19862642Sn_hibma
19962642Sn_hibma	pos = h->pos;
20062642Sn_hibma	for (i = 0; i < h->report_count; i++) {
20162642Sn_hibma		data = hid_get_data(buf, h);
202224511Smav		if (i > 0)
203224511Smav			printf(" ");
20462642Sn_hibma		if (h->logical_minimum < 0)
20562642Sn_hibma			printf("%d", (int)data);
20662642Sn_hibma		else
20762642Sn_hibma			printf("%u", data);
208164531Sgrog                if (hexdump)
209164531Sgrog			printf(" [0x%x]", data);
210224511Smav		h->pos += h->report_size;
21162642Sn_hibma	}
212224511Smav	h->pos = pos;
21362642Sn_hibma}
21462642Sn_hibma
21562642Sn_hibmavoid
21662642Sn_hibmadumpdata(int f, report_desc_t rd, int loop)
21762642Sn_hibma{
21862642Sn_hibma	struct hid_data *d;
21962642Sn_hibma	struct hid_item h, *hids, *n;
22062642Sn_hibma	int r, dlen;
22162642Sn_hibma	u_char *dbuf;
22262642Sn_hibma	u_int32_t colls[100];
22362642Sn_hibma	int sp = 0;
22462642Sn_hibma	char namebuf[10000], *namep;
22562642Sn_hibma
22662642Sn_hibma	hids = 0;
227224511Smav	for (d = hid_start_parse(rd, 1<<hid_input, -1);
22862642Sn_hibma	     hid_get_item(d, &h); ) {
22962642Sn_hibma		if (h.kind == hid_collection)
23062642Sn_hibma			colls[++sp] = h.usage;
23162642Sn_hibma		else if (h.kind == hid_endcollection)
23262642Sn_hibma			--sp;
23362642Sn_hibma		if (h.kind != hid_input || (h.flags & HIO_CONST))
23462642Sn_hibma			continue;
23562642Sn_hibma		h.next = hids;
23662642Sn_hibma		h.collection = colls[sp];
23762642Sn_hibma		hids = malloc(sizeof *hids);
23862642Sn_hibma		*hids = h;
23962642Sn_hibma	}
24062642Sn_hibma	hid_end_parse(d);
24162642Sn_hibma	rev(&hids);
242224511Smav	dlen = hid_report_size(rd, hid_input, -1);
24362642Sn_hibma	dbuf = malloc(dlen);
24462642Sn_hibma	if (!loop)
245187994Salfred		if (hid_set_immed(f, 1) < 0) {
24662642Sn_hibma			if (errno == EOPNOTSUPP)
24762642Sn_hibma				warnx("device does not support immediate mode, only changes reported.");
24862642Sn_hibma			else
24962642Sn_hibma				err(1, "USB_SET_IMMED");
25062642Sn_hibma		}
25162642Sn_hibma	do {
25262642Sn_hibma		r = read(f, dbuf, dlen);
253224511Smav		if (r < 1) {
254224511Smav			err(1, "read error");
25562642Sn_hibma		}
25662642Sn_hibma		for (n = hids; n; n = n->next) {
257224511Smav			if (n->report_ID != 0 && dbuf[0] != n->report_ID)
258224511Smav				continue;
25962642Sn_hibma			namep = namebuf;
26062642Sn_hibma			namep += sprintf(namep, "%s:%s.",
26162642Sn_hibma					 hid_usage_page(HID_PAGE(n->collection)),
26262642Sn_hibma					 hid_usage_in_page(n->collection));
26362642Sn_hibma			namep += sprintf(namep, "%s:%s",
26462642Sn_hibma					 hid_usage_page(HID_PAGE(n->usage)),
26562642Sn_hibma					 hid_usage_in_page(n->usage));
26662642Sn_hibma			if (all || gotname(namebuf)) {
26762642Sn_hibma				if (!noname)
26862642Sn_hibma					printf("%s=", namebuf);
269224511Smav				prdata(dbuf, n);
27062642Sn_hibma				printf("\n");
27162642Sn_hibma			}
27262642Sn_hibma		}
27362642Sn_hibma		if (loop)
27462642Sn_hibma			printf("\n");
27562642Sn_hibma	} while (loop);
27662642Sn_hibma	free(dbuf);
27762642Sn_hibma}
27862642Sn_hibma
27962642Sn_hibmaint
28062642Sn_hibmamain(int argc, char **argv)
28162642Sn_hibma{
28262642Sn_hibma	int f;
28362642Sn_hibma	report_desc_t r;
28487699Smarkm	char devnam[100], *dev = 0;
28562642Sn_hibma	int ch;
28662642Sn_hibma	int repdump = 0;
28762642Sn_hibma	int loop = 0;
28862642Sn_hibma	char *table = 0;
28962642Sn_hibma
290164531Sgrog	while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) {
29162642Sn_hibma		switch(ch) {
29262642Sn_hibma		case 'a':
29362642Sn_hibma			all++;
29462642Sn_hibma			break;
29562642Sn_hibma		case 'f':
29662642Sn_hibma			dev = optarg;
29762642Sn_hibma			break;
29862642Sn_hibma		case 'l':
29962642Sn_hibma			loop ^= 1;
30062642Sn_hibma			break;
30162642Sn_hibma		case 'n':
30262642Sn_hibma			noname++;
30362642Sn_hibma			break;
30462642Sn_hibma		case 'r':
30562642Sn_hibma			repdump++;
30662642Sn_hibma			break;
30762642Sn_hibma		case 't':
30862642Sn_hibma			table = optarg;
30962642Sn_hibma			break;
31062642Sn_hibma		case 'v':
31162642Sn_hibma			verbose++;
31262642Sn_hibma			break;
313164531Sgrog		case 'x':
314164544Sgrog			hexdump = 1;
315164531Sgrog			break;
31662642Sn_hibma		case '?':
31762642Sn_hibma		default:
31862642Sn_hibma			usage();
31962642Sn_hibma		}
32062642Sn_hibma	}
32162642Sn_hibma	argc -= optind;
32262642Sn_hibma	argv += optind;
32362642Sn_hibma	if (dev == 0)
32462642Sn_hibma		usage();
32562642Sn_hibma	names = argv;
32662642Sn_hibma	nnames = argc;
32762642Sn_hibma
32862642Sn_hibma	if (nnames == 0 && !all && !repdump)
32962642Sn_hibma		usage();
33062642Sn_hibma
33162642Sn_hibma	if (dev[0] != '/') {
33262642Sn_hibma		if (isdigit(dev[0]))
33387699Smarkm			snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
33462642Sn_hibma		else
33587699Smarkm			snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
33687699Smarkm		dev = devnam;
33762642Sn_hibma	}
33862642Sn_hibma
33962642Sn_hibma	hid_init(table);
34062642Sn_hibma
34162642Sn_hibma	f = open(dev, O_RDWR);
34262642Sn_hibma	if (f < 0)
34362642Sn_hibma		err(1, "%s", dev);
34462642Sn_hibma
34562642Sn_hibma	r = hid_get_report_desc(f);
346164531Sgrog	if (r == 0)
34762642Sn_hibma		errx(1, "USB_GET_REPORT_DESC");
348164531Sgrog
34962642Sn_hibma	if (repdump) {
35062642Sn_hibma		printf("Report descriptor:\n");
35162642Sn_hibma		dumpitems(r);
35262642Sn_hibma	}
35362642Sn_hibma	if (nnames != 0 || all)
35462642Sn_hibma		dumpdata(f, r, loop);
35562642Sn_hibma
35662642Sn_hibma	hid_dispose_report_desc(r);
35762642Sn_hibma	exit(0);
35862642Sn_hibma}
359