diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-05-22 05:32:31 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-05-22 05:32:31 -0400 |
commit | 56ccd186f1837dd418cd094f0e96b3196bbab9ef (patch) | |
tree | 195cdd3973a1288eb84f51f0ec28a947b333c2c5 /drivers | |
parent | b3d07e0344ea36dd3f3a2fdbfaab883e1c5ca69e (diff) | |
parent | d1257081aecf44455fcab8675f1d54e8b242faa1 (diff) |
Merge branch 'upstream' into for-linus
Conflicts:
drivers/hid/hid-core.c
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/Kconfig | 6 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/hid-apple.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-aureal.c | 54 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 31 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 4 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic.c | 141 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 19 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 65 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 9 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbhid.h | 1 |
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 | ||
107 | config 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 | |||
107 | config HID_BELKIN | 113 | config 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 | |||
38 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o | 38 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
39 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o | 39 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o |
40 | obj-$(CONFIG_HID_APPLE) += hid-apple.o | 40 | obj-$(CONFIG_HID_APPLE) += hid-apple.o |
41 | obj-$(CONFIG_HID_AUREAL) += hid-aureal.o | ||
41 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o | 42 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o |
42 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o | 43 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o |
43 | obj-$(CONFIG_HID_CHICONY) += hid-chicony.o | 44 | obj-$(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 | |||
21 | static __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 | |||
30 | static const struct hid_device_id aureal_devices[] = { | ||
31 | { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, | ||
32 | { } | ||
33 | }; | ||
34 | MODULE_DEVICE_TABLE(hid, aureal_devices); | ||
35 | |||
36 | static struct hid_driver aureal_driver = { | ||
37 | .name = "aureal", | ||
38 | .id_table = aureal_devices, | ||
39 | .report_fixup = aureal_report_fixup, | ||
40 | }; | ||
41 | |||
42 | static int __init aureal_init(void) | ||
43 | { | ||
44 | return hid_register_driver(&aureal_driver); | ||
45 | } | ||
46 | |||
47 | static void __exit aureal_exit(void) | ||
48 | { | ||
49 | hid_unregister_driver(&aureal_driver); | ||
50 | } | ||
51 | |||
52 | module_init(aureal_init); | ||
53 | module_exit(aureal_exit); | ||
54 | MODULE_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 | ||
1152 | void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, | 1159 | int 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); |
1202 | out: | ||
1203 | return ret; | ||
1191 | } | 1204 | } |
1192 | EXPORT_SYMBOL_GPL(hid_report_raw_event); | 1205 | EXPORT_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 | ||
1269 | unlock: | 1282 | unlock: |
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) */ | ||
367 | static __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) */ | ||
410 | static __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) */ | ||
447 | static __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 | |||
355 | static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 469 | static __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 | }; |
407 | MODULE_DEVICE_TABLE(hid, uclogic_devices); | 548 | MODULE_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 | ||
440 | void hidraw_report_event(struct hid_device *hid, u8 *data, int len) | 442 | int 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 | } |
454 | EXPORT_SYMBOL_GPL(hidraw_report_event); | 461 | EXPORT_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, | |||
700 | int usbhid_open(struct hid_device *hid) | 708 | int 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 | } |
737 | done: | ||
720 | mutex_unlock(&hid_open_mut); | 738 | mutex_unlock(&hid_open_mut); |
721 | return 0; | 739 | return res; |
722 | } | 740 | } |
723 | 741 | ||
724 | void usbhid_close(struct hid_device *hid) | 742 | void 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); |
323 | bail: | 324 | bail: |
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 |