aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-core.c19
-rw-r--r--drivers/hid/hid-debug.c2
-rw-r--r--drivers/hid/hid-input-quirks.c24
-rw-r--r--drivers/hid/usbhid/Kconfig12
-rw-r--r--drivers/hid/usbhid/Makefile3
-rw-r--r--drivers/hid/usbhid/hid-core.c69
-rw-r--r--drivers/hid/usbhid/hid-ff.c3
-rw-r--r--drivers/hid/usbhid/hid-lg2ff.c114
-rw-r--r--drivers/hid/usbhid/hid-quirks.c85
-rw-r--r--drivers/hid/usbhid/hiddev.c286
-rw-r--r--drivers/hid/usbhid/usbhid.h3
11 files changed, 417 insertions, 203 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index f0b00ec1e47e..e03c67dd3e63 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -44,8 +44,8 @@
44 44
45#ifdef CONFIG_HID_DEBUG 45#ifdef CONFIG_HID_DEBUG
46int hid_debug = 0; 46int hid_debug = 0;
47module_param_named(debug, hid_debug, bool, 0600); 47module_param_named(debug, hid_debug, int, 0600);
48MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off"); 48MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
49EXPORT_SYMBOL_GPL(hid_debug); 49EXPORT_SYMBOL_GPL(hid_debug);
50#endif 50#endif
51 51
@@ -97,7 +97,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
97 field->index = report->maxfield++; 97 field->index = report->maxfield++;
98 report->field[field->index] = field; 98 report->field[field->index] = field;
99 field->usage = (struct hid_usage *)(field + 1); 99 field->usage = (struct hid_usage *)(field + 1);
100 field->value = (unsigned *)(field->usage + usages); 100 field->value = (s32 *)(field->usage + usages);
101 field->report = report; 101 field->report = report;
102 102
103 return field; 103 return field;
@@ -830,7 +830,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
830 * reporting to the layer). 830 * reporting to the layer).
831 */ 831 */
832 832
833void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) 833static void hid_input_field(struct hid_device *hid, struct hid_field *field,
834 __u8 *data, int interrupt)
834{ 835{
835 unsigned n; 836 unsigned n;
836 unsigned count = field->report_count; 837 unsigned count = field->report_count;
@@ -876,7 +877,6 @@ void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data
876exit: 877exit:
877 kfree(value); 878 kfree(value);
878} 879}
879EXPORT_SYMBOL_GPL(hid_input_field);
880 880
881/* 881/*
882 * Output the field into the report. 882 * Output the field into the report.
@@ -988,8 +988,13 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
988 988
989 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) 989 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
990 hid->hiddev_report_event(hid, report); 990 hid->hiddev_report_event(hid, report);
991 if (hid->claimed & HID_CLAIMED_HIDRAW) 991 if (hid->claimed & HID_CLAIMED_HIDRAW) {
992 hidraw_report_event(hid, data, size); 992 /* numbered reports need to be passed with the report num */
993 if (report_enum->numbered)
994 hidraw_report_event(hid, data - 1, size + 1);
995 else
996 hidraw_report_event(hid, data, size);
997 }
993 998
994 for (n = 0; n < report->maxfield; n++) 999 for (n = 0; n < report->maxfield; n++)
995 hid_input_field(hid, report->field[n], data, interrupt); 1000 hid_input_field(hid, report->field[n], data, interrupt);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 5c24fe46d8eb..f88714b06000 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -498,7 +498,7 @@ void hid_dump_device(struct hid_device *device) {
498EXPORT_SYMBOL_GPL(hid_dump_device); 498EXPORT_SYMBOL_GPL(hid_dump_device);
499 499
500void hid_dump_input(struct hid_usage *usage, __s32 value) { 500void hid_dump_input(struct hid_usage *usage, __s32 value) {
501 if (!hid_debug) 501 if (hid_debug < 2)
502 return; 502 return;
503 503
504 printk(KERN_DEBUG "hid-debug: input "); 504 printk(KERN_DEBUG "hid-debug: input ");
diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
index dceadd0c1419..4c2052c658f1 100644
--- a/drivers/hid/hid-input-quirks.c
+++ b/drivers/hid/hid-input-quirks.c
@@ -276,6 +276,21 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
276 return 1; 276 return 1;
277} 277}
278 278
279static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
280 unsigned long **bit, int *max)
281{
282 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
283 return 0;
284
285 switch (usage->hid & HID_USAGE) {
286 case 0x2003: map_key_clear(KEY_ZOOMIN); break;
287 case 0x2103: map_key_clear(KEY_ZOOMOUT); break;
288 default:
289 return 0;
290 }
291 return 1;
292}
293
279#define VENDOR_ID_BELKIN 0x1020 294#define VENDOR_ID_BELKIN 0x1020
280#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 295#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006
281 296
@@ -306,6 +321,9 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
306#define VENDOR_ID_PETALYNX 0x18b1 321#define VENDOR_ID_PETALYNX 0x18b1
307#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 322#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
308 323
324#define VENDOR_ID_SUNPLUS 0x04fc
325#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
326
309static const struct hid_input_blacklist { 327static const struct hid_input_blacklist {
310 __u16 idVendor; 328 __u16 idVendor;
311 __u16 idProduct; 329 __u16 idProduct;
@@ -332,8 +350,10 @@ static const struct hid_input_blacklist {
332 { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, 350 { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
333 351
334 { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, 352 { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
335 353
336 { 0, 0, 0 } 354 { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
355
356 { 0, 0, NULL }
337}; 357};
338 358
339int hidinput_mapping_quirks(struct hid_usage *usage, 359int hidinput_mapping_quirks(struct hid_usage *usage,
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 7160fa65d79b..18f09104765c 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -71,6 +71,14 @@ config LOGITECH_FF
71 Note: if you say N here, this device will still be supported, but without 71 Note: if you say N here, this device will still be supported, but without
72 force feedback. 72 force feedback.
73 73
74config LOGIRUMBLEPAD2_FF
75 bool "Logitech Rumblepad 2 support"
76 depends on HID_FF
77 select INPUT_FF_MEMLESS if USB_HID
78 help
79 Say Y here if you want to enable force feedback support for Logitech
80 Rumblepad 2 devices.
81
74config PANTHERLORD_FF 82config PANTHERLORD_FF
75 bool "PantherLord/GreenAsia based device support" 83 bool "PantherLord/GreenAsia based device support"
76 depends on HID_FF 84 depends on HID_FF
@@ -80,8 +88,8 @@ config PANTHERLORD_FF
80 or adapter and want to enable force feedback support for it. 88 or adapter and want to enable force feedback support for it.
81 89
82config THRUSTMASTER_FF 90config THRUSTMASTER_FF
83 bool "ThrustMaster devices support (EXPERIMENTAL)" 91 bool "ThrustMaster devices support"
84 depends on HID_FF && EXPERIMENTAL 92 depends on HID_FF
85 select INPUT_FF_MEMLESS if USB_HID 93 select INPUT_FF_MEMLESS if USB_HID
86 help 94 help
87 Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 95 Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 8e6ab5b164a2..00a7b7090192 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -16,6 +16,9 @@ endif
16ifeq ($(CONFIG_LOGITECH_FF),y) 16ifeq ($(CONFIG_LOGITECH_FF),y)
17 usbhid-objs += hid-lgff.o 17 usbhid-objs += hid-lgff.o
18endif 18endif
19ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
20 usbhid-objs += hid-lg2ff.o
21endif
19ifeq ($(CONFIG_PANTHERLORD_FF),y) 22ifeq ($(CONFIG_PANTHERLORD_FF),y)
20 usbhid-objs += hid-plff.o 23 usbhid-objs += hid-plff.o
21endif 24endif
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index d95979f0e028..e0d805f1b2bf 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -82,6 +82,7 @@ static int hid_start_in(struct hid_device *hid)
82 82
83 spin_lock_irqsave(&usbhid->inlock, flags); 83 spin_lock_irqsave(&usbhid->inlock, flags);
84 if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && 84 if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
85 !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
85 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { 86 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
86 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); 87 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
87 if (rc != 0) 88 if (rc != 0)
@@ -155,7 +156,7 @@ static void hid_io_error(struct hid_device *hid)
155 spin_lock_irqsave(&usbhid->inlock, flags); 156 spin_lock_irqsave(&usbhid->inlock, flags);
156 157
157 /* Stop when disconnected */ 158 /* Stop when disconnected */
158 if (usb_get_intfdata(usbhid->intf) == NULL) 159 if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
159 goto done; 160 goto done;
160 161
161 /* If it has been a while since the last error, we'll assume 162 /* If it has been a while since the last error, we'll assume
@@ -341,7 +342,7 @@ static void hid_irq_out(struct urb *urb)
341 if (usbhid->outhead != usbhid->outtail) { 342 if (usbhid->outhead != usbhid->outtail) {
342 if (hid_submit_out(hid)) { 343 if (hid_submit_out(hid)) {
343 clear_bit(HID_OUT_RUNNING, &usbhid->iofl); 344 clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
344 wake_up(&hid->wait); 345 wake_up(&usbhid->wait);
345 } 346 }
346 spin_unlock_irqrestore(&usbhid->outlock, flags); 347 spin_unlock_irqrestore(&usbhid->outlock, flags);
347 return; 348 return;
@@ -349,7 +350,7 @@ static void hid_irq_out(struct urb *urb)
349 350
350 clear_bit(HID_OUT_RUNNING, &usbhid->iofl); 351 clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
351 spin_unlock_irqrestore(&usbhid->outlock, flags); 352 spin_unlock_irqrestore(&usbhid->outlock, flags);
352 wake_up(&hid->wait); 353 wake_up(&usbhid->wait);
353} 354}
354 355
355/* 356/*
@@ -391,7 +392,7 @@ static void hid_ctrl(struct urb *urb)
391 if (usbhid->ctrlhead != usbhid->ctrltail) { 392 if (usbhid->ctrlhead != usbhid->ctrltail) {
392 if (hid_submit_ctrl(hid)) { 393 if (hid_submit_ctrl(hid)) {
393 clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); 394 clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
394 wake_up(&hid->wait); 395 wake_up(&usbhid->wait);
395 } 396 }
396 spin_unlock_irqrestore(&usbhid->ctrllock, flags); 397 spin_unlock_irqrestore(&usbhid->ctrllock, flags);
397 return; 398 return;
@@ -399,7 +400,7 @@ static void hid_ctrl(struct urb *urb)
399 400
400 clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); 401 clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
401 spin_unlock_irqrestore(&usbhid->ctrllock, flags); 402 spin_unlock_irqrestore(&usbhid->ctrllock, flags);
402 wake_up(&hid->wait); 403 wake_up(&usbhid->wait);
403} 404}
404 405
405void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) 406void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
@@ -478,8 +479,9 @@ int usbhid_wait_io(struct hid_device *hid)
478{ 479{
479 struct usbhid_device *usbhid = hid->driver_data; 480 struct usbhid_device *usbhid = hid->driver_data;
480 481
481 if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && 482 if (!wait_event_timeout(usbhid->wait,
482 !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 483 (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
484 !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
483 10*HZ)) { 485 10*HZ)) {
484 dbg_hid("timeout waiting for ctrl or out queue to clear\n"); 486 dbg_hid("timeout waiting for ctrl or out queue to clear\n");
485 return -1; 487 return -1;
@@ -610,10 +612,11 @@ static void usbhid_set_leds(struct hid_device *hid)
610/* 612/*
611 * Traverse the supplied list of reports and find the longest 613 * Traverse the supplied list of reports and find the longest
612 */ 614 */
613static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max) 615static void hid_find_max_report(struct hid_device *hid, unsigned int type,
616 unsigned int *max)
614{ 617{
615 struct hid_report *report; 618 struct hid_report *report;
616 int size; 619 unsigned int size;
617 620
618 list_for_each_entry(report, &hid->report_enum[type].report_list, list) { 621 list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
619 size = ((report->size - 1) >> 3) + 1; 622 size = ((report->size - 1) >> 3) + 1;
@@ -705,9 +708,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
705 struct hid_descriptor *hdesc; 708 struct hid_descriptor *hdesc;
706 struct hid_device *hid; 709 struct hid_device *hid;
707 u32 quirks = 0; 710 u32 quirks = 0;
708 unsigned rsize = 0; 711 unsigned int insize = 0, rsize = 0;
709 char *rdesc; 712 char *rdesc;
710 int n, len, insize = 0; 713 int n, len;
711 struct usbhid_device *usbhid; 714 struct usbhid_device *usbhid;
712 715
713 quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), 716 quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
@@ -800,6 +803,22 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
800 goto fail; 803 goto fail;
801 } 804 }
802 805
806 hid->name[0] = 0;
807
808 if (dev->manufacturer)
809 strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
810
811 if (dev->product) {
812 if (dev->manufacturer)
813 strlcat(hid->name, " ", sizeof(hid->name));
814 strlcat(hid->name, dev->product, sizeof(hid->name));
815 }
816
817 if (!strlen(hid->name))
818 snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
819 le16_to_cpu(dev->descriptor.idVendor),
820 le16_to_cpu(dev->descriptor.idProduct));
821
803 for (n = 0; n < interface->desc.bNumEndpoints; n++) { 822 for (n = 0; n < interface->desc.bNumEndpoints; n++) {
804 823
805 struct usb_endpoint_descriptor *endpoint; 824 struct usb_endpoint_descriptor *endpoint;
@@ -812,6 +831,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
812 831
813 interval = endpoint->bInterval; 832 interval = endpoint->bInterval;
814 833
834 /* Some vendors give fullspeed interval on highspeed devides */
835 if (quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
836 dev->speed == USB_SPEED_HIGH) {
837 interval = fls(endpoint->bInterval*8);
838 printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
839 hid->name, endpoint->bInterval, interval);
840 }
841
815 /* Change the polling interval of mice. */ 842 /* Change the polling interval of mice. */
816 if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) 843 if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
817 interval = hid_mousepoll_interval; 844 interval = hid_mousepoll_interval;
@@ -844,8 +871,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
844 goto fail; 871 goto fail;
845 } 872 }
846 873
847 init_waitqueue_head(&hid->wait); 874 init_waitqueue_head(&usbhid->wait);
848
849 INIT_WORK(&usbhid->reset_work, hid_reset); 875 INIT_WORK(&usbhid->reset_work, hid_reset);
850 setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); 876 setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
851 877
@@ -859,22 +885,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
859 usbhid->intf = intf; 885 usbhid->intf = intf;
860 usbhid->ifnum = interface->desc.bInterfaceNumber; 886 usbhid->ifnum = interface->desc.bInterfaceNumber;
861 887
862 hid->name[0] = 0;
863
864 if (dev->manufacturer)
865 strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
866
867 if (dev->product) {
868 if (dev->manufacturer)
869 strlcat(hid->name, " ", sizeof(hid->name));
870 strlcat(hid->name, dev->product, sizeof(hid->name));
871 }
872
873 if (!strlen(hid->name))
874 snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
875 le16_to_cpu(dev->descriptor.idVendor),
876 le16_to_cpu(dev->descriptor.idProduct));
877
878 hid->bus = BUS_USB; 888 hid->bus = BUS_USB;
879 hid->vendor = le16_to_cpu(dev->descriptor.idVendor); 889 hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
880 hid->product = le16_to_cpu(dev->descriptor.idProduct); 890 hid->product = le16_to_cpu(dev->descriptor.idProduct);
@@ -932,6 +942,7 @@ static void hid_disconnect(struct usb_interface *intf)
932 942
933 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ 943 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
934 usb_set_intfdata(intf, NULL); 944 usb_set_intfdata(intf, NULL);
945 set_bit(HID_DISCONNECTED, &usbhid->iofl);
935 spin_unlock_irq(&usbhid->inlock); 946 spin_unlock_irq(&usbhid->inlock);
936 usb_kill_urb(usbhid->urbin); 947 usb_kill_urb(usbhid->urbin);
937 usb_kill_urb(usbhid->urbout); 948 usb_kill_urb(usbhid->urbout);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
index 4c210e16b1b4..1d0dac52f166 100644
--- a/drivers/hid/usbhid/hid-ff.c
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -59,6 +59,9 @@ static struct hid_ff_initializer inits[] = {
59 { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ 59 { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
60 { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ 60 { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
61#endif 61#endif
62#ifdef CONFIG_LOGIRUMBLEPAD2_FF
63 { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
64#endif
62#ifdef CONFIG_PANTHERLORD_FF 65#ifdef CONFIG_PANTHERLORD_FF
63 { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ 66 { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
64 { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ 67 { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/usbhid/hid-lg2ff.c
new file mode 100644
index 000000000000..d469bd0061c9
--- /dev/null
+++ b/drivers/hid/usbhid/hid-lg2ff.c
@@ -0,0 +1,114 @@
1/*
2 * Force feedback support for Logitech Rumblepad 2
3 *
4 * Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24#include <linux/input.h>
25#include <linux/usb.h>
26#include <linux/hid.h>
27#include "usbhid.h"
28
29struct lg2ff_device {
30 struct hid_report *report;
31};
32
33static int play_effect(struct input_dev *dev, void *data,
34 struct ff_effect *effect)
35{
36 struct hid_device *hid = input_get_drvdata(dev);
37 struct lg2ff_device *lg2ff = data;
38 int weak, strong;
39
40 strong = effect->u.rumble.strong_magnitude;
41 weak = effect->u.rumble.weak_magnitude;
42
43 if (weak || strong) {
44 weak = weak * 0xff / 0xffff;
45 strong = strong * 0xff / 0xffff;
46
47 lg2ff->report->field[0]->value[0] = 0x51;
48 lg2ff->report->field[0]->value[2] = weak;
49 lg2ff->report->field[0]->value[4] = strong;
50 } else {
51 lg2ff->report->field[0]->value[0] = 0xf3;
52 lg2ff->report->field[0]->value[2] = 0x00;
53 lg2ff->report->field[0]->value[4] = 0x00;
54 }
55
56 usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
57 return 0;
58}
59
60int hid_lg2ff_init(struct hid_device *hid)
61{
62 struct lg2ff_device *lg2ff;
63 struct hid_report *report;
64 struct hid_input *hidinput = list_entry(hid->inputs.next,
65 struct hid_input, list);
66 struct list_head *report_list =
67 &hid->report_enum[HID_OUTPUT_REPORT].report_list;
68 struct input_dev *dev = hidinput->input;
69 int error;
70
71 if (list_empty(report_list)) {
72 printk(KERN_ERR "hid-lg2ff: no output report found\n");
73 return -ENODEV;
74 }
75
76 report = list_entry(report_list->next, struct hid_report, list);
77
78 if (report->maxfield < 1) {
79 printk(KERN_ERR "hid-lg2ff: output report is empty\n");
80 return -ENODEV;
81 }
82 if (report->field[0]->report_count < 7) {
83 printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
84 return -ENODEV;
85 }
86
87 lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
88 if (!lg2ff)
89 return -ENOMEM;
90
91 set_bit(FF_RUMBLE, dev->ffbit);
92
93 error = input_ff_create_memless(dev, lg2ff, play_effect);
94 if (error) {
95 kfree(lg2ff);
96 return error;
97 }
98
99 lg2ff->report = report;
100 report->field[0]->value[0] = 0xf3;
101 report->field[0]->value[1] = 0x00;
102 report->field[0]->value[2] = 0x00;
103 report->field[0]->value[3] = 0x00;
104 report->field[0]->value[4] = 0x00;
105 report->field[0]->value[5] = 0x00;
106 report->field[0]->value[6] = 0x00;
107
108 usbhid_submit_report(hid, report, USB_DIR_OUT);
109
110 printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
111 "Anssi Hannula <anssi.hannula@gmail.com>\n");
112
113 return 0;
114}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 17b2f49675d8..d3f8d9194f30 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -32,6 +32,9 @@
32#define USB_VENDOR_ID_ADS_TECH 0x06e1 32#define USB_VENDOR_ID_ADS_TECH 0x06e1
33#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 33#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
34 34
35#define USB_VENDOR_ID_AFATECH 0x15a4
36#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
37
35#define USB_VENDOR_ID_AIPTEK 0x08ca 38#define USB_VENDOR_ID_AIPTEK 0x08ca
36#define USB_DEVICE_ID_AIPTEK_01 0x0001 39#define USB_DEVICE_ID_AIPTEK_01 0x0001
37#define USB_DEVICE_ID_AIPTEK_10 0x0010 40#define USB_DEVICE_ID_AIPTEK_10 0x0010
@@ -124,6 +127,9 @@
124#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 127#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
125#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 128#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
126 129
130#define USB_VENDOR_ID_DMI 0x0c0b
131#define USB_DEVICE_ID_DMI_ENC 0x5fab
132
127#define USB_VENDOR_ID_ELO 0x04E7 133#define USB_VENDOR_ID_ELO 0x04E7
128#define USB_DEVICE_ID_ELO_TS2700 0x0020 134#define USB_DEVICE_ID_ELO_TS2700 0x0020
129 135
@@ -199,17 +205,6 @@
199#define USB_DEVICE_ID_GTCO_502 0x0502 205#define USB_DEVICE_ID_GTCO_502 0x0502
200#define USB_DEVICE_ID_GTCO_503 0x0503 206#define USB_DEVICE_ID_GTCO_503 0x0503
201#define USB_DEVICE_ID_GTCO_504 0x0504 207#define USB_DEVICE_ID_GTCO_504 0x0504
202#define USB_DEVICE_ID_GTCO_600 0x0600
203#define USB_DEVICE_ID_GTCO_601 0x0601
204#define USB_DEVICE_ID_GTCO_602 0x0602
205#define USB_DEVICE_ID_GTCO_603 0x0603
206#define USB_DEVICE_ID_GTCO_604 0x0604
207#define USB_DEVICE_ID_GTCO_605 0x0605
208#define USB_DEVICE_ID_GTCO_606 0x0606
209#define USB_DEVICE_ID_GTCO_607 0x0607
210#define USB_DEVICE_ID_GTCO_608 0x0608
211#define USB_DEVICE_ID_GTCO_609 0x0609
212#define USB_DEVICE_ID_GTCO_609 0x0609
213#define USB_DEVICE_ID_GTCO_1000 0x1000 208#define USB_DEVICE_ID_GTCO_1000 0x1000
214#define USB_DEVICE_ID_GTCO_1001 0x1001 209#define USB_DEVICE_ID_GTCO_1001 0x1001
215#define USB_DEVICE_ID_GTCO_1002 0x1002 210#define USB_DEVICE_ID_GTCO_1002 0x1002
@@ -320,6 +315,7 @@
320#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 315#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
321#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 316#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
322#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 317#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
318#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
323 319
324#define USB_VENDOR_ID_MCC 0x09db 320#define USB_VENDOR_ID_MCC 0x09db
325#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 321#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
@@ -332,6 +328,7 @@
332#define USB_VENDOR_ID_MICROSOFT 0x045e 328#define USB_VENDOR_ID_MICROSOFT 0x045e
333#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b 329#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
334#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d 330#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
331#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
335#define USB_DEVICE_ID_MS_NE4K 0x00db 332#define USB_DEVICE_ID_MS_NE4K 0x00db
336#define USB_DEVICE_ID_MS_LK6K 0x00f9 333#define USB_DEVICE_ID_MS_LK6K 0x00f9
337 334
@@ -377,6 +374,9 @@
377#define USB_VENDOR_ID_SUN 0x0430 374#define USB_VENDOR_ID_SUN 0x0430
378#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab 375#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
379 376
377#define USB_VENDOR_ID_SUNPLUS 0x04fc
378#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
379
380#define USB_VENDOR_ID_TOPMAX 0x0663 380#define USB_VENDOR_ID_TOPMAX 0x0663
381#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 381#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
382 382
@@ -438,9 +438,13 @@ static const struct hid_blacklist {
438 { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, 438 { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
439 439
440 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, 440 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
441 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
442
443 { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
441 444
442 { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, 445 { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
443 { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, 446 { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
447 { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
444 { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, 448 { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
445 449
446 { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT }, 450 { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
@@ -521,16 +525,6 @@ static const struct hid_blacklist {
521 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE }, 525 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
522 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE }, 526 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
523 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE }, 527 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
524 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_600, HID_QUIRK_IGNORE },
525 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_601, HID_QUIRK_IGNORE },
526 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_602, HID_QUIRK_IGNORE },
527 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_603, HID_QUIRK_IGNORE },
528 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_604, HID_QUIRK_IGNORE },
529 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_605, HID_QUIRK_IGNORE },
530 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_606, HID_QUIRK_IGNORE },
531 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_607, HID_QUIRK_IGNORE },
532 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_608, HID_QUIRK_IGNORE },
533 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_609, HID_QUIRK_IGNORE },
534 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE }, 528 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
535 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE }, 529 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
536 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE }, 530 { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
@@ -604,6 +598,7 @@ static const struct hid_blacklist {
604 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, 598 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
605 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, 599 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
606 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, 600 { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
601 { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
607 { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, 602 { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
608 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET }, 603 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
609 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, 604 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
@@ -611,7 +606,7 @@ static const struct hid_blacklist {
611 { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, 606 { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
612 { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, 607 { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
613 { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, 608 { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
614 { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, 609 { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
615 { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, 610 { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
616 611
617 { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, 612 { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -723,6 +718,7 @@ static const struct hid_rdesc_blacklist {
723 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, 718 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
724 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, 719 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
725 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, 720 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
721 { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
726 722
727 { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, 723 { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
728 724
@@ -732,6 +728,8 @@ static const struct hid_rdesc_blacklist {
732 728
733 { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, 729 { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
734 730
731 { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
732
735 { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, 733 { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
736 { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, 734 { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
737 735
@@ -797,8 +795,8 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
797 * 795 *
798 * Returns: 0 OK, -error on failure. 796 * Returns: 0 OK, -error on failure.
799 */ 797 */
800int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, 798static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
801 const u32 quirks) 799 const u32 quirks)
802{ 800{
803 struct quirks_list_struct *q_new, *q; 801 struct quirks_list_struct *q_new, *q;
804 int list_edited = 0; 802 int list_edited = 0;
@@ -1006,6 +1004,17 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
1006 } 1004 }
1007} 1005}
1008 1006
1007static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
1008{
1009 if (rsize >= 107 && rdesc[104] == 0x26
1010 && rdesc[105] == 0x80
1011 && rdesc[106] == 0x03) {
1012 printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
1013 rdesc[105] = rdesc[110] = 0x03;
1014 rdesc[106] = rdesc[111] = 0x21;
1015 }
1016}
1017
1009/* 1018/*
1010 * Samsung IrDA remote controller (reports as Cypress USB Mouse). 1019 * Samsung IrDA remote controller (reports as Cypress USB Mouse).
1011 * 1020 *
@@ -1093,6 +1102,28 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs
1093 } 1102 }
1094} 1103}
1095 1104
1105/*
1106 * Microsoft Wireless Desktop Receiver (Model 1028) has several
1107 * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
1108 */
1109static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
1110{
1111 if (rsize == 571 && rdesc[284] == 0x19
1112 && rdesc[286] == 0x2a
1113 && rdesc[304] == 0x19
1114 && rdesc[306] == 0x29
1115 && rdesc[352] == 0x1a
1116 && rdesc[355] == 0x2a
1117 && rdesc[557] == 0x19
1118 && rdesc[559] == 0x29) {
1119 printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
1120 rdesc[284] = rdesc[304] = rdesc[558] = 0x35;
1121 rdesc[352] = 0x36;
1122 rdesc[286] = rdesc[355] = 0x46;
1123 rdesc[306] = rdesc[559] = 0x45;
1124 }
1125}
1126
1096static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) 1127static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
1097{ 1128{
1098 if ((quirks & HID_QUIRK_RDESC_CYMOTION)) 1129 if ((quirks & HID_QUIRK_RDESC_CYMOTION))
@@ -1116,6 +1147,11 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
1116 if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) 1147 if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
1117 usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); 1148 usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
1118 1149
1150 if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
1151 usbhid_fixup_microsoft_descriptor(rdesc, rsize);
1152
1153 if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
1154 usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
1119} 1155}
1120 1156
1121/** 1157/**
@@ -1154,5 +1190,4 @@ void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
1154 else if (paramVendor == idVendor && paramProduct == idProduct) 1190 else if (paramVendor == idVendor && paramProduct == idProduct)
1155 __usbhid_fixup_report_descriptor(quirks, rdesc, rsize); 1191 __usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
1156 } 1192 }
1157
1158} 1193}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 5fc4019956ba..95cc192bc7af 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
393/* 393/*
394 * "ioctl" file op 394 * "ioctl" file op
395 */ 395 */
396static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
397{
398 struct hid_device *hid = hiddev->hid;
399 struct hiddev_report_info rinfo;
400 struct hiddev_usage_ref_multi *uref_multi = NULL;
401 struct hiddev_usage_ref *uref;
402 struct hid_report *report;
403 struct hid_field *field;
404 int i;
405
406 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
407 if (!uref_multi)
408 return -ENOMEM;
409 uref = &uref_multi->uref;
410 if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
411 if (copy_from_user(uref_multi, user_arg,
412 sizeof(*uref_multi)))
413 goto fault;
414 } else {
415 if (copy_from_user(uref, user_arg, sizeof(*uref)))
416 goto fault;
417 }
418
419 switch (cmd) {
420 case HIDIOCGUCODE:
421 rinfo.report_type = uref->report_type;
422 rinfo.report_id = uref->report_id;
423 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
424 goto inval;
425
426 if (uref->field_index >= report->maxfield)
427 goto inval;
428
429 field = report->field[uref->field_index];
430 if (uref->usage_index >= field->maxusage)
431 goto inval;
432
433 uref->usage_code = field->usage[uref->usage_index].hid;
434
435 if (copy_to_user(user_arg, uref, sizeof(*uref)))
436 goto fault;
437
438 kfree(uref_multi);
439 return 0;
440
441 default:
442 if (cmd != HIDIOCGUSAGE &&
443 cmd != HIDIOCGUSAGES &&
444 uref->report_type == HID_REPORT_TYPE_INPUT)
445 goto inval;
446
447 if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
448 field = hiddev_lookup_usage(hid, uref);
449 if (field == NULL)
450 goto inval;
451 } else {
452 rinfo.report_type = uref->report_type;
453 rinfo.report_id = uref->report_id;
454 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
455 goto inval;
456
457 if (uref->field_index >= report->maxfield)
458 goto inval;
459
460 field = report->field[uref->field_index];
461
462 if (cmd == HIDIOCGCOLLECTIONINDEX) {
463 if (uref->usage_index >= field->maxusage)
464 goto inval;
465 } else if (uref->usage_index >= field->report_count)
466 goto inval;
467
468 else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
469 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
470 uref->usage_index + uref_multi->num_values > field->report_count))
471 goto inval;
472 }
473
474 switch (cmd) {
475 case HIDIOCGUSAGE:
476 uref->value = field->value[uref->usage_index];
477 if (copy_to_user(user_arg, uref, sizeof(*uref)))
478 goto fault;
479 goto goodreturn;
480
481 case HIDIOCSUSAGE:
482 field->value[uref->usage_index] = uref->value;
483 goto goodreturn;
484
485 case HIDIOCGCOLLECTIONINDEX:
486 kfree(uref_multi);
487 return field->usage[uref->usage_index].collection_index;
488 case HIDIOCGUSAGES:
489 for (i = 0; i < uref_multi->num_values; i++)
490 uref_multi->values[i] =
491 field->value[uref->usage_index + i];
492 if (copy_to_user(user_arg, uref_multi,
493 sizeof(*uref_multi)))
494 goto fault;
495 goto goodreturn;
496 case HIDIOCSUSAGES:
497 for (i = 0; i < uref_multi->num_values; i++)
498 field->value[uref->usage_index + i] =
499 uref_multi->values[i];
500 goto goodreturn;
501 }
502
503goodreturn:
504 kfree(uref_multi);
505 return 0;
506fault:
507 kfree(uref_multi);
508 return -EFAULT;
509inval:
510 kfree(uref_multi);
511 return -EINVAL;
512 }
513}
514
515static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
516{
517 struct hid_device *hid = hiddev->hid;
518 struct usb_device *dev = hid_to_usb_dev(hid);
519 int idx, len;
520 char *buf;
521
522 if (get_user(idx, (int __user *)user_arg))
523 return -EFAULT;
524
525 if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
526 return -ENOMEM;
527
528 if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
529 kfree(buf);
530 return -EINVAL;
531 }
532
533 if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
534 kfree(buf);
535 return -EFAULT;
536 }
537
538 kfree(buf);
539
540 return len;
541}
542
396static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 543static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
397{ 544{
398 struct hiddev_list *list = file->private_data; 545 struct hiddev_list *list = file->private_data;
@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
402 struct hiddev_collection_info cinfo; 549 struct hiddev_collection_info cinfo;
403 struct hiddev_report_info rinfo; 550 struct hiddev_report_info rinfo;
404 struct hiddev_field_info finfo; 551 struct hiddev_field_info finfo;
405 struct hiddev_usage_ref_multi *uref_multi = NULL;
406 struct hiddev_usage_ref *uref;
407 struct hiddev_devinfo dinfo; 552 struct hiddev_devinfo dinfo;
408 struct hid_report *report; 553 struct hid_report *report;
409 struct hid_field *field; 554 struct hid_field *field;
@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
470 } 615 }
471 616
472 case HIDIOCGSTRING: 617 case HIDIOCGSTRING:
473 { 618 return hiddev_ioctl_string(hiddev, cmd, user_arg);
474 int idx, len;
475 char *buf;
476
477 if (get_user(idx, (int __user *)arg))
478 return -EFAULT;
479
480 if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
481 return -ENOMEM;
482
483 if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
484 kfree(buf);
485 return -EINVAL;
486 }
487
488 if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
489 kfree(buf);
490 return -EFAULT;
491 }
492
493 kfree(buf);
494
495 return len;
496 }
497 619
498 case HIDIOCINITREPORT: 620 case HIDIOCINITREPORT:
499 usbhid_init_reports(hid); 621 usbhid_init_reports(hid);
@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
578 return 0; 700 return 0;
579 701
580 case HIDIOCGUCODE: 702 case HIDIOCGUCODE:
581 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 703 /* fall through */
582 if (!uref_multi)
583 return -ENOMEM;
584 uref = &uref_multi->uref;
585 if (copy_from_user(uref, user_arg, sizeof(*uref)))
586 goto fault;
587
588 rinfo.report_type = uref->report_type;
589 rinfo.report_id = uref->report_id;
590 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
591 goto inval;
592
593 if (uref->field_index >= report->maxfield)
594 goto inval;
595
596 field = report->field[uref->field_index];
597 if (uref->usage_index >= field->maxusage)
598 goto inval;
599
600 uref->usage_code = field->usage[uref->usage_index].hid;
601
602 if (copy_to_user(user_arg, uref, sizeof(*uref)))
603 goto fault;
604
605 kfree(uref_multi);
606 return 0;
607
608 case HIDIOCGUSAGE: 704 case HIDIOCGUSAGE:
609 case HIDIOCSUSAGE: 705 case HIDIOCSUSAGE:
610 case HIDIOCGUSAGES: 706 case HIDIOCGUSAGES:
611 case HIDIOCSUSAGES: 707 case HIDIOCSUSAGES:
612 case HIDIOCGCOLLECTIONINDEX: 708 case HIDIOCGCOLLECTIONINDEX:
613 uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); 709 return hiddev_ioctl_usage(hiddev, cmd, user_arg);
614 if (!uref_multi)
615 return -ENOMEM;
616 uref = &uref_multi->uref;
617 if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
618 if (copy_from_user(uref_multi, user_arg,
619 sizeof(*uref_multi)))
620 goto fault;
621 } else {
622 if (copy_from_user(uref, user_arg, sizeof(*uref)))
623 goto fault;
624 }
625
626 if (cmd != HIDIOCGUSAGE &&
627 cmd != HIDIOCGUSAGES &&
628 uref->report_type == HID_REPORT_TYPE_INPUT)
629 goto inval;
630
631 if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
632 field = hiddev_lookup_usage(hid, uref);
633 if (field == NULL)
634 goto inval;
635 } else {
636 rinfo.report_type = uref->report_type;
637 rinfo.report_id = uref->report_id;
638 if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
639 goto inval;
640
641 if (uref->field_index >= report->maxfield)
642 goto inval;
643
644 field = report->field[uref->field_index];
645
646 if (cmd == HIDIOCGCOLLECTIONINDEX) {
647 if (uref->usage_index >= field->maxusage)
648 goto inval;
649 } else if (uref->usage_index >= field->report_count)
650 goto inval;
651
652 else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
653 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
654 uref->usage_index + uref_multi->num_values > field->report_count))
655 goto inval;
656 }
657
658 switch (cmd) {
659 case HIDIOCGUSAGE:
660 uref->value = field->value[uref->usage_index];
661 if (copy_to_user(user_arg, uref, sizeof(*uref)))
662 goto fault;
663 goto goodreturn;
664
665 case HIDIOCSUSAGE:
666 field->value[uref->usage_index] = uref->value;
667 goto goodreturn;
668
669 case HIDIOCGCOLLECTIONINDEX:
670 kfree(uref_multi);
671 return field->usage[uref->usage_index].collection_index;
672 case HIDIOCGUSAGES:
673 for (i = 0; i < uref_multi->num_values; i++)
674 uref_multi->values[i] =
675 field->value[uref->usage_index + i];
676 if (copy_to_user(user_arg, uref_multi,
677 sizeof(*uref_multi)))
678 goto fault;
679 goto goodreturn;
680 case HIDIOCSUSAGES:
681 for (i = 0; i < uref_multi->num_values; i++)
682 field->value[uref->usage_index + i] =
683 uref_multi->values[i];
684 goto goodreturn;
685 }
686
687goodreturn:
688 kfree(uref_multi);
689 return 0;
690fault:
691 kfree(uref_multi);
692 return -EFAULT;
693inval:
694 kfree(uref_multi);
695 return -EINVAL;
696 710
697 case HIDIOCGCOLLECTIONINFO: 711 case HIDIOCGCOLLECTIONINFO:
698 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) 712 if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 0023f96d4294..62d2d7c925bd 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -28,6 +28,7 @@
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/list.h> 29#include <linux/list.h>
30#include <linux/timer.h> 30#include <linux/timer.h>
31#include <linux/wait.h>
31#include <linux/workqueue.h> 32#include <linux/workqueue.h>
32#include <linux/input.h> 33#include <linux/input.h>
33 34
@@ -77,7 +78,7 @@ struct usbhid_device {
77 unsigned long stop_retry; /* Time to give up, in jiffies */ 78 unsigned long stop_retry; /* Time to give up, in jiffies */
78 unsigned int retry_delay; /* Delay length in ms */ 79 unsigned int retry_delay; /* Delay length in ms */
79 struct work_struct reset_work; /* Task context for resets */ 80 struct work_struct reset_work; /* Task context for resets */
80 81 wait_queue_head_t wait; /* For sleeping */
81}; 82};
82 83
83#define hid_to_usb_dev(hid_dev) \ 84#define hid_to_usb_dev(hid_dev) \