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
diff --git a/MAINTAINERS b/MAINTAINERS
index 480ccb9..1dfba85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1492,6 +1492,7 @@
 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 @@
 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
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7452399..f4ee1af 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -667,7 +667,6 @@
 
 		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 @@
 		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 @@
 		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 @@
 	}
 
 	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 @@
 
 	/* 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 */
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 89241be..83c4126 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -29,6 +29,7 @@
  */
 
 #include <linux/hid.h>
+#include <linux/hid-debug.h>
 
 struct hid_usage_entry {
 	unsigned  page;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 25d180a..c843402 100644
--- a/drivers/hid/hid-input.c
+++ b/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 @@
 #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 @@
 					}
 			}
 
-			map_key_clear(code);
+			map_key(code);
 			break;
 
 
@@ -347,9 +346,9 @@
 				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 @@
 				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 @@
 				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 @@
 
 	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);
 
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index ef09952..12ec8b4 100644
--- a/drivers/usb/input/hid-core.c
+++ b/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 @@
 
 #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 @@
 	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 @@
 	{ 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 @@
 	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 @@
 	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 @@
 			 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));
diff --git a/include/linux/hid.h b/include/linux/hid.h
index d26b08f..8c97d4d 100644
--- a/include/linux/hid.h
+++ b/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 @@
 #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 @@
  */
 
 #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 {