Unified · Split
| @@ -104,6 +104,12 @@ config HID_APPLE · 103 unmodified lines | ||
| 104 | 104 | Say Y here if you want support for keyboards of Apple iBooks, PowerBooks, |
| 105 | 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 | 113 | config HID_BELKIN |
| 108 | 114 | tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT |
| 109 | 115 | depends on USB_HID |
| @@ -38,6 +38,7 @@ endif · 37 unmodified lines | ||
| 38 | 38 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
| 39 | 39 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o |
| 40 | 40 | obj-$(CONFIG_HID_APPLE) += hid-apple.o |
| 41 | +obj-$(CONFIG_HID_AUREAL) += hid-aureal.o | |
| 41 | 42 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o |
| 42 | 43 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o |
| 43 | 44 | obj-$(CONFIG_HID_CHICONY) += hid-chicony.o |
| @@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, · 233 unmodified lines | ||
| 234 | 234 | } |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | − if (iso_layout) { | |
| 237 | + if (iso_layout) { | |
| 238 | 238 | if (asc->quirks & APPLE_ISO_KEYBOARD) { |
| 239 | 239 | trans = apple_find_translation(apple_iso_keyboard, usage->code); |
| 240 | 240 | if (trans) { |
| @@ -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"); | |
| @@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign · 229 unmodified lines | ||
| 230 | 230 | return -1; |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | − if (parser->global.logical_maximum < parser->global.logical_minimum) { | |
| 234 | − hid_err(parser->device, "logical range invalid %d %d\n", | |
| 235 | − parser->global.logical_minimum, parser->global.logical_maximum); | |
| 233 | + /* Handle both signed and unsigned cases properly */ | |
| 234 | + if ((parser->global.logical_minimum < 0 && | |
| 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 | 243 | return -1; |
| 237 | 244 | } |
| 238 | 245 | |
| @@ -1149,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, · 910 unmodified lines | ||
| 1149 | 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 | 1160 | int interrupt) |
| 1154 | 1161 | { |
| 1155 | 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, · 1 unmodified line | ||
| 1157 | 1164 | unsigned int a; |
| 1158 | 1165 | int rsize, csize = size; |
| 1159 | 1166 | u8 *cdata = data; |
| 1167 | + int ret = 0; | |
| 1160 | 1168 | |
| 1161 | 1169 | report = hid_get_report(report_enum, data); |
| 1162 | 1170 | if (!report) |
| 1163 | − return; | |
| 1171 | + goto out; | |
| 1164 | 1172 | |
| 1165 | 1173 | if (report_enum->numbered) { |
| 1166 | 1174 | cdata++; |
| @@ -1180,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, · 13 unmodified lines | ||
| 1180 | 1188 | |
| 1181 | 1189 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) |
| 1182 | 1190 | hid->hiddev_report_event(hid, report); |
| 1183 | − if (hid->claimed & HID_CLAIMED_HIDRAW) | |
| 1184 | − hidraw_report_event(hid, data, size); | |
| 1191 | + if (hid->claimed & HID_CLAIMED_HIDRAW) { | |
| 1192 | + ret = hidraw_report_event(hid, data, size); | |
| 1193 | + if (ret) | |
| 1194 | + goto out; | |
| 1195 | + } | |
| 1185 | 1196 | |
| 1186 | 1197 | for (a = 0; a < report->maxfield; a++) |
| 1187 | 1198 | hid_input_field(hid, report->field[a], cdata, interrupt); |
| 1188 | 1199 | |
| 1189 | 1200 | if (hid->claimed & HID_CLAIMED_INPUT) |
| 1190 | 1201 | hidinput_report_event(hid, report); |
| 1202 | +out: | |
| 1203 | + return ret; | |
| 1191 | 1204 | } |
| 1192 | 1205 | EXPORT_SYMBOL_GPL(hid_report_raw_event); |
| 1193 | 1206 | |
| @@ -1264,7 +1277,7 @@ nomem: · 70 unmodified lines | ||
| 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 | 1282 | unlock: |
| 1270 | 1283 | up(&hid->driver_lock); |
| @@ -1496,6 +1509,7 @@ static const struct hid_device_id hid_have_special_driver[] = { · 225 unmodified lines | ||
| 1496 | 1509 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, |
| 1497 | 1510 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, |
| 1498 | 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 | 1513 | { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, |
| 1500 | 1514 | { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), }, |
| 1501 | 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[] = { · 129 unmodified lines | ||
| 1631 | 1645 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, |
| 1632 | 1646 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, |
| 1633 | 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 | 1649 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, |
| 1635 | 1650 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, |
| 1636 | 1651 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, |
| @@ -154,6 +154,9 @@ · 153 unmodified lines | ||
| 154 | 154 | #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c |
| 155 | 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 | 160 | #define USB_VENDOR_ID_AVERMEDIA 0x07ca |
| 158 | 161 | #define USB_DEVICE_ID_AVER_FM_MR800 0xb800 |
| 159 | 162 | |
| @@ -729,6 +732,7 @@ · 569 unmodified lines | ||
| 729 | 732 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 |
| 730 | 733 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 |
| 731 | 734 | #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 |
| 735 | +#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 | |
| 732 | 736 | |
| 733 | 737 | #define USB_VENDOR_ID_UNITEC 0x227d |
| 734 | 738 | #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/device.h> |
| 15 | 15 | #include <linux/hid.h> |
| 16 | 16 | #include <linux/module.h> |
| 17 | +#include <linux/usb.h> | |
| 17 | 18 | |
| 18 | 19 | #include "hid-ids.h" |
| 19 | 20 | |
| @@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = { · 332 unmodified lines | ||
| 352 | 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 | 469 | static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
| 356 | 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 | 475 | switch (hdev->product) { |
| 359 | 476 | case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209: |
| 360 | 477 | if (*rsize == PF1209_RDESC_ORIG_SIZE) { |
| @@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, · 25 unmodified lines | ||
| 386 | 503 | *rsize = sizeof(wp1062_rdesc_fixed); |
| 387 | 504 | } |
| 388 | 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 | 530 | return rdesc; |
| @@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = { · 10 unmodified lines | ||
| 402 | 541 | USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, |
| 403 | 542 | { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, |
| 404 | 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 | 548 | MODULE_DEVICE_TABLE(hid, uclogic_devices); |
| @@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, · 86 unmodified lines | ||
| 87 | 87 | len = list->buffer[list->tail].len > count ? |
| 88 | 88 | count : list->buffer[list->tail].len; |
| 89 | 89 | |
| 90 | − if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { | |
| 91 | − ret = -EFAULT; | |
| 92 | − goto out; | |
| 90 | + if (list->buffer[list->tail].value) { | |
| 91 | + if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { | |
| 92 | + ret = -EFAULT; | |
| 93 | + goto out; | |
| 94 | + } | |
| 95 | + ret = len; | |
| 93 | 96 | } |
| 94 | − ret = len; | |
| 95 | 97 | |
| 96 | 98 | kfree(list->buffer[list->tail].value); |
| 97 | 99 | list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); |
| @@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = { · 339 unmodified lines | ||
| 437 | 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 | 444 | struct hidraw *dev = hid->hidraw; |
| 443 | 445 | struct hidraw_list *list; |
| 446 | + int ret = 0; | |
| 444 | 447 | |
| 445 | 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 | 453 | list->buffer[list->head].len = len; |
| 448 | 454 | list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); |
| 449 | 455 | kill_fasync(&list->fasync, SIGIO, POLL_IN); |
| 450 | 456 | } |
| 451 | 457 | |
| 452 | 458 | wake_up_interruptible(&dev->wait); |
| 459 | + return ret; | |
| 453 | 460 | } |
| 454 | 461 | EXPORT_SYMBOL_GPL(hidraw_report_event); |
| 455 | 462 | |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/input.h> |
| 29 | 29 | #include <linux/wait.h> |
| 30 | 30 | #include <linux/workqueue.h> |
| 31 | +#include <linux/string.h> | |
| 31 | 32 | |
| 32 | 33 | #include <linux/usb.h> |
| 33 | 34 | |
| @@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid) · 52 unmodified lines | ||
| 86 | 87 | !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && |
| 87 | 88 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { |
| 88 | 89 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); |
| 89 | − if (rc != 0) | |
| 90 | + if (rc != 0) { | |
| 90 | 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 | 98 | spin_unlock_irqrestore(&usbhid->lock, flags); |
| 93 | 99 | return rc; |
| @@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid) · 79 unmodified lines | ||
| 173 | 179 | |
| 174 | 180 | if (time_after(jiffies, usbhid->stop_retry)) { |
| 175 | 181 | |
| 176 | − /* Retries failed, so do a port reset */ | |
| 177 | − if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { | |
| 182 | + /* Retries failed, so do a port reset unless we lack bandwidth*/ | |
| 183 | + if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) | |
| 184 | + && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { | |
| 185 | + | |
| 178 | 186 | schedule_work(&usbhid->reset_work); |
| 179 | 187 | goto done; |
| 180 | 188 | } |
| @@ -700,7 +708,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, · 519 unmodified lines | ||
| 700 | 708 | int usbhid_open(struct hid_device *hid) |
| 701 | 709 | { |
| 702 | 710 | struct usbhid_device *usbhid = hid->driver_data; |
| 703 | − int res; | |
| 711 | + int res = 0; | |
| 704 | 712 | |
| 705 | 713 | mutex_lock(&hid_open_mut); |
| 706 | 714 | if (!hid->open++) { |
| @@ -708,17 +716,27 @@ int usbhid_open(struct hid_device *hid) · 1 unmodified line | ||
| 708 | 716 | /* the device must be awake to reliably request remote wakeup */ |
| 709 | 717 | if (res < 0) { |
| 710 | 718 | hid->open--; |
| 711 | − mutex_unlock(&hid_open_mut); | |
| 712 | − return -EIO; | |
| 719 | + res = -EIO; | |
| 720 | + goto done; | |
| 713 | 721 | } |
| 714 | 722 | usbhid->intf->needs_remote_wakeup = 1; |
| 715 | − if (hid_start_in(hid)) | |
| 716 | − hid_io_error(hid); | |
| 717 | − | |
| 723 | + res = hid_start_in(hid); | |
| 724 | + if (res) { | |
| 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 | 735 | usb_autopm_put_interface(usbhid->intf); |
| 719 | 736 | } |
| 737 | +done: | |
| 720 | 738 | mutex_unlock(&hid_open_mut); |
| 721 | − return 0; | |
| 739 | + return res; | |
| 722 | 740 | } |
| 723 | 741 | |
| 724 | 742 | void usbhid_close(struct hid_device *hid) |
| @@ -1347,7 +1365,34 @@ static int hid_post_reset(struct usb_interface *intf) · 622 unmodified lines | ||
| 1347 | 1365 | struct usb_device *dev = interface_to_usbdev (intf); |
| 1348 | 1366 | struct hid_device *hid = usb_get_intfdata(intf); |
| 1349 | 1367 | struct usbhid_device *usbhid = hid->driver_data; |
| 1368 | + struct usb_host_interface *interface = intf->cur_altsetting; | |
| 1350 | 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 | 1397 | spin_lock_irq(&usbhid->lock); |
| 1353 | 1398 | clear_bit(HID_RESET_PENDING, &usbhid->iofl); |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #include <linux/hid.h> |
| 35 | 35 | #include <linux/hiddev.h> |
| 36 | 36 | #include <linux/compat.h> |
| 37 | +#include <linux/vmalloc.h> | |
| 37 | 38 | #include "usbhid.h" |
| 38 | 39 | |
| 39 | 40 | #ifdef CONFIG_USB_DYNAMIC_MINORS |
| @@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file) · 210 unmodified lines | ||
| 250 | 251 | } else { |
| 251 | 252 | mutex_unlock(&list->hiddev->existancelock); |
| 252 | 253 | kfree(list->hiddev); |
| 253 | − kfree(list); | |
| 254 | + vfree(list); | |
| 254 | 255 | return 0; |
| 255 | 256 | } |
| 256 | 257 | } |
| 257 | 258 | |
| 258 | 259 | mutex_unlock(&list->hiddev->existancelock); |
| 259 | − kfree(list); | |
| 260 | + vfree(list); | |
| 260 | 261 | |
| 261 | 262 | return 0; |
| 262 | 263 | } |
| @@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file) · 15 unmodified lines | ||
| 278 | 279 | hid = usb_get_intfdata(intf); |
| 279 | 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 | 283 | return -ENOMEM; |
| 283 | 284 | mutex_init(&list->thread_lock); |
| 284 | 285 | list->hiddev = hiddev; |
| @@ -322,7 +323,7 @@ bail_unlock: · 37 unmodified lines | ||
| 322 | 323 | mutex_unlock(&hiddev->existancelock); |
| 323 | 324 | bail: |
| 324 | 325 | file->private_data = NULL; |
| 325 | − kfree(list); | |
| 326 | + vfree(list); | |
| 326 | 327 | return res; |
| 327 | 328 | } |
| 328 | 329 | |
| @@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor); · 54 unmodified lines | ||
| 55 | 55 | #define HID_STARTED 8 |
| 56 | 56 | #define HID_REPORTED_IDLE 9 |
| 57 | 57 | #define HID_KEYS_PRESSED 10 |
| 58 | +#define HID_NO_BANDWIDTH 11 | |
| 58 | 59 | |
| 59 | 60 | /* |
| 60 | 61 | * USB-specific HID struct, to be pointed to |
| @@ -896,7 +896,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level) · 895 unmodified lines | ||
| 896 | 896 | return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0; |
| 897 | 897 | } |
| 898 | 898 | |
| 899 | −void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, | |
| 899 | +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, | |
| 900 | 900 | int interrupt); |
| 901 | 901 | |
| 902 | 902 | extern int hid_generic_init(void); |
| @@ -76,13 +76,13 @@ struct hidraw_list { · 75 unmodified lines | ||
| 76 | 76 | #ifdef CONFIG_HIDRAW |
| 77 | 77 | int hidraw_init(void); |
| 78 | 78 | void hidraw_exit(void); |
| 79 | −void hidraw_report_event(struct hid_device *, u8 *, int); | |
| 79 | +int hidraw_report_event(struct hid_device *, u8 *, int); | |
| 80 | 80 | int hidraw_connect(struct hid_device *); |
| 81 | 81 | void hidraw_disconnect(struct hid_device *); |
| 82 | 82 | #else |
| 83 | 83 | static inline int hidraw_init(void) { return 0; } |
| 84 | 84 | static inline void hidraw_exit(void) { } |
| 85 | −static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { } | |
| 85 | +static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; } | |
| 86 | 86 | static inline int hidraw_connect(struct hid_device *hid) { return -1; } |
| 87 | 87 | static inline void hidraw_disconnect(struct hid_device *hid) { } |
| 88 | 88 | #endif |