diff options
author | Jiri Kosina <jkosina@suse.cz> | 2007-02-21 13:27:49 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2007-03-01 03:52:45 -0500 |
commit | b55fd23ccdf32f969a7b4180c6e52d62d8e99972 (patch) | |
tree | 307897845c80f2bf61ec9d870dc95dc2c0224658 | |
parent | 776c0e96edecf77f827a62d2a1641cc2ca479043 (diff) |
HID: fix broken Logitech S510 keyboard report descriptor; make extra keys work
This patch makes extra keys (F1-F12 in special mode, zooming, rotate, shuffle)
on Logitech S510 keyboard work.
Logitech S510 keyboard sends in report no. 3 keys which are far above the
logical maximum described in descriptor for given report.
This patch introduces a HID quirk for this wireless USB receiver/keyboard
in order to fix the report descriptor before it's being parsed - the logical
maximum and the number of usages is bumped up to 0x104d). The values are in the
"Reserved" area of consumer HUT, so HID_MAX_USAGE had to be changed too.
In addition to proper extracting of the values from report descriptor, proper
HID-input mapping is introduced for them.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-input.c | 22 | ||||
-rw-r--r-- | drivers/usb/input/hid-core.c | 23 | ||||
-rw-r--r-- | include/linux/hid.h | 5 |
3 files changed, 46 insertions, 4 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 25d180a24fc4..eeba66513997 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ | 2 | * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ |
3 | * | 3 | * |
4 | * Copyright (c) 2000-2001 Vojtech Pavlik | 4 | * Copyright (c) 2000-2001 Vojtech Pavlik |
5 | * Copyright (c) 2006 Jiri Kosina | 5 | * Copyright (c) 2006-2007 Jiri Kosina |
6 | * | 6 | * |
7 | * HID to Linux Input mapping | 7 | * HID to Linux Input mapping |
8 | */ | 8 | */ |
@@ -532,6 +532,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
532 | case 0x302: map_key_clear(KEY_PROG2); break; | 532 | case 0x302: map_key_clear(KEY_PROG2); break; |
533 | case 0x303: map_key_clear(KEY_PROG3); break; | 533 | case 0x303: map_key_clear(KEY_PROG3); break; |
534 | 534 | ||
535 | /* Reported on Logitech S510 wireless keyboard */ | ||
536 | case 0x101f: map_key_clear(KEY_ZOOMIN); break; | ||
537 | case 0x1020: map_key_clear(KEY_ZOOMOUT); break; | ||
538 | case 0x1021: map_key_clear(KEY_ZOOMRESET); break; | ||
539 | /* this one is marked as 'Rotate' */ | ||
540 | case 0x1028: map_key_clear(KEY_ANGLE); break; | ||
541 | case 0x1029: map_key_clear(KEY_SHUFFLE); break; | ||
542 | case 0x1041: map_key_clear(KEY_BATTERY); break; | ||
543 | case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; | ||
544 | case 0x1043: map_key_clear(KEY_SPREADSHEET); break; | ||
545 | case 0x1044: map_key_clear(KEY_PRESENTATION); break; | ||
546 | case 0x1045: map_key_clear(KEY_UNDO); break; | ||
547 | case 0x1046: map_key_clear(KEY_REDO); break; | ||
548 | case 0x1047: map_key_clear(KEY_PRINT); break; | ||
549 | case 0x1048: map_key_clear(KEY_SAVE); break; | ||
550 | case 0x1049: map_key_clear(KEY_PROG1); break; | ||
551 | case 0x104a: map_key_clear(KEY_PROG2); break; | ||
552 | case 0x104b: map_key_clear(KEY_PROG3); break; | ||
553 | case 0x104c: map_key_clear(KEY_PROG4); break; | ||
554 | |||
535 | default: goto ignore; | 555 | default: goto ignore; |
536 | } | 556 | } |
537 | break; | 557 | break; |
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 378af7ae2bfb..5d5221324e63 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright (c) 1999 Andreas Gal | 4 | * Copyright (c) 1999 Andreas Gal |
5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
7 | * Copyright (c) 2006 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* | 10 | /* |
@@ -755,6 +755,7 @@ void usbhid_init_reports(struct hid_device *hid) | |||
755 | 755 | ||
756 | #define USB_VENDOR_ID_LOGITECH 0x046d | 756 | #define USB_VENDOR_ID_LOGITECH 0x046d |
757 | #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 | 757 | #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 |
758 | #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517 | ||
758 | 759 | ||
759 | #define USB_VENDOR_ID_IMATION 0x0718 | 760 | #define USB_VENDOR_ID_IMATION 0x0718 |
760 | #define USB_DEVICE_ID_DISC_STAKKA 0xd000 | 761 | #define USB_DEVICE_ID_DISC_STAKKA 0xd000 |
@@ -941,6 +942,7 @@ static const struct hid_blacklist { | |||
941 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, | 942 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, |
942 | 943 | ||
943 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, | 944 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, |
945 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR }, | ||
944 | 946 | ||
945 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, | 947 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, |
946 | 948 | ||
@@ -1038,6 +1040,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) | |||
1038 | kfree(buf); | 1040 | kfree(buf); |
1039 | } | 1041 | } |
1040 | 1042 | ||
1043 | /* | ||
1044 | * Logitech S510 keyboard sends in report #3 keys which are far | ||
1045 | * above the logical maximum described in descriptor. This extends | ||
1046 | * the original value of 0x28c of logical maximum to 0x104d | ||
1047 | */ | ||
1048 | static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize) | ||
1049 | { | ||
1050 | if (rsize >= 90 && rdesc[83] == 0x26 | ||
1051 | && rdesc[84] == 0x8c | ||
1052 | && rdesc[85] == 0x02) { | ||
1053 | info("Fixing up Logitech S510 report descriptor"); | ||
1054 | rdesc[84] = rdesc[89] = 0x4d; | ||
1055 | rdesc[85] = rdesc[90] = 0x10; | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1041 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) | 1059 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) |
1042 | { | 1060 | { |
1043 | struct usb_host_interface *interface = intf->cur_altsetting; | 1061 | struct usb_host_interface *interface = intf->cur_altsetting; |
@@ -1106,6 +1124,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
1106 | if ((quirks & HID_QUIRK_CYMOTION)) | 1124 | if ((quirks & HID_QUIRK_CYMOTION)) |
1107 | hid_fixup_cymotion_descriptor(rdesc, rsize); | 1125 | hid_fixup_cymotion_descriptor(rdesc, rsize); |
1108 | 1126 | ||
1127 | if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR) | ||
1128 | hid_fixup_s510_descriptor(rdesc, rsize); | ||
1129 | |||
1109 | #ifdef CONFIG_HID_DEBUG | 1130 | #ifdef CONFIG_HID_DEBUG |
1110 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); | 1131 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); |
1111 | for (n = 0; n < rsize; n++) | 1132 | for (n = 0; n < rsize; n++) |
diff --git a/include/linux/hid.h b/include/linux/hid.h index d26b08f461f2..b08ad8a23699 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (c) 1999 Andreas Gal | 7 | * Copyright (c) 1999 Andreas Gal |
8 | * Copyright (c) 2000-2001 Vojtech Pavlik | 8 | * Copyright (c) 2000-2001 Vojtech Pavlik |
9 | * Copyright (c) 2006 Jiri Kosina | 9 | * Copyright (c) 2006-2007 Jiri Kosina |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
@@ -267,6 +267,7 @@ struct hid_item { | |||
267 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 | 267 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 |
268 | #define HID_QUIRK_IGNORE_MOUSE 0x00040000 | 268 | #define HID_QUIRK_IGNORE_MOUSE 0x00040000 |
269 | #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 | 269 | #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 |
270 | #define HID_QUIRK_LOGITECH_S510_DESCRIPTOR 0x00100000 | ||
270 | 271 | ||
271 | /* | 272 | /* |
272 | * This is the global environment of the parser. This information is | 273 | * This is the global environment of the parser. This information is |
@@ -292,7 +293,7 @@ struct hid_global { | |||
292 | */ | 293 | */ |
293 | 294 | ||
294 | #define HID_MAX_DESCRIPTOR_SIZE 4096 | 295 | #define HID_MAX_DESCRIPTOR_SIZE 4096 |
295 | #define HID_MAX_USAGES 1024 | 296 | #define HID_MAX_USAGES 8192 |
296 | #define HID_DEFAULT_NUM_COLLECTIONS 16 | 297 | #define HID_DEFAULT_NUM_COLLECTIONS 16 |
297 | 298 | ||
298 | struct hid_local { | 299 | struct hid_local { |