Author: kaiw
Date: Sat Mar 27 08:00:16 2010
New Revision: 205728
URL: http://svn.freebsd.org/changeset/base/205728

Log:
  Merge improvements from kernel HID parser to the userland usbhid(3)
  parser.  This merge does not change any API and should not break any
  native or thirdparty applications.
  
  Changes include:
  
  * Merge multiple report ID support and other improvements from kernel
    HID parser.
  * Ignore rid argument in hid_start_parser, parse all the report items since
    we now support multiple report ID.
  * Skip report ID byte in hid_get_data() and set report ID byte in
    hid_set_data(), if report ID is non-zero.
  * Reimplement hid_get_report_id: instead get report id from uhid device
    (which is always 0), try parsing the report descriptor and return the
    first report ID encountered.
  
  Reviewed by:  hps
  Silent on:    -usb mailing list

Modified:
  head/lib/libusbhid/data.c
  head/lib/libusbhid/descr.c
  head/lib/libusbhid/parse.c
  head/lib/libusbhid/usage.c
  head/lib/libusbhid/usbhid.h
  head/lib/libusbhid/usbvar.h

Modified: head/lib/libusbhid/data.c
==============================================================================
--- head/lib/libusbhid/data.c   Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/data.c   Sat Mar 27 08:00:16 2010        (r205728)
@@ -29,6 +29,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
 #include <assert.h>
 #include <stdlib.h>
 #include "usbhid.h"
@@ -36,18 +37,27 @@ __FBSDID("$FreeBSD$");
 int
 hid_get_data(const void *p, const hid_item_t *h)
 {
-       const unsigned char *buf;
-       unsigned int hpos;
-       unsigned int hsize;
-       int data;
+       const uint8_t *buf;
+       uint32_t hpos;
+       uint32_t hsize;
+       uint32_t data;
        int i, end, offs;
 
        buf = p;
+
+       /* Skip report ID byte. */
+       if (h->report_ID > 0)
+               buf++;
+
        hpos = h->pos;                  /* bit position of data */
        hsize = h->report_size;         /* bit length of data */
 
+       /* Range check and limit */
        if (hsize == 0)
                return (0);
+       if (hsize > 32)
+               hsize = 32;
+
        offs = hpos / 8;
        end = (hpos + hsize) / 8 - offs;
        data = 0;
@@ -66,12 +76,17 @@ hid_get_data(const void *p, const hid_it
 void
 hid_set_data(void *p, const hid_item_t *h, int data)
 {
-       unsigned char *buf;
-       unsigned int hpos;
-       unsigned int hsize;
+       uint8_t *buf;
+       uint32_t hpos;
+       uint32_t hsize;
        int i, end, offs, mask;
 
        buf = p;
+
+       /* Set report ID byte. */
+       if (h->report_ID > 0)
+               *buf++ = h->report_ID & 0xff;
+
        hpos = h->pos;                  /* bit position of data */
        hsize = h->report_size;         /* bit length of data */
 
@@ -90,5 +105,5 @@ hid_set_data(void *p, const hid_item_t *
 
        for (i = 0; i <= end; i++)
                buf[offs + i] = (buf[offs + i] & (mask >> (i*8))) |
-                       ((data >> (i*8)) & 0xff);
+                   ((data >> (i*8)) & 0xff);
 }

Modified: head/lib/libusbhid/descr.c
==============================================================================
--- head/lib/libusbhid/descr.c  Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/descr.c  Sat Mar 27 08:00:16 2010        (r205728)
@@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
-
 #include <dev/usb/usb_ioctl.h>
 
 #include "usbhid.h"
@@ -59,9 +58,30 @@ hid_set_immed(int fd, int enable)
 int
 hid_get_report_id(int fd)
 {
+       report_desc_t rep;
+       hid_data_t d;
+       hid_item_t h;
+       int kindset;
        int temp = -1;
        int ret;
 
+       if ((rep = hid_get_report_desc(fd)) == NULL)
+               goto use_ioctl;
+       kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature;
+       for (d = hid_start_parse(rep, kindset, 0); hid_get_item(d, &h); ) {
+               /* Return the first report ID we met. */
+               if (h.report_ID != 0) {
+                       temp = h.report_ID;
+                       break;
+               }
+       }
+       hid_end_parse(d);
+       hid_dispose_report_desc(rep);
+
+       if (temp > 0)
+               return (temp);
+
+use_ioctl:
        ret = ioctl(fd, USB_GET_REPORT_ID, &temp);
 #ifdef HID_COMPAT7
        if (ret < 0)

Modified: head/lib/libusbhid/parse.c
==============================================================================
--- head/lib/libusbhid/parse.c  Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/parse.c  Sat Mar 27 08:00:16 2010        (r205728)
@@ -40,42 +40,43 @@ __FBSDID("$FreeBSD$");
 #include "usbhid.h"
 #include "usbvar.h"
 
-#define MAXUSAGE 100
-struct hid_data {
-       u_char *start;
-       u_char *end;
-       u_char *p;
-       hid_item_t cur;
-       unsigned int usages[MAXUSAGE];
-       int nusage;
-       int minset;
-       int logminsize;
-       int multi;
-       int multimax;
-       int kindset;
-       int reportid;
-
-       /*
-        * The start of collection item has no report ID set, so save
-        * it until we know the ID.
-        */
-       hid_item_t savedcoll;
-       u_char hassavedcoll;
-       /*
-        * Absolute data position (bits) for input/output/feature.
-        *  Assumes that hid_input, hid_output and hid_feature have
-        *  values 0, 1 and 2.
-        */
-       unsigned int kindpos[3];
+#define        MAXUSAGE 100
+#define        MAXPUSH 4
+#define        MAXID 64
+
+struct hid_pos_data {
+       int32_t rid;
+       uint32_t pos;
 };
 
-static int min(int x, int y) { return x < y ? x : y; }
-
-static int hid_get_item_raw(hid_data_t s, hid_item_t *h);
+struct hid_data {
+       const uint8_t *start;
+       const uint8_t *end;
+       const uint8_t *p;
+       struct hid_item cur[MAXPUSH];
+       struct hid_pos_data last_pos[MAXID];
+       int32_t usages_min[MAXUSAGE];
+       int32_t usages_max[MAXUSAGE];
+       int32_t usage_last;     /* last seen usage */
+       uint32_t loc_size;      /* last seen size */
+       uint32_t loc_count;     /* last seen count */
+       uint8_t kindset;        /* we have 5 kinds so 8 bits are enough */
+       uint8_t pushlevel;      /* current pushlevel */
+       uint8_t ncount;         /* end usage item count */
+       uint8_t icount;         /* current usage item count */
+       uint8_t nusage;         /* end "usages_min/max" index */
+       uint8_t iusage;         /* current "usages_min/max" index */
+       uint8_t ousage;         /* current "usages_min/max" offset */
+       uint8_t susage;         /* usage set flags */
+};
 
+/*------------------------------------------------------------------------*
+ *     hid_clear_local
+ *------------------------------------------------------------------------*/
 static void
 hid_clear_local(hid_item_t *c)
 {
+
        c->usage = 0;
        c->usage_minimum = 0;
        c->usage_maximum = 0;
@@ -88,8 +89,61 @@ hid_clear_local(hid_item_t *c)
        c->set_delimiter = 0;
 }
 
+static void
+hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
+{
+       uint8_t i;
+
+       /* check for same report ID - optimise */
+
+       if (c->report_ID == next_rID)
+               return;
+
+       /* save current position for current rID */
+
+       if (c->report_ID == 0) {
+               i = 0;
+       } else {
+               for (i = 1; i != MAXID; i++) {
+                       if (s->last_pos[i].rid == c->report_ID)
+                               break;
+                       if (s->last_pos[i].rid == 0)
+                               break;
+               }
+       }
+       if (i != MAXID) {
+               s->last_pos[i].rid = c->report_ID;
+               s->last_pos[i].pos = c->pos;
+       }
+
+       /* store next report ID */
+
+       c->report_ID = next_rID;
+
+       /* lookup last position for next rID */
+
+       if (next_rID == 0) {
+               i = 0;
+       } else {
+               for (i = 1; i != MAXID; i++) {
+                       if (s->last_pos[i].rid == next_rID)
+                               break;
+                       if (s->last_pos[i].rid == 0)
+                               break;
+               }
+       }
+       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. */
+}
+
+/*------------------------------------------------------------------------*
+ *     hid_start_parse
+ *------------------------------------------------------------------------*/
 hid_data_t
-hid_start_parse(report_desc_t d, int kindset, int id)
+hid_start_parse(report_desc_t d, int kindset, int id __unused)
 {
        struct hid_data *s;
 
@@ -98,213 +152,207 @@ hid_start_parse(report_desc_t d, int kin
        s->start = s->p = d->data;
        s->end = d->data + d->size;
        s->kindset = kindset;
-       s->reportid = id;
-       s->hassavedcoll = 0;
        return (s);
 }
 
+/*------------------------------------------------------------------------*
+ *     hid_end_parse
+ *------------------------------------------------------------------------*/
 void
 hid_end_parse(hid_data_t s)
 {
-       while (s->cur.next) {
-               hid_item_t *hi = s->cur.next->next;
-               free(s->cur.next);
-               s->cur.next = hi;
-       }
+
+       if (s == NULL)
+               return;
+
        free(s);
 }
 
-int
-hid_get_item(hid_data_t s, hid_item_t *h)
+/*------------------------------------------------------------------------*
+ *     get byte from HID descriptor
+ *------------------------------------------------------------------------*/
+static uint8_t
+hid_get_byte(struct hid_data *s, const uint16_t wSize)
 {
-       int r;
+       const uint8_t *ptr;
+       uint8_t retval;
 
-       for (;;) {
-               r = hid_get_item_raw(s, h);
-               if (r <= 0)
-                       break;
-               if (h->report_ID == s->reportid || s->reportid == -1)
-                       break;
-       }
-       return (r);
-}
+       ptr = s->p;
+
+       /* check if end is reached */
+       if (ptr == s->end)
+               return (0);
 
-#define REPORT_SAVED_COLL \
-       do { \
-               if (s->hassavedcoll) { \
-                       *h = s->savedcoll; \
-                       h->report_ID = c->report_ID; \
-                       s->hassavedcoll = 0; \
-                       return (1); \
-               } \
-       } while(/*LINTED*/ 0)
+       /* read out a byte */
+       retval = *ptr;
 
-static int
-hid_get_item_raw(hid_data_t s, hid_item_t *h)
+       /* check if data pointer can be advanced by "wSize" bytes */
+       if ((s->end - ptr) < wSize)
+               ptr = s->end;
+       else
+               ptr += wSize;
+
+       /* update pointer */
+       s->p = ptr;
+
+       return (retval);
+}
+
+/*------------------------------------------------------------------------*
+ *     hid_get_item
+ *------------------------------------------------------------------------*/
+int
+hid_get_item(hid_data_t s, hid_item_t *h)
 {
        hid_item_t *c;
-       unsigned int bTag = 0, bType = 0, bSize;
-       unsigned char *data;
-       int dval;
-       unsigned char *p;
-       hid_item_t *hi;
-       hid_item_t nc;
-       int i;
-       hid_kind_t retkind;
+       unsigned int bTag, bType, bSize;
+       uint32_t oldpos;
+       int32_t mask;
+       int32_t dval;
 
-       c = &s->cur;
+       if (s == NULL)
+               return (0);
+
+       c = &s->cur[s->pushlevel];
 
  top:
-       if (s->multimax) {
-               REPORT_SAVED_COLL;
-               if (c->logical_minimum >= c->logical_maximum) {
-                       if (s->logminsize == 1)
-                               c->logical_minimum =(int8_t)c->logical_minimum;
-                       else if (s->logminsize == 2)
-                               c->logical_minimum =(int16_t)c->logical_minimum;
+       /* check if there is an array of items */
+       if (s->icount < s->ncount) {
+               /* get current usage */
+               if (s->iusage < s->nusage) {
+                       dval = s->usages_min[s->iusage] + s->ousage;
+                       c->usage = dval;
+                       s->usage_last = dval;
+                       if (dval == s->usages_max[s->iusage]) {
+                               s->iusage ++;
+                               s->ousage = 0;
+                       } else {
+                               s->ousage ++;
+                       }
+               } else {
+                       /* Using last usage */
+                       dval = s->usage_last;
                }
-               if (s->multi < s->multimax) {
-                       c->usage = s->usages[min(s->multi, s->nusage-1)];
-                       s->multi++;
+               s->icount ++;
+               /* 
+                * Only copy HID item, increment position and return
+                * if correct kindset!
+                */
+               if (s->kindset & (1 << c->kind)) {
                        *h = *c;
-                       /*
-                        * 'multimax' is only non-zero if the current
-                         *  item kind is input/output/feature
-                        */
-                       h->pos = s->kindpos[c->kind];
-                       s->kindpos[c->kind] += c->report_size;
-                       h->next = 0;
+                       c->pos += c->report_size * c->report_count;
                        return (1);
-               } else {
-                       c->report_count = s->multimax;
-                       s->multimax = 0;
-                       s->nusage = 0;
-                       hid_clear_local(c);
                }
        }
-       for (;;) {
-               p = s->p;
-               if (p >= s->end)
-                       return (0);
 
-               bSize = *p++;
+       /* reset state variables */
+       s->icount = 0;
+       s->ncount = 0;
+       s->iusage = 0;
+       s->nusage = 0;
+       s->susage = 0;
+       s->ousage = 0;
+       hid_clear_local(c);
+
+       /* get next item */
+       while (s->p != s->end) {
+
+               bSize = hid_get_byte(s, 1);
                if (bSize == 0xfe) {
                        /* long item */
-                       bSize = *p++;
-                       bSize |= *p++ << 8;
-                       bTag = *p++;
-                       data = p;
-                       p += bSize;
+                       bSize = hid_get_byte(s, 1);
+                       bSize |= hid_get_byte(s, 1) << 8;
+                       bTag = hid_get_byte(s, 1);
+                       bType = 0xff;   /* XXX what should it be */
                } else {
                        /* short item */
                        bTag = bSize >> 4;
                        bType = (bSize >> 2) & 3;
                        bSize &= 3;
-                       if (bSize == 3) bSize = 4;
-                       data = p;
-                       p += bSize;
+                       if (bSize == 3)
+                               bSize = 4;
                }
-               s->p = p;
-               /*
-                * The spec is unclear if the data is signed or unsigned.
-                */
+
                switch(bSize) {
                case 0:
                        dval = 0;
+                       mask = 0;
                        break;
                case 1:
-                       dval = *data++;
+                       dval = (int8_t)hid_get_byte(s, 1);
+                       mask = 0xFF;
                        break;
                case 2:
-                       dval = *data++;
-                       dval |= *data++ << 8;
+                       dval = hid_get_byte(s, 1);
+                       dval |= hid_get_byte(s, 1) << 8;
+                       dval = (int16_t)dval;
+                       mask = 0xFFFF;
                        break;
                case 4:
-                       dval = *data++;
-                       dval |= *data++ << 8;
-                       dval |= *data++ << 16;
-                       dval |= *data++ << 24;
+                       dval = hid_get_byte(s, 1);
+                       dval |= hid_get_byte(s, 1) << 8;
+                       dval |= hid_get_byte(s, 1) << 16;
+                       dval |= hid_get_byte(s, 1) << 24;
+                       mask = 0xFFFFFFFF;
                        break;
                default:
-                       return (-1);
+                       dval = hid_get_byte(s, bSize);
+                       continue;
                }
 
                switch (bType) {
-               case 0:                 /* Main */
+               case 0:         /* Main */
                        switch (bTag) {
-                       case 8:         /* Input */
-                               retkind = hid_input;
-                       ret:
-                               if (!(s->kindset & (1 << retkind))) {
-                                       /* Drop the items of this kind */
-                                       s->nusage = 0;
-                                       continue;
-                               }
-                               c->kind = retkind;
+                       case 8: /* Input */
+                               c->kind = hid_input;
                                c->flags = dval;
+               ret:
+                               c->report_count = s->loc_count;
+                               c->report_size = s->loc_size;
+
                                if (c->flags & HIO_VARIABLE) {
-                                       s->multimax = c->report_count;
-                                       s->multi = 0;
+                                       /* range check usage count */
+                                       if (c->report_count > 255) {
+                                               s->ncount = 255;
+                                       } else
+                                               s->ncount = c->report_count;
+
+                                       /* 
+                                        * The "top" loop will return
+                                        * one and one item:
+                                        */
                                        c->report_count = 1;
-                                       if (s->minset) {
-                                               for (i = c->usage_minimum;
-                                                    i <= c->usage_maximum;
-                                                    i++) {
-                                                       s->usages[s->nusage] = 
i;
-                                                       if (s->nusage < 
MAXUSAGE-1)
-                                                               s->nusage++;
-                                               }
-                                               c->usage_minimum = 0;
-                                               c->usage_maximum = 0;
-                                               s->minset = 0;
-                                       }
-                                       goto top;
                                } else {
-                                       if (s->minset)
-                                               c->usage = c->usage_minimum;
-                                       *h = *c;
-                                       h->next = 0;
-                                       h->pos = s->kindpos[c->kind];
-                                       s->kindpos[c->kind] +=
-                                           c->report_size * c->report_count;
-                                       hid_clear_local(c);
-                                       s->minset = 0;
-                                       return (1);
+                                       s->ncount = 1;
                                }
-                       case 9:         /* Output */
-                               retkind = hid_output;
+                               goto top;
+
+                       case 9: /* Output */
+                               c->kind = hid_output;
+                               c->flags = dval;
                                goto ret;
                        case 10:        /* Collection */
                                c->kind = hid_collection;
                                c->collection = dval;
                                c->collevel++;
-                               nc = *c;
-                               hid_clear_local(c);
-                               /*c->report_ID = NO_REPORT_ID;*/
-                               s->nusage = 0;
-                               if (s->hassavedcoll) {
-                                       *h = s->savedcoll;
-                                       h->report_ID = nc.report_ID;
-                                       s->savedcoll = nc;
-                                       return (1);
-                               } else {
-                                       s->hassavedcoll = 1;
-                                       s->savedcoll = nc;
-                               }
-                               break;
+                               c->usage = s->usage_last;
+                               *h = *c;
+                               return (1);
                        case 11:        /* Feature */
-                               retkind = hid_feature;
+                               c->kind = hid_feature;
+                               c->flags = dval;
                                goto ret;
                        case 12:        /* End collection */
-                               REPORT_SAVED_COLL;
                                c->kind = hid_endcollection;
+                               if (c->collevel == 0) {
+                                       /* Invalid end collection. */
+                                       return (0);
+                               }
                                c->collevel--;
                                *h = *c;
-                               /*hid_clear_local(c);*/
-                               s->nusage = 0;
                                return (1);
                        default:
-                               return (-2);
+                               break;
                        }
                        break;
 
@@ -315,13 +363,12 @@ hid_get_item_raw(hid_data_t s, hid_item_
                                break;
                        case 1:
                                c->logical_minimum = dval;
-                               s->logminsize = bSize;
                                break;
                        case 2:
                                c->logical_maximum = dval;
                                break;
                        case 3:
-                               c->physical_maximum = dval;
+                               c->physical_minimum = dval;
                                break;
                        case 4:
                                c->physical_maximum = dval;
@@ -333,45 +380,97 @@ hid_get_item_raw(hid_data_t s, hid_item_
                                c->unit = dval;
                                break;
                        case 7:
-                               c->report_size = dval;
+                               /* mask because value is unsigned */
+                               s->loc_size = dval & mask;
                                break;
                        case 8:
-                               c->report_ID = dval;
-                               s->kindpos[hid_input] =
-                                   s->kindpos[hid_output] =
-                                   s->kindpos[hid_feature] = 0;
+                               hid_switch_rid(s, c, dval);
                                break;
                        case 9:
-                               c->report_count = dval;
+                               /* mask because value is unsigned */
+                               s->loc_count = dval & mask;
                                break;
-                       case 10: /* Push */
-                               hi = malloc(sizeof *hi);
-                               *hi = s->cur;
-                               c->next = hi;
-                               break;
-                       case 11: /* Pop */
-                               hi = c->next;
-                               s->cur = *hi;
-                               free(hi);
+                       case 10:        /* Push */
+                               s->pushlevel ++;
+                               if (s->pushlevel < MAXPUSH) {
+                                       s->cur[s->pushlevel] = *c;
+                                       /* store size and count */
+                                       c->report_size = s->loc_size;
+                                       c->report_count = s->loc_count;
+                                       /* update current item pointer */
+                                       c = &s->cur[s->pushlevel];
+                               }
+                               break;
+                       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;
+                               }
                                break;
                        default:
-                               return (-3);
+                               break;
                        }
                        break;
                case 2:         /* Local */
                        switch (bTag) {
                        case 0:
-                               c->usage = c->_usage_page | dval;
-                               if (s->nusage < MAXUSAGE)
-                                       s->usages[s->nusage++] = c->usage;
+                               if (bSize != 4)
+                                       dval = (dval & mask) | c->_usage_page;
+
+                               /* set last usage, in case of a collection */
+                               s->usage_last = dval;
+
+                               if (s->nusage < MAXUSAGE) {
+                                       s->usages_min[s->nusage] = dval;
+                                       s->usages_max[s->nusage] = dval;
+                                       s->nusage ++;
+                               }
                                /* else XXX */
+
+                               /* clear any pending usage sets */
+                               s->susage = 0;
                                break;
                        case 1:
-                               s->minset = 1;
-                               c->usage_minimum = c->_usage_page | dval;
-                               break;
+                               s->susage |= 1;
+
+                               if (bSize != 4)
+                                       dval = (dval & mask) | c->_usage_page;
+                               c->usage_minimum = dval;
+
+                               goto check_set;
                        case 2:
-                               c->usage_maximum = c->_usage_page | dval;
+                               s->susage |= 2;
+
+                               if (bSize != 4)
+                                       dval = (dval & mask) | c->_usage_page;
+                               c->usage_maximum = dval;
+
+                       check_set:
+                               if (s->susage != 3)
+                                       break;
+
+                               /* sanity check */
+                               if ((s->nusage < MAXUSAGE) &&
+                                   (c->usage_minimum <= c->usage_maximum)) {
+                                       /* add usage range */
+                                       s->usages_min[s->nusage] = 
+                                           c->usage_minimum;
+                                       s->usages_max[s->nusage] = 
+                                           c->usage_maximum;
+                                       s->nusage ++;
+                               }
+                               /* else XXX */
+
+                               s->susage = 0;
                                break;
                        case 3:
                                c->designator_index = dval;
@@ -395,40 +494,63 @@ hid_get_item_raw(hid_data_t s, hid_item_
                                c->set_delimiter = dval;
                                break;
                        default:
-                               return (-4);
+                               break;
                        }
                        break;
                default:
-                       return (-5);
+                       break;
                }
        }
+       return (0);
 }
 
 int
 hid_report_size(report_desc_t r, enum hid_kind k, int id)
 {
        struct hid_data *d;
-       hid_item_t h;
-       int size;
+       struct hid_item h;
+       uint32_t temp;
+       uint32_t hpos;
+       uint32_t lpos;
+
+       hpos = 0;
+       lpos = 0xFFFFFFFF;
 
        memset(&h, 0, sizeof h);
-       size = 0;
-       for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) {
+       for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) {
                if (h.report_ID == id && h.kind == k) {
-                       size = d->kindpos[k];
+                       /* compute minimum */
+                       if (lpos > h.pos)
+                               lpos = h.pos;
+                       /* compute end position */
+                       temp = h.pos + (h.report_size * h.report_count);
+                       /* compute maximum */
+                       if (hpos < temp)
+                               hpos = temp;
                }
        }
        hid_end_parse(d);
-       return ((size + 7) / 8);
+
+       /* safety check - can happen in case of currupt descriptors */
+       if (lpos > hpos)
+               temp = 0;
+       else
+               temp = hpos - lpos;
+
+       if (id)
+               temp += 8;
+
+       /* return length in bytes rounded up */
+       return ((temp + 7) / 8);
 }
 
 int
 hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
           hid_item_t *h, int id)
 {
-       hid_data_t d;
+       struct hid_data *d;
 
-       for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) {
+       for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) {
                if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
                        hid_end_parse(d);
                        return (1);

Modified: head/lib/libusbhid/usage.c
==============================================================================
--- head/lib/libusbhid/usage.c  Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/usage.c  Sat Mar 27 08:00:16 2010        (r205728)
@@ -29,6 +29,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
 #include <assert.h>
 #include <ctype.h>
 #include <err.h>

Modified: head/lib/libusbhid/usbhid.h
==============================================================================
--- head/lib/libusbhid/usbhid.h Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/usbhid.h Sat Mar 27 08:00:16 2010        (r205728)
@@ -29,52 +29,48 @@
  *
  */
 
-#include <sys/cdefs.h>
+#include <sys/types.h>
 
 typedef struct report_desc *report_desc_t;
 
 typedef struct hid_data *hid_data_t;
 
 typedef enum hid_kind {
-       hid_input = 0,
-       hid_output = 1,
-       hid_feature = 2,
-       hid_collection,
-       hid_endcollection
+       hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
 } hid_kind_t;
 
 typedef struct hid_item {
        /* Global */
-       unsigned int _usage_page;
-       int logical_minimum;
-       int logical_maximum;
-       int physical_minimum;
-       int physical_maximum;
-       int unit_exponent;
-       int unit;
-       int report_size;
-       int report_ID;
+       uint32_t _usage_page;
+       int32_t logical_minimum;
+       int32_t logical_maximum;
+       int32_t physical_minimum;
+       int32_t physical_maximum;
+       int32_t unit_exponent;
+       int32_t unit;
+       int32_t report_size;
+       int32_t report_ID;
 #define NO_REPORT_ID 0
-       int report_count;
+       int32_t report_count;
        /* Local */
-       unsigned int usage;
-       int usage_minimum;
-       int usage_maximum;
-       int designator_index;
-       int designator_minimum;
-       int designator_maximum;
-       int string_index;
-       int string_minimum;
-       int string_maximum;
-       int set_delimiter;
+       uint32_t usage;
+       int32_t usage_minimum;
+       int32_t usage_maximum;
+       int32_t designator_index;
+       int32_t designator_minimum;
+       int32_t designator_maximum;
+       int32_t string_index;
+       int32_t string_minimum;
+       int32_t string_maximum;
+       int32_t set_delimiter;
        /* Misc */
-       int collection;
-       int collevel;
+       int32_t collection;
+       int     collevel;
        enum hid_kind kind;
-       unsigned int flags;
-       /* Absolute data position (bits) */
-       unsigned int pos;
-       /* */
+       uint32_t flags;
+       /* Location */
+       uint32_t pos;
+       /* unused */
        struct hid_item *next;
 } hid_item_t;
 
@@ -95,7 +91,8 @@ hid_data_t hid_start_parse(report_desc_t
 void hid_end_parse(hid_data_t s);
 int hid_get_item(hid_data_t s, hid_item_t *h);
 int hid_report_size(report_desc_t d, enum hid_kind k, int id);
-int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k, 
hid_item_t *h, int id);
+int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k,
+    hid_item_t *h, int id);
 
 /* Conversion to/from usage names, usage.c: */
 const char *hid_usage_page(int i);

Modified: head/lib/libusbhid/usbvar.h
==============================================================================
--- head/lib/libusbhid/usbvar.h Sat Mar 27 06:53:11 2010        (r205727)
+++ head/lib/libusbhid/usbvar.h Sat Mar 27 08:00:16 2010        (r205728)
@@ -30,8 +30,8 @@
  */
 
 struct report_desc {
-       unsigned int size;
-       unsigned char data[1];
+       uint32_t size;
+       uint8_t data[1];
 };
 
 /* internal backwards compatibility functions */
_______________________________________________
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