Module Name:    src
Committed By:   plunky
Date:           Wed May 12 18:44:49 UTC 2010

Modified Files:
        src/sys/dev/usb: hid.c hid.h

Log Message:
hid_get_data() does not work if the size of data is less than
a byte and crosses a byte boundary, and it always returns a
sign-extended value.

fix this by using the algorithm from libusbhid to read bytes,
and provide a hid_get_udata() function to return unsigned data
values.

while here, const args


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/usb/hid.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/usb/hid.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/hid.c
diff -u src/sys/dev/usb/hid.c:1.28 src/sys/dev/usb/hid.c:1.29
--- src/sys/dev/usb/hid.c:1.28	Mon Apr 28 20:23:59 2008
+++ src/sys/dev/usb/hid.c	Wed May 12 18:44:48 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: hid.c,v 1.28 2008/04/28 20:23:59 martin Exp $	*/
+/*	$NetBSD: hid.c,v 1.29 2010/05/12 18:44:48 plunky Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.28 2008/04/28 20:23:59 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.29 2010/05/12 18:44:48 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -427,30 +427,43 @@
 	return (0);
 }
 
+long
+hid_get_data(const u_char *buf, const struct hid_location *loc)
+{
+	u_int hsize = loc->size;
+	u_long data;
+
+	if (hsize == 0)
+		return (0);
+
+	data = hid_get_udata(buf, loc);
+	if (data < (1 << (hsize - 1)))
+		return (data);
+	return data - (1 << hsize);
+}
+
 u_long
-hid_get_data(u_char *buf, struct hid_location *loc)
+hid_get_udata(const u_char *buf, const struct hid_location *loc)
 {
 	u_int hpos = loc->pos;
 	u_int hsize = loc->size;
-	u_int32_t data;
-	int i, s;
-
-	DPRINTFN(10, ("hid_get_data: loc %d/%d\n", hpos, hsize));
+	u_int i, num, off;
+	u_long data;
 
 	if (hsize == 0)
 		return (0);
 
 	data = 0;
-	s = hpos / 8;
-	for (i = hpos; i < hpos+hsize; i += 8)
-		data |= buf[i / 8] << ((i / 8 - s) * 8);
+	off = hpos / 8;
+	num = (hpos + hsize + 7) / 8 - off;
+
+	for (i = 0; i < num; i++)
+		data |= buf[off + i] << (i * 8);
+
 	data >>= hpos % 8;
 	data &= (1 << hsize) - 1;
-	hsize = 32 - hsize;
-	/* Sign extend */
-	data = ((int32_t)data << hsize) >> hsize;
-	DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n",
-		    loc->pos, loc->size, (long)data));
+
+	DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n", hpos, hsize, data));
 	return (data);
 }
 

Index: src/sys/dev/usb/hid.h
diff -u src/sys/dev/usb/hid.h:1.12 src/sys/dev/usb/hid.h:1.13
--- src/sys/dev/usb/hid.h:1.12	Mon Apr 28 20:23:59 2008
+++ src/sys/dev/usb/hid.h	Wed May 12 18:44:49 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: hid.h,v 1.12 2008/04/28 20:23:59 martin Exp $	*/
+/*	$NetBSD: hid.h,v 1.13 2010/05/12 18:44:49 plunky Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */
 
 /*
@@ -84,5 +84,6 @@
 int hid_report_size(const void *, int, enum hid_kind, u_int8_t);
 int hid_locate(const void *, int, u_int32_t, u_int8_t, enum hid_kind,
     struct hid_location *, u_int32_t *);
-u_long hid_get_data(u_char *, struct hid_location *);
+long hid_get_data(const u_char *, const struct hid_location *);
+u_long hid_get_udata(const u_char *, const struct hid_location *);
 int hid_is_collection(const void *, int, u_int8_t, u_int32_t);

Reply via email to