Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Jun 2004 20:16:47 -0400
From:      Anish Mistry <mistry.7@osu.edu>
To:        freebsd-hardware@freebsd.org
Cc:        Markus Wild <mwild@vianetworks.ch>
Subject:   Re: Fix for Logitech DiNovo cordless mouse [PATCH]
Message-ID:  <200406092016.54347.mistry.7@osu.edu>
In-Reply-To: <200406091838.i59Icugc063061@smsgw.vianetworks.ch>
References:  <200406091838.i59Icugc063061@smsgw.vianetworks.ch>

next in thread | previous in thread | raw e-mail | index | archive | help

--Boundary-00=_vh6xAi/EQRz9Qhb
Content-Type: Text/Plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Wednesday 09 June 2004 02:38 pm, Markus Wild wrote:
> Since yesterday I'm a happy owner of a Logitech dinovo
> cordless USB keyboard/mouse. The keyboard works fine, however
> the mouse didn't move a bit. I saw that other people had similar
> "luck", so I enabled a bit of debugging. This is with FreeBSD-current,
> btw.
>
> The result of the quest was: the hid.c:hid_report_size() function returns=
 a
> bogus iid value:
>
> Jun  9 19:37:06 mothra kernel: ums0: Logitech USB Receiver, rev 1.10/24.0=
4,
> addr 3, iclass 3/1
> Jun  9 19:37:06 mothra kernel: ums_attach: bLength=3D7 bDescriptorType=3D5
> bEndpoint Address=3D2-in bmAttributes=3D3 wMaxPacketSize=3D8 bInterval=3D=
10
> Jun  9 19:37:06 mothra kernel: ums0: 7 buttons and Z dir.
> Jun  9 19:37:06 mothra kernel: ums_attach: sc=3D0xc23a1800
> Jun  9 19:37:06 mothra kernel: ums_attach: X    8/12
> Jun  9 19:37:06 mothra kernel: ums_attach: Y    20/12
> Jun  9 19:37:06 mothra kernel: ums_attach: Z    32/8
> Jun  9 19:37:06 mothra kernel: ums_attach: B1   0/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B2   1/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B3   2/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B4   3/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B5   4/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B6   5/1
> Jun  9 19:37:06 mothra kernel: ums_attach: B7   6/1
> Jun  9 19:37:06 mothra kernel: ums_attach: size=3D36, id=3D17
>
> Since actual interrupt reports are issed with id 2:
> Jun  9 18:42:10 mothra kernel: ums_intr: sc=3D0xc23a1800 status=3D0
> Jun  9 18:42:10 mothra kernel: ums_intr: data =3D 02 00 fa
>
> So I added a bit of debugging to the id setting for-loop. It
> looks like the ID cycles thru the following values at attach() time:
> Jun  9 19:40:57 mothra kernel: hid_report_size: 00 -> 02
> Jun  9 19:40:57 mothra kernel: hid_report_size: 02 -> 03
> Jun  9 19:40:57 mothra kernel: hid_report_size: 03 -> 04
> Jun  9 19:40:57 mothra kernel: hid_report_size: 04 -> 10
> Jun  9 19:40:57 mothra kernel: hid_report_size: 10 -> 11
> (numbers are hex here)
>
> With this, my current fix is simple: only set id if it's not
> set already:
> diff -u -r1.23 hid.c
> --- hid.c       24 Aug 2003 17:55:54 -0000      1.23
> +++ hid.c       9 Jun 2004 18:34:23 -0000
> @@ -374,9 +374,10 @@
>         int size, id;
>
>         id =3D 0;
> +       bzero (&h, sizeof (h));
>         for (d =3D hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); )
> -               if (h.report_ID !=3D 0)
> -                       id =3D h.report_ID;
> +         if (h.report_ID !=3D 0 && !id)
> +               id =3D h.report_ID;
>         hid_end_parse(d);
>         size =3D h.loc.pos;
>         if (id !=3D 0) {
>
I've attached at big patch that should fix the problem as well as a bunch o=
f=20
updates from the NetBSD sources.  This is a patch against -CURRENT, so you=
=20
may have to massage it a bit if you are on -STABLE.  I won't have an=20
offending device to test for at least a week so let me know of any problems.

Thanks,

=2D --=20
Anish Mistry
=2D----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (FreeBSD)

iD8DBQFAx6hvxqA5ziudZT0RAspMAJ9y4i5rXALWKnn7zrQ3TigCSK0dGACdHcmU
x/J7ZJXwjFeiJptFzZmaXS8=3D
=3Deg+L
=2D----END PGP SIGNATURE-----

--Boundary-00=_vh6xAi/EQRz9Qhb
Content-Type: text/x-diff;
  charset="iso-8859-1";
  name="hid-updates.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="hid-updates.patch"

diff -ruN sys/dev/usb.orig/hid.c sys/dev/usb/hid.c
--- sys/dev/usb.orig/hid.c	Wed Jun  9 20:10:55 2004
+++ sys/dev/usb/hid.c	Wed Jun  9 20:08:30 2004
@@ -1,8 +1,6 @@
-/*	$NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $	*/
+/*	$NetBSD: hid.c,v 1.21 2002/01/02 11:10:50 augustss Exp $	*/
+/*	$FreeBSD: src/sys/dev/usb/usbhid.h,v 1.13 2002/01/02 20:16:53 joe Exp $ */
 
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/usb/hid.c,v 1.23 2003/08/24 17:55:54 obrien Exp $");
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -40,22 +38,24 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #if defined(__NetBSD__)
 #include <sys/kernel.h>
 #endif
 #include <sys/malloc.h>
-
+ 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbhid.h>
 
 #include <dev/usb/hid.h>
 
-#ifdef USB_DEBUG
-#define DPRINTF(x)	if (usbdebug) logprintf x
-#define DPRINTFN(n,x)	if (usbdebug>(n)) logprintf x
-extern int usbdebug;
+#ifdef UHIDEV_DEBUG
+#define DPRINTF(x)	if (uhidevdebug) logprintf x
+#define DPRINTFN(n,x)	if (uhidevdebug>(n)) logprintf x
+extern int uhidevdebug;
 #else
 #define DPRINTF(x)
 #define DPRINTFN(n,x)
@@ -63,7 +63,7 @@
 
 Static void hid_clear_local(struct hid_item *);
 
-#define MAXUSAGE 100
+#define MAXUSAGE 256
 struct hid_data {
 	u_char *start;
 	u_char *end;
@@ -74,13 +74,14 @@
 	int minset;
 	int multi;
 	int multimax;
-	int kindset;
+	enum hid_kind kind;
 };
 
 Static void
 hid_clear_local(struct hid_item *c)
 {
 
+	DPRINTFN(5,("hid_clear_local\n"));
 	c->usage = 0;
 	c->usage_minimum = 0;
 	c->usage_maximum = 0;
@@ -94,14 +95,15 @@
 }
 
 struct hid_data *
-hid_start_parse(void *d, int len, int kindset)
+hid_start_parse(void *d, int len, enum hid_kind kind)
 {
 	struct hid_data *s;
 
-	s = malloc(sizeof *s, M_TEMP, M_WAITOK|M_ZERO);
+	s = malloc(sizeof *s, M_TEMP, M_WAITOK);
+	memset(s, 0, sizeof *s);
 	s->start = s->p = d;
 	s->end = (char *)d + len;
-	s->kindset = kindset;
+	s->kind = kind;
 	return (s);
 }
 
@@ -128,15 +130,19 @@
 	u_char *p;
 	struct hid_item *hi;
 	int i;
+	enum hid_kind retkind;
 
  top:
+	DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n",
+		    s->multi, s->multimax));
 	if (s->multimax != 0) {
 		if (s->multi < s->multimax) {
 			c->usage = s->usages[min(s->multi, s->nu-1)];
 			s->multi++;
 			*h = *c;
 			c->loc.pos += c->loc.size;
-			h->next = 0;
+			h->next = NULL;
+			DPRINTFN(5,("return multi\n"));
 			return (1);
 		} else {
 			c->loc.count = s->multimax;
@@ -174,12 +180,12 @@
 			dval = 0;
 			break;
 		case 1:
-			dval = (int8_t)*data++;
+			dval = /*(int8_t)*/ *data++;
 			break;
 		case 2:
 			dval = *data++;
 			dval |= *data++ << 8;
-			dval = (int16_t)dval;
+			dval = /*(int16_t)*/ dval;
 			break;
 		case 4:
 			dval = *data++;
@@ -191,23 +197,30 @@
 			printf("BAD LENGTH %d\n", bSize);
 			continue;
 		}
-
+		
+		DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d\n",
+			 bType, bTag, dval));
 		switch (bType) {
 		case 0:			/* Main */
 			switch (bTag) {
 			case 8:		/* Input */
-				if (!(s->kindset & (1 << hid_input)))
+				retkind = hid_input;
+			ret:
+				if (s->kind != retkind) {
+					s->minset = 0;
+					s->nu = 0;
+					hid_clear_local(c);
 					continue;
-				c->kind = hid_input;
+				}
+				c->kind = retkind;
 				c->flags = dval;
-			ret:
 				if (c->flags & HIO_VARIABLE) {
 					s->multimax = c->loc.count;
 					s->multi = 0;
 					c->loc.count = 1;
 					if (s->minset) {
-						for (i = c->usage_minimum;
-						     i <= c->usage_maximum;
+						for (i = c->usage_minimum; 
+						     i <= c->usage_maximum; 
 						     i++) {
 							s->usages[s->nu] = i;
 							if (s->nu < MAXUSAGE-1)
@@ -217,19 +230,18 @@
 					}
 					goto top;
 				} else {
+					c->usage = c->_usage_page; /* XXX */
 					*h = *c;
-					h->next = 0;
-					c->loc.pos +=
-						c->loc.size * c->loc.count;
-					hid_clear_local(c);
+					h->next = NULL;
+					c->loc.pos += 
+					    c->loc.size * c->loc.count;
 					s->minset = 0;
+					s->nu = 0;
+					hid_clear_local(c);
 					return (1);
 				}
 			case 9:		/* Output */
-				if (!(s->kindset & (1 << hid_output)))
-					continue;
-				c->kind = hid_output;
-				c->flags = dval;
+				retkind = hid_output;
 				goto ret;
 			case 10:	/* Collection */
 				c->kind = hid_collection;
@@ -240,16 +252,12 @@
 				s->nu = 0;
 				return (1);
 			case 11:	/* Feature */
-				if (!(s->kindset & (1 << hid_feature)))
-					continue;
-				c->kind = hid_feature;
-				c->flags = dval;
+				retkind = hid_feature;
 				goto ret;
 			case 12:	/* End collection */
 				c->kind = hid_endcollection;
 				c->collevel--;
 				*h = *c;
-				hid_clear_local(c);
 				s->nu = 0;
 				return (1);
 			default:
@@ -285,6 +293,7 @@
 				break;
 			case 8:
 				c->report_ID = dval;
+				c->loc.pos = 0;
 				break;
 			case 9:
 				c->loc.count = dval;
@@ -309,9 +318,9 @@
 		case 2:		/* Local */
 			switch (bTag) {
 			case 0:
-				if (bSize == 1)
+				if (bSize == 1) 
 					dval = c->_usage_page | (dval&0xff);
-				else if (bSize == 2)
+				else if (bSize == 2) 
 					dval = c->_usage_page | (dval&0xffff);
 				c->usage = dval;
 				if (s->nu < MAXUSAGE)
@@ -320,16 +329,16 @@
 				break;
 			case 1:
 				s->minset = 1;
-				if (bSize == 1)
+				if (bSize == 1) 
 					dval = c->_usage_page | (dval&0xff);
-				else if (bSize == 2)
+				else if (bSize == 2) 
 					dval = c->_usage_page | (dval&0xffff);
 				c->usage_minimum = dval;
 				break;
 			case 2:
-				if (bSize == 1)
+				if (bSize == 1) 
 					dval = c->_usage_page | (dval&0xff);
-				else if (bSize == 2)
+				else if (bSize == 2) 
 					dval = c->_usage_page | (dval&0xffff);
 				c->usage_maximum = dval;
 				break;
@@ -367,35 +376,51 @@
 }
 
 int
-hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *idp)
+hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id)
 {
 	struct hid_data *d;
 	struct hid_item h;
-	int size, id;
+	int lo, hi;
 
-	id = 0;
-	for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); )
-		if (h.report_ID != 0)
-			id = h.report_ID;
+	h.report_ID = 0;
+	lo = hi = -1;
+	DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id));
+	for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
+		DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
+			    "size=%d count=%d\n",
+			    h.kind, h.report_ID, h.loc.pos, h.loc.size,
+			    h.loc.count));
+		if (h.report_ID == id && h.kind == k) {
+			if (lo < 0) {
+				lo = h.loc.pos;
+#ifdef DIAGNOSTIC
+				if (lo != 0) {
+					printf("hid_report_size: lo != 0\n");
+				}
+#endif
+			}
+			hi = h.loc.pos + h.loc.size * h.loc.count;
+			DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi));
+		}
+	}
 	hid_end_parse(d);
-	size = h.loc.pos;
-	if (id != 0) {
-		size += 8;
-		*idp = id;	/* XXX wrong */
-	} else
-		*idp = 0;
-	return ((size + 7) / 8);
+	return ((hi - lo + 7) / 8);
 }
 
 int
-hid_locate(void *desc, int size, u_int32_t u, enum hid_kind k,
+hid_locate(void *desc, int size, u_int32_t u, u_int8_t id, enum hid_kind k,
 	   struct hid_location *loc, u_int32_t *flags)
 {
 	struct hid_data *d;
 	struct hid_item h;
 
-	for (d = hid_start_parse(desc, size, 1<<k); hid_get_item(d, &h); ) {
-		if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
+	h.report_ID = 0;
+	DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id));
+	for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
+		DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
+			    h.usage, h.kind, h.report_ID, h.flags));
+		if (h.kind == k && !(h.flags & HIO_CONST) && 
+		    h.usage == u && h.report_ID == id) {
 			if (loc != NULL)
 				*loc = h.loc;
 			if (flags != NULL)
@@ -423,7 +448,7 @@
 		return (0);
 
 	data = 0;
-	s = hpos / 8;
+	s = hpos / 8; 
 	for (i = hpos; i < hpos+hsize; i += 8)
 		data |= buf[i / 8] << ((i / 8 - s) * 8);
 	data >>= hpos % 8;
@@ -431,25 +456,39 @@
 	hsize = 32 - hsize;
 	/* Sign extend */
 	data = ((int32_t)data << hsize) >> hsize;
-	DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n",
+	DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n", 
 		    loc->pos, loc->size, (long)data));
 	return (data);
 }
 
 int
-hid_is_collection(void *desc, int size, u_int32_t usage)
+hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage)
 {
 	struct hid_data *hd;
 	struct hid_item hi;
-	int err;
+	u_int32_t coll_usage = ~0;
 
-	hd = hid_start_parse(desc, size, hid_input);
+	hd = hid_start_parse(desc, size, hid_none);
 	if (hd == NULL)
 		return (0);
 
-	err = hid_get_item(hd, &hi) &&
-	    hi.kind == hid_collection &&
-	    hi.usage == usage;
+	DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage));
+	while (hid_get_item(hd, &hi)) {
+		DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
+			    "(0x%x)\n",
+			    hi.kind, hi.report_ID, hi.usage, coll_usage));
+		if (hi.kind == hid_collection && 
+		    hi.collection == HCOLL_APPLICATION)
+			coll_usage = hi.usage;
+		if (hi.kind == hid_endcollection &&
+		    coll_usage == usage &&
+		    hi.report_ID == id) {
+			DPRINTFN(2,("hid_is_collection: found\n"));
+			hid_end_parse(hd);
+			return (1);
+		}
+	}
+	DPRINTFN(2,("hid_is_collection: not found\n"));
 	hid_end_parse(hd);
-	return (err);
+	return (0);
 }
diff -ruN sys/dev/usb.orig/hid.h sys/dev/usb/hid.h
--- sys/dev/usb.orig/hid.h	Wed Jun  9 20:10:55 2004
+++ sys/dev/usb/hid.h	Wed Jun  9 20:04:57 2004
@@ -1,4 +1,4 @@
-/*	$NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $	*/
+/*	$NetBSD: hid.h,v 1.7 2001/12/28 17:32:36 augustss Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/hid.h,v 1.12 2003/07/04 01:50:38 jmg Exp $ */
 
 /*
@@ -38,8 +38,13 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-enum hid_kind {
-	hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
+enum hid_kind { 
+	hid_input,
+	hid_output,
+	hid_feature,
+	hid_collection,
+	hid_endcollection,
+	hid_none
 };
 
 struct hid_location {
@@ -80,12 +85,11 @@
 	struct hid_item *next;
 };
 
-struct hid_data *hid_start_parse(void *d, int len, int kindset);
+struct hid_data *hid_start_parse(void *d, int len, enum hid_kind kind);
 void hid_end_parse(struct hid_data *s);
 int hid_get_item(struct hid_data *s, struct hid_item *h);
-int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *id);
-int hid_locate(void *desc, int size, u_int32_t usage,
-		    enum hid_kind kind, struct hid_location *loc,
-		    u_int32_t *flags);
+int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id);
+int hid_locate(void *desc, int size, u_int32_t usage, u_int8_t id,
+	       enum hid_kind kind, struct hid_location *loc, u_int32_t *flags);
 u_long hid_get_data(u_char *buf, struct hid_location *loc);
-int hid_is_collection(void *desc, int size, u_int32_t usage);
+int hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage);
diff -ruN sys/dev/usb.orig/uhid.c sys/dev/usb/uhid.c
--- sys/dev/usb.orig/uhid.c	Wed Jun  9 20:10:55 2004
+++ sys/dev/usb/uhid.c	Wed Jun  9 20:35:14 2004
@@ -266,9 +266,9 @@
 
 	(void)usbd_set_idle(iface, 0, 0);
 
-	sc->sc_isize = hid_report_size(desc, size, hid_input,   &sc->sc_iid);
-	sc->sc_osize = hid_report_size(desc, size, hid_output,  &sc->sc_oid);
-	sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid);
+	sc->sc_isize = hid_report_size(desc, size, hid_input,   sc->sc_iid);
+	sc->sc_osize = hid_report_size(desc, size, hid_output,  sc->sc_oid);
+	sc->sc_fsize = hid_report_size(desc, size, hid_feature, sc->sc_fid);
 
 	sc->sc_repdesc = desc;
 	sc->sc_repdesc_size = size;
diff -ruN sys/dev/usb.orig/usbhid.h sys/dev/usb/usbhid.h
--- sys/dev/usb.orig/usbhid.h	Wed Jun  9 20:10:53 2004
+++ sys/dev/usb/usbhid.h	Wed Jun  9 20:07:13 2004
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss Exp $	*/
+/*	$NetBSD: usbhid.h,v 1.9.4.1 2002/01/10 19:59:11 thorpej Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usbhid.h,v 1.13 2002/01/02 20:16:53 joe Exp $ */
 
 /*
@@ -164,11 +164,24 @@
 #define HUD_ERASER		0x0045
 #define HUD_TABLET_PICK		0x0046
 
-#define HID_USAGE2(p,u) (((p) << 16) | u)
+/* Usages LEDs */
+#define HUD_LED_NUM_LOCK	0x0001
+#define HUD_LED_CAPS_LOCK	0x0002
+#define HUD_LED_SCROLL_LOCK	0x0003
+#define HUD_LED_COMPOSE		0x0004
+#define HUD_LED_KANA		0x0005
+
+#define HID_USAGE2(p, u) (((p) << 16) | u)
+#define HID_GET_USAGE(u) ((u) & 0xffff)
+#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff)
 
 #define UHID_INPUT_REPORT 0x01
 #define UHID_OUTPUT_REPORT 0x02
 #define UHID_FEATURE_REPORT 0x03
+
+#define HCOLL_PHYSICAL		0
+#define HCOLL_APPLICATION	1
+#define HCOLL_LOGICAL		2
 
 /* Bits in the input/output/feature items */
 #define HIO_CONST	0x001

--Boundary-00=_vh6xAi/EQRz9Qhb--



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