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");
                        }
                }
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to