Commit b55fd23c authored by Jiri Kosina's avatar Jiri Kosina

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: default avatarJiri Kosina <jkosina@suse.cz>
parent 776c0e96
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
* *
* Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2006 Jiri Kosina * Copyright (c) 2006-2007 Jiri Kosina
* *
* HID to Linux Input mapping * HID to Linux Input mapping
*/ */
...@@ -532,6 +532,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -532,6 +532,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x302: map_key_clear(KEY_PROG2); break; case 0x302: map_key_clear(KEY_PROG2); break;
case 0x303: map_key_clear(KEY_PROG3); break; case 0x303: map_key_clear(KEY_PROG3); break;
/* Reported on Logitech S510 wireless keyboard */
case 0x101f: map_key_clear(KEY_ZOOMIN); break;
case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
/* this one is marked as 'Rotate' */
case 0x1028: map_key_clear(KEY_ANGLE); break;
case 0x1029: map_key_clear(KEY_SHUFFLE); break;
case 0x1041: map_key_clear(KEY_BATTERY); break;
case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x1043: map_key_clear(KEY_SPREADSHEET); break;
case 0x1044: map_key_clear(KEY_PRESENTATION); break;
case 0x1045: map_key_clear(KEY_UNDO); break;
case 0x1046: map_key_clear(KEY_REDO); break;
case 0x1047: map_key_clear(KEY_PRINT); break;
case 0x1048: map_key_clear(KEY_SAVE); break;
case 0x1049: map_key_clear(KEY_PROG1); break;
case 0x104a: map_key_clear(KEY_PROG2); break;
case 0x104b: map_key_clear(KEY_PROG3); break;
case 0x104c: map_key_clear(KEY_PROG4); break;
default: goto ignore; default: goto ignore;
} }
break; break;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright (c) 1999 Andreas Gal * Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2006 Jiri Kosina * Copyright (c) 2006-2007 Jiri Kosina
*/ */
/* /*
...@@ -755,6 +755,7 @@ void usbhid_init_reports(struct hid_device *hid) ...@@ -755,6 +755,7 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_LOGITECH 0x046d #define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517
#define USB_VENDOR_ID_IMATION 0x0718 #define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000 #define USB_DEVICE_ID_DISC_STAKKA 0xd000
...@@ -941,6 +942,7 @@ static const struct hid_blacklist { ...@@ -941,6 +942,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
...@@ -1038,6 +1040,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) ...@@ -1038,6 +1040,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
kfree(buf); kfree(buf);
} }
/*
* Logitech S510 keyboard sends in report #3 keys which are far
* above the logical maximum described in descriptor. This extends
* the original value of 0x28c of logical maximum to 0x104d
*/
static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
{
if (rsize >= 90 && rdesc[83] == 0x26
&& rdesc[84] == 0x8c
&& rdesc[85] == 0x02) {
info("Fixing up Logitech S510 report descriptor");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
}
static struct hid_device *usb_hid_configure(struct usb_interface *intf) static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{ {
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_host_interface *interface = intf->cur_altsetting;
...@@ -1106,6 +1124,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1106,6 +1124,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if ((quirks & HID_QUIRK_CYMOTION)) if ((quirks & HID_QUIRK_CYMOTION))
hid_fixup_cymotion_descriptor(rdesc, rsize); hid_fixup_cymotion_descriptor(rdesc, rsize);
if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
hid_fixup_s510_descriptor(rdesc, rsize);
#ifdef CONFIG_HID_DEBUG #ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++) for (n = 0; n < rsize; n++)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1999 Andreas Gal * Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2006 Jiri Kosina * Copyright (c) 2006-2007 Jiri Kosina
*/ */
/* /*
...@@ -267,6 +267,7 @@ struct hid_item { ...@@ -267,6 +267,7 @@ struct hid_item {
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000
#define HID_QUIRK_IGNORE_MOUSE 0x00040000 #define HID_QUIRK_IGNORE_MOUSE 0x00040000
#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000
#define HID_QUIRK_LOGITECH_S510_DESCRIPTOR 0x00100000
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -292,7 +293,7 @@ struct hid_global { ...@@ -292,7 +293,7 @@ struct hid_global {
*/ */
#define HID_MAX_DESCRIPTOR_SIZE 4096 #define HID_MAX_DESCRIPTOR_SIZE 4096
#define HID_MAX_USAGES 1024 #define HID_MAX_USAGES 8192
#define HID_DEFAULT_NUM_COLLECTIONS 16 #define HID_DEFAULT_NUM_COLLECTIONS 16
struct hid_local { struct hid_local {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment