Author: mav
Date: Tue Jan  3 12:47:55 2012
New Revision: 229387
URL: http://svn.freebsd.org/changeset/base/229387

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/9/lib/libusbhid/data.c
  stable/9/lib/libusbhid/parse.c
  stable/9/lib/libusbhid/usbhid.3
  stable/9/lib/libusbhid/usbhid.h
  stable/9/sys/dev/usb/input/uhid.c
  stable/9/usr.bin/usbhidaction/usbhidaction.1
  stable/9/usr.bin/usbhidaction/usbhidaction.c
  stable/9/usr.bin/usbhidctl/usbhid.c
  stable/9/usr.bin/usbhidctl/usbhidctl.1
Directory Properties:
  stable/9/lib/libusbhid/   (props changed)
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/usr.bin/usbhidaction/   (props changed)
  stable/9/usr.bin/usbhidctl/   (props changed)

Modified: stable/9/lib/libusbhid/data.c
==============================================================================
--- stable/9/lib/libusbhid/data.c       Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/lib/libusbhid/data.c       Tue Jan  3 12:47:55 2012        
(r229387)
@@ -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/9/lib/libusbhid/parse.c
==============================================================================
--- stable/9/lib/libusbhid/parse.c      Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/lib/libusbhid/parse.c      Tue Jan  3 12:47:55 2012        
(r229387)
@@ -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/9/lib/libusbhid/usbhid.3
==============================================================================
--- stable/9/lib/libusbhid/usbhid.3     Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/lib/libusbhid/usbhid.3     Tue Jan  3 12:47:55 2012        
(r229387)
@@ -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/9/lib/libusbhid/usbhid.h
==============================================================================
--- stable/9/lib/libusbhid/usbhid.h     Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/lib/libusbhid/usbhid.h     Tue Jan  3 12:47:55 2012        
(r229387)
@@ -76,6 +76,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
 
@@ -104,5 +105,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/9/sys/dev/usb/input/uhid.c
==============================================================================
--- stable/9/sys/dev/usb/input/uhid.c   Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/sys/dev/usb/input/uhid.c   Tue Jan  3 12:47:55 2012        
(r229387)
@@ -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/9/usr.bin/usbhidaction/usbhidaction.1
==============================================================================
--- stable/9/usr.bin/usbhidaction/usbhidaction.1        Tue Jan  3 11:13:07 
2012        (r229386)
+++ stable/9/usr.bin/usbhidaction/usbhidaction.1        Tue Jan  3 12:47:55 
2012        (r229387)
@@ -99,8 +99,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/9/usr.bin/usbhidaction/usbhidaction.c
==============================================================================
--- stable/9/usr.bin/usbhidaction/usbhidaction.c        Tue Jan  3 11:13:07 
2012        (r229386)
+++ stable/9/usr.bin/usbhidaction/usbhidaction.c        Tue Jan  3 12:47:55 
2012        (r229387)
@@ -280,12 +280,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)
@@ -317,6 +316,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)
@@ -361,6 +366,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)
@@ -380,24 +386,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/9/usr.bin/usbhidctl/usbhid.c
==============================================================================
--- stable/9/usr.bin/usbhidctl/usbhid.c Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/usr.bin/usbhidctl/usbhid.c Tue Jan  3 12:47:55 2012        
(r229387)
@@ -42,45 +42,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)
 {
 
@@ -92,10 +188,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 +234,7 @@ hid_collection_type(int32_t type)
        return (num);
 }
 
-void
+static void
 dumpitems(report_desc_t r)
 {
        struct hid_data *d;
@@ -174,23 +274,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 +296,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++;
@@ -310,9 +474,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 +490,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 +518,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/9/usr.bin/usbhidctl/usbhidctl.1
==============================================================================
--- stable/9/usr.bin/usbhidctl/usbhidctl.1      Tue Jan  3 11:13:07 2012        
(r229386)
+++ stable/9/usr.bin/usbhidctl/usbhidctl.1      Tue Jan  3 12:47:55 2012        
(r229387)
@@ -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,9 +93,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.
@@ -84,7 +146,3 @@ The
 .Nm
 command appeared in
 .Nx 1.4 .
-.Sh BUGS
-The
-.Nm
-utility cannot show nor set output and feature items.
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to