Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Aug 2011 12:04:12 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r224572 - projects/hid/usr.bin/usbhidctl
Message-ID:  <201108011204.p71C4CCD095768@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Aug  1 12:04:12 2011
New Revision: 224572
URL: http://svn.freebsd.org/changeset/base/224572

Log:
  Refactor usbhidctl to support items writing and and few other features.

Modified:
  projects/hid/usr.bin/usbhidctl/usbhid.c
  projects/hid/usr.bin/usbhidctl/usbhidctl.1

Modified: projects/hid/usr.bin/usbhidctl/usbhid.c
==============================================================================
--- projects/hid/usr.bin/usbhidctl/usbhid.c	Mon Aug  1 11:24:55 2011	(r224571)
+++ projects/hid/usr.bin/usbhidctl/usbhid.c	Mon Aug  1 12:04:12 2011	(r224572)
@@ -1,4 +1,3 @@
-/*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
 /*	$FreeBSD$ */
 
 /*
@@ -42,45 +41,120 @@
 #include <usbhid.h>
 #include <dev/usb/usbhid.h>
 
+struct variable {
+	char *name;
+	int instance;
+	int val;
+	struct hid_item h;
+	struct variable *next;
+} *vars;
+
 int verbose = 0;
-int all = 0;
 int noname = 0;
 int hexdump = 0;
+int wflag = 0;
+int zflag = 0;
 
-char **names;
-int nnames;
-
-void prbits(int bits, char **strs, int n);
-void usage(void);
-void dumpitem(const char *label, struct hid_item *h);
-void dumpitems(report_desc_t r);
-void rev(struct hid_item **p);
-void prdata(u_char *buf, struct hid_item *h);
-void dumpdata(int f, report_desc_t r, int loop);
-int gotname(char *n);
+static void usage(void);
+static void dumpitem(const char *label, struct hid_item *h);
+static void dumpitems(report_desc_t r);
+static void prdata(u_char *buf, struct hid_item *h);
+static void dumpdata(int f, report_desc_t r, int loop);
+static void writedata(int f, report_desc_t r);
 
-int
-gotname(char *n)
+static void
+parceargs(report_desc_t r, int all, int nnames, char **names)
 {
-	int i;
-
-	for (i = 0; i < nnames; i++)
-		if (strcmp(names[i], n) == 0)
-			return 1;
-	return 0;
-}
-
-void
-prbits(int bits, char **strs, int n)
-{
-	int i;
-
-	for(i = 0; i < n; i++, bits >>= 1)
-		if (strs[i*2])
-			printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]);
+	struct hid_data *d;
+	struct hid_item h;
+	u_int32_t colls[100];
+	int i, sp, instance;
+	char hname[1000], *tmp1, *tmp2;
+	struct variable *var, **pnext;
+
+	pnext = &vars;
+	if (all) {
+		if (wflag)
+			errx(1, "Must not specify -w to read variables");
+		sp = 0;
+		for (d = hid_start_parse(r,
+		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
+		    hid_get_item(d, &h); ) {
+			if (h.kind == hid_collection)
+				colls[++sp] = h.usage;
+			else if (h.kind == hid_endcollection)
+				--sp;
+			if ((h.kind != hid_input && h.kind != hid_output &&
+			    h.kind != hid_feature) || (h.flags & HIO_CONST))
+				continue;
+			var = malloc(sizeof(*var));
+			memset(var, 0, sizeof(*var));
+			asprintf(&var->name, "%s:%s.%s:%s",
+			    hid_usage_page(HID_PAGE(colls[sp])),
+			    hid_usage_in_page(colls[sp]),
+			    hid_usage_page(HID_PAGE(h.usage)),
+			    hid_usage_in_page(h.usage));
+			var->h = h;
+			*pnext = var;
+			pnext = &var->next;
+		}
+		hid_end_parse(d);
+		return;
+	}
+	for (i = 0; i < nnames; i++) {
+		var = malloc(sizeof(*var));
+		memset(var, 0, sizeof(*var));
+		tmp1 = tmp2 = strdup(names[i]);
+		strsep(&tmp2, "=");
+		var->name = strsep(&tmp1, "#");
+		if (tmp1 != NULL)
+			var->instance = atoi(tmp1);
+		if (tmp2 != NULL) {
+			if (!wflag)
+				errx(1, "Must specify -w to write variables");
+			var->val = atoi(tmp2);
+		} else
+			if (wflag)
+				errx(1, "Must not specify -w to read variables");
+		*pnext = var;
+		pnext = &var->next;
+
+		instance = 0;
+		sp = 0;
+		for (d = hid_start_parse(r,
+		    1<<hid_input | 1<<hid_output | 1<<hid_feature, -1);
+		    hid_get_item(d, &h); ) {
+			if (h.kind == hid_collection)
+				colls[++sp] = h.usage;
+			else if (h.kind == hid_endcollection)
+				--sp;
+			if ((h.kind != hid_input && h.kind != hid_output &&
+			    h.kind != hid_feature) || (h.flags & HIO_CONST))
+				continue;
+			snprintf(hname, sizeof(hname), "%s:%s",
+			    hid_usage_page(HID_PAGE(h.usage)),
+			    hid_usage_in_page(h.usage));
+			if (strcmp(hname, var->name) != 0) {
+				snprintf(hname, sizeof(hname), "%s:%s.%s:%s",
+				    hid_usage_page(HID_PAGE(colls[sp])),
+				    hid_usage_in_page(colls[sp]),
+				    hid_usage_page(HID_PAGE(h.usage)),
+				    hid_usage_in_page(h.usage));
+				if (strcmp(hname, var->name) != 0)
+					continue;
+			}
+			if (var->instance != instance++)
+				continue;
+			var->h = h;
+			break;
+		}
+		hid_end_parse(d);
+		if (var->h.usage == 0)
+			errx(1, "Unknown usage '%s'", var->name);
+	}
 }
 
-void
+static void
 usage(void)
 {
 
@@ -92,10 +166,14 @@ usage(void)
                 "       %s -f device "
                 "[-l] [-n] [-r] [-t tablefile] [-v] [-x] -a\n",
                 getprogname());
+	fprintf(stderr,
+                "       %s -f device "
+                "[-t tablefile] [-v] [-z] -w name=value\n",
+                getprogname());
 	exit(1);
 }
 
-void
+static void
 dumpitem(const char *label, struct hid_item *h)
 {
 	if ((h->flags & HIO_CONST) && !verbose)
@@ -134,7 +212,7 @@ hid_collection_type(int32_t type)
 	return (num);
 }
 
-void
+static void
 dumpitems(report_desc_t r)
 {
 	struct hid_data *d;
@@ -174,23 +252,7 @@ dumpitems(report_desc_t r)
 	printf("Total feature size %d bytes\n", size);
 }
 
-void
-rev(struct hid_item **p)
-{
-	struct hid_item *cur, *prev, *next;
-
-	prev = 0;
-	cur = *p;
-	while(cur != 0) {
-		next = cur->next;
-		cur->next = prev;
-		prev = cur;
-		cur = next;
-	}
-	*p = prev;
-}
-
-void
+static void
 prdata(u_char *buf, struct hid_item *h)
 {
 	u_int data;
@@ -212,82 +274,162 @@ prdata(u_char *buf, struct hid_item *h)
 	h->pos = pos;
 }
 
-void
+static void
 dumpdata(int f, report_desc_t rd, int loop)
 {
-	struct hid_data *d;
-	struct hid_item h, *hids, *n;
-	int r, dlen;
+	struct variable *var;
+	int dlen, havedata, i, match, r, rid, use_rid;
 	u_char *dbuf;
-	u_int32_t colls[100];
-	int sp = 0;
-	char namebuf[10000], *namep;
+	enum hid_kind kind;
 
-	hids = 0;
-	for (d = hid_start_parse(rd, 1<<hid_input, -1);
-	     hid_get_item(d, &h); ) {
-		if (h.kind == hid_collection)
-			colls[++sp] = h.usage;
-		else if (h.kind == hid_endcollection)
-			--sp;
-		if (h.kind != hid_input || (h.flags & HIO_CONST))
+	kind = 0;
+	rid = -1;
+	use_rid = !!hid_get_report_id(f);
+	do {
+		if (kind < 3) {
+			if (++rid >= 256) {
+				rid = 0;
+				kind++;
+			}
+			if (kind >= 3)
+				rid = -1;
+			for (var = vars; var; var = var->next) {
+				if (rid == var->h.report_ID &&
+				    kind == var->h.kind)
+					break;
+			}
+			if (var == NULL)
+				continue;
+		}
+		dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid);
+		if (dlen <= 0)
 			continue;
-		h.next = hids;
-		h.collection = colls[sp];
-		hids = malloc(sizeof *hids);
-		*hids = h;
-	}
-	hid_end_parse(d);
-	rev(&hids);
-	dlen = hid_report_size(rd, hid_input, -1);
-	dbuf = malloc(dlen);
-	if (!loop)
-		if (hid_set_immed(f, 1) < 0) {
-			if (errno == EOPNOTSUPP)
-				warnx("device does not support immediate mode, only changes reported.");
-			else
-				err(1, "USB_SET_IMMED");
+		dbuf = malloc(dlen);
+		memset(dbuf, 0, dlen);
+		if (kind < 3) {
+			dbuf[0] = rid;
+			r = hid_get_report(f, kind, dbuf, dlen);
+			if (r < 0)
+				warn("hid_get_report(rid %d)", rid);
+			havedata = !r && (rid == 0 || dbuf[0] == rid);
+			if (rid != 0)
+				dbuf[0] = rid;
+		} else {
+			r = read(f, dbuf, dlen);
+			if (r < 1)
+				err(1, "read error");
+			havedata = 1;
 		}
-	do {
-		r = read(f, dbuf, dlen);
-		if (r < 1) {
-			err(1, "read error");
+		if (verbose) {
+			printf("Got %s report %d (%d bytes):",
+			    kind == hid_output ? "output" :
+			    kind == hid_feature ? "feature" : "input",
+			    use_rid ? dbuf[0] : 0, dlen);
+			if (havedata) {
+				for (i = 0; i < dlen; i++)
+					printf(" %02x", dbuf[i]);
+			}
+			printf("\n");
 		}
-		for (n = hids; n; n = n->next) {
-			if (n->report_ID != 0 && dbuf[0] != n->report_ID)
+		match = 0;
+		for (var = vars; var; var = var->next) {
+			if ((kind < 3 ? kind : hid_input) != var->h.kind)
+				continue;
+			if (var->h.report_ID != 0 &&
+			    dbuf[0] != var->h.report_ID)
 				continue;
-			namep = namebuf;
-			namep += sprintf(namep, "%s:%s.",
-					 hid_usage_page(HID_PAGE(n->collection)),
-					 hid_usage_in_page(n->collection));
-			namep += sprintf(namep, "%s:%s",
-					 hid_usage_page(HID_PAGE(n->usage)),
-					 hid_usage_in_page(n->usage));
-			if (all || gotname(namebuf)) {
-				if (!noname)
-					printf("%s=", namebuf);
-				prdata(dbuf, n);
+			match = 1;
+			if (!noname)
+				printf("%s=", var->name);
+			if (havedata)
+				prdata(dbuf, &var->h);
+			printf("\n");
+		}
+		if (match)
+			printf("\n");
+		free(dbuf);
+	} while (loop || kind < 3);
+}
+
+static void
+writedata(int f, report_desc_t rd)
+{
+	struct variable *var;
+	int dlen, i, r, rid;
+	u_char *dbuf;
+	enum hid_kind kind;
+
+	kind = 0;
+	rid = 0;
+	for (kind = 0; kind < 3; kind ++) {
+	    for (rid = 0; rid < 256; rid ++) {
+		for (var = vars; var; var = var->next) {
+			if (rid == var->h.report_ID && kind == var->h.kind)
+				break;
+		}
+		if (var == NULL)
+			continue;
+		dlen = hid_report_size(rd, kind, rid);
+		if (dlen <= 0)
+			continue;
+		dbuf = malloc(dlen);
+		memset(dbuf, 0, dlen);
+		dbuf[0] = rid;
+		if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) {
+			if (verbose) {
+				printf("Got %s report %d (%d bytes):",
+				    kind == hid_input ? "input" :
+				    kind == hid_output ? "output" : "feature",
+				    rid, dlen);
+				for (i = 0; i < dlen; i++)
+					printf(" %02x", dbuf[i]);
 				printf("\n");
 			}
+		} else if (!zflag) {
+			warn("hid_get_report(rid %d)", rid);
+			if (verbose) {
+				printf("Can't get %s report %d (%d bytes). "
+				    "Will be initialized with zeros.\n",
+				    kind == hid_input ? "input" :
+				    kind == hid_output ? "output" : "feature",
+				    rid, dlen);
+			}
 		}
-		if (loop)
+		for (var = vars; var; var = var->next) {
+			if (rid != var->h.report_ID || kind != var->h.kind)
+				continue;
+			hid_set_data(dbuf, &var->h, var->val);
+		}
+		if (verbose) {
+			printf("Setting %s report %d (%d bytes):",
+			    kind == hid_output ? "output" :
+			    kind == hid_feature ? "feature" : "input",
+			    rid, dlen);
+			for (i = 0; i < dlen; i++)
+				printf(" %02x", dbuf[i]);
 			printf("\n");
-	} while (loop);
-	free(dbuf);
+		}
+		r = hid_set_report(f, kind, dbuf, dlen);
+		if (r != 0)
+			warn("hid_set_report(rid %d)", rid);
+		free(dbuf);
+	    }
+	}
 }
 
 int
 main(int argc, char **argv)
 {
-	int f;
 	report_desc_t r;
-	char devnam[100], *dev = 0;
+	char *table = 0;
+	char devnam[100], *dev = NULL;
+	int f;
+	int all = 0;
 	int ch;
 	int repdump = 0;
 	int loop = 0;
-	char *table = 0;
 
-	while ((ch = getopt(argc, argv, "af:lnrt:vx")) != -1) {
+	while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) {
 		switch(ch) {
 		case 'a':
 			all++;
@@ -310,9 +452,15 @@ main(int argc, char **argv)
 		case 'v':
 			verbose++;
 			break;
+		case 'w':
+			wflag = 1;
+			break;
 		case 'x':
 			hexdump = 1;
 			break;
+		case 'z':
+			zflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -320,12 +468,10 @@ main(int argc, char **argv)
 	}
 	argc -= optind;
 	argv += optind;
-	if (dev == 0)
+	if (dev == NULL)
 		usage();
-	names = argv;
-	nnames = argc;
 
-	if (nnames == 0 && !all && !repdump)
+	if (argc == 0 && !all && !repdump)
 		usage();
 
 	if (dev[0] != '/') {
@@ -350,8 +496,13 @@ main(int argc, char **argv)
 		printf("Report descriptor:\n");
 		dumpitems(r);
 	}
-	if (nnames != 0 || all)
-		dumpdata(f, r, loop);
+	if (argc != 0 || all) {
+		parceargs(r, all, argc, argv);
+		if (wflag)
+			writedata(f, r);
+		else
+			dumpdata(f, r, loop);
+	}
 
 	hid_dispose_report_desc(r);
 	exit(0);

Modified: projects/hid/usr.bin/usbhidctl/usbhidctl.1
==============================================================================
--- projects/hid/usr.bin/usbhidctl/usbhidctl.1	Mon Aug  1 11:24:55 2011	(r224571)
+++ projects/hid/usr.bin/usbhidctl/usbhidctl.1	Mon Aug  1 12:04:12 2011	(r224572)
@@ -28,7 +28,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd November 23, 2006
+.Dd August 01, 2011
 .Dt USBHIDCTL 1
 .Os
 .Sh NAME
@@ -36,27 +36,51 @@
 .Nd manipulate USB HID devices
 .Sh SYNOPSIS
 .Nm
-.Op Fl a
 .Fl f Ar device
+.Op Fl t Ar table
+.Op Fl v
+.Op Fl x
+.Fl r
+.Nm
+.Fl f Ar device
+.Op Fl t Ar table
 .Op Fl l
-.Op Fl n
-.Op Fl r
+.Op Fl v
+.Op Fl x
+.Fl a
+.Nm
+.Fl f Ar device
 .Op Fl t Ar table
+.Op Fl l
+.Op Fl n
 .Op Fl v
 .Op Fl x
-.Op Ar item ...
+.Ar item ...
+.Nm
+.Fl f Ar device
+.Op Fl t Ar table
+.Op Fl v
+.Op Fl z
+.Fl w
+.Ar item=value ...
 .Sh DESCRIPTION
 The
 .Nm
-utility can be used to dump the state of a USB HID (Human Interface Device).
+utility can be used to dump and modify the state of a USB HID (Human
+Interface Device).
 Each named
 .Ar item
 is printed.
+If the
+.Fl w
+flag is specified
+.Nm
+attempts to set the specified items to the given values.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
 .It Fl a
-Show all items.
+Show all items and their current values if device returns.
 .It Fl f Ar device
 Specify a path name for the device to operate on.
 .It Fl l
@@ -69,8 +93,15 @@ Dump the report descriptor.
 Specify a path name for the HID usage table file.
 .It Fl v
 Be verbose.
+.It Fl w
+Change item values.
+Only 'output' and 'feature' kinds can be set with this option.
 .It Fl x
 Dump data in hexadecimal as well as decimal.
+.It Fl z
+Reset reports to zero before processing
+.Fl w
+arguments. If not specified, current values will be requested from device.
 .El
 .Sh FILES
 .Pa /usr/share/misc/usb_hid_usages
@@ -84,7 +115,3 @@ The
 .Nm
 command appeared in
 .Nx 1.4 .
-.Sh BUGS
-The
-.Nm
-utility cannot show nor set output and feature items.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108011204.p71C4CCD095768>