# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.294   -> 1.295  
#	   drivers/usb/hid.h	1.8     -> 1.9    
#	drivers/usb/hid-debug.h	1.2     -> 1.3    
#	 drivers/usb/wacom.c	1.8     -> 1.9    
#	drivers/usb/usbmouse.c	1.8     -> 1.9    
#	drivers/usb/usbkbd.c	1.10    -> 1.11   
#	drivers/usb/hid-input.c	1.2     -> 1.3    
#	drivers/usb/hiddev.c	1.4     -> 1.5    
#	drivers/usb/hid-core.c	1.11    -> 1.12   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/02/11	vojtech@suse.cz	1.295
# [PATCH] Update of USB input drivers to the latest versions
# 
# Now that the input core changes have made it into 2.5 I can finally
# update the USB input drivers to their latest versions.
# 
# Here is a patch that does that.
# 
# In detail:
# 
# 	HID driver:
# 		Fix a bug in descriptor parsing (array/variable),
# 			namely visible with Logitech new joysticks and mice
# 		Fix bugs in logical/physical min/max parsing
# 		Fix bugs in exponent parsing
# 		Remove workaround for low-speed devices with >8 byte
# 			reports, fix this in a correct way (bigger irq
# 			request)
# 		Untangle some code (fetc_item())
# 		Implement asynchronous input/output/feature report
# 			reading and writing
# 		Implement (hopefully) proper locking in the above
# 		Implement support for devices with an output endpoint
# 		Add some support functions for force feedback support
# 			currently in development
# 		Add entries to the debug dump code, including FF and
# 			exponents
# 		Add more mappings into the hid-input interface
# 		Cleanups here and there
# 
# 	usbkbd driver:
# 
# 		Make LED URBS use GFP_ATOMIC, they'll be called from a
# 			completion handler
# 		Remove dependency on hid.h
# 
# 	usbmouse driver:
# 
# 		Just conversion to the new input core, minor cleanups
# 
# 	wacom driver:
# 
# 		Just conversion to the new input core.
# --------------------------------------------
#
diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c
--- a/drivers/usb/hid-core.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/hid-core.c	Mon Feb 11 23:34:47 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: hid-core.c,v 1.8 2001/05/23 12:02:18 vojtech Exp $
+ * $Id: hid-core.c,v 1.42 2002/01/27 00:22:46 vojtech Exp $
  *
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  USB HID support for Linux
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -25,8 +23,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/module.h>
@@ -56,9 +54,10 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v1.8"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
-#define DRIVER_DESC "USB HID support drivers"
+#define DRIVER_VERSION "v1.31"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB HID core driver"
+#define DRIVER_LICENSE "GPL"
 
 static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
 				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
@@ -205,16 +204,11 @@
 		return -1;
 	}
 
-	if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */
-		if (parser->global.logical_maximum <= parser->global.logical_minimum) {
-			dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
-			return -1;
-		}
-		usages = parser->local.usage_index;
-		/* Hint: we can assume usages < MAX_USAGE here */
-	} else { /* VARIABLE */
-		usages = parser->global.report_count;
+	if (parser->global.logical_maximum <= parser->global.logical_minimum) {
+		dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+		return -1;
 	}
+	usages = parser->local.usage_index;
 
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
@@ -311,7 +305,10 @@
 			return 0;
 
 		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-			parser->global.logical_maximum = item_sdata(item);
+			if (parser->global.logical_minimum < 0)
+				parser->global.logical_maximum = item_sdata(item);
+			else
+				parser->global.logical_maximum = item_udata(item);
 			return 0;
 
 		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
@@ -319,11 +316,14 @@
 			return 0;
 
 		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-			parser->global.physical_maximum = item_sdata(item);
+			if (parser->global.physical_minimum < 0)
+				parser->global.physical_maximum = item_sdata(item);
+			else
+				parser->global.physical_maximum = item_udata(item);
 			return 0;
 
 		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-			parser->global.unit_exponent = item_udata(item);
+			parser->global.unit_exponent = item_sdata(item);
 			return 0;
 
 		case HID_GLOBAL_ITEM_TAG_UNIT:
@@ -508,8 +508,6 @@
 
 	for (n = 0; n < report->maxfield; n++)
 		kfree(report->field[n]);
-	if (report->data)
-		kfree(report->data);
 	kfree(report);
 }
 
@@ -538,60 +536,64 @@
  * items, though they are not used yet.
  */
 
-static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
 {
-	if ((end - start) > 0) {
+	u8 b;
 
-		__u8 b = *start++;
-		item->type = (b >> 2) & 3;
-		item->tag  = (b >> 4) & 15;
+	if ((end - start) <= 0)
+		return NULL;
 
-		if (item->tag == HID_ITEM_TAG_LONG) {
+	b = *start++;
 
-			item->format = HID_ITEM_FORMAT_LONG;
+	item->type = (b >> 2) & 3;
+	item->tag  = (b >> 4) & 15;
 
-			if ((end - start) >= 2) {
+	if (item->tag == HID_ITEM_TAG_LONG) {
 
-				item->size = *start++;
-				item->tag  = *start++;
+		item->format = HID_ITEM_FORMAT_LONG;
 
-				if ((end - start) >= item->size) {
-					item->data.longdata = start;
-					start += item->size;
-					return start;
-				}
-			}
-		} else {
+		if ((end - start) < 2)
+			return NULL;
 
-			item->format = HID_ITEM_FORMAT_SHORT;
-			item->size = b & 3;
-			switch (item->size) {
-
-				case 0:
-					return start;
-
-				case 1:
-					if ((end - start) >= 1) {
-						item->data.u8 = *start++;
-						return start;
-					}
-					break;
-
-				case 2:
-					if ((end - start) >= 2) {
-						item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
-						return start;
-					}
-
-				case 3:
-					item->size++;
-					if ((end - start) >= 4) {
-						item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
-						return start;
-					}
-			}
-		}
+		item->size = *start++;
+		item->tag  = *start++;
+
+		if ((end - start) < item->size) 
+			return NULL;
+
+		item->data.longdata = start;
+		start += item->size;
+		return start;
+	} 
+
+	item->format = HID_ITEM_FORMAT_SHORT;
+	item->size = b & 3;
+
+	switch (item->size) {
+
+		case 0:
+			return start;
+
+		case 1:
+			if ((end - start) < 1)
+				return NULL;
+			item->data.u8 = *start++;
+			return start;
+
+		case 2:
+			if ((end - start) < 2) 
+				return NULL;
+			item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++));
+			return start;
+
+		case 3:
+			item->size++;
+			if ((end - start) < 4)
+				return NULL;
+			item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++));
+			return start;
 	}
+
 	return NULL;
 }
 
@@ -638,12 +640,14 @@
 
 	end = start + size;
 	while ((start = fetch_item(start, end, &item)) != 0) {
+
 		if (item.format != HID_ITEM_FORMAT_SHORT) {
 			dbg("unexpected long global item");
 			hid_free_device(device);
 			kfree(parser);
 			return NULL;
 		}
+
 		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);
@@ -742,7 +746,6 @@
 #endif
 }
 
-
 /*
  * Analyse a received field, and fetch the data from it. The field
  * content is stored for next report processing (we do differential
@@ -797,9 +800,12 @@
 	memcpy(field->value, value, count * sizeof(__s32));
 }
 
-static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid)
+static int hid_input_report(int type, struct urb *urb)
 {
+	struct hid_device *hid = urb->context;
 	struct hid_report_enum *report_enum = hid->report_enum + type;
+	u8 *data = urb->transfer_buffer;
+	int len = urb->actual_length;
 	struct hid_report *report;
 	int n, size;
 
@@ -818,92 +824,46 @@
 		len--;
 	}
 
-	if (!(report = report_enum->report_id_hash[n])) {
-		dbg("undefined report_id %d received", n);
-#ifdef DEBUG
-			printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len);
-			for (n = 0; n < len; n++)
-				printk(" %02x", data[n]);
-			printk("\n");
+#ifdef DEBUG_DATA
+	{
+		int i;
+		printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
+		for (i = 0; i < n; i++)
+			printk(" %02x", data[i]);
+		printk("\n");
+	}
 #endif
 
+	if (!(report = report_enum->report_id_hash[n])) {
+		dbg("undefined report_id %d received", n);
 		return -1;
 	}
 
 	size = ((report->size - 1) >> 3) + 1;
 
 	if (len < size) {
-
-		if (size <= 8) {
-			dbg("report %d is too short, (%d < %d)", report->id, len, size);
-			return -1;
-		}
-
-		/*
-		 * Some low-speed devices have large reports and maxpacketsize 8.
-		 * We buffer the data in that case and parse it when we got it all.
-		 * Works only for unnumbered reports. Doesn't make sense for numbered
-		 * reports anyway - then they don't need to be large.
-		 */
-
-		if (!report->data)
-			if (!(report->data = kmalloc(size, GFP_ATOMIC))) {
-				dbg("couldn't allocate report buffer");
-				return -1;
-			}
-
-		if (report->idx + len > size) {
-			dbg("report data buffer overflow");
-			report->idx = 0;
-			return -1;
-		}
-
-		memcpy(report->data + report->idx, data, len);
-		report->idx += len;
-
-		if (report->idx < size)
-			return 0;
-
-		data = report->data;
+		dbg("report %d is too short, (%d < %d)", report->id, len, size);
+		return -1;
 	}
 
 	for (n = 0; n < report->maxfield; n++)
 		hid_input_field(hid, report->field[n], data);
 
-	report->idx = 0;
 	return 0;
 }
 
 /*
- * Interrupt input handler.
+ * Input interrupt completion handler.
  */
 
-static void hid_irq(struct urb *urb)
+static void hid_irq_in(struct urb *urb)
 {
 	if (urb->status) {
-		dbg("nonzero status in irq %d", urb->status);
-		return;
-	}
-
-	hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context);
-}
-
-/*
- * hid_read_report() reads in report values without waiting for an irq urb.
- */
-
-void hid_read_report(struct hid_device *hid, struct hid_report *report)
-{
-	int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered;
-	u8 data[len];
-	int read;
-
-	if ((read = hid_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) {
-		dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read);
+		dbg("nonzero status in input irq %d", urb->status);
 		return;
 	}
 
-	hid_input_report(report->type, data, len, hid);
+	hid_input_report(HID_INPUT_REPORT, urb);
 }
 
 /*
@@ -949,7 +909,8 @@
 	hid_dump_input(field->usage + offset, value);
 
 	if (offset >= field->report_count) {
-		dbg("offset exceeds report_count");
+		dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+		hid_dump_field(field, 8);
 		return -1;
 	}
 	if (field->logical_minimum < 0) {
@@ -958,11 +919,6 @@
 			return -1;
 		}
 	}
-	if (   (value > field->logical_maximum)
-	    || (value < field->logical_minimum)) {
-		dbg("value %d is invalid", value);
-		return -1;
-	}
 	field->value[offset] = value;
 	return 0;
 }
@@ -986,14 +942,56 @@
 	return -1;
 }
 
+/*
+ * Find a report with a specified HID usage.
+ */
+
+int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type)
+{
+	struct hid_report_enum *report_enum = hid->report_enum + type;
+	struct list_head *list = report_enum->report_list.next;
+	int i, j;
+
+	while (list != &report_enum->report_list) {
+		*report = (struct hid_report *) list;
+		list = list->next;
+		for (i = 0; i < (*report)->maxfield; i++) {
+			struct hid_field *field = (*report)->field[i];
+			for (j = 0; j < field->maxusage; j++)
+				if (field->logical == wanted_usage)
+					return j;
+		}
+	}
+	return -1;
+}
+
+int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field)
+{
+	int i, j;
+
+	for (i = 0; i < report->maxfield; i++) {
+		*field = report->field[i];
+		for (j = 0; j < (*field)->maxusage; j++)
+			if ((*field)->usage[j].hid == wanted_usage)
+				return j;
+	}
+
+	return -1;
+}
+
 static int hid_submit_out(struct hid_device *hid)
 {
-	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength);
-	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
-	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
-	hid->urbout.dev = hid->dev;
+	struct hid_report *report;
+
+	report = hid->out[hid->outtail];
+
+	hid_output_report(report, hid->outbuf);
+	hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1;
+	hid->urbout->dev = hid->dev;
 
-	if (usb_submit_urb(&hid->urbout, GFP_KERNEL)) {
+	dbg("submitting out urb");
+
+	if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) {
 		err("usb_submit_urb(out) failed");
 		return -1;
 	}
@@ -1001,33 +999,168 @@
 	return 0;
 }
 
+static int hid_submit_ctrl(struct hid_device *hid)
+{
+	struct hid_report *report;
+	unsigned char dir;
+
+	report = hid->ctrl[hid->ctrltail].report;
+	dir = hid->ctrl[hid->ctrltail].dir;
+
+	if (dir == USB_DIR_OUT)
+		hid_output_report(report, hid->ctrlbuf);
+
+	hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT));
+	hid->urbctrl->pipe = (dir == USB_DIR_OUT) ?  usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0);
+	hid->urbctrl->dev = hid->dev;
+
+	hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+	hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+	hid->cr.wValue = ((report->type + 1) << 8) | report->id;
+	hid->cr.wIndex = cpu_to_le16(hid->ifnum);
+	hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length);
+
+	dbg("submitting ctrl urb");
+
+	if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
+		err("usb_submit_urb(ctrl) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Output interrupt completion handler.
+ */
+
+static void hid_irq_out(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+	unsigned long flags;
+
+	if (urb->status)
+		warn("output irq status %d received", urb->status);
+
+	spin_lock_irqsave(&hid->outlock, flags);
+
+	hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+
+	if (hid->outhead != hid->outtail) {
+		hid_submit_out(hid);
+		return;
+	}
+
+	clear_bit(HID_OUT_RUNNING, &hid->iofl);
+
+	spin_unlock_irqrestore(&hid->outlock, flags);
+
+	wake_up(&hid->wait);
+}
+
+/*
+ * Control pipe completion handler.
+ */
+
 static void hid_ctrl(struct urb *urb)
 {
 	struct hid_device *hid = urb->context;
+	unsigned long flags;
 
 	if (urb->status)
 		warn("ctrl urb status %d received", urb->status);
 
-	hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+	spin_lock_irqsave(&hid->ctrllock, flags);
 
-	if (hid->outhead != hid->outtail)
-		hid_submit_out(hid);
+	if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) 
+		hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb);
+
+	hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+	if (hid->ctrlhead != hid->ctrltail) {
+		hid_submit_ctrl(hid);
+		return;
+	}
+
+	clear_bit(HID_CTRL_RUNNING, &hid->iofl);
+
+	spin_unlock_irqrestore(&hid->ctrllock, flags);
+
+	wake_up(&hid->wait);
 }
 
-void hid_write_report(struct hid_device *hid, struct hid_report *report)
+void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
 {
-	hid_output_report(report, hid->out[hid->outhead].buffer);
+	int head;
+	unsigned long flags;
 
-	hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id);
-	hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3);
+	if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
 
-	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+		spin_lock_irqsave(&hid->outlock, flags);
 
-	if (hid->outhead == hid->outtail)
-		hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+		if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) {
+			spin_unlock_irqrestore(&hid->outlock, flags);
+			warn("output queue full");
+			return;
+		}
 
-	if (hid->urbout.status != -EINPROGRESS)
-		hid_submit_out(hid);
+		hid->out[hid->outhead] = report;
+		hid->outhead = head;
+
+		if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl))
+			hid_submit_out(hid);
+
+		spin_unlock_irqrestore(&hid->outlock, flags);
+		return;
+	}
+
+	spin_lock_irqsave(&hid->ctrllock, flags);
+
+	if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) {
+		spin_unlock_irqrestore(&hid->ctrllock, flags);
+		warn("control queue full");
+		return;
+	}
+
+	hid->ctrl[hid->ctrlhead].report = report;
+	hid->ctrl[hid->ctrlhead].dir = dir;
+	hid->ctrlhead = head;
+
+	if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl))
+		hid_submit_ctrl(hid);
+
+	spin_unlock_irqrestore(&hid->ctrllock, flags);
+}
+
+int hid_wait_io(struct hid_device *hid)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = 10*HZ;
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&hid->wait, &wait);
+
+	while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
+			  test_bit(HID_OUT_RUNNING, &hid->iofl))
+		timeout = schedule_timeout(timeout);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&hid->wait, &wait);
+
+	if (!timeout) {
+		dbg("timeout waiting for ctrl or out queue to clear");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
+		unsigned char type, void *buf, int size)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+		(type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
 }
 
 int hid_open(struct hid_device *hid)
@@ -1035,9 +1168,9 @@
 	if (hid->open++)
 		return 0;
 
-	hid->urb.dev = hid->dev;
+	hid->urbin->dev = hid->dev;
 
-	if (usb_submit_urb(&hid->urb, GFP_KERNEL))
+	if (usb_submit_urb(hid->urbin, GFP_KERNEL))
 		return -EIO;
 
 	return 0;
@@ -1046,30 +1179,52 @@
 void hid_close(struct hid_device *hid)
 {
 	if (!--hid->open)
-		usb_unlink_urb(&hid->urb);
+		usb_unlink_urb(hid->urbin);
 }
 
 /*
- * Initialize all readable reports
+ * Initialize all reports
  */
+
 void hid_init_reports(struct hid_device *hid)
 {
-	int i;
-	struct hid_report *report;
 	struct hid_report_enum *report_enum;
+	struct hid_report *report;
 	struct list_head *list;
+	int len;
 
-	for (i = 0; i < HID_REPORT_TYPES; i++) {
-		if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) {
-			report_enum = hid->report_enum + i;
-			list = report_enum->report_list.next;
-			while (list != &report_enum->report_list) {
-				report = (struct hid_report *) list;
-				hid_set_idle(hid->dev, hid->ifnum, 0, report->id);
-				hid_read_report(hid, report);
-				list = list->next;
-			}
-		}
+	report_enum = hid->report_enum + HID_INPUT_REPORT;
+	list = report_enum->report_list.next;
+	while (list != &report_enum->report_list) {
+		report = (struct hid_report *) list;
+		hid_submit_report(hid, report, USB_DIR_IN);
+		list = list->next;
+	}
+
+	report_enum = hid->report_enum + HID_FEATURE_REPORT;
+	list = report_enum->report_list.next;
+	while (list != &report_enum->report_list) {
+		report = (struct hid_report *) list;
+		hid_submit_report(hid, report, USB_DIR_IN);
+		list = list->next;
+	}
+
+	if (hid_wait_io(hid)) {
+		warn("timeout initializing reports\n");
+		return;
+	}
+
+	report_enum = hid->report_enum + HID_INPUT_REPORT;
+	list = report_enum->report_list.next;
+	while (list != &report_enum->report_list) {
+		report = (struct hid_report *) list;
+		len = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
+		if (len > hid->urbin->transfer_buffer_length)
+			hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE;
+		usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
+			0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
+			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+		list = list->next;
 	}
 }
 
@@ -1077,6 +1232,10 @@
 #define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
 
+#define USB_VENDOR_ID_GRIFFIN		0x077d
+#define USB_DEVICE_ID_POWERMATE		0x0410
+#define USB_DEVICE_ID_SOUNDKNOB		0x04AA
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1087,19 +1246,11 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB },
 	{ 0, 0 }
 };
 
-static int get_class_descriptor(struct usb_device *dev, int ifnum,
-		unsigned char type, void *buf, int size)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
-		(type << 8), ifnum, buf, size,
-		HZ * USB_CTRL_GET_TIMEOUT);
-}
-
-
 static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
 {
 	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
@@ -1131,7 +1282,7 @@
 	{
 		__u8 rdesc[rsize];
 
-		if ((n = get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+		if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
 			dbg("reading report descriptor failed");
 			return NULL;
 		}
@@ -1152,73 +1303,83 @@
 	for (n = 0; n < interface->bNumEndpoints; n++) {
 
 		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
-		int pipe, maxp;
+		int pipe;
 
 		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
 			continue;
 
-		if (!(endpoint->bEndpointAddress & 0x80))	/* Not an input endpoint */
-			continue;
-
-		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-		FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);
-
-		break;
+		if (endpoint->bEndpointAddress & USB_DIR_IN) {
+			if (hid->urbin)
+				continue;
+			if (!(hid->urbin = usb_alloc_urb(0)))
+				goto fail;
+			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+			FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval);
+		} else {
+			if (hid->urbout)
+				continue;
+			if (!(hid->urbout = usb_alloc_urb(0)))
+				goto fail;
+			pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress);
+			FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid);
+		}
 	}
 
-	if (n == interface->bNumEndpoints) {
-		dbg("couldn't find an input interrupt endpoint");
-		hid_free_device(hid);
-		return NULL;
+	if (!hid->urbin) {
+		err("couldn't find an input interrupt endpoint");
+		goto fail;
 	}
 
+	init_waitqueue_head(&hid->wait);
+	
+	hid->outlock = SPIN_LOCK_UNLOCKED;
+	hid->ctrllock = SPIN_LOCK_UNLOCKED;
+
 	hid->version = hdesc->bcdHID;
 	hid->country = hdesc->bCountryCode;
 	hid->dev = dev;
 	hid->ifnum = interface->bInterfaceNumber;
 
-	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
-		hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-		hid->out[n].dr.bRequest = HID_REQ_SET_REPORT;
-		hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum);
-	}
-
 	hid->name[0] = 0;
 
-	if (!(buf = kmalloc(63, GFP_KERNEL)))
-		return NULL;
+	if (!(buf = kmalloc(64, GFP_KERNEL)))
+		goto fail;
 
-	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) {
+	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
 		strcat(hid->name, buf);
-		if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
+		if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
 			sprintf(hid->name, "%s %s", hid->name, buf);
 	} else
 		sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
 
-	kfree(buf);
+	usb_make_path(dev, buf, 63);
+	sprintf(hid->phys, "%s/input%d", buf, ifnum);
 
-	FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
-		(void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);
+	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+		hid->uniq[0] = 0;
 
-/*
- * Some devices don't like this and crash. I don't know of any devices
- * needing this, so it is disabled for now.
- */
+	kfree(buf);
 
-#if 0
-	if (interface->bInterfaceSubClass == 1)
-		hid_set_protocol(dev, hid->ifnum, 1);
-#endif
+	hid->urbctrl = usb_alloc_urb(0);
+	FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid);
 
 	return hid;
+
+fail:
+
+	hid_free_device(hid);
+	if (hid->urbin) usb_free_urb(hid->urbin);
+	if (hid->urbout) usb_free_urb(hid->urbout);
+	if (hid->urbctrl) usb_free_urb(hid->urbctrl);
+
+	return NULL;
 }
 
 static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
 		       const struct usb_device_id *id)
 {
 	struct hid_device *hid;
+	char path[64];
 	int i;
 	char *c;
 
@@ -1236,10 +1397,16 @@
 	if (!hiddev_connect(hid))
 		hid->claimed |= HID_CLAIMED_HIDDEV;
 #endif
+
+	if (!hid->claimed) {
+		hid_free_device(hid);
+		return NULL;
+	}
+
 	printk(KERN_INFO);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
-		printk("input%d", hid->input.number);
+		printk("input");
 	if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
 		printk(",");
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
@@ -1252,9 +1419,10 @@
 			break;
 		}
 
-	printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n",
-		hid->version >> 8, hid->version & 0xff, c, hid->name,
-		dev->bus->busnum, dev->devnum, ifnum);
+	usb_make_path(dev, path, 63);
+
+	printk(": USB HID v%x.%02x %s [%s] on %s\n",
+		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
 	return hid;
 }
@@ -1264,7 +1432,14 @@
 	struct hid_device *hid = ptr;
 
 	dbg("cleanup called");
-	usb_unlink_urb(&hid->urb);
+	usb_unlink_urb(hid->urbin);
+	usb_unlink_urb(hid->urbout);
+	usb_unlink_urb(hid->urbctrl);
+
+	usb_free_urb(hid->urbin);
+	usb_free_urb(hid->urbctrl);
+	if (hid->urbout)
+		usb_free_urb(hid->urbout);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_disconnect(hid);
@@ -1276,8 +1451,7 @@
 }
 
 static struct usb_device_id hid_usb_ids [] = {
-	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
-	    bInterfaceClass: USB_INTERFACE_CLASS_HID },
+	{ bInterfaceClass: USB_INTERFACE_CLASS_HID },
 	{ }						/* Terminating entry */
 };
 
@@ -1296,8 +1470,7 @@
 	hiddev_init();
 #endif
 	usb_register(&hid_driver);
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
 
 	return 0;
 }
@@ -1313,6 +1486,6 @@
 module_init(hid_init);
 module_exit(hid_exit);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff -Nru a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h
--- a/drivers/usb/hid-debug.h	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/hid-debug.h	Mon Feb 11 23:34:47 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: hid-debug.h,v 1.3 2001/05/10 15:56:07 vojtech Exp $
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
  *
  *  (c) 1999 Andreas Gal		<gal@cs.uni-magdeburg.de>
- *  (c) 2000-2001 Vojtech Pavlik	<vojtech@suse.cz>
+ *  (c) 2000-2001 Vojtech Pavlik	<vojtech@ucw.cz>
  *
  *  Some debug stuff for the HID parser.
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -25,8 +23,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 struct hid_usage_entry {
@@ -36,6 +34,7 @@
 };
 
 static struct hid_usage_entry hid_usage_table[] = {
+  {  0,      0, "Undefined" },
   {  1,      0, "GenericDesktop" },
     {0, 0x01, "Pointer"},
     {0, 0x02, "Mouse"},
@@ -87,6 +86,7 @@
   {  7, 0, "Keyboard" },
   {  8, 0, "LED" },
   {  9, 0, "Button" },
+  { 10, 0, "Ordinal" },
   { 12, 0, "Hotkey" },
   { 13, 0, "Digitizers" },
     {0, 0x01, "Digitizer"},
@@ -112,6 +112,112 @@
     {0, 0x45, "Eraser"},
     {0, 0x46, "TabletPick"},
   { 15, 0, "PhysicalInterfaceDevice" },
+    {0, 0x00, "Undefined"},
+    {0, 0x01, "Physical_Interface_Device"},
+      {0, 0x20, "Normal"},
+    {0, 0x21, "Set_Effect_Report"},
+      {0, 0x22, "Effect_Block_Index"},
+      {0, 0x23, "Parameter_Block_Offset"},
+      {0, 0x24, "ROM_Flag"},
+      {0, 0x25, "Effect_Type"},
+        {0, 0x26, "ET_Constant_Force"},
+        {0, 0x27, "ET_Ramp"},
+        {0, 0x28, "ET_Custom_Force_Data"},
+        {0, 0x30, "ET_Square"},
+        {0, 0x31, "ET_Sine"},
+        {0, 0x32, "ET_Triangle"},
+        {0, 0x33, "ET_Sawtooth_Up"},
+        {0, 0x34, "ET_Sawtooth_Down"},
+        {0, 0x40, "ET_Spring"},
+        {0, 0x41, "ET_Damper"},
+        {0, 0x42, "ET_Inertia"},
+        {0, 0x43, "ET_Friction"},
+      {0, 0x50, "Duration"},
+      {0, 0x51, "Sample_Period"},
+      {0, 0x52, "Gain"},
+      {0, 0x53, "Trigger_Button"},
+      {0, 0x54, "Trigger_Repeat_Interval"},
+      {0, 0x55, "Axes_Enable"},
+        {0, 0x56, "Direction_Enable"},
+      {0, 0x57, "Direction"},
+      {0, 0x58, "Type_Specific_Block_Offset"},
+        {0, 0x59, "Block_Type"},
+        {0, 0x5A, "Set_Envelope_Report"},
+          {0, 0x5B, "Attack_Level"},
+          {0, 0x5C, "Attack_Time"},
+          {0, 0x5D, "Fade_Level"},
+          {0, 0x5E, "Fade_Time"},
+        {0, 0x5F, "Set_Condition_Report"},
+        {0, 0x60, "CP_Offset"},
+        {0, 0x61, "Positive_Coefficient"},
+        {0, 0x62, "Negative_Coefficient"},
+        {0, 0x63, "Positive_Saturation"},
+        {0, 0x64, "Negative_Saturation"},
+        {0, 0x65, "Dead_Band"},
+      {0, 0x66, "Download_Force_Sample"},
+      {0, 0x67, "Isoch_Custom_Force_Enable"},
+      {0, 0x68, "Custom_Force_Data_Report"},
+        {0, 0x69, "Custom_Force_Data"},
+        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+      {0, 0x6B, "Set_Custom_Force_Report"},
+        {0, 0x6C, "Custom_Force_Data_Offset"},
+        {0, 0x6D, "Sample_Count"},
+      {0, 0x6E, "Set_Periodic_Report"},
+        {0, 0x6F, "Offset"},
+        {0, 0x70, "Magnitude"},
+        {0, 0x71, "Phase"},
+        {0, 0x72, "Period"},
+      {0, 0x73, "Set_Constant_Force_Report"},
+        {0, 0x74, "Set_Ramp_Force_Report"},
+        {0, 0x75, "Ramp_Start"},
+        {0, 0x76, "Ramp_End"},
+      {0, 0x77, "Effect_Operation_Report"},
+        {0, 0x78, "Effect_Operation"},
+          {0, 0x79, "Op_Effect_Start"},
+          {0, 0x7A, "Op_Effect_Start_Solo"},
+          {0, 0x7B, "Op_Effect_Stop"},
+          {0, 0x7C, "Loop_Count"},
+      {0, 0x7D, "Device_Gain_Report"},
+        {0, 0x7E, "Device_Gain"},
+    {0, 0x7F, "PID_Pool_Report"},
+      {0, 0x80, "RAM_Pool_Size"},
+      {0, 0x81, "ROM_Pool_Size"},
+      {0, 0x82, "ROM_Effect_Block_Count"},
+      {0, 0x83, "Simultaneous_Effects_Max"},
+      {0, 0x84, "Pool_Alignment"},
+    {0, 0x85, "PID_Pool_Move_Report"},
+      {0, 0x86, "Move_Source"},
+      {0, 0x87, "Move_Destination"},
+      {0, 0x88, "Move_Length"},
+    {0, 0x89, "PID_Block_Load_Report"},
+      {0, 0x8B, "Block_Load_Status"},
+      {0, 0x8C, "Block_Load_Success"},
+      {0, 0x8D, "Block_Load_Full"},
+      {0, 0x8E, "Block_Load_Error"},
+      {0, 0x8F, "Block_Handle"},
+      {0, 0x90, "PID_Block_Free_Report"},
+      {0, 0x91, "Type_Specific_Block_Handle"},
+    {0, 0x92, "PID_State_Report"},
+      {0, 0x94, "Effect_Playing"},
+      {0, 0x95, "PID_Device_Control_Report"},
+        {0, 0x96, "PID_Device_Control"},
+        {0, 0x97, "DC_Enable_Actuators"},
+        {0, 0x98, "DC_Disable_Actuators"},
+        {0, 0x99, "DC_Stop_All_Effects"},
+        {0, 0x9A, "DC_Device_Reset"},
+        {0, 0x9B, "DC_Device_Pause"},
+        {0, 0x9C, "DC_Device_Continue"},
+      {0, 0x9F, "Device_Paused"},
+      {0, 0xA0, "Actuators_Enabled"},
+      {0, 0xA4, "Safety_Switch"},
+      {0, 0xA5, "Actuator_Override_Switch"},
+      {0, 0xA6, "Actuator_Power"},
+    {0, 0xA7, "Start_Delay"},
+    {0, 0xA8, "Parameter_Block_Size"},
+    {0, 0xA9, "Device_Managed_Pool"},
+    {0, 0xAA, "Shared_Parameter_Blocks"},
+    {0, 0xAB, "Create_New_Effect_Report"},
+    {0, 0xAC, "RAM_Pool_Available"},
   { 0, 0, NULL }
 };
 
@@ -176,7 +282,50 @@
 		tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
 	}
 	if (field->unit) {
-		tab(n); printk("Unit(%u)\n", field->unit);
+		char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+		char *units[5][8] = {
+			{ "None", "None", "None", "None", "None", "None", "None", "None" },
+			{ "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+			{ "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+			{ "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+			{ "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+		};
+
+		int i;
+		int sys;
+                __u32 data = field->unit;
+
+		/* First nibble tells us which system we're in. */
+		sys = data & 0xf;
+		data >>= 4;
+
+		if(sys > 4) {
+			tab(n); printk("Unit(Invalid)\n");
+		}
+		else {
+			int earlier_unit = 0;
+
+			tab(n); printk("Unit(%s : ", systems[sys]);
+
+			for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+				char nibble = data & 0xf;
+				data >>= 4;
+				if (nibble != 0) {
+					if(earlier_unit++ > 0)
+						printk("*");
+					printk("%s", units[sys][i]);
+					if(nibble != 1) {
+						/* This is a _signed_ nibble(!) */
+	
+						int val = nibble & 0x7;
+						if(nibble & 0x08)
+							val = -((0x7 & ~val) +1);
+						printk("^%d", val);
+					}
+				}
+			}
+			printk(")\n");
+		}
 	}
 	tab(n); printk("Report Size(%u)\n", field->report_size);
 	tab(n); printk("Report Count(%u)\n", field->report_count);
diff -Nru a/drivers/usb/hid-input.c b/drivers/usb/hid-input.c
--- a/drivers/usb/hid-input.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/hid-input.c	Mon Feb 11 23:34:47 2002
@@ -1,11 +1,9 @@
 /*
- * $Id: hid-input.c,v 1.5 2001/05/23 09:25:02 vojtech Exp $
+ * $Id: hid-input.c,v 1.18 2001/11/07 09:01:18 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
- *  USB HID to Linux Input mapping module
- *
- *  Sponsored by SuSE
+ *  USB HID to Linux Input mapping
  */
 
 /*
@@ -24,13 +22,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/input.h>
 #include <linux/usb.h>
@@ -61,12 +58,13 @@
 static struct {
 	__s32 x;
 	__s32 y;
-}  hid_hat_to_axis[] = {{0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+}  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
 static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage)
 {
 	struct input_dev *input = &device->input;
 	int max;
+	int is_abs = 0;
 	unsigned long *bit;
 
 	switch (usage->hid & HID_USAGE_PAGE) {
@@ -198,6 +196,7 @@
 
 		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
 
+			set_bit(EV_REP, input->evbit);
 			switch (usage->hid & HID_USAGE) {
 				case 0x000: usage->code = 0; break;
 				case 0x034: usage->code = KEY_SLEEP;		break;
@@ -205,14 +204,21 @@
 				case 0x08a: usage->code = KEY_WWW;		break;
 				case 0x095: usage->code = KEY_HELP;		break;
 
+				case 0x0b0: usage->code = KEY_PLAY;		break;
+				case 0x0b1: usage->code = KEY_PAUSE;		break;
+				case 0x0b2: usage->code = KEY_RECORD;		break;
+				case 0x0b3: usage->code = KEY_FASTFORWARD;	break;
 				case 0x0b4: usage->code = KEY_REWIND;		break;
 				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
 				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
 				case 0x0b7: usage->code = KEY_STOPCD;		break;
 				case 0x0b8: usage->code = KEY_EJECTCD;		break;
 				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
-
+			        case 0x0e0: is_abs = 1;
+					    usage->code = ABS_VOLUME;
+					    break;
 				case 0x0e2: usage->code = KEY_MUTE;		break;
+				case 0x0e5: usage->code = KEY_BASSBOOST;	break;
 				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
 				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
 
@@ -220,7 +226,6 @@
 				case 0x18a: usage->code = KEY_MAIL;		break;
 				case 0x192: usage->code = KEY_CALC;		break;
 				case 0x194: usage->code = KEY_FILE;		break;
-
 				case 0x21a: usage->code = KEY_UNDO;		break;
 				case 0x21b: usage->code = KEY_COPY;		break;
 				case 0x21c: usage->code = KEY_CUT;		break;
@@ -235,6 +240,34 @@
 				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
 
 				default:    usage->code = KEY_UNKNOWN;		break;
+			}
+
+			if (is_abs) {
+			        usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+			} else  {
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			}
+			break;
+
+		case HID_UP_HPVENDOR:	/* Reported on a Dutch layout HP5308 */
+
+			set_bit(EV_REP, input->evbit);
+			switch (usage->hid & HID_USAGE) {
+			        case 0x021: usage->code = KEY_PRINT;            break;
+				case 0x070: usage->code = KEY_HP;		break;
+				case 0x071: usage->code = KEY_CAMERA;		break;
+				case 0x072: usage->code = KEY_SOUND;		break;
+				case 0x073: usage->code = KEY_QUESTION;		break;
+
+				case 0x080: usage->code = KEY_EMAIL;		break;
+				case 0x081: usage->code = KEY_CHAT;		break;
+				case 0x082: usage->code = KEY_SEARCH;		break;
+				case 0x083: usage->code = KEY_CONNECT;	        break;
+				case 0x084: usage->code = KEY_FINANCE;		break;
+				case 0x085: usage->code = KEY_SPORT;		break;
+				case 0x086: usage->code = KEY_SHOP;	        break;
+
+				default:    usage->code = KEY_UNKNOWN;		break;
 
 			}
 
@@ -353,7 +386,7 @@
 	}
 
 	hid_set_field(field, offset, value);
-	hid_write_report(hid, field->report);
+	hid_submit_report(hid, field->report, USB_DIR_OUT);
 
 	return 0;
 }
@@ -397,6 +430,8 @@
 	hid->input.close = hidinput_close;
 
 	hid->input.name = hid->name;
+	hid->input.phys = hid->phys;
+	hid->input.uniq = hid->uniq;
 	hid->input.idbus = BUS_USB;
 	hid->input.idvendor = dev->descriptor.idVendor;
 	hid->input.idproduct = dev->descriptor.idProduct;
diff -Nru a/drivers/usb/hid.h b/drivers/usb/hid.h
--- a/drivers/usb/hid.h	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/hid.h	Mon Feb 11 23:34:47 2002
@@ -2,12 +2,10 @@
 #define __HID_H
 
 /*
- * $Id: hid.h,v 1.10 2001/05/10 15:56:07 vojtech Exp $
+ * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $
  *
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -26,13 +24,24 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+/*
+ * USB HID (Human Interface Device) interface class code
+ */
+
+#define USB_INTERFACE_CLASS_HID		3
+
 /*
  * HID class requests
  */
+
 #define HID_REQ_GET_REPORT		0x01
 #define HID_REQ_GET_IDLE		0x02
 #define HID_REQ_GET_PROTOCOL		0x03
@@ -43,86 +52,12 @@
 /*
  * HID class descriptor types
  */
+
 #define HID_DT_HID			(USB_TYPE_CLASS | 0x01)
 #define HID_DT_REPORT			(USB_TYPE_CLASS | 0x02)
 #define HID_DT_PHYSICAL			(USB_TYPE_CLASS | 0x03)
 
 /*
- * Utilities for class control messaging
- */
-static inline int
-hid_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		(duration << 8) | report_id, ifnum, NULL, 0,
-		HZ * USB_CTRL_SET_TIMEOUT);
-}
-
-static inline int
-hid_get_protocol(struct usb_device *dev, int ifnum)
-{
-	unsigned char type;
-	int ret;
-
-	if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			HID_REQ_GET_PROTOCOL,
-			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, ifnum, &type, 1, 
-			HZ * USB_CTRL_GET_TIMEOUT)) < 0)
-		return ret;
-
-	return type;
-}
-
-static inline int
-hid_set_protocol(struct usb_device *dev, int ifnum, int protocol)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		HID_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		protocol, ifnum, NULL, 0, 
-		HZ * USB_CTRL_SET_TIMEOUT);
-}
-
-static inline int
-hid_get_report(struct usb_device *dev, int ifnum, unsigned char type,
-	unsigned char id, void *buf, int size)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		HID_REQ_GET_REPORT,
-		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		(type << 8) + id, ifnum, buf, size, 
-		HZ * USB_CTRL_GET_TIMEOUT);
-}
-
-static inline int
-hid_set_report(struct usb_device *dev, int ifnum, unsigned char type,
-	unsigned char id, void *buf, int size)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		(type << 8) + id, ifnum, buf, size, HZ);
-		// FIXME USB_CTRL_SET_TIMEOUT
-}
-
-
-/*
- * "Boot Protocol" keyboard/mouse drivers use don't use all of HID;
- * they're a lot smaller but can't support all the device features.
- */
-#ifndef	_HID_BOOT_PROTOCOL
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-
-/*
- * USB HID (Human Interface Device) interface class code
- */
-
-#define USB_INTERFACE_CLASS_HID		3
-
-/*
  * We parse each description item into this structure. Short items data
  * values are expanded to 32-bit signed int, long items contain a pointer
  * into the data area.
@@ -240,9 +175,11 @@
 #define HID_UP_KEYBOARD 	0x00070000
 #define HID_UP_LED 		0x00080000
 #define HID_UP_BUTTON 		0x00090000
+#define HID_UP_ORDINAL 		0x000a0000
 #define HID_UP_CONSUMER		0x000c0000
 #define HID_UP_DIGITIZER 	0x000d0000
 #define HID_UP_PID 		0x000f0000
+#define HID_UP_HPVENDOR         0xff7f0000
 
 #define HID_USAGE		0x0000ffff
 
@@ -279,7 +216,7 @@
 	__s32    logical_maximum;
 	__s32    physical_minimum;
 	__s32    physical_maximum;
-	unsigned unit_exponent;
+	__s32    unit_exponent;
 	unsigned unit;
 	unsigned report_id;
 	unsigned report_size;
@@ -336,7 +273,7 @@
 	__s32     logical_maximum;
 	__s32     physical_minimum;
 	__s32     physical_maximum;
-	unsigned  unit_exponent;
+	__s32     unit_exponent;
 	unsigned  unit;
 	struct hid_report *report;	/* associated report */
 };
@@ -350,8 +287,6 @@
 	struct hid_field *field[HID_MAX_FIELDS];	/* fields of the report */
 	unsigned maxfield;				/* maximum valid field index */
 	unsigned size;					/* size of the report (bits) */
-	unsigned idx;					/* where we're in data */
-	unsigned char *data;				/* data for multi-packet reports */
 	struct hid_device *device;			/* associated device */
 };
 
@@ -364,16 +299,20 @@
 #define HID_REPORT_TYPES 3
 
 #define HID_BUFFER_SIZE		32
-#define HID_CONTROL_FIFO_SIZE	8
+#define HID_CONTROL_FIFO_SIZE	64
+#define HID_OUTPUT_FIFO_SIZE	64
 
 struct hid_control_fifo {
-	struct usb_ctrlrequest dr;
-	char buffer[HID_BUFFER_SIZE];
+	unsigned char dir;
+	struct hid_report *report;
 };
 
 #define HID_CLAIMED_INPUT	1
 #define HID_CLAIMED_HIDDEV	2
 
+#define HID_CTRL_RUNNING	1
+#define HID_OUT_RUNNING		2
+
 struct hid_device {							/* device report descriptor */
 	 __u8 *rdesc;
 	unsigned rsize;
@@ -386,12 +325,23 @@
 	struct usb_device *dev;						/* USB device */
 	int ifnum;							/* USB interface number */
 
-	struct urb urb;							/* USB URB structure */
-	char buffer[HID_BUFFER_SIZE];					/* Rx buffer */
+	unsigned long iofl;						/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
 
-	struct urb urbout;						/* Output URB */
-	struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE];		/* Transmit buffer */
-	unsigned char outhead, outtail;					/* Tx buffer head & tail */
+	struct urb *urbin;						/* Input URB */
+	char inbuf[HID_BUFFER_SIZE];					/* Input buffer */
+
+	struct urb *urbctrl;						/* Control URB */
+	struct usb_ctrlrequest cr;					/* Control request struct */
+	struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];		/* Control fifo */
+	unsigned char ctrlhead, ctrltail;				/* Control fifo head & tail */
+	char ctrlbuf[HID_BUFFER_SIZE];					/* Control buffer */
+	spinlock_t ctrllock;						/* Control fifo spinlock */
+
+	struct urb *urbout;						/* Output URB */
+	struct hid_report *out[HID_CONTROL_FIFO_SIZE];			/* Output pipe fifo */
+	unsigned char outhead, outtail;					/* Output pipe fifo head & tail */
+	char outbuf[HID_BUFFER_SIZE];					/* Output buffer */
+	spinlock_t outlock;						/* Output fifo spinlock */
 
 	unsigned claimed;						/* Claimed by hidinput, hiddev? */	
 	unsigned quirks;						/* Various quirks the device can pull on us */
@@ -400,8 +350,12 @@
 	void *hiddev;							/* The hiddev structure */
 	int minor;							/* Hiddev minor number */
 
+	wait_queue_head_t wait;						/* For sleeping */
+
 	int open;							/* is the device open by anyone? */
 	char name[128];							/* Device name */
+	char phys[64];							/* Device physical location */
+	char uniq[64];							/* Device unique identifier (serial #) */
 };
 
 #define HID_GLOBAL_STACK_SIZE 4
@@ -441,19 +395,18 @@
 #else
 #define hid_dump_input(a,b)	do { } while (0)
 #define hid_dump_device(c)	do { } while (0)
-#endif /* DEBUG */
+#define hid_dump_field(a,b)	do { } while (0)
+#endif
 
-#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || ( a == 0x000c0001))
+#endif
+
+/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
+/* We ignore a few input applications that are not widely used */
+#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
 
 int hid_open(struct hid_device *);
 void hid_close(struct hid_device *);
 int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **);
 int hid_set_field(struct hid_field *, unsigned, __s32);
-void hid_write_report(struct hid_device *, struct hid_report *);
-void hid_read_report(struct hid_device *, struct hid_report *);
+void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
 void hid_init_reports(struct hid_device *hid);
-
-#endif	/* !_HID_BOOT_PROTOCOL */
-
-#endif	/* !__HID_H */
-
diff -Nru a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c
--- a/drivers/usb/hiddev.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/hiddev.c	Mon Feb 11 23:34:47 2002
@@ -400,7 +400,7 @@
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
-		hid_read_report(hid, report);
+		hid_submit_report(hid, report, USB_DIR_IN);
 
 		return 0;
 
@@ -414,7 +414,7 @@
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
-		hid_write_report(hid, report);
+		hid_submit_report(hid, report, USB_DIR_OUT);
 
 		return 0;
 
diff -Nru a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
--- a/drivers/usb/usbkbd.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/usbkbd.c	Mon Feb 11 23:34:47 2002
@@ -1,11 +1,9 @@
 /*
- * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $
+ * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  USB HIDBP Keyboard support
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -24,8 +22,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -35,19 +33,17 @@
 #include <linux/init.h>
 #include <linux/usb.h>
 
-#define	_HID_BOOT_PROTOCOL
-#include "hid.h"
-
 /*
  * Version Information
  */
 #define DRIVER_VERSION ""
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
+#define DRIVER_LICENSE "GPL"
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
 
 static unsigned char usb_kbd_keycode[256] = {
 	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
@@ -74,9 +70,10 @@
 	unsigned char new[8];
 	unsigned char old[8];
 	struct urb *irq, *led;
-	struct usb_ctrlrequest dr;
+	struct usb_ctrlrequest cr;
 	unsigned char leds, newleds;
 	char name[128];
+	char phys[64];
 	int open;
 };
 
@@ -129,7 +126,7 @@
 
 	kbd->leds = kbd->newleds;
 	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led, GFP_KERNEL))
+	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
 		err("usb_submit_urb(leds) failed");
 
 	return 0;
@@ -147,7 +144,7 @@
 
 	kbd->leds = kbd->newleds;
 	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led, GFP_KERNEL))
+	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
 		err("usb_submit_urb(leds) failed");
 }
 
@@ -181,6 +178,7 @@
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_kbd *kbd;
 	int i, pipe, maxp;
+	char path[64];
 	char *buf;
 
 	iface = &dev->actconfig->interface[ifnum];
@@ -195,9 +193,6 @@
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-	hid_set_protocol(dev, interface->bInterfaceNumber, 0);
-	hid_set_idle(dev, interface->bInterfaceNumber, 0, 0);
-
 	if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
 	memset(kbd, 0, sizeof(struct usb_kbd));
 
@@ -230,13 +225,17 @@
 	FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
 		usb_kbd_irq, kbd, endpoint->bInterval);
 
-	kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	kbd->dr.bRequest = HID_REQ_SET_REPORT;
-	kbd->dr.wValue = 0x200;
-	kbd->dr.wIndex = interface->bInterfaceNumber;
-	kbd->dr.wLength = 1;
+	kbd->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kbd->cr.bRequest = 0x09;
+	kbd->cr.wValue = 0x200;
+	kbd->cr.wIndex = interface->bInterfaceNumber;
+	kbd->cr.wLength = 1;
+
+	usb_make_path(dev, path, 64);
+	sprintf(kbd->phys, "%s/input0", path);
 
 	kbd->dev.name = kbd->name;
+	kbd->dev.phys = kbd->phys;	
 	kbd->dev.idbus = BUS_USB;
 	kbd->dev.idvendor = dev->descriptor.idVendor;
 	kbd->dev.idproduct = dev->descriptor.idProduct;
@@ -261,12 +260,11 @@
 	kfree(buf);
 
 	FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
-		(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
+		(void*) &kbd->cr, &kbd->leds, 1, usb_kbd_led, kbd);
 			
 	input_register_device(&kbd->dev);
 
-	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-		 kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);
+	printk(KERN_INFO "input: %s on %s\n", kbd->name, path);
 
 	return kbd;
 }
diff -Nru a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c
--- a/drivers/usb/usbmouse.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/usbmouse.c	Mon Feb 11 23:34:47 2002
@@ -1,11 +1,9 @@
 /*
- * $Id: usbmouse.c,v 1.6 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  USB HIDBP Mouse support
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -24,8 +22,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -35,23 +33,22 @@
 #include <linux/init.h>
 #include <linux/usb.h>
 
-#define	_HID_BOOT_PROTOCOL
-#include "hid.h"
-
 /*
  * Version Information
  */
 #define DRIVER_VERSION "v1.6"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB HID Boot Protocol mouse driver"
+#define DRIVER_LICENSE "GPL"
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
 
 struct usb_mouse {
 	signed char data[8];
 	char name[128];
+	char phys[64];
 	struct usb_device *usbdev;
 	struct input_dev dev;
 	struct urb *irq;
@@ -107,6 +104,7 @@
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_mouse *mouse;
 	int pipe, maxp;
+	char path[64];
 	char *buf;
 
 	iface = &dev->actconfig->interface[ifnum];
@@ -121,8 +119,6 @@
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-	hid_set_idle(dev, interface->bInterfaceNumber, 0, 0);
-
 	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
 	memset(mouse, 0, sizeof(struct usb_mouse));
 
@@ -144,7 +140,11 @@
 	mouse->dev.open = usb_mouse_open;
 	mouse->dev.close = usb_mouse_close;
 
+	usb_make_path(dev, path, 64);
+	sprintf(mouse->phys, "%s/input0", path);
+
 	mouse->dev.name = mouse->name;
+	mouse->dev.phys = mouse->phys;
 	mouse->dev.idbus = BUS_USB;
 	mouse->dev.idvendor = dev->descriptor.idVendor;
 	mouse->dev.idproduct = dev->descriptor.idProduct;
@@ -173,8 +173,7 @@
 
 	input_register_device(&mouse->dev);
 
-	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-		 mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum);
+	printk(KERN_INFO "input: %s on %s\n", mouse->name, path);
 
 	return mouse;
 }
diff -Nru a/drivers/usb/wacom.c b/drivers/usb/wacom.c
--- a/drivers/usb/wacom.c	Mon Feb 11 23:34:47 2002
+++ b/drivers/usb/wacom.c	Mon Feb 11 23:34:47 2002
@@ -1,7 +1,7 @@
 /*
- * $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $
+ * $Id: wacom.c,v 1.28 2001/09/25 10:12:07 vojtech Exp $
  *
- *  Copyright (c) 2000-2001 Vojtech Pavlik	<vojtech@suse.cz>
+ *  Copyright (c) 2000-2001 Vojtech Pavlik	<vojtech@ucw.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
  *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
  *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
@@ -11,8 +11,6 @@
  *
  *  USB Wacom Graphire and Wacom Intuos tablet support
  *
- *  Sponsored by SuSE
- *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
  *      v0.2 (aba) - Support for all buttons / combinations
@@ -57,8 +55,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -72,12 +70,13 @@
  * Version Information
  */
 #define DRIVER_VERSION "v1.21"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
+#define DRIVER_LICENSE "GPL"
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
 
 #define USB_VENDOR_ID_WACOM	0x056a
 
@@ -106,6 +105,7 @@
 	int open;
 	int x, y;
 	__u32 serial[2];
+	char phys[32];
 };
 
 static void wacom_pl_irq(struct urb *urb)
@@ -354,6 +354,7 @@
 {
 	struct usb_endpoint_descriptor *endpoint;
 	struct wacom *wacom;
+	char path[64];
 
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
 	memset(wacom, 0, sizeof(struct wacom));
@@ -394,7 +395,11 @@
 	wacom->dev.open = wacom_open;
 	wacom->dev.close = wacom_close;
 
+	usb_make_path(dev, path, 64);
+	sprintf(wacom->phys, "%s/input0", path);
+
 	wacom->dev.name = wacom->features->name;
+	wacom->dev.phys = wacom->phys;
 	wacom->dev.idbus = BUS_USB;
 	wacom->dev.idvendor = dev->descriptor.idVendor;
 	wacom->dev.idproduct = dev->descriptor.idProduct;
@@ -408,8 +413,7 @@
 
 	input_register_device(&wacom->dev);
 
-	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-		 wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum);
+	printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);
 
 	return wacom;
 }
