aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2007-02-21 13:27:49 -0500
committerJiri Kosina <jkosina@suse.cz>2007-03-01 03:52:45 -0500
commitb55fd23ccdf32f969a7b4180c6e52d62d8e99972 (patch)
tree307897845c80f2bf61ec9d870dc95dc2c0224658
parent776c0e96edecf77f827a62d2a1641cc2ca479043 (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.c22
-rw-r--r--drivers/usb/input/hid-core.c23
-rw-r--r--include/linux/hid.h5
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 */
1048static 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
1041static struct hid_device *usb_hid_configure(struct usb_interface *intf) 1059static 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
298struct hid_local { 299struct hid_local {