Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 30 Jul 2011 13:22:44 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r224511 - in head: lib/libusbhid usr.bin/usbhidaction usr.bin/usbhidctl
Message-ID:  <201107301322.p6UDMicQ001442@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Jul 30 13:22:44 2011
New Revision: 224511
URL: http://svn.freebsd.org/changeset/base/224511

Log:
  MFprojects/hid:
   - Fix usbhidctl and usbhidaction to handle HID devices with multiple
  report ids, such as multimedia keyboards.
   - Add collection type and report id to the `usbhidctl -r` output. They
  are important for proper device understanding and debugging.
   - Fix usbhidaction tool to properly handle items having report_count
  more then 1.
  
  Approved by:	re (kib)
  MFC after:	2 weeks

Modified:
  head/lib/libusbhid/parse.c
  head/usr.bin/usbhidaction/usbhidaction.c
  head/usr.bin/usbhidctl/usbhid.c

Modified: head/lib/libusbhid/parse.c
==============================================================================
--- head/lib/libusbhid/parse.c	Sat Jul 30 13:21:33 2011	(r224510)
+++ head/lib/libusbhid/parse.c	Sat Jul 30 13:22:44 2011	(r224511)
@@ -322,6 +322,8 @@ hid_get_item(hid_data_t s, hid_item_t *h
 					 * one and one item:
 					 */
 					c->report_count = 1;
+					c->usage_minimum = 0;
+					c->usage_maximum = 0;
 				} else {
 					s->ncount = 1;
 				}
@@ -512,13 +514,14 @@ hid_report_size(report_desc_t r, enum hi
 	uint32_t temp;
 	uint32_t hpos;
 	uint32_t lpos;
+	int report_id = 0;
 
 	hpos = 0;
 	lpos = 0xFFFFFFFF;
 
 	memset(&h, 0, sizeof h);
 	for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) {
-		if (h.report_ID == id && h.kind == k) {
+		if ((h.report_ID == id || id < 0) && h.kind == k) {
 			/* compute minimum */
 			if (lpos > h.pos)
 				lpos = h.pos;
@@ -527,6 +530,8 @@ hid_report_size(report_desc_t r, enum hi
 			/* compute maximum */
 			if (hpos < temp)
 				hpos = temp;
+			if (h.report_ID != 0)
+				report_id = 1;
 		}
 	}
 	hid_end_parse(d);
@@ -537,11 +542,8 @@ hid_report_size(report_desc_t r, enum hi
 	else
 		temp = hpos - lpos;
 
-	if (id)
-		temp += 8;
-
 	/* return length in bytes rounded up */
-	return ((temp + 7) / 8);
+	return ((temp + 7) / 8 + report_id);
 }
 
 int

Modified: head/usr.bin/usbhidaction/usbhidaction.c
==============================================================================
--- head/usr.bin/usbhidaction/usbhidaction.c	Sat Jul 30 13:21:33 2011	(r224510)
+++ head/usr.bin/usbhidaction/usbhidaction.c	Sat Jul 30 13:22:44 2011	(r224511)
@@ -92,12 +92,12 @@ main(int argc, char **argv)
 	char buf[100];
 	char devnamebuf[PATH_MAX];
 	struct command *cmd;
-	int reportid;
+	int reportid = -1;
 
 	demon = 1;
 	ignore = 0;
 	dieearly = 0;
-	while ((ch = getopt(argc, argv, "c:def:ip:t:v")) != -1) {
+	while ((ch = getopt(argc, argv, "c:def:ip:r:t:v")) != -1) {
 		switch(ch) {
 		case 'c':
 			conf = optarg;
@@ -117,6 +117,9 @@ main(int argc, char **argv)
 		case 'p':
 			pidfile = optarg;
 			break;
+		case 'r':
+			reportid = atoi(optarg);
+			break;
 		case 't':
 			table = optarg;
 			break;
@@ -146,14 +149,13 @@ main(int argc, char **argv)
 	fd = open(dev, O_RDWR);
 	if (fd < 0)
 		err(1, "%s", dev);
-	reportid = hid_get_report_id(fd);
 	repd = hid_get_report_desc(fd);
 	if (repd == NULL)
 		err(1, "hid_get_report_desc() failed");
 
 	commands = parse_conf(conf, repd, reportid, ignore);
 
-	sz = (size_t)hid_report_size(repd, hid_input, reportid);
+	sz = (size_t)hid_report_size(repd, hid_input, -1);
 
 	if (verbose)
 		printf("report size %zu\n", sz);
@@ -198,7 +200,23 @@ main(int argc, char **argv)
 		}
 #endif
 		for (cmd = commands; cmd; cmd = cmd->next) {
-			val = hid_get_data(buf, &cmd->item);
+			if (cmd->item.report_ID != 0 &&
+			    buf[0] != cmd->item.report_ID)
+				continue;
+			if (cmd->item.flags & HIO_VARIABLE)
+				val = hid_get_data(buf, &cmd->item);
+			else {
+				uint32_t pos = cmd->item.pos;
+				for (i = 0; i < cmd->item.report_count; i++) {
+					val = hid_get_data(buf, &cmd->item);
+					if (val == cmd->value)
+						break;
+					cmd->item.pos += cmd->item.report_size;
+				}
+				cmd->item.pos = pos;
+				val = (i < cmd->item.report_count) ?
+				    cmd->value : -1;
+			}
 			if (cmd->value != val && cmd->anyvalue == 0)
 				goto next;
 			if ((cmd->debounce == 0) ||

Modified: head/usr.bin/usbhidctl/usbhid.c
==============================================================================
--- head/usr.bin/usbhidctl/usbhid.c	Sat Jul 30 13:21:33 2011	(r224510)
+++ head/usr.bin/usbhidctl/usbhid.c	Sat Jul 30 13:22:44 2011	(r224511)
@@ -46,7 +46,6 @@ int verbose = 0;
 int all = 0;
 int noname = 0;
 int hexdump = 0;
-static int reportid;
 
 char **names;
 int nnames;
@@ -101,11 +100,12 @@ dumpitem(const char *label, struct hid_i
 {
 	if ((h->flags & HIO_CONST) && !verbose)
 		return;
-	printf("%s size=%d count=%d page=%s usage=%s%s", label,
-	       h->report_size, h->report_count,
+	printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label,
+	       h->report_ID, h->report_size, h->report_count,
 	       hid_usage_page(HID_PAGE(h->usage)),
 	       hid_usage_in_page(h->usage),
-	       h->flags & HIO_CONST ? " Const" : "");
+	       h->flags & HIO_CONST ? " Const" : "",
+	       h->flags & HIO_VARIABLE ? "" : " Array");
 	printf(", logical range %d..%d",
 	       h->logical_minimum, h->logical_maximum);
 	if (h->physical_minimum != h->physical_maximum)
@@ -116,6 +116,24 @@ dumpitem(const char *label, struct hid_i
 	printf("\n");
 }
 
+static const char *
+hid_collection_type(int32_t type)
+{
+	static char num[8];
+
+	switch (type) {
+	case 0: return ("Physical");
+	case 1: return ("Application");
+	case 2: return ("Logical");
+	case 3: return ("Report");
+	case 4: return ("Named_Array");
+	case 5: return ("Usage_Switch");
+	case 6: return ("Usage_Modifier");
+	}
+	snprintf(num, sizeof(num), "0x%02x", type);
+	return (num);
+}
+
 void
 dumpitems(report_desc_t r)
 {
@@ -123,10 +141,11 @@ dumpitems(report_desc_t r)
 	struct hid_item h;
 	int size;
 
-	for (d = hid_start_parse(r, ~0, reportid); hid_get_item(d, &h); ) {
+	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
 		switch (h.kind) {
 		case hid_collection:
-			printf("Collection page=%s usage=%s\n",
+			printf("Collection type=%s page=%s usage=%s\n",
+			       hid_collection_type(h.collection),
 			       hid_usage_page(HID_PAGE(h.usage)),
 			       hid_usage_in_page(h.usage));
 			break;
@@ -145,13 +164,13 @@ dumpitems(report_desc_t r)
 		}
 	}
 	hid_end_parse(d);
-	size = hid_report_size(r, hid_input, 0);
+	size = hid_report_size(r, hid_input, -1);
 	printf("Total   input size %d bytes\n", size);
 
-	size = hid_report_size(r, hid_output, 0);
+	size = hid_report_size(r, hid_output, -1);
 	printf("Total  output size %d bytes\n", size);
 
-	size = hid_report_size(r, hid_feature, 0);
+	size = hid_report_size(r, hid_feature, -1);
 	printf("Total feature size %d bytes\n", size);
 }
 
@@ -180,14 +199,17 @@ prdata(u_char *buf, struct hid_item *h)
 	pos = h->pos;
 	for (i = 0; i < h->report_count; i++) {
 		data = hid_get_data(buf, h);
+		if (i > 0)
+			printf(" ");
 		if (h->logical_minimum < 0)
 			printf("%d", (int)data);
 		else
 			printf("%u", data);
                 if (hexdump)
 			printf(" [0x%x]", data);
-		pos += h->report_size;
+		h->pos += h->report_size;
 	}
+	h->pos = pos;
 }
 
 void
@@ -202,7 +224,7 @@ dumpdata(int f, report_desc_t rd, int lo
 	char namebuf[10000], *namep;
 
 	hids = 0;
-	for (d = hid_start_parse(rd, 1<<hid_input, reportid);
+	for (d = hid_start_parse(rd, 1<<hid_input, -1);
 	     hid_get_item(d, &h); ) {
 		if (h.kind == hid_collection)
 			colls[++sp] = h.usage;
@@ -217,7 +239,7 @@ dumpdata(int f, report_desc_t rd, int lo
 	}
 	hid_end_parse(d);
 	rev(&hids);
-	dlen = hid_report_size(rd, hid_input, 0);
+	dlen = hid_report_size(rd, hid_input, -1);
 	dbuf = malloc(dlen);
 	if (!loop)
 		if (hid_set_immed(f, 1) < 0) {
@@ -228,10 +250,12 @@ dumpdata(int f, report_desc_t rd, int lo
 		}
 	do {
 		r = read(f, dbuf, dlen);
-		if (r != dlen) {
-			err(1, "bad read %d != %d", r, dlen);
+		if (r < 1) {
+			err(1, "read error");
 		}
 		for (n = hids; n; n = n->next) {
+			if (n->report_ID != 0 && dbuf[0] != n->report_ID)
+				continue;
 			namep = namebuf;
 			namep += sprintf(namep, "%s:%s.",
 					 hid_usage_page(HID_PAGE(n->collection)),
@@ -242,7 +266,7 @@ dumpdata(int f, report_desc_t rd, int lo
 			if (all || gotname(namebuf)) {
 				if (!noname)
 					printf("%s=", namebuf);
-				prdata(dbuf + (reportid != 0), n);
+				prdata(dbuf, n);
 				printf("\n");
 			}
 		}



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