usb/103418: [usb] [patch] usbhidctl: add ability to write output and feature items

Rene Ladan r.c.ladan at gmail.com
Wed Sep 20 07:40:37 PDT 2006


>Number:         103418
>Category:       usb
>Synopsis:       [usb] [patch] usbhidctl: add ability to write output and feature items
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-usb
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 20 14:40:25 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Rene Ladan
>Release:        FreeBSD 6.2-PRERELEASE i386
>Organization:
>Environment:
System: FreeBSD dyn172.win.tue.nl 6.2-PRERELEASE FreeBSD 6.2-PRERELEASE
#5: Tue Sep 19 21:13:50 CEST 2006
root at s000655.campus.tue.nl:/usr/obj/usr/src6/sys/RENE i386
>Description:
The usbhidctl(1) utility can read input items, but not set output nor
feature items.  This patch, loosely based on OpenBSD's usbhidctl, adds
write support to usbhidctl(1) so that it can set output and feature items.

Note: I am unable to test this patch as I do not have any usb hid with a
known output report descriptor.  It is therefore advisable that a committer
with good hid knowledge or a device with a known output report descriptor
reviews this patch before committing it.  But at least it compiles :)
>How-To-Repeat:
>Fix:

--- /usr/src/usr.bin/usbhidctl/usbhid.c	Mon May 26 06:58:26 2003
+++ usbhid.c	Tue Sep 19 23:59:07 2006
@@ -1,7 +1,7 @@
 /*	$NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $	*/
 /*	$FreeBSD: src/usr.bin/usbhidctl/usbhid.c,v 1.9 2003/05/26 04:58:26
mdodd Exp $ */

-/*
+/*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
@@ -51,6 +51,8 @@
 #include <dev/usb/usb.h>
 #include <dev/usb/usbhid.h>

+#define DELIM_SET '='
+
 int verbose = 0;
 int all = 0;
 int noname = 0;
@@ -66,6 +68,8 @@
 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);
+void wrdata(u_char *buf, struct hid_item *h, char const *name);
+void setdata(int f, report_desc_t r);
 int gotname(char *n);

 int
@@ -96,6 +100,7 @@

 	fprintf(stderr, "usage: %s -f device [-l] [-n] [-r] [-t tablefile]
[-v] name ...\n", __progname);
 	fprintf(stderr, "       %s -f device [-l] [-n] [-r] [-t tablefile]
[-v] -a\n", __progname);
+	fprintf(stderr, "       %s -f device [-t tablefile] -w name=value
...\n", __progname);
 	exit(1);
 }

@@ -254,6 +259,57 @@
 	free(dbuf);
 }

+void
+wrdata(u_char *buf, struct hid_item *h, char const *name)
+{
+	u_int dataval;
+	char const *valuesep;
+	valuesep = strchr(name, DELIM_SET);
+	if (valuesep) {
+		/* Set up variable */
+		dataval = (u_int)strtol(valuesep + 1, NULL, 10);
+		hid_set_data(buf, h, dataval);
+	}
+}
+
+void
+setdata(int f, report_desc_t rd)
+{
+	struct hid_data *d;
+	struct hid_item h, *hids, *n;
+	int dlen;
+	u_char *dbuf;
+	u_int32_t colls[100];
+	int sp = 0;
+	int i;
+
+	for (d = hid_start_parse(rd, 1<<hid_output | 1<<hid_feature, reportid);
+		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_output && h.kind != hid_feature) ||
+			(h.flags & HIO_CONST))
+			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, 0, hid_output | hid_feature);
+	dbuf = calloc(1, dlen);	
+
+	for (n = hids; n; n = n->next) {
+		for (i = 0; i < nnames; i++)
+			wrdata(dbuf + (reportid != 0), n, names[i]);
+	}
+	write(f, dbuf, dlen);
+	free(dbuf);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -263,9 +319,10 @@
 	int ch;
 	int repdump = 0;
 	int loop = 0;
+	int wflag = 0;
 	char *table = 0;

-	while ((ch = getopt(argc, argv, "af:lnrt:v")) != -1) {
+	while ((ch = getopt(argc, argv, "af:lnrt:vw")) != -1) {
 		switch(ch) {
 		case 'a':
 			all++;
@@ -288,6 +345,9 @@
 		case 'v':
 			verbose++;
 			break;
+		case 'w':
+			wflag = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -295,7 +355,11 @@
 	}
 	argc -= optind;
 	argv += optind;
-	if (dev == 0)
+	if (dev == 0 || (loop && (wflag || repdump)))
+		/*
+		 * No device specified, or attempting to loop and set
+		 * or dump report at the same time
+		 */
 		usage();
 	names = argv;
 	nnames = argc;
@@ -325,7 +389,11 @@
 		printf("Report descriptor:\n");
 		dumpitems(r);
 	}
-	if (nnames != 0 || all)
+
+	if (wflag)
+		setdata(f, r);
+
+	if ((nnames != 0 && !wflag) || all)
 		dumpdata(f, r, loop);

 	hid_dispose_report_desc(r);

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-usb mailing list