Commit b4350861 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid:
  HID: fix Logitech DiNovo Edge touchwheel and Logic3 /SpectraVideo middle button
  HID: add git tree information to MAINTAINERS
  HID: fix broken Logitech S510 keyboard report descriptor; make extra keys work
  HID: fix possible double-free on error path in hid parser
  HID: hid-debug.c should #include <linux/hid-debug.h>
  HID: fix bug in zeroing the last field byte in output reports
  USB HID: use CONFIG_HID_DEBUG for outputting report descriptor
  USB HID: Fix USB vendor and product IDs endianness for USB HID devices
parents 132a69c6 25914662
...@@ -1492,6 +1492,7 @@ HID CORE LAYER ...@@ -1492,6 +1492,7 @@ HID CORE LAYER
P: Jiri Kosina P: Jiri Kosina
M: jkosina@suse.cz M: jkosina@suse.cz
L: linux-input@atrey.karlin.mff.cuni.cz L: linux-input@atrey.karlin.mff.cuni.cz
T: git kernel.org:/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained S: Maintained
HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
...@@ -3423,6 +3424,7 @@ USB HID/HIDBP DRIVERS ...@@ -3423,6 +3424,7 @@ USB HID/HIDBP DRIVERS
P: Jiri Kosina P: Jiri Kosina
M: jkosina@suse.cz M: jkosina@suse.cz
L: linux-usb-devel@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net
T: git kernel.org:/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained S: Maintained
USB HUB DRIVER USB HUB DRIVER
......
...@@ -667,7 +667,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) ...@@ -667,7 +667,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (item.format != HID_ITEM_FORMAT_SHORT) { if (item.format != HID_ITEM_FORMAT_SHORT) {
dbg("unexpected long global item"); dbg("unexpected long global item");
kfree(device->collection);
hid_free_device(device); hid_free_device(device);
kfree(parser); kfree(parser);
return NULL; return NULL;
...@@ -676,7 +675,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) ...@@ -676,7 +675,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (dispatch_type[item.type](parser, &item)) { if (dispatch_type[item.type](parser, &item)) {
dbg("item %u %u %u %u parsing failed\n", dbg("item %u %u %u %u parsing failed\n",
item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
kfree(device->collection);
hid_free_device(device); hid_free_device(device);
kfree(parser); kfree(parser);
return NULL; return NULL;
...@@ -685,14 +683,12 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) ...@@ -685,14 +683,12 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (start == end) { if (start == end) {
if (parser->collection_stack_ptr) { if (parser->collection_stack_ptr) {
dbg("unbalanced collection at end of report description"); dbg("unbalanced collection at end of report description");
kfree(device->collection);
hid_free_device(device); hid_free_device(device);
kfree(parser); kfree(parser);
return NULL; return NULL;
} }
if (parser->local.delimiter_depth) { if (parser->local.delimiter_depth) {
dbg("unbalanced delimiter at end of report description"); dbg("unbalanced delimiter at end of report description");
kfree(device->collection);
hid_free_device(device); hid_free_device(device);
kfree(parser); kfree(parser);
return NULL; return NULL;
...@@ -703,7 +699,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) ...@@ -703,7 +699,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
} }
dbg("item fetching failed at offset %d\n", (int)(end - start)); dbg("item fetching failed at offset %d\n", (int)(end - start));
kfree(device->collection);
hid_free_device(device); hid_free_device(device);
kfree(parser); kfree(parser);
return NULL; return NULL;
...@@ -880,7 +875,7 @@ static void hid_output_field(struct hid_field *field, __u8 *data) ...@@ -880,7 +875,7 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
/* make sure the unused bits in the last byte are zeros */ /* make sure the unused bits in the last byte are zeros */
if (count > 0 && size > 0) if (count > 0 && size > 0)
data[(count*size-1)/8] = 0; data[(offset+count*size-1)/8] = 0;
for (n = 0; n < count; n++) { for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */ if (field->logical_minimum < 0) /* signed values */
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
*/ */
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hid-debug.h>
struct hid_usage_entry { struct hid_usage_entry {
unsigned page; unsigned page;
......
...@@ -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
*/ */
...@@ -71,7 +71,6 @@ static const struct { ...@@ -71,7 +71,6 @@ static const struct {
#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
#define map_rel_clear(c) do { map_rel(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
...@@ -296,7 +295,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -296,7 +295,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
} }
map_key_clear(code); map_key(code);
break; break;
...@@ -347,9 +346,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -347,9 +346,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE) if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel_clear(usage->hid & 0xf); map_rel(usage->hid & 0xf);
else else
map_abs_clear(usage->hid & 0xf); map_abs(usage->hid & 0xf);
break; break;
case HID_GD_HATSWITCH: case HID_GD_HATSWITCH:
...@@ -519,7 +518,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -519,7 +518,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x22f: map_key_clear(KEY_ZOOMRESET); break; case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
case 0x233: map_key_clear(KEY_SCROLLUP); break; case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break; case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
case 0x238: map_rel_clear(REL_HWHEEL); break; case 0x238: map_rel(REL_HWHEEL); break;
case 0x25f: map_key_clear(KEY_CANCEL); break; case 0x25f: map_key_clear(KEY_CANCEL); break;
case 0x279: map_key_clear(KEY_REDO); break; case 0x279: map_key_clear(KEY_REDO); break;
...@@ -532,6 +531,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -532,6 +531,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;
...@@ -647,6 +666,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -647,6 +666,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(usage->type, input->evbit); set_bit(usage->type, input->evbit);
if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
(usage->type == EV_KEY ||
usage->type == EV_REL ||
usage->type == EV_ABS))
clear_bit(usage->code, bit);
while (usage->code <= max && test_and_set_bit(usage->code, bit)) while (usage->code <= max && test_and_set_bit(usage->code, bit))
usage->code = find_next_zero_bit(bit, max + 1, usage->code); usage->code = find_next_zero_bit(bit, max + 1, usage->code);
......
...@@ -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
*/ */
/* /*
...@@ -27,9 +27,6 @@ ...@@ -27,9 +27,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/wait.h> #include <linux/wait.h>
#undef DEBUG
#undef DEBUG_DATA
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
...@@ -758,6 +755,8 @@ void usbhid_init_reports(struct hid_device *hid) ...@@ -758,6 +755,8 @@ 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_DEVICE_ID_DINOVO_EDGE 0xc714
#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
...@@ -778,6 +777,8 @@ static const struct hid_blacklist { ...@@ -778,6 +777,8 @@ static const struct hid_blacklist {
unsigned quirks; unsigned quirks;
} hid_blacklist[] = { } hid_blacklist[] = {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
...@@ -944,6 +945,7 @@ static const struct hid_blacklist { ...@@ -944,6 +945,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 },
...@@ -1041,6 +1043,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) ...@@ -1041,6 +1043,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;
...@@ -1109,7 +1127,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1109,7 +1127,10 @@ 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);
#ifdef DEBUG_DATA if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
hid_fixup_s510_descriptor(rdesc, rsize);
#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++)
printk(" %02x", (unsigned char) rdesc[n]); printk(" %02x", (unsigned char) rdesc[n]);
...@@ -1225,8 +1246,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1225,8 +1246,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idProduct));
hid->bus = BUS_USB; hid->bus = BUS_USB;
hid->vendor = dev->descriptor.idVendor; hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
hid->product = dev->descriptor.idProduct; hid->product = le16_to_cpu(dev->descriptor.idProduct);
usb_make_path(dev, hid->phys, sizeof(hid->phys)); usb_make_path(dev, hid->phys, sizeof(hid->phys));
strlcat(hid->phys, "/input", sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys));
......
...@@ -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,8 @@ struct hid_item { ...@@ -267,6 +267,8 @@ 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
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -292,7 +294,7 @@ struct hid_global { ...@@ -292,7 +294,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