Date: Tue, 3 Jan 2012 13:16:47 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r229389 - in stable/8: lib/libusbhid sys/conf sys/dev/usb/input usr.bin/usbhidaction usr.bin/usbhidctl Message-ID: <201201031316.q03DGl0D025473@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Tue Jan 3 13:16:47 2012 New Revision: 229389 URL: http://svn.freebsd.org/changeset/base/229389 Log: MFC r225839: Import the rest of HID improvements from the branch: - improve report descriptor parser in libusbhid to handle several kinds of reports same time; - add to the libusbhid API two functions wrapping respective kernel IOCTLs for reading and writing reports; - tune uhid IOCTL interface to allow reading and writing arbitrary report, when multiple supported by the device; - teach usbhidctl to set output and feature reports; - make usbhidaction support all the same item names as bhidctl. Sponsored by: iXsystems, inc. Modified: stable/8/lib/libusbhid/data.c stable/8/lib/libusbhid/parse.c stable/8/lib/libusbhid/usbhid.3 stable/8/lib/libusbhid/usbhid.h stable/8/sys/dev/usb/input/uhid.c stable/8/usr.bin/usbhidaction/usbhidaction.1 stable/8/usr.bin/usbhidaction/usbhidaction.c stable/8/usr.bin/usbhidctl/usbhid.c stable/8/usr.bin/usbhidctl/usbhidctl.1 Directory Properties: stable/8/lib/libusbhid/ (props changed) stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/conf/ldscript.mips.octeon1.32 (props changed) stable/8/sys/conf/ldscript.mips.octeon1.64 (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/usr.bin/usbhidaction/ (props changed) stable/8/usr.bin/usbhidctl/ (props changed) Modified: stable/8/lib/libusbhid/data.c ============================================================================== --- stable/8/lib/libusbhid/data.c Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/lib/libusbhid/data.c Tue Jan 3 13:16:47 2012 (r229389) @@ -32,7 +32,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <assert.h> #include <stdlib.h> +#include <string.h> +#include <dev/usb/usb_ioctl.h> #include "usbhid.h" +#include "usbvar.h" int32_t hid_get_data(const void *p, const hid_item_t *h) @@ -114,3 +117,27 @@ hid_set_data(void *p, const hid_item_t * buf[offs + i] = (buf[offs + i] & (mask >> (i*8))) | ((data >> (i*8)) & 0xff); } + +int +hid_get_report(int fd, enum hid_kind k, unsigned char *data, unsigned int size) +{ + struct usb_gen_descriptor ugd; + + memset(&ugd, 0, sizeof(ugd)); + ugd.ugd_data = hid_pass_ptr(data); + ugd.ugd_maxlen = size; + ugd.ugd_report_type = k + 1; + return (ioctl(fd, USB_GET_REPORT, &ugd)); +} + +int +hid_set_report(int fd, enum hid_kind k, unsigned char *data, unsigned int size) +{ + struct usb_gen_descriptor ugd; + + memset(&ugd, 0, sizeof(ugd)); + ugd.ugd_data = hid_pass_ptr(data); + ugd.ugd_maxlen = size; + ugd.ugd_report_type = k + 1; + return (ioctl(fd, USB_SET_REPORT, &ugd)); +} Modified: stable/8/lib/libusbhid/parse.c ============================================================================== --- stable/8/lib/libusbhid/parse.c Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/lib/libusbhid/parse.c Tue Jan 3 13:16:47 2012 (r229389) @@ -43,10 +43,11 @@ __FBSDID("$FreeBSD$"); #define MAXUSAGE 100 #define MAXPUSH 4 #define MAXID 64 +#define ITEMTYPES 3 struct hid_pos_data { int32_t rid; - uint32_t pos; + uint32_t pos[ITEMTYPES]; }; struct hid_data { @@ -55,6 +56,7 @@ struct hid_data { const uint8_t *p; struct hid_item cur[MAXPUSH]; struct hid_pos_data last_pos[MAXID]; + uint32_t pos[ITEMTYPES]; int32_t usages_min[MAXUSAGE]; int32_t usages_max[MAXUSAGE]; int32_t usage_last; /* last seen usage */ @@ -92,7 +94,7 @@ hid_clear_local(hid_item_t *c) static void hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) { - uint8_t i; + uint8_t i, j; /* check for same report ID - optimise */ @@ -113,7 +115,8 @@ hid_switch_rid(struct hid_data *s, struc } if (i != MAXID) { s->last_pos[i].rid = c->report_ID; - s->last_pos[i].pos = c->pos; + for (j = 0; j < ITEMTYPES; j++) + s->last_pos[i].pos[j] = s->pos[j]; } /* store next report ID */ @@ -134,9 +137,12 @@ hid_switch_rid(struct hid_data *s, struc } if (i != MAXID) { s->last_pos[i].rid = next_rID; - c->pos = s->last_pos[i].pos; - } else - c->pos = 0; /* Out of RID entries. */ + for (j = 0; j < ITEMTYPES; j++) + s->pos[j] = s->last_pos[i].pos[j]; + } else { + for (j = 0; j < ITEMTYPES; j++) + s->pos[j] = 0; /* Out of RID entries. */ + } } /*------------------------------------------------------------------------* @@ -206,7 +212,6 @@ hid_get_item(hid_data_t s, hid_item_t *h { hid_item_t *c; unsigned int bTag, bType, bSize; - uint32_t oldpos; int32_t mask; int32_t dval; @@ -240,7 +245,8 @@ hid_get_item(hid_data_t s, hid_item_t *h */ if (s->kindset & (1 << c->kind)) { *h = *c; - c->pos += c->report_size * c->report_count; + h->pos = s->pos[c->kind]; + s->pos[c->kind] += c->report_size * c->report_count; return (1); } } @@ -406,14 +412,10 @@ hid_get_item(hid_data_t s, hid_item_t *h case 11: /* Pop */ s->pushlevel --; if (s->pushlevel < MAXPUSH) { - /* preserve position */ - oldpos = c->pos; c = &s->cur[s->pushlevel]; /* restore size and count */ s->loc_size = c->report_size; s->loc_count = c->report_count; - /* set default item location */ - c->pos = oldpos; c->report_size = 0; c->report_count = 0; } Modified: stable/8/lib/libusbhid/usbhid.3 ============================================================================== --- stable/8/lib/libusbhid/usbhid.3 Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/lib/libusbhid/usbhid.3 Tue Jan 3 13:16:47 2012 (r229389) @@ -44,7 +44,9 @@ .Nm hid_usage_in_page , .Nm hid_init , .Nm hid_get_data , -.Nm hid_set_data +.Nm hid_set_data , +.Nm hid_get_report , +.Nm hid_set_report .Nd USB HID access routines .Sh LIBRARY .Lb libusbhid @@ -84,6 +86,10 @@ .Fn hid_get_data "const void *data" "const hid_item_t *h" .Ft void .Fn hid_set_data "void *buf" "const hid_item_t *h" "int data" +.Ft int +.Fn hid_get_report "int fd" "enum hid_kind k" "unsigned char *data" "unsigned int size" +.Ft int +.Fn hid_set_report "int fd" "enum hid_kind k" "unsigned char *data" "unsigned int size" .Sh DESCRIPTION The .Nm @@ -105,6 +111,14 @@ Synchronous HID operation can be enabled If the second argument is zero synchronous HID operation is disabled. Else synchronous HID operation is enabled. The function returns a negative value on failure. +.Pp +.Fn hid_get_report +and +.Fn hid_set_report +functions allow to synchronously get and set specific report if device +supports it. +For devices with multiple report IDs, wanted ID should be provided in the +first byte of the buffer for both get and set. .Ss Descriptor Functions The report descriptor ID can be obtained by calling .Fn hid_get_report_id . Modified: stable/8/lib/libusbhid/usbhid.h ============================================================================== --- stable/8/lib/libusbhid/usbhid.h Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/lib/libusbhid/usbhid.h Tue Jan 3 13:16:47 2012 (r229389) @@ -77,6 +77,7 @@ typedef struct hid_item { #define HID_PAGE(u) (((u) >> 16) & 0xffff) #define HID_USAGE(u) ((u) & 0xffff) +#define HID_HAS_GET_SET_REPORT 1 __BEGIN_DECLS @@ -105,5 +106,9 @@ int hid_parse_usage_page(const char *nam /* Extracting/insertion of data, data.c: */ int32_t hid_get_data(const void *p, const hid_item_t *h); void hid_set_data(void *p, const hid_item_t *h, int32_t data); +int hid_get_report(int fd, enum hid_kind k, + unsigned char *data, unsigned int size); +int hid_set_report(int fd, enum hid_kind k, + unsigned char *data, unsigned int size); __END_DECLS Modified: stable/8/sys/dev/usb/input/uhid.c ============================================================================== --- stable/8/sys/dev/usb/input/uhid.c Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/sys/dev/usb/input/uhid.c Tue Jan 3 13:16:47 2012 (r229389) @@ -566,8 +566,10 @@ uhid_ioctl(struct usb_fifo *fifo, u_long default: return (EINVAL); } + if (id != 0) + copyin(ugd->ugd_data, &id, 1); error = uhid_get_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, size); + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_SET_REPORT: @@ -592,8 +594,10 @@ uhid_ioctl(struct usb_fifo *fifo, u_long default: return (EINVAL); } + if (id != 0) + copyin(ugd->ugd_data, &id, 1); error = uhid_set_report(sc, ugd->ugd_report_type, id, - NULL, ugd->ugd_data, size); + NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size)); break; case USB_GET_REPORT_ID: Modified: stable/8/usr.bin/usbhidaction/usbhidaction.1 ============================================================================== --- stable/8/usr.bin/usbhidaction/usbhidaction.1 Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/usr.bin/usbhidaction/usbhidaction.1 Tue Jan 3 13:16:47 2012 (r229389) @@ -106,8 +106,7 @@ a debounce value, and an action. There must be whitespace between the parts. .Pp The item names are similar to those used by -.Xr usbhidctl 1 , -but each part must be prefixed by its page name. +.Xr usbhidctl 1 . .Pp The value is simply a numeric value. When the item reports this value, Modified: stable/8/usr.bin/usbhidaction/usbhidaction.c ============================================================================== --- stable/8/usr.bin/usbhidaction/usbhidaction.c Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/usr.bin/usbhidaction/usbhidaction.c Tue Jan 3 13:16:47 2012 (r229389) @@ -286,12 +286,11 @@ parse_conf(const char *conf, report_desc char *p; int line; char buf[SIZE], name[SIZE], value[SIZE], debounce[SIZE], action[SIZE]; - char usbuf[SIZE], coll[SIZE]; + char usbuf[SIZE], coll[SIZE], *tmp; struct command *cmd, *cmds; struct hid_data *d; struct hid_item h; - int u, lo, hi, range; - + int inst, cinst, u, lo, hi, range, t; f = fopen(conf, "r"); if (f == NULL) @@ -323,6 +322,12 @@ parse_conf(const char *conf, report_desc ", syntax error: %s", conf, line, buf); } } + tmp = strchr(name, '#'); + if (tmp != NULL) { + *tmp = 0; + inst = atoi(tmp + 1); + } else + inst = 0; cmd = malloc(sizeof *cmd); if (cmd == NULL) @@ -367,6 +372,7 @@ parse_conf(const char *conf, report_desc } coll[0] = 0; + cinst = 0; for (d = hid_start_parse(repd, 1 << hid_input, reportid); hid_get_item(d, &h); ) { if (verbose > 2) @@ -386,24 +392,29 @@ parse_conf(const char *conf, report_desc range = 0; } for (u = lo; u <= hi; u++) { - snprintf(usbuf, sizeof usbuf, "%s:%s", - hid_usage_page(HID_PAGE(u)), - hid_usage_in_page(u)); - if (verbose > 2) - printf("usage %s\n", usbuf); - if (!strcasecmp(usbuf, name)) - goto foundhid; if (coll[0]) { snprintf(usbuf, sizeof usbuf, "%s.%s:%s", coll+1, - hid_usage_page(HID_PAGE(u)), + hid_usage_page(HID_PAGE(u)), + hid_usage_in_page(u)); + } else { + snprintf(usbuf, sizeof usbuf, + "%s:%s", + hid_usage_page(HID_PAGE(u)), hid_usage_in_page(u)); - if (verbose > 2) - printf("usage %s\n", - usbuf); - if (!strcasecmp(usbuf, name)) - goto foundhid; } + if (verbose > 2) + printf("usage %s\n", usbuf); + t = strlen(usbuf) - strlen(name); + if (t > 0) { + if (strcmp(usbuf + t, name)) + continue; + if (usbuf[t - 1] != '.') + continue; + } else if (strcmp(usbuf, name)) + continue; + if (inst == cinst++) + goto foundhid; } break; case hid_collection: Modified: stable/8/usr.bin/usbhidctl/usbhid.c ============================================================================== --- stable/8/usr.bin/usbhidctl/usbhid.c Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/usr.bin/usbhidctl/usbhid.c Tue Jan 3 13:16:47 2012 (r229389) @@ -49,45 +49,141 @@ #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; + char colls[1000]; + char hname[1000], *tmp1, *tmp2; + struct variable *var, **pnext; + int i, instance, cp, t; + + pnext = &vars; + if (all) { + if (wflag) + errx(1, "Must not specify -w to read variables"); + cp = 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) { + cp += sprintf(&colls[cp], "%s%s:%s", + cp != 0 ? "." : "", + hid_usage_page(HID_PAGE(h.usage)), + hid_usage_in_page(h.usage)); + } else if (h.kind == hid_endcollection) { + tmp1 = strrchr(colls, '.'); + if (tmp1 != NULL) { + cp -= strlen(tmp1); + tmp1[0] = 0; + } else { + cp = 0; + colls[0] = 0; + } + } + 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", + colls, colls[0] != 0 ? "." : "", + 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; + cp = 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) { + cp += sprintf(&colls[cp], "%s%s:%s", + cp != 0 ? "." : "", + hid_usage_page(HID_PAGE(h.usage)), + hid_usage_in_page(h.usage)); + } else if (h.kind == hid_endcollection) { + tmp1 = strrchr(colls, '.'); + if (tmp1 != NULL) { + cp -= strlen(tmp1); + tmp1[0] = 0; + } else { + cp = 0; + colls[0] = 0; + } + } + if ((h.kind != hid_input && h.kind != hid_output && + h.kind != hid_feature) || (h.flags & HIO_CONST)) + continue; + snprintf(hname, sizeof(hname), "%s%s%s:%s", + colls, colls[0] != 0 ? "." : "", + hid_usage_page(HID_PAGE(h.usage)), + hid_usage_in_page(h.usage)); + t = strlen(hname) - strlen(var->name); + if (t > 0) { + if (strcmp(hname + t, var->name) != 0) + continue; + if (hname[t - 1] != '.') + continue; + } else 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 item '%s'", var->name); + } } -void +static void usage(void) { @@ -99,10 +195,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) @@ -141,7 +241,7 @@ hid_collection_type(int32_t type) return (num); } -void +static void dumpitems(report_desc_t r) { struct hid_data *d; @@ -181,23 +281,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; @@ -219,82 +303,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; - - 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)) + enum hid_kind kind; + + 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; - 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); + if (var->h.report_ID != 0 && + dbuf[0] != var->h.report_ID) + continue; + 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++; @@ -317,9 +481,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(); @@ -327,12 +497,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] != '/') { @@ -357,8 +525,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: stable/8/usr.bin/usbhidctl/usbhidctl.1 ============================================================================== --- stable/8/usr.bin/usbhidctl/usbhidctl.1 Tue Jan 3 13:13:31 2012 (r229388) +++ stable/8/usr.bin/usbhidctl/usbhidctl.1 Tue Jan 3 13:16:47 2012 (r229389) @@ -35,7 +35,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 @@ -43,27 +43,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 @@ -76,9 +100,47 @@ 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 SYNTAX +.Nm +compares the names of items specified on the command line against the human +interface items reported by the USB device. +Each human interface item is mapped from its native form to a human readable +name, using the HID usage table file. +Command line items are compared with the generated item names, +and the USB HID device is operated on when a match is found. +.Pp +Each human interface item is named by the +.Qq page +it appears in, the +.Qq usage +within that page, and the list of +.Qq collections +containing the item. +Each collection in turn is also identified by page, and +the usage within that page. +.Pp +On the +.Nm +command line the page name is separated from the usage name with the character +.Sq Cm \&: . +The collections are separated by the character +.Sq Cm \&. . +.Pp +Some devices give the same name to more than one item. +.Nm +supports isolating each item by appending a +.Sq Cm \&# . +character and a decimal item instance number, starting at zero. .Sh FILES .Pa /usr/share/misc/usb_hid_usages The default HID usage table. @@ -91,7 +153,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?201201031316.q03DGl0D025473>