diff options
| author | plunky <plunky@NetBSD.org> | 2010-05-12 18:44:48 +0000 |
|---|---|---|
| committer | plunky <plunky@NetBSD.org> | 2010-05-12 18:44:48 +0000 |
| commit | ba2b0dff29f058178581ab3d2719b10be729a451 (patch) | |
| tree | 7be34820854a12c4bcdc2e16eac90555c11fa0af /sys/dev | |
| parent | 38cd0f0b2e948c6b4ddf4640d5790a9568688eba (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.c | 43 | ||||
| -rw-r--r-- | sys/dev/usb/hid.h | 5 |
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); |
