Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 May 2010 10:32:20 +0000 (UTC)
From:      Kai Wang <kaiw@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: r208262 - in stable/8: lib/libusbhid usr.sbin/bluetooth/bthidd
Message-ID:  <201005181032.o4IAWK50019971@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kaiw
Date: Tue May 18 10:32:20 2010
New Revision: 208262
URL: http://svn.freebsd.org/changeset/base/208262

Log:
  MFC r205728
  
    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.
  
  MFC r207812
  
    hid_get_data() now expects that the hid data passed in always contains
    the report ID byte. Thus we should not skip the the report ID byte in
    hid_interrupt().  Also, if HUP_KEYBOARD usage is an array, do not try
    to modify the 'data' pointer, instead, increase the hid_item_t field
    'pos' by 'report_size' before calling hid_get_data() during each
    iteration.

Modified:
  stable/8/lib/libusbhid/data.c
  stable/8/lib/libusbhid/descr.c
  stable/8/lib/libusbhid/parse.c
  stable/8/lib/libusbhid/usage.c
  stable/8/lib/libusbhid/usbhid.h
  stable/8/lib/libusbhid/usbvar.h
  stable/8/usr.sbin/bluetooth/bthidd/hid.c
Directory Properties:
  stable/8/lib/libusbhid/   (props changed)
  stable/8/usr.sbin/bluetooth/   (props changed)

Modified: stable/8/lib/libusbhid/data.c
==============================================================================
--- stable/8/lib/libusbhid/data.c	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/data.c	Tue May 18 10:32:20 2010	(r208262)
@@ -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$");
 int32_t
 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;
@@ -70,15 +80,20 @@ hid_get_data(const void *p, const hid_it
 void
 hid_set_data(void *p, const hid_item_t *h, int32_t data)
 {
-	unsigned char *buf;
-	unsigned int hpos;
-	unsigned int hsize;
+	uint8_t *buf;
+	uint32_t hpos;
+	uint32_t hsize;
 	uint32_t mask;
 	int i;
 	int end;
 	int offs;
 
 	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 */
 
@@ -97,5 +112,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: stable/8/lib/libusbhid/descr.c
==============================================================================
--- stable/8/lib/libusbhid/descr.c	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/descr.c	Tue May 18 10:32:20 2010	(r208262)
@@ -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: stable/8/lib/libusbhid/parse.c
==============================================================================
--- stable/8/lib/libusbhid/parse.c	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/parse.c	Tue May 18 10:32:20 2010	(r208262)
@@ -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: stable/8/lib/libusbhid/usage.c
==============================================================================
--- stable/8/lib/libusbhid/usage.c	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/usage.c	Tue May 18 10:32:20 2010	(r208262)
@@ -29,6 +29,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
 #include <assert.h>
 #include <ctype.h>
 #include <err.h>

Modified: stable/8/lib/libusbhid/usbhid.h
==============================================================================
--- stable/8/lib/libusbhid/usbhid.h	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/usbhid.h	Tue May 18 10:32:20 2010	(r208262)
@@ -29,7 +29,7 @@
  *
  */
 
-#include <sys/cdefs.h>
+#include <sys/types.h>
 #include <sys/types.h>
 
 typedef struct report_desc *report_desc_t;
@@ -37,45 +37,41 @@ typedef struct report_desc *report_desc_
 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;
 
@@ -96,7 +92,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: stable/8/lib/libusbhid/usbvar.h
==============================================================================
--- stable/8/lib/libusbhid/usbvar.h	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/lib/libusbhid/usbvar.h	Tue May 18 10:32:20 2010	(r208262)
@@ -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 */

Modified: stable/8/usr.sbin/bluetooth/bthidd/hid.c
==============================================================================
--- stable/8/usr.sbin/bluetooth/bthidd/hid.c	Tue May 18 10:24:23 2010	(r208261)
+++ stable/8/usr.sbin/bluetooth/bthidd/hid.c	Tue May 18 10:32:20 2010	(r208262)
@@ -130,7 +130,7 @@ hid_interrupt(bthid_session_p s, uint8_t
 	hid_item_t	h;
 	int32_t		report_id, usage, page, val,
 			mouse_x, mouse_y, mouse_z, mouse_butt,
-			mevents, kevents;
+			mevents, kevents, i;
 
 	assert(s != NULL);
 	assert(s->srv != NULL);
@@ -150,8 +150,8 @@ hid_interrupt(bthid_session_p s, uint8_t
 	}
 
 	report_id = data[1];
-	data += 2;
-	len -= 2;
+	data ++;
+	len --;
 
 	hid_device = get_hid_device(&s->bdaddr);
 	assert(hid_device != NULL);
@@ -202,17 +202,11 @@ hid_interrupt(bthid_session_p s, uint8_t
 				if (val && val < kbd_maxkey())
 					bit_set(s->keys1, val);
 
-				data ++;
-				len --;
-
-				len = min(len, h.report_size);
-				while (len > 0) {
+				for (i = 1; i < h.report_count; i++) {
+					h.pos += h.report_size;
 					val = hid_get_data(data, &h);
 					if (val && val < kbd_maxkey())
 						bit_set(s->keys1, val);
-
-					data ++;
-					len --;
 				}
 			}
 			break;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005181032.o4IAWK50019971>