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>

+46 -4
+21 -1
drivers/hid/hid-input.c
··· 2 * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ 3 * 4 * Copyright (c) 2000-2001 Vojtech Pavlik 5 - * Copyright (c) 2006 Jiri Kosina 6 * 7 * HID to Linux Input mapping 8 */ ··· 531 case 0x301: map_key_clear(KEY_PROG1); break; 532 case 0x302: map_key_clear(KEY_PROG2); break; 533 case 0x303: map_key_clear(KEY_PROG3); break; 534 535 default: goto ignore; 536 }
··· 2 * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ 3 * 4 * Copyright (c) 2000-2001 Vojtech Pavlik 5 + * Copyright (c) 2006-2007 Jiri Kosina 6 * 7 * HID to Linux Input mapping 8 */ ··· 531 case 0x301: map_key_clear(KEY_PROG1); break; 532 case 0x302: map_key_clear(KEY_PROG2); break; 533 case 0x303: map_key_clear(KEY_PROG3); break; 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 555 default: goto ignore; 556 }
+22 -1
drivers/usb/input/hid-core.c
··· 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 - * Copyright (c) 2006 Jiri Kosina 8 */ 9 10 /* ··· 755 756 #define USB_VENDOR_ID_LOGITECH 0x046d 757 #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 758 759 #define USB_VENDOR_ID_IMATION 0x0718 760 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 ··· 942 { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, 943 944 { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, 945 946 { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, 947 ··· 1040 kfree(buf); 1041 } 1042 1043 static struct hid_device *usb_hid_configure(struct usb_interface *intf) 1044 { 1045 struct usb_host_interface *interface = intf->cur_altsetting; ··· 1123 1124 if ((quirks & HID_QUIRK_CYMOTION)) 1125 hid_fixup_cymotion_descriptor(rdesc, rsize); 1126 1127 #ifdef CONFIG_HID_DEBUG 1128 printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
··· 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 + * Copyright (c) 2006-2007 Jiri Kosina 8 */ 9 10 /* ··· 755 756 #define USB_VENDOR_ID_LOGITECH 0x046d 757 #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 758 + #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517 759 760 #define USB_VENDOR_ID_IMATION 0x0718 761 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 ··· 941 { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, 942 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_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR }, 945 946 { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, 947 ··· 1038 kfree(buf); 1039 } 1040 1041 + /* 1042 + * Logitech S510 keyboard sends in report #3 keys which are far 1043 + * above the logical maximum described in descriptor. This extends 1044 + * the original value of 0x28c of logical maximum to 0x104d 1045 + */ 1046 + static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize) 1047 + { 1048 + if (rsize >= 90 && rdesc[83] == 0x26 1049 + && rdesc[84] == 0x8c 1050 + && rdesc[85] == 0x02) { 1051 + info("Fixing up Logitech S510 report descriptor"); 1052 + rdesc[84] = rdesc[89] = 0x4d; 1053 + rdesc[85] = rdesc[90] = 0x10; 1054 + } 1055 + } 1056 + 1057 static struct hid_device *usb_hid_configure(struct usb_interface *intf) 1058 { 1059 struct usb_host_interface *interface = intf->cur_altsetting; ··· 1105 1106 if ((quirks & HID_QUIRK_CYMOTION)) 1107 hid_fixup_cymotion_descriptor(rdesc, rsize); 1108 + 1109 + if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR) 1110 + hid_fixup_s510_descriptor(rdesc, rsize); 1111 1112 #ifdef CONFIG_HID_DEBUG 1113 printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+3 -2
include/linux/hid.h
··· 6 * 7 * Copyright (c) 1999 Andreas Gal 8 * Copyright (c) 2000-2001 Vojtech Pavlik 9 - * Copyright (c) 2006 Jiri Kosina 10 */ 11 12 /* ··· 267 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 268 #define HID_QUIRK_IGNORE_MOUSE 0x00040000 269 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 270 271 /* 272 * This is the global environment of the parser. This information is ··· 293 */ 294 295 #define HID_MAX_DESCRIPTOR_SIZE 4096 296 - #define HID_MAX_USAGES 1024 297 #define HID_DEFAULT_NUM_COLLECTIONS 16 298 299 struct hid_local {
··· 6 * 7 * Copyright (c) 1999 Andreas Gal 8 * Copyright (c) 2000-2001 Vojtech Pavlik 9 + * Copyright (c) 2006-2007 Jiri Kosina 10 */ 11 12 /* ··· 267 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 268 #define HID_QUIRK_IGNORE_MOUSE 0x00040000 269 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 270 + #define HID_QUIRK_LOGITECH_S510_DESCRIPTOR 0x00100000 271 272 /* 273 * This is the global environment of the parser. This information is ··· 292 */ 293 294 #define HID_MAX_DESCRIPTOR_SIZE 4096 295 + #define HID_MAX_USAGES 8192 296 #define HID_DEFAULT_NUM_COLLECTIONS 16 297 298 struct hid_local {