Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 drivers/usb/input/hid-core.c |   60 ++++++++++++++++++++++++++++++-------------
 drivers/usb/input/hid.h      |    5 ++-
 2 files changed, 46 insertions(+), 19 deletions(-)

diff -puN drivers/usb/input/hid-core.c~input-hid-variable-max-buffer-size.diff drivers/usb/input/hid-core.c
--- devel/drivers/usb/input/hid-core.c~input-hid-variable-max-buffer-size.diff	2005-08-21 23:47:35.000000000 -0700
+++ devel-akpm/drivers/usb/input/hid-core.c	2005-08-21 23:47:35.000000000 -0700
@@ -2,7 +2,8 @@
  *  USB HID support for Linux
  *
  *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2001 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
  */
 
 /*
@@ -38,7 +39,7 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v2.01"
+#define DRIVER_VERSION "v2.6"
 #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
 #define DRIVER_DESC "USB HID core driver"
 #define DRIVER_LICENSE "GPL"
@@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_de
 		if (maxpacket > 0) {
 			padlen = (len + maxpacket - 1) / maxpacket;
 			padlen *= maxpacket;
-			if (padlen > HID_BUFFER_SIZE)
-				padlen = HID_BUFFER_SIZE;
+			if (padlen > hid->bufsize)
+				padlen = hid->bufsize; 
 		} else
 			padlen = 0;
 		hid->urbctrl->transfer_buffer_length = padlen;
@@ -1284,13 +1285,8 @@ void hid_init_reports(struct hid_device 
 	struct hid_report *report;
 	int err, ret;
 
-	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) {
-		int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
-		if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
-		if (size > hid->urbin->transfer_buffer_length)
-			hid->urbin->transfer_buffer_length = size;
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
 		hid_submit_report(hid, report, USB_DIR_IN);
-	}
 
 	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
 		hid_submit_report(hid, report, USB_DIR_IN);
@@ -1564,15 +1560,30 @@ static struct hid_blacklist {
 	{ 0, 0 }
 };
 
+/*
+ * Traverse the supplied list of reports and find the longest
+ */
+static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max) {
+	struct hid_report *report;
+	int size;
+
+	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
+		size = ((report->size - 1) >> 3) + 1 + 
+		       ((type == HID_INPUT_REPORT) && hid->report_enum[type].numbered);
+		if (*max < size)
+			*max = size;
+	}
+}
+
 static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
 {
-	if (!(hid->inbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->inbuf_dma)))
+	if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma)))
 		return -1;
-	if (!(hid->outbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->outbuf_dma)))
+	if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma)))
 		return -1;
 	if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma)))
 		return -1;
-	if (!(hid->ctrlbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->ctrlbuf_dma)))
+	if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma)))
 		return -1;
 
 	return 0;
@@ -1581,13 +1592,13 @@ static int hid_alloc_buffers(struct usb_
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
 	if (hid->inbuf)
-		usb_buffer_free(dev, HID_BUFFER_SIZE, hid->inbuf, hid->inbuf_dma);
+		usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma);
 	if (hid->outbuf)
-		usb_buffer_free(dev, HID_BUFFER_SIZE, hid->outbuf, hid->outbuf_dma);
+		usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma);
 	if (hid->cr)
 		usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma);
 	if (hid->ctrlbuf)
-		usb_buffer_free(dev, HID_BUFFER_SIZE, hid->ctrlbuf, hid->ctrlbuf_dma);
+		usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
 }
 
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
@@ -1598,7 +1609,7 @@ static struct hid_device *usb_hid_config
 	struct hid_device *hid;
 	unsigned quirks = 0, rsize = 0;
 	char *buf, *rdesc;
-	int n;
+	int n, insize = 0;
 
 	for (n = 0; hid_blacklist[n].idVendor; n++)
 		if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
@@ -1652,6 +1663,19 @@ static struct hid_device *usb_hid_config
 	kfree(rdesc);
 	hid->quirks = quirks;
 
+	hid->bufsize = HID_MIN_BUFFER_SIZE;
+	hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize);
+	hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize);
+	hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize);
+
+	if (hid->bufsize > HID_MAX_BUFFER_SIZE)
+		hid->bufsize = HID_MAX_BUFFER_SIZE;
+
+	hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
+
+	if (insize > HID_MAX_BUFFER_SIZE)
+		insize = HID_MAX_BUFFER_SIZE;
+
 	if (hid_alloc_buffers(dev, hid)) {
 		hid_free_buffers(dev, hid);
 		goto fail;
@@ -1682,7 +1706,7 @@ static struct hid_device *usb_hid_config
 			if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
 				goto fail;
 			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
+			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize,
 					 hid_irq_in, hid, interval);
 			hid->urbin->transfer_dma = hid->inbuf_dma;
 			hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
diff -puN drivers/usb/input/hid.h~input-hid-variable-max-buffer-size.diff drivers/usb/input/hid.h
--- devel/drivers/usb/input/hid.h~input-hid-variable-max-buffer-size.diff	2005-08-21 23:47:35.000000000 -0700
+++ devel-akpm/drivers/usb/input/hid.h	2005-08-21 23:47:35.000000000 -0700
@@ -351,7 +351,8 @@ struct hid_report_enum {
 
 #define HID_REPORT_TYPES 3
 
-#define HID_BUFFER_SIZE		64		/* use 64 for compatibility with all possible packetlen */
+#define HID_MIN_BUFFER_SIZE	64		/* make sure there is at least a packet size of space */
+#define HID_MAX_BUFFER_SIZE	4096		/* 4kb */
 #define HID_CONTROL_FIFO_SIZE	256		/* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE	64
 
@@ -389,6 +390,8 @@ struct hid_device {							/* device repo
 
 	unsigned long iofl;						/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
 
+	unsigned int bufsize;						/* URB buffer size */
+
 	struct urb *urbin;						/* Input URB */
 	char *inbuf;							/* Input buffer */
 	dma_addr_t inbuf_dma;						/* Input buffer dma */
_