summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorplunky <plunky@NetBSD.org>2010-05-12 18:44:48 +0000
committerplunky <plunky@NetBSD.org>2010-05-12 18:44:48 +0000
commitba2b0dff29f058178581ab3d2719b10be729a451 (patch)
tree7be34820854a12c4bcdc2e16eac90555c11fa0af /sys/dev
parent38cd0f0b2e948c6b4ddf4640d5790a9568688eba (diff)
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
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/hid.c43
-rw-r--r--sys/dev/usb/hid.h5
2 files changed, 31 insertions, 17 deletions
diff --git a/sys/dev/usb/hid.c b/sys/dev/usb/hid.c
index 4ac4ee69179..98a9ea85a83 100644
--- a/sys/dev/usb/hid.c
+++ b/sys/dev/usb/hid.c
@@ -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 @@ hid_locate(const void *desc, int size, u_int32_t u, u_int8_t id, enum hid_kind k
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);
}
diff --git a/sys/dev/usb/hid.h b/sys/dev/usb/hid.h
index 0d6bb94d38e..0225fa7195d 100644
--- a/sys/dev/usb/hid.h
+++ b/sys/dev/usb/hid.h
@@ -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_get_item(struct hid_data *, struct hid_item *);
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);