瀏覽代碼

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
Linus Torvalds 18 年之前
父節點
當前提交
b4350861dd
共有 6 個文件被更改,包括 67 次插入21 次删除
  1. 2 0
      MAINTAINERS
  2. 1 6
      drivers/hid/hid-core.c
  3. 1 0
      drivers/hid/hid-debug.c
  4. 31 6
      drivers/hid/hid-input.c
  5. 28 7
      drivers/usb/input/hid-core.c
  6. 4 2
      include/linux/hid.h

+ 2 - 0
MAINTAINERS

@@ -1492,6 +1492,7 @@ HID CORE LAYER
 P:	Jiri Kosina
 M:	jkosina@suse.cz
 L:	linux-input@atrey.karlin.mff.cuni.cz
+T:	git kernel.org:/pub/scm/linux/kernel/git/jikos/hid.git
 S:	Maintained
 
 HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
@@ -3423,6 +3424,7 @@ USB HID/HIDBP DRIVERS
 P:	Jiri Kosina
 M:	jkosina@suse.cz
 L:	linux-usb-devel@lists.sourceforge.net
+T:	git kernel.org:/pub/scm/linux/kernel/git/jikos/hid.git
 S:	Maintained
 
 USB HUB DRIVER

+ 1 - 6
drivers/hid/hid-core.c

@@ -667,7 +667,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 
 		if (item.format != HID_ITEM_FORMAT_SHORT) {
 			dbg("unexpected long global item");
-			kfree(device->collection);
 			hid_free_device(device);
 			kfree(parser);
 			return NULL;
@@ -676,7 +675,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 		if (dispatch_type[item.type](parser, &item)) {
 			dbg("item %u %u %u %u parsing failed\n",
 				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
-			kfree(device->collection);
 			hid_free_device(device);
 			kfree(parser);
 			return NULL;
@@ -685,14 +683,12 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 		if (start == end) {
 			if (parser->collection_stack_ptr) {
 				dbg("unbalanced collection at end of report description");
-				kfree(device->collection);
 				hid_free_device(device);
 				kfree(parser);
 				return NULL;
 			}
 			if (parser->local.delimiter_depth) {
 				dbg("unbalanced delimiter at end of report description");
-				kfree(device->collection);
 				hid_free_device(device);
 				kfree(parser);
 				return NULL;
@@ -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));
-	kfree(device->collection);
 	hid_free_device(device);
 	kfree(parser);
 	return NULL;
@@ -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 */
 	if (count > 0 && size > 0)
-		data[(count*size-1)/8] = 0;
+		data[(offset+count*size-1)/8] = 0;
 
 	for (n = 0; n < count; n++) {
 		if (field->logical_minimum < 0)	/* signed values */

+ 1 - 0
drivers/hid/hid-debug.c

@@ -29,6 +29,7 @@
  */
 
 #include <linux/hid.h>
+#include <linux/hid-debug.h>
 
 struct hid_usage_entry {
 	unsigned  page;

+ 31 - 6
drivers/hid/hid-input.c

@@ -2,7 +2,7 @@
  * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2006 Jiri Kosina
+ *  Copyright (c) 2006-2007 Jiri Kosina
  *
  *  HID to Linux Input mapping
  */
@@ -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_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)
 
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
@@ -296,7 +295,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 					}
 			}
 
-			map_key_clear(code);
+			map_key(code);
 			break;
 
 
@@ -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_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
 					if (field->flags & HID_MAIN_ITEM_RELATIVE)
-						map_rel_clear(usage->hid & 0xf);
+						map_rel(usage->hid & 0xf);
 					else
-						map_abs_clear(usage->hid & 0xf);
+						map_abs(usage->hid & 0xf);
 					break;
 
 				case HID_GD_HATSWITCH:
@@ -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 0x233: map_key_clear(KEY_SCROLLUP);	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 0x279: map_key_clear(KEY_REDO);		break;
 
@@ -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 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;
 			}
 			break;
@@ -647,6 +666,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
 	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))
 		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
 

+ 28 - 7
drivers/usb/input/hid-core.c

@@ -4,7 +4,7 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  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 @@
 #include <linux/input.h>
 #include <linux/wait.h>
 
-#undef DEBUG
-#undef DEBUG_DATA
-
 #include <linux/usb.h>
 
 #include <linux/hid.h>
@@ -758,6 +755,8 @@ void usbhid_init_reports(struct hid_device *hid)
 
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #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_DEVICE_ID_DISC_STAKKA	0xd000
@@ -778,6 +777,8 @@ static const struct hid_blacklist {
 	unsigned quirks;
 } 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_10, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
@@ -944,6 +945,7 @@ static const struct hid_blacklist {
 	{ 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_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 },
 
@@ -1041,6 +1043,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
 	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)
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1109,7 +1127,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 	if ((quirks & HID_QUIRK_CYMOTION))
 		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);
 	for (n = 0; n < rsize; n++)
 		printk(" %02x", (unsigned char) rdesc[n]);
@@ -1225,8 +1246,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 			 le16_to_cpu(dev->descriptor.idProduct));
 
 	hid->bus = BUS_USB;
-	hid->vendor = dev->descriptor.idVendor;
-	hid->product = dev->descriptor.idProduct;
+	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+	hid->product = le16_to_cpu(dev->descriptor.idProduct);
 
 	usb_make_path(dev, hid->phys, sizeof(hid->phys));
 	strlcat(hid->phys, "/input", sizeof(hid->phys));

+ 4 - 2
include/linux/hid.h

@@ -6,7 +6,7 @@
  *
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2006 Jiri Kosina
+ *  Copyright (c) 2006-2007 Jiri Kosina
  */
 
 /*
@@ -267,6 +267,8 @@ struct hid_item {
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00020000
 #define HID_QUIRK_IGNORE_MOUSE			0x00040000
 #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
@@ -292,7 +294,7 @@ struct hid_global {
  */
 
 #define HID_MAX_DESCRIPTOR_SIZE		4096
-#define HID_MAX_USAGES			1024
+#define HID_MAX_USAGES			8192
 #define HID_DEFAULT_NUM_COLLECTIONS	16
 
 struct hid_local {