usbhid.c revision 225839
115103Sphk/*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
215103Sphk/*	$FreeBSD: head/usr.bin/usbhidctl/usbhid.c 225839 2011-09-28 14:52:25Z mav $ */
315103Sphk
415103Sphk/*
515103Sphk * Copyright (c) 1998 The NetBSD Foundation, Inc.
615103Sphk * All rights reserved.
715103Sphk *
815103Sphk * This code is derived from software contributed to The NetBSD Foundation
915103Sphk * by Lennart Augustsson (augustss@netbsd.org).
1015103Sphk *
1115103Sphk * Redistribution and use in source and binary forms, with or without
1215103Sphk * modification, are permitted provided that the following conditions
1315103Sphk * are met:
1415103Sphk * 1. Redistributions of source code must retain the above copyright
1515103Sphk *    notice, this list of conditions and the following disclaimer.
1615103Sphk * 2. Redistributions in binary form must reproduce the above copyright
1715103Sphk *    notice, this list of conditions and the following disclaimer in the
1815103Sphk *    documentation and/or other materials provided with the distribution.
1915103Sphk *
2015103Sphk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2115103Sphk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2215103Sphk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2315103Sphk * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2415103Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2515103Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2615103Sphk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2715103Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2815103Sphk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2915103Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3015103Sphk * POSSIBILITY OF SUCH DAMAGE.
3115103Sphk */
3215103Sphk
3315103Sphk#include <stdio.h>
3415103Sphk#include <stdlib.h>
3515103Sphk#include <string.h>
3615103Sphk#include <sys/types.h>
3715103Sphk#include <fcntl.h>
3815103Sphk#include <unistd.h>
3915103Sphk#include <err.h>
4050477Speter#include <ctype.h>
4115103Sphk#include <errno.h>
4215103Sphk#include <usbhid.h>
4386190Srwatson#include <dev/usb/usbhid.h>
4484611Srwatson
4515103Sphkstruct variable {
4615103Sphk	char *name;
4715103Sphk	int instance;
4815103Sphk	int val;
4915103Sphk	struct hid_item h;
5087275Srwatson	struct variable *next;
5187275Srwatson} *vars;
5246155Sphk
5376078Sjhbint verbose = 0;
54105046Smikeint noname = 0;
5528918Skatoint hexdump = 0;
5615103Sphkint wflag = 0;
5715103Sphkint zflag = 0;
5815103Sphk
5915103Sphkstatic void usage(void);
6015103Sphkstatic void dumpitem(const char *label, struct hid_item *h);
6115103Sphkstatic void dumpitems(report_desc_t r);
6223382Sbdestatic void prdata(u_char *buf, struct hid_item *h);
6315103Sphkstatic void dumpdata(int f, report_desc_t r, int loop);
6415103Sphkstatic void writedata(int f, report_desc_t r);
6515103Sphk
6615103Sphkstatic void
6715103Sphkparceargs(report_desc_t r, int all, int nnames, char **names)
6848891Sphk{
6948891Sphk	struct hid_data *d;
7015103Sphk	struct hid_item h;
7115103Sphk	char colls[1000];
7215103Sphk	char hname[1000], *tmp1, *tmp2;
7315103Sphk	struct variable *var, **pnext;
7415103Sphk	int i, instance, cp, t;
7515103Sphk
7634925Sdufault	pnext = &vars;
7734925Sdufault	if (all) {
7834029Sdufault		if (wflag)
7950465Smarcel			errx(1, "Must not specify -w to read variables");
8050465Smarcel		cp = 0;
8189414Sarr		for (d = hid_start_parse(r,
8289414Sarr		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
8386190Srwatson		    hid_get_item(d, &h); ) {
8486190Srwatson			if (h.kind == hid_collection) {
8586190Srwatson				cp += sprintf(&colls[cp], "%s%s:%s",
8686190Srwatson				    cp != 0 ? "." : "",
8750465Smarcel				    hid_usage_page(HID_PAGE(h.usage)),
8886189Srwatson				    hid_usage_in_page(h.usage));
8988019Sluigi			} else if (h.kind == hid_endcollection) {
9015103Sphk				tmp1 = strrchr(colls, '.');
9186189Srwatson				if (tmp1 != NULL) {
9246381Sbillf					cp -= strlen(tmp1);
9315103Sphk					tmp1[0] = 0;
9486189Srwatson				} else {
9546381Sbillf					cp = 0;
9615103Sphk					colls[0] = 0;
9786189Srwatson				}
9846381Sbillf			}
9915103Sphk			if ((h.kind != hid_input && h.kind != hid_output &&
10015103Sphk			    h.kind != hid_feature) || (h.flags & HIO_CONST))
10186189Srwatson				continue;
10246381Sbillf			var = malloc(sizeof(*var));
10315103Sphk			memset(var, 0, sizeof(*var));
10486189Srwatson			asprintf(&var->name, "%s%s%s:%s",
10546381Sbillf			    colls, colls[0] != 0 ? "." : "",
10615103Sphk			    hid_usage_page(HID_PAGE(h.usage)),
10786189Srwatson			    hid_usage_in_page(h.usage));
10846381Sbillf			var->h = h;
10915103Sphk			*pnext = var;
11086189Srwatson			pnext = &var->next;
11180418Speter		}
11280418Speter		hid_end_parse(d);
11386189Srwatson		return;
11446381Sbillf	}
11515103Sphk	for (i = 0; i < nnames; i++) {
11686189Srwatson		var = malloc(sizeof(*var));
117105046Smike		memset(var, 0, sizeof(*var));
11815103Sphk		tmp1 = tmp2 = strdup(names[i]);
11986189Srwatson		strsep(&tmp2, "=");
12046381Sbillf		var->name = strsep(&tmp1, "#");
12115103Sphk		if (tmp1 != NULL)
12286189Srwatson			var->instance = atoi(tmp1);
12346381Sbillf		if (tmp2 != NULL) {
12415103Sphk			if (!wflag)
12515103Sphk				errx(1, "Must specify -w to write variables");
12686189Srwatson			var->val = atoi(tmp2);
12746381Sbillf		} else
12815103Sphk			if (wflag)
12986189Srwatson				errx(1, "Must not specify -w to read variables");
13046381Sbillf		*pnext = var;
13115103Sphk		pnext = &var->next;
13215103Sphk
13315103Sphk		instance = 0;
13415103Sphk		cp = 0;
13586189Srwatson		for (d = hid_start_parse(r,
13646381Sbillf		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
13715103Sphk		    hid_get_item(d, &h); ) {
13831990Sgpalmer			if (h.kind == hid_collection) {
13986189Srwatson				cp += sprintf(&colls[cp], "%s%s:%s",
14046381Sbillf				    cp != 0 ? "." : "",
14131990Sgpalmer				    hid_usage_page(HID_PAGE(h.usage)),
14286189Srwatson				    hid_usage_in_page(h.usage));
14346381Sbillf			} else if (h.kind == hid_endcollection) {
14431990Sgpalmer				tmp1 = strrchr(colls, '.');
14515103Sphk				if (tmp1 != NULL) {
14686189Srwatson					cp -= strlen(tmp1);
14746381Sbillf					tmp1[0] = 0;
14815103Sphk				} else {
14986189Srwatson					cp = 0;
15046381Sbillf					colls[0] = 0;
15115103Sphk				}
152106605Stmm			}
153106605Stmm			if ((h.kind != hid_input && h.kind != hid_output &&
154106605Stmm			    h.kind != hid_feature) || (h.flags & HIO_CONST))
155106605Stmm				continue;
156106605Stmm			snprintf(hname, sizeof(hname), "%s%s%s:%s",
157106605Stmm			    colls, colls[0] != 0 ? "." : "",
158106605Stmm			    hid_usage_page(HID_PAGE(h.usage)),
159106605Stmm			    hid_usage_in_page(h.usage));
160106605Stmm			t = strlen(hname) - strlen(var->name);
161106605Stmm			if (t > 0) {
162106605Stmm				if (strcmp(hname + t, var->name) != 0)
163106605Stmm					continue;
164106605Stmm				if (hname[t - 1] != '.')
165106605Stmm					continue;
166106605Stmm			} else if (strcmp(hname, var->name) != 0)
167106605Stmm				continue;
168106605Stmm			if (var->instance != instance++)
169106605Stmm				continue;
170106605Stmm			var->h = h;
171106605Stmm			break;
172106605Stmm		}
173106605Stmm		hid_end_parse(d);
174106605Stmm		if (var->h.usage == 0)
175106605Stmm			errx(1, "Unknown item '%s'", var->name);
176106605Stmm	}
177106605Stmm}
17828885Skato
17928885Skatostatic void
18046381Sbillfusage(void)
18128885Skato{
18215103Sphk
18315103Sphk	fprintf(stderr,
18446155Sphk                "usage: %s -f device "
18562573Sphk                "[-l] [-n] [-r] [-t tablefile] [-v] [-x] name ...\n",
18646155Sphk                getprogname());
18787072Srwatson	fprintf(stderr,
18887275Srwatson                "       %s -f device "
18946155Sphk                "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
19015103Sphk                getprogname());
19191406Sjhb	fprintf(stderr,
19287072Srwatson                "       %s -f device "
19357163Srwatson                "[-t tablefile] [-v] [-z] -w name=value\n",
19486190Srwatson                getprogname());
19587275Srwatson	exit(1);
19687275Srwatson}
19787275Srwatson
19887275Srwatsonstatic void
19987275Srwatsondumpitem(const char *label, struct hid_item *h)
20087275Srwatson{
20187275Srwatson	if ((h->flags & HIO_CONST) && !verbose)
20287275Srwatson		return;
20387275Srwatson	printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
20487275Srwatson	       h->report_ID, h->report_size, h->report_count,
20587072Srwatson	       hid_usage_page(HID_PAGE(h->usage)),
20687275Srwatson	       hid_usage_in_page(h->usage),
20787275Srwatson	       h->flags & HIO_CONST ? " Const" : "",
20887275Srwatson	       h->flags & HIO_VARIABLE ? "" : " Array");
20987275Srwatson	printf(", logical range %d..%d",
21087275Srwatson	       h->logical_minimum, h->logical_maximum);
21187275Srwatson	if (h->physical_minimum != h->physical_maximum)
21287275Srwatson		printf(", physical range %d..%d",
21387275Srwatson		       h->physical_minimum, h->physical_maximum);
21487275Srwatson	if (h->unit)
21587275Srwatson		printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
21657111Srwatson	printf("\n");
21786189Srwatson}
21846155Sphk
21946155Sphkstatic const char *
22046155Sphkhid_collection_type(int32_t type)
22146155Sphk{
22286189Srwatson	static char num[8];
22346155Sphk
22446381Sbillf	switch (type) {
22546155Sphk	case 0: return ("Physical");
22686190Srwatson	case 1: return ("Application");
22784611Srwatson	case 2: return ("Logical");
22887072Srwatson	case 3: return ("Report");
22984611Srwatson	case 4: return ("Named_Array");
23084611Srwatson	case 5: return ("Usage_Switch");
23186190Srwatson	case 6: return ("Usage_Modifier");
23284611Srwatson	}
23315103Sphk	snprintf(num, sizeof(num), "0x%02x", type);
23493686Sarr	return (num);
23515103Sphk}
23693686Sarr
23793686Sarrstatic void
23893686Sarrdumpitems(report_desc_t r)
23915103Sphk{
24062573Sphk	struct hid_data *d;
24115103Sphk	struct hid_item h;
24286145Srwatson	int size;
24386140Srwatson
24415103Sphk	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
24591406Sjhb		switch (h.kind) {
24686145Srwatson		case hid_collection:
24786140Srwatson			printf("Collection type=%s page=%s usage=%s\n",
24886140Srwatson			       hid_collection_type(h.collection),
24986140Srwatson			       hid_usage_page(HID_PAGE(h.usage)),
25086140Srwatson			       hid_usage_in_page(h.usage));
25187275Srwatson			break;
25287275Srwatson		case hid_endcollection:
25386145Srwatson			printf("End collection\n");
25487275Srwatson			break;
25587275Srwatson		case hid_input:
25686140Srwatson			dumpitem("Input  ", &h);
25786140Srwatson			break;
25886140Srwatson		case hid_output:
25986140Srwatson			dumpitem("Output ", &h);
26086140Srwatson			break;
26186140Srwatson		case hid_feature:
26286140Srwatson			dumpitem("Feature", &h);
26386140Srwatson			break;
26486145Srwatson		}
26587275Srwatson	}
26687072Srwatson	hid_end_parse(d);
26787275Srwatson	size = hid_report_size(r, hid_input, -1);
26887275Srwatson	printf("Total   input size %d bytes\n", size);
26986140Srwatson
27087275Srwatson	size = hid_report_size(r, hid_output, -1);
27186145Srwatson	printf("Total  output size %d bytes\n", size);
27287275Srwatson
27386140Srwatson	size = hid_report_size(r, hid_feature, -1);
27493686Sarr	printf("Total feature size %d bytes\n", size);
27587072Srwatson}
27693686Sarr
27793686Sarrstatic void
27886140Srwatsonprdata(u_char *buf, struct hid_item *h)
27993686Sarr{
28086140Srwatson	u_int data;
28193686Sarr	int i, pos;
28286140Srwatson
28386140Srwatson	pos = h->pos;
28415103Sphk	for (i = 0; i < h->report_count; i++) {
28515103Sphk		data = hid_get_data(buf, h);
28683990Srwatson		if (i > 0)
28783990Srwatson			printf(" ");
28883990Srwatson		if (h->logical_minimum < 0)
28961370Srwatson			printf("%d", (int)data);
29015103Sphk		else
29117281Swollman			printf("%u", data);
29246381Sbillf                if (hexdump)
29315103Sphk			printf(" [0x%x]", data);
29486190Srwatson		h->pos += h->report_size;
29578609Spirzyk	}
29615103Sphk	h->pos = pos;
29715103Sphk}
29815103Sphk
29986189Srwatsonstatic void
30015103Sphkdumpdata(int f, report_desc_t rd, int loop)
30115103Sphk{
30286189Srwatson	struct variable *var;
30346381Sbillf	int dlen, havedata, i, match, r, rid, use_rid;
30486189Srwatson	u_char *dbuf;
30546381Sbillf	enum hid_kind kind;
30686189Srwatson
30746381Sbillf	kind = 0;
30886189Srwatson	rid = -1;
30946381Sbillf	use_rid = !!hid_get_report_id(f);
31086189Srwatson	do {
31146381Sbillf		if (kind < 3) {
31286189Srwatson			if (++rid >= 256) {
31346381Sbillf				rid = 0;
31418540Sbde				kind++;
31586189Srwatson			}
31646381Sbillf			if (kind >= 3)
31786189Srwatson				rid = -1;
31846381Sbillf			for (var = vars; var; var = var->next) {
31986189Srwatson				if (rid == var->h.report_ID &&
32086189Srwatson				    kind == var->h.kind)
32146381Sbillf					break;
32286189Srwatson			}
32346381Sbillf			if (var == NULL)
32486189Srwatson				continue;
32546381Sbillf		}
32686189Srwatson		dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid);
32746381Sbillf		if (dlen <= 0)
32886189Srwatson			continue;
32946381Sbillf		dbuf = malloc(dlen);
33086189Srwatson		memset(dbuf, 0, dlen);
33146381Sbillf		if (kind < 3) {
33286189Srwatson			dbuf[0] = rid;
33346381Sbillf			r = hid_get_report(f, kind, dbuf, dlen);
33486189Srwatson			if (r < 0)
33546381Sbillf				warn("hid_get_report(rid %d)", rid);
33686189Srwatson			havedata = !r && (rid == 0 || dbuf[0] == rid);
33746381Sbillf			if (rid != 0)
33886189Srwatson				dbuf[0] = rid;
33946381Sbillf		} else {
34086189Srwatson			r = read(f, dbuf, dlen);
34146381Sbillf			if (r < 1)
34248891Sphk				err(1, "read error");
34348891Sphk			havedata = 1;
34486189Srwatson		}
34548891Sphk		if (verbose) {
34648891Sphk			printf("Got %s report %d (%d bytes):",
34786189Srwatson			    kind == hid_output ? "output" :
34848891Sphk			    kind == hid_feature ? "feature" : "input",
34948927Sphk			    use_rid ? dbuf[0] : 0, dlen);
35049535Sphk			if (havedata) {
351104043Sphk				for (i = 0; i < dlen; i++)
352104043Sphk					printf(" %02x", dbuf[i]);
35358926Sphk			}
35460041Sphk			printf("\n");
35558926Sphk		}
35658926Sphk		match = 0;
35758926Sphk		for (var = vars; var; var = var->next) {
35858926Sphk			if ((kind < 3 ? kind : hid_input) != var->h.kind)
35958926Sphk				continue;
36072376Sjake			if (var->h.report_ID != 0 &&
36172376Sjake			    dbuf[0] != var->h.report_ID)
36272376Sjake				continue;
36372376Sjake			match = 1;
364			if (!noname)
365				printf("%s=", var->name);
366			if (havedata)
367				prdata(dbuf, &var->h);
368			printf("\n");
369		}
370		if (match)
371			printf("\n");
372		free(dbuf);
373	} while (loop || kind < 3);
374}
375
376static void
377writedata(int f, report_desc_t rd)
378{
379	struct variable *var;
380	int dlen, i, r, rid;
381	u_char *dbuf;
382	enum hid_kind kind;
383
384	kind = 0;
385	rid = 0;
386	for (kind = 0; kind < 3; kind ++) {
387	    for (rid = 0; rid < 256; rid ++) {
388		for (var = vars; var; var = var->next) {
389			if (rid == var->h.report_ID && kind == var->h.kind)
390				break;
391		}
392		if (var == NULL)
393			continue;
394		dlen = hid_report_size(rd, kind, rid);
395		if (dlen <= 0)
396			continue;
397		dbuf = malloc(dlen);
398		memset(dbuf, 0, dlen);
399		dbuf[0] = rid;
400		if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) {
401			if (verbose) {
402				printf("Got %s report %d (%d bytes):",
403				    kind == hid_input ? "input" :
404				    kind == hid_output ? "output" : "feature",
405				    rid, dlen);
406				for (i = 0; i < dlen; i++)
407					printf(" %02x", dbuf[i]);
408				printf("\n");
409			}
410		} else if (!zflag) {
411			warn("hid_get_report(rid %d)", rid);
412			if (verbose) {
413				printf("Can't get %s report %d (%d bytes). "
414				    "Will be initialized with zeros.\n",
415				    kind == hid_input ? "input" :
416				    kind == hid_output ? "output" : "feature",
417				    rid, dlen);
418			}
419		}
420		for (var = vars; var; var = var->next) {
421			if (rid != var->h.report_ID || kind != var->h.kind)
422				continue;
423			hid_set_data(dbuf, &var->h, var->val);
424		}
425		if (verbose) {
426			printf("Setting %s report %d (%d bytes):",
427			    kind == hid_output ? "output" :
428			    kind == hid_feature ? "feature" : "input",
429			    rid, dlen);
430			for (i = 0; i < dlen; i++)
431				printf(" %02x", dbuf[i]);
432			printf("\n");
433		}
434		r = hid_set_report(f, kind, dbuf, dlen);
435		if (r != 0)
436			warn("hid_set_report(rid %d)", rid);
437		free(dbuf);
438	    }
439	}
440}
441
442int
443main(int argc, char **argv)
444{
445	report_desc_t r;
446	char *table = 0;
447	char devnam[100], *dev = NULL;
448	int f;
449	int all = 0;
450	int ch;
451	int repdump = 0;
452	int loop = 0;
453
454	while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) {
455		switch(ch) {
456		case 'a':
457			all++;
458			break;
459		case 'f':
460			dev = optarg;
461			break;
462		case 'l':
463			loop ^= 1;
464			break;
465		case 'n':
466			noname++;
467			break;
468		case 'r':
469			repdump++;
470			break;
471		case 't':
472			table = optarg;
473			break;
474		case 'v':
475			verbose++;
476			break;
477		case 'w':
478			wflag = 1;
479			break;
480		case 'x':
481			hexdump = 1;
482			break;
483		case 'z':
484			zflag = 1;
485			break;
486		case '?':
487		default:
488			usage();
489		}
490	}
491	argc -= optind;
492	argv += optind;
493	if (dev == NULL)
494		usage();
495
496	if (argc == 0 && !all && !repdump)
497		usage();
498
499	if (dev[0] != '/') {
500		if (isdigit(dev[0]))
501			snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev);
502		else
503			snprintf(devnam, sizeof(devnam), "/dev/%s", dev);
504		dev = devnam;
505	}
506
507	hid_init(table);
508
509	f = open(dev, O_RDWR);
510	if (f < 0)
511		err(1, "%s", dev);
512
513	r = hid_get_report_desc(f);
514	if (r == 0)
515		errx(1, "USB_GET_REPORT_DESC");
516
517	if (repdump) {
518		printf("Report descriptor:\n");
519		dumpitems(r);
520	}
521	if (argc != 0 || all) {
522		parceargs(r, all, argc, argv);
523		if (wflag)
524			writedata(f, r);
525		else
526			dumpdata(f, r, loop);
527	}
528
529	hid_dispose_report_desc(r);
530	exit(0);
531}
532