aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2012-05-22 05:32:31 -0400
committerJiri Kosina <jkosina@suse.cz>2012-05-22 05:32:31 -0400
commit56ccd186f1837dd418cd094f0e96b3196bbab9ef (patch)
tree195cdd3973a1288eb84f51f0ec28a947b333c2c5 /drivers
parentb3d07e0344ea36dd3f3a2fdbfaab883e1c5ca69e (diff)
parentd1257081aecf44455fcab8675f1d54e8b242faa1 (diff)
Merge branch 'upstream' into for-linus
Conflicts: drivers/hid/hid-core.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/Kconfig6
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-apple.c2
-rw-r--r--drivers/hid/hid-aureal.c54
-rw-r--r--drivers/hid/hid-core.c31
-rw-r--r--drivers/hid/hid-ids.h4
-rw-r--r--drivers/hid/hid-uclogic.c141
-rw-r--r--drivers/hid/hidraw.c19
-rw-r--r--drivers/hid/usbhid/hid-core.c65
-rw-r--r--drivers/hid/usbhid/hiddev.c9
-rw-r--r--drivers/hid/usbhid/usbhid.h1
11 files changed, 304 insertions, 29 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 9a581e1a1903..80175c37a6a5 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -104,6 +104,12 @@ config HID_APPLE
104 Say Y here if you want support for keyboards of Apple iBooks, PowerBooks, 104 Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
105 MacBooks, MacBook Pros and Apple Aluminum. 105 MacBooks, MacBook Pros and Apple Aluminum.
106 106
107config HID_AUREAL
108 tristate "Aureal"
109 depends on USB_HID
110 ---help---
111 Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
112
107config HID_BELKIN 113config HID_BELKIN
108 tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT 114 tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
109 depends on USB_HID 115 depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index a04cffa4784f..ca6cc9f0485c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -38,6 +38,7 @@ endif
38obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o 38obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
39obj-$(CONFIG_HID_ACRUX) += hid-axff.o 39obj-$(CONFIG_HID_ACRUX) += hid-axff.o
40obj-$(CONFIG_HID_APPLE) += hid-apple.o 40obj-$(CONFIG_HID_APPLE) += hid-apple.o
41obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
41obj-$(CONFIG_HID_BELKIN) += hid-belkin.o 42obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
42obj-$(CONFIG_HID_CHERRY) += hid-cherry.o 43obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
43obj-$(CONFIG_HID_CHICONY) += hid-chicony.o 44obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 299d23871122..7a79e39efc7e 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
234 } 234 }
235 } 235 }
236 236
237 if (iso_layout) { 237 if (iso_layout) {
238 if (asc->quirks & APPLE_ISO_KEYBOARD) { 238 if (asc->quirks & APPLE_ISO_KEYBOARD) {
239 trans = apple_find_translation(apple_iso_keyboard, usage->code); 239 trans = apple_find_translation(apple_iso_keyboard, usage->code);
240 if (trans) { 240 if (trans) {
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
new file mode 100644
index 000000000000..ba64b041b8bf
--- /dev/null
+++ b/drivers/hid/hid-aureal.c
@@ -0,0 +1,54 @@
1/*
2 * HID driver for Aureal Cy se W-01RN USB_V3.1 devices
3 *
4 * Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
5 * Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
6 *
7 * Based on HID sunplus driver by
8 * Copyright (c) 1999 Andreas Gal
9 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
10 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
11 * Copyright (c) 2006-2007 Jiri Kosina
12 * Copyright (c) 2007 Paul Walmsley
13 * Copyright (c) 2008 Jiri Slaby
14 */
15#include <linux/device.h>
16#include <linux/hid.h>
17#include <linux/module.h>
18
19#include "hid-ids.h"
20
21static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
22 unsigned int *rsize)
23{
24 if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
25 dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
26 rdesc[53] = 0x65;
27 } return rdesc;
28}
29
30static const struct hid_device_id aureal_devices[] = {
31 { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
32 { }
33};
34MODULE_DEVICE_TABLE(hid, aureal_devices);
35
36static struct hid_driver aureal_driver = {
37 .name = "aureal",
38 .id_table = aureal_devices,
39 .report_fixup = aureal_report_fixup,
40};
41
42static int __init aureal_init(void)
43{
44 return hid_register_driver(&aureal_driver);
45}
46
47static void __exit aureal_exit(void)
48{
49 hid_unregister_driver(&aureal_driver);
50}
51
52module_init(aureal_init);
53module_exit(aureal_exit);
54MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index df2ca0af855f..9831a2ccae3d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
230 return -1; 230 return -1;
231 } 231 }
232 232
233 if (parser->global.logical_maximum < parser->global.logical_minimum) { 233 /* Handle both signed and unsigned cases properly */
234 hid_err(parser->device, "logical range invalid %d %d\n", 234 if ((parser->global.logical_minimum < 0 &&
235 parser->global.logical_minimum, parser->global.logical_maximum); 235 parser->global.logical_maximum <
236 parser->global.logical_minimum) ||
237 (parser->global.logical_minimum >= 0 &&
238 (__u32)parser->global.logical_maximum <
239 (__u32)parser->global.logical_minimum)) {
240 dbg_hid("logical range invalid 0x%x 0x%x\n",
241 parser->global.logical_minimum,
242 parser->global.logical_maximum);
236 return -1; 243 return -1;
237 } 244 }
238 245
@@ -1149,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
1149 return report; 1156 return report;
1150} 1157}
1151 1158
1152void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, 1159int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1153 int interrupt) 1160 int interrupt)
1154{ 1161{
1155 struct hid_report_enum *report_enum = hid->report_enum + type; 1162 struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1157,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1157 unsigned int a; 1164 unsigned int a;
1158 int rsize, csize = size; 1165 int rsize, csize = size;
1159 u8 *cdata = data; 1166 u8 *cdata = data;
1167 int ret = 0;
1160 1168
1161 report = hid_get_report(report_enum, data); 1169 report = hid_get_report(report_enum, data);
1162 if (!report) 1170 if (!report)
1163 return; 1171 goto out;
1164 1172
1165 if (report_enum->numbered) { 1173 if (report_enum->numbered) {
1166 cdata++; 1174 cdata++;
@@ -1180,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
1180 1188
1181 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) 1189 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
1182 hid->hiddev_report_event(hid, report); 1190 hid->hiddev_report_event(hid, report);
1183 if (hid->claimed & HID_CLAIMED_HIDRAW) 1191 if (hid->claimed & HID_CLAIMED_HIDRAW) {
1184 hidraw_report_event(hid, data, size); 1192 ret = hidraw_report_event(hid, data, size);
1193 if (ret)
1194 goto out;
1195 }
1185 1196
1186 for (a = 0; a < report->maxfield; a++) 1197 for (a = 0; a < report->maxfield; a++)
1187 hid_input_field(hid, report->field[a], cdata, interrupt); 1198 hid_input_field(hid, report->field[a], cdata, interrupt);
1188 1199
1189 if (hid->claimed & HID_CLAIMED_INPUT) 1200 if (hid->claimed & HID_CLAIMED_INPUT)
1190 hidinput_report_event(hid, report); 1201 hidinput_report_event(hid, report);
1202out:
1203 return ret;
1191} 1204}
1192EXPORT_SYMBOL_GPL(hid_report_raw_event); 1205EXPORT_SYMBOL_GPL(hid_report_raw_event);
1193 1206
@@ -1264,7 +1277,7 @@ nomem:
1264 } 1277 }
1265 } 1278 }
1266 1279
1267 hid_report_raw_event(hid, type, data, size, interrupt); 1280 ret = hid_report_raw_event(hid, type, data, size, interrupt);
1268 1281
1269unlock: 1282unlock:
1270 up(&hid->driver_lock); 1283 up(&hid->driver_lock);
@@ -1496,6 +1509,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1496 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, 1509 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
1497 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, 1510 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
1498 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, 1511 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
1512 { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
1499 { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, 1513 { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
1500 { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), }, 1514 { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), },
1501 { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, 1515 { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
@@ -1631,6 +1645,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1631 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, 1645 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
1632 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, 1646 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
1633 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, 1647 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
1648 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
1634 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, 1649 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
1635 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, 1650 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
1636 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, 1651 { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e44932af8da2..4ff994166c04 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -154,6 +154,9 @@
154#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c 154#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
155#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118 155#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
156 156
157#define USB_VENDOR_ID_AUREAL 0x0755
158#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
159
157#define USB_VENDOR_ID_AVERMEDIA 0x07ca 160#define USB_VENDOR_ID_AVERMEDIA 0x07ca
158#define USB_DEVICE_ID_AVER_FM_MR800 0xb800 161#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
159 162
@@ -729,6 +732,7 @@
729#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 732#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
730#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 733#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
731#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 734#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
735#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
732 736
733#define USB_VENDOR_ID_UNITEC 0x227d 737#define USB_VENDOR_ID_UNITEC 0x227d
734#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 738#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 1f1128910337..3aba02be1f26 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -14,6 +14,7 @@
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/hid.h> 15#include <linux/hid.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/usb.h>
17 18
18#include "hid-ids.h" 19#include "hid-ids.h"
19 20
@@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {
352 0xC0 /* End Collection */ 353 0xC0 /* End Collection */
353}; 354};
354 355
356/*
357 * See TWHL850 description, device and HID report descriptors at
358 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
359 */
360
361/* Size of the original descriptors of TWHL850 tablet */
362#define TWHL850_RDESC_ORIG_SIZE0 182
363#define TWHL850_RDESC_ORIG_SIZE1 161
364#define TWHL850_RDESC_ORIG_SIZE2 92
365
366/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
367static __u8 twhl850_rdesc_fixed0[] = {
368 0x05, 0x0D, /* Usage Page (Digitizer), */
369 0x09, 0x02, /* Usage (Pen), */
370 0xA1, 0x01, /* Collection (Application), */
371 0x85, 0x09, /* Report ID (9), */
372 0x09, 0x20, /* Usage (Stylus), */
373 0xA0, /* Collection (Physical), */
374 0x14, /* Logical Minimum (0), */
375 0x25, 0x01, /* Logical Maximum (1), */
376 0x75, 0x01, /* Report Size (1), */
377 0x95, 0x03, /* Report Count (3), */
378 0x09, 0x42, /* Usage (Tip Switch), */
379 0x09, 0x44, /* Usage (Barrel Switch), */
380 0x09, 0x46, /* Usage (Tablet Pick), */
381 0x81, 0x02, /* Input (Variable), */
382 0x81, 0x03, /* Input (Constant, Variable), */
383 0x95, 0x01, /* Report Count (1), */
384 0x09, 0x32, /* Usage (In Range), */
385 0x81, 0x02, /* Input (Variable), */
386 0x81, 0x03, /* Input (Constant, Variable), */
387 0x75, 0x10, /* Report Size (16), */
388 0xA4, /* Push, */
389 0x05, 0x01, /* Usage Page (Desktop), */
390 0x65, 0x13, /* Unit (Inch), */
391 0x55, 0xFD, /* Unit Exponent (-3), */
392 0x34, /* Physical Minimum (0), */
393 0x09, 0x30, /* Usage (X), */
394 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
395 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
396 0x81, 0x02, /* Input (Variable), */
397 0x09, 0x31, /* Usage (Y), */
398 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
399 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
400 0x81, 0x02, /* Input (Variable), */
401 0xB4, /* Pop, */
402 0x09, 0x30, /* Usage (Tip Pressure), */
403 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
404 0x81, 0x02, /* Input (Variable), */
405 0xC0, /* End Collection, */
406 0xC0 /* End Collection */
407};
408
409/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
410static __u8 twhl850_rdesc_fixed1[] = {
411 0x05, 0x01, /* Usage Page (Desktop), */
412 0x09, 0x02, /* Usage (Mouse), */
413 0xA1, 0x01, /* Collection (Application), */
414 0x85, 0x01, /* Report ID (1), */
415 0x09, 0x01, /* Usage (Pointer), */
416 0xA0, /* Collection (Physical), */
417 0x05, 0x09, /* Usage Page (Button), */
418 0x75, 0x01, /* Report Size (1), */
419 0x95, 0x03, /* Report Count (3), */
420 0x19, 0x01, /* Usage Minimum (01h), */
421 0x29, 0x03, /* Usage Maximum (03h), */
422 0x14, /* Logical Minimum (0), */
423 0x25, 0x01, /* Logical Maximum (1), */
424 0x81, 0x02, /* Input (Variable), */
425 0x95, 0x05, /* Report Count (5), */
426 0x81, 0x03, /* Input (Constant, Variable), */
427 0x05, 0x01, /* Usage Page (Desktop), */
428 0x09, 0x30, /* Usage (X), */
429 0x09, 0x31, /* Usage (Y), */
430 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
431 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
432 0x75, 0x10, /* Report Size (16), */
433 0x95, 0x02, /* Report Count (2), */
434 0x81, 0x06, /* Input (Variable, Relative), */
435 0x09, 0x38, /* Usage (Wheel), */
436 0x15, 0xFF, /* Logical Minimum (-1), */
437 0x25, 0x01, /* Logical Maximum (1), */
438 0x95, 0x01, /* Report Count (1), */
439 0x75, 0x08, /* Report Size (8), */
440 0x81, 0x06, /* Input (Variable, Relative), */
441 0x81, 0x03, /* Input (Constant, Variable), */
442 0xC0, /* End Collection, */
443 0xC0 /* End Collection */
444};
445
446/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
447static __u8 twhl850_rdesc_fixed2[] = {
448 0x05, 0x01, /* Usage Page (Desktop), */
449 0x09, 0x06, /* Usage (Keyboard), */
450 0xA1, 0x01, /* Collection (Application), */
451 0x85, 0x03, /* Report ID (3), */
452 0x05, 0x07, /* Usage Page (Keyboard), */
453 0x14, /* Logical Minimum (0), */
454 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
455 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
456 0x25, 0x01, /* Logical Maximum (1), */
457 0x75, 0x01, /* Report Size (1), */
458 0x95, 0x08, /* Report Count (8), */
459 0x81, 0x02, /* Input (Variable), */
460 0x18, /* Usage Minimum (None), */
461 0x29, 0xFF, /* Usage Maximum (FFh), */
462 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
463 0x75, 0x08, /* Report Size (8), */
464 0x95, 0x06, /* Report Count (6), */
465 0x80, /* Input, */
466 0xC0 /* End Collection */
467};
468
355static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, 469static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
356 unsigned int *rsize) 470 unsigned int *rsize)
357{ 471{
472 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
473 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
474
358 switch (hdev->product) { 475 switch (hdev->product) {
359 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209: 476 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
360 if (*rsize == PF1209_RDESC_ORIG_SIZE) { 477 if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
386 *rsize = sizeof(wp1062_rdesc_fixed); 503 *rsize = sizeof(wp1062_rdesc_fixed);
387 } 504 }
388 break; 505 break;
506 case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
507 switch (iface_num) {
508 case 0:
509 if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
510 rdesc = twhl850_rdesc_fixed0;
511 *rsize = sizeof(twhl850_rdesc_fixed0);
512 }
513 break;
514 case 1:
515 if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
516 rdesc = twhl850_rdesc_fixed1;
517 *rsize = sizeof(twhl850_rdesc_fixed1);
518 }
519 break;
520 case 2:
521 if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
522 rdesc = twhl850_rdesc_fixed2;
523 *rsize = sizeof(twhl850_rdesc_fixed2);
524 }
525 break;
526 }
527 break;
389 } 528 }
390 529
391 return rdesc; 530 return rdesc;
@@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {
402 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, 541 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
403 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 542 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
404 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, 543 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
544 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
545 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
405 { } 546 { }
406}; 547};
407MODULE_DEVICE_TABLE(hid, uclogic_devices); 548MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cf7d6d58e79f..36fa77b40ffb 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
87 len = list->buffer[list->tail].len > count ? 87 len = list->buffer[list->tail].len > count ?
88 count : list->buffer[list->tail].len; 88 count : list->buffer[list->tail].len;
89 89
90 if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { 90 if (list->buffer[list->tail].value) {
91 ret = -EFAULT; 91 if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
92 goto out; 92 ret = -EFAULT;
93 goto out;
94 }
95 ret = len;
93 } 96 }
94 ret = len;
95 97
96 kfree(list->buffer[list->tail].value); 98 kfree(list->buffer[list->tail].value);
97 list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); 99 list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
437 .llseek = noop_llseek, 439 .llseek = noop_llseek,
438}; 440};
439 441
440void hidraw_report_event(struct hid_device *hid, u8 *data, int len) 442int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
441{ 443{
442 struct hidraw *dev = hid->hidraw; 444 struct hidraw *dev = hid->hidraw;
443 struct hidraw_list *list; 445 struct hidraw_list *list;
446 int ret = 0;
444 447
445 list_for_each_entry(list, &dev->list, node) { 448 list_for_each_entry(list, &dev->list, node) {
446 list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); 449 if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
450 ret = -ENOMEM;
451 break;
452 }
447 list->buffer[list->head].len = len; 453 list->buffer[list->head].len = len;
448 list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); 454 list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
449 kill_fasync(&list->fasync, SIGIO, POLL_IN); 455 kill_fasync(&list->fasync, SIGIO, POLL_IN);
450 } 456 }
451 457
452 wake_up_interruptible(&dev->wait); 458 wake_up_interruptible(&dev->wait);
459 return ret;
453} 460}
454EXPORT_SYMBOL_GPL(hidraw_report_event); 461EXPORT_SYMBOL_GPL(hidraw_report_event);
455 462
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 9cba5006b5ed..df3789f5d9a5 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -28,6 +28,7 @@
28#include <linux/input.h> 28#include <linux/input.h>
29#include <linux/wait.h> 29#include <linux/wait.h>
30#include <linux/workqueue.h> 30#include <linux/workqueue.h>
31#include <linux/string.h>
31 32
32#include <linux/usb.h> 33#include <linux/usb.h>
33 34
@@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)
86 !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && 87 !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
87 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { 88 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
88 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); 89 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
89 if (rc != 0) 90 if (rc != 0) {
90 clear_bit(HID_IN_RUNNING, &usbhid->iofl); 91 clear_bit(HID_IN_RUNNING, &usbhid->iofl);
92 if (rc == -ENOSPC)
93 set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
94 } else {
95 clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
96 }
91 } 97 }
92 spin_unlock_irqrestore(&usbhid->lock, flags); 98 spin_unlock_irqrestore(&usbhid->lock, flags);
93 return rc; 99 return rc;
@@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)
173 179
174 if (time_after(jiffies, usbhid->stop_retry)) { 180 if (time_after(jiffies, usbhid->stop_retry)) {
175 181
176 /* Retries failed, so do a port reset */ 182 /* Retries failed, so do a port reset unless we lack bandwidth*/
177 if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { 183 if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
184 && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
185
178 schedule_work(&usbhid->reset_work); 186 schedule_work(&usbhid->reset_work);
179 goto done; 187 goto done;
180 } 188 }
@@ -700,7 +708,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
700int usbhid_open(struct hid_device *hid) 708int usbhid_open(struct hid_device *hid)
701{ 709{
702 struct usbhid_device *usbhid = hid->driver_data; 710 struct usbhid_device *usbhid = hid->driver_data;
703 int res; 711 int res = 0;
704 712
705 mutex_lock(&hid_open_mut); 713 mutex_lock(&hid_open_mut);
706 if (!hid->open++) { 714 if (!hid->open++) {
@@ -708,17 +716,27 @@ int usbhid_open(struct hid_device *hid)
708 /* the device must be awake to reliably request remote wakeup */ 716 /* the device must be awake to reliably request remote wakeup */
709 if (res < 0) { 717 if (res < 0) {
710 hid->open--; 718 hid->open--;
711 mutex_unlock(&hid_open_mut); 719 res = -EIO;
712 return -EIO; 720 goto done;
713 } 721 }
714 usbhid->intf->needs_remote_wakeup = 1; 722 usbhid->intf->needs_remote_wakeup = 1;
715 if (hid_start_in(hid)) 723 res = hid_start_in(hid);
716 hid_io_error(hid); 724 if (res) {
717 725 if (res != -ENOSPC) {
726 hid_io_error(hid);
727 res = 0;
728 } else {
729 /* no use opening if resources are insufficient */
730 hid->open--;
731 res = -EBUSY;
732 usbhid->intf->needs_remote_wakeup = 0;
733 }
734 }
718 usb_autopm_put_interface(usbhid->intf); 735 usb_autopm_put_interface(usbhid->intf);
719 } 736 }
737done:
720 mutex_unlock(&hid_open_mut); 738 mutex_unlock(&hid_open_mut);
721 return 0; 739 return res;
722} 740}
723 741
724void usbhid_close(struct hid_device *hid) 742void usbhid_close(struct hid_device *hid)
@@ -1347,7 +1365,34 @@ static int hid_post_reset(struct usb_interface *intf)
1347 struct usb_device *dev = interface_to_usbdev (intf); 1365 struct usb_device *dev = interface_to_usbdev (intf);
1348 struct hid_device *hid = usb_get_intfdata(intf); 1366 struct hid_device *hid = usb_get_intfdata(intf);
1349 struct usbhid_device *usbhid = hid->driver_data; 1367 struct usbhid_device *usbhid = hid->driver_data;
1368 struct usb_host_interface *interface = intf->cur_altsetting;
1350 int status; 1369 int status;
1370 char *rdesc;
1371
1372 /* Fetch and examine the HID report descriptor. If this
1373 * has changed, then rebind. Since usbcore's check of the
1374 * configuration descriptors passed, we already know that
1375 * the size of the HID report descriptor has not changed.
1376 */
1377 rdesc = kmalloc(hid->rsize, GFP_KERNEL);
1378 if (!rdesc) {
1379 dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
1380 return 1;
1381 }
1382 status = hid_get_class_descriptor(dev,
1383 interface->desc.bInterfaceNumber,
1384 HID_DT_REPORT, rdesc, hid->rsize);
1385 if (status < 0) {
1386 dbg_hid("reading report descriptor failed (post_reset)\n");
1387 kfree(rdesc);
1388 return 1;
1389 }
1390 status = memcmp(rdesc, hid->rdesc, hid->rsize);
1391 kfree(rdesc);
1392 if (status != 0) {
1393 dbg_hid("report descriptor changed\n");
1394 return 1;
1395 }
1351 1396
1352 spin_lock_irq(&usbhid->lock); 1397 spin_lock_irq(&usbhid->lock);
1353 clear_bit(HID_RESET_PENDING, &usbhid->iofl); 1398 clear_bit(HID_RESET_PENDING, &usbhid->iofl);
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index b1ec0e2aeb57..14599e256791 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
34#include <linux/hid.h> 34#include <linux/hid.h>
35#include <linux/hiddev.h> 35#include <linux/hiddev.h>
36#include <linux/compat.h> 36#include <linux/compat.h>
37#include <linux/vmalloc.h>
37#include "usbhid.h" 38#include "usbhid.h"
38 39
39#ifdef CONFIG_USB_DYNAMIC_MINORS 40#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)
250 } else { 251 } else {
251 mutex_unlock(&list->hiddev->existancelock); 252 mutex_unlock(&list->hiddev->existancelock);
252 kfree(list->hiddev); 253 kfree(list->hiddev);
253 kfree(list); 254 vfree(list);
254 return 0; 255 return 0;
255 } 256 }
256 } 257 }
257 258
258 mutex_unlock(&list->hiddev->existancelock); 259 mutex_unlock(&list->hiddev->existancelock);
259 kfree(list); 260 vfree(list);
260 261
261 return 0; 262 return 0;
262} 263}
@@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
278 hid = usb_get_intfdata(intf); 279 hid = usb_get_intfdata(intf);
279 hiddev = hid->hiddev; 280 hiddev = hid->hiddev;
280 281
281 if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) 282 if (!(list = vzalloc(sizeof(struct hiddev_list))))
282 return -ENOMEM; 283 return -ENOMEM;
283 mutex_init(&list->thread_lock); 284 mutex_init(&list->thread_lock);
284 list->hiddev = hiddev; 285 list->hiddev = hiddev;
@@ -322,7 +323,7 @@ bail_unlock:
322 mutex_unlock(&hiddev->existancelock); 323 mutex_unlock(&hiddev->existancelock);
323bail: 324bail:
324 file->private_data = NULL; 325 file->private_data = NULL;
325 kfree(list); 326 vfree(list);
326 return res; 327 return res;
327} 328}
328 329
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index cb8f703efde5..1883d7b94870 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
55#define HID_STARTED 8 55#define HID_STARTED 8
56#define HID_REPORTED_IDLE 9 56#define HID_REPORTED_IDLE 9
57#define HID_KEYS_PRESSED 10 57#define HID_KEYS_PRESSED 10
58#define HID_NO_BANDWIDTH 11
58 59
59/* 60/*
60 * USB-specific HID struct, to be pointed to 61 * USB-specific HID struct, to be pointed to