aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorMichael Haboustak <mike-@cinci.rr.com>2005-09-05 01:12:01 -0400
committerDmitry Torokhov <dtor_core@ameritech.net>2005-09-05 01:12:01 -0400
commitbf0964dcda97e42964d312d0ff73a832171e080a (patch)
tree6435056655586ed66a96fbba03305331f8828a28 /drivers/usb
parent903b126bffb77dc313b7c2971880df408bf41a9e (diff)
Input: HID - handle multi-transascion reports
Fixes handling of multi-transaction reports for HID devices. New function hid_size_buffers() that calculates the longest report for each endpoint and stores the result in the hid_device object. These lengths are used to allocate buffers that are large enough to store any report on the endpoint. For compatibility, the minimum size for an endpoint buffer set to HID_BUFFER_SIZE rather than the known optimal case (the longest report length). It fixes bug #3063 in bugzilla. Signed-off-by: Michael Haboustak <mike-@cinci.rr.com> I simplified the patch a bit to use just a single buffer size. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/input/hid-core.c62
-rw-r--r--drivers/usb/input/hid.h5
2 files changed, 48 insertions, 19 deletions
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index b2cb2b35892e..376b6043bbff 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -2,7 +2,8 @@
2 * USB HID support for Linux 2 * USB HID support for Linux
3 * 3 *
4 * Copyright (c) 1999 Andreas Gal 4 * Copyright (c) 1999 Andreas Gal
5 * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
6 */ 7 */
7 8
8/* 9/*
@@ -38,7 +39,7 @@
38 * Version Information 39 * Version Information
39 */ 40 */
40 41
41#define DRIVER_VERSION "v2.01" 42#define DRIVER_VERSION "v2.6"
42#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" 43#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
43#define DRIVER_DESC "USB HID core driver" 44#define DRIVER_DESC "USB HID core driver"
44#define DRIVER_LICENSE "GPL" 45#define DRIVER_LICENSE "GPL"
@@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_device *hid)
1058 if (maxpacket > 0) { 1059 if (maxpacket > 0) {
1059 padlen = (len + maxpacket - 1) / maxpacket; 1060 padlen = (len + maxpacket - 1) / maxpacket;
1060 padlen *= maxpacket; 1061 padlen *= maxpacket;
1061 if (padlen > HID_BUFFER_SIZE) 1062 if (padlen > hid->bufsize)
1062 padlen = HID_BUFFER_SIZE; 1063 padlen = hid->bufsize;
1063 } else 1064 } else
1064 padlen = 0; 1065 padlen = 0;
1065 hid->urbctrl->transfer_buffer_length = padlen; 1066 hid->urbctrl->transfer_buffer_length = padlen;
@@ -1284,13 +1285,8 @@ void hid_init_reports(struct hid_device *hid)
1284 struct hid_report *report; 1285 struct hid_report *report;
1285 int err, ret; 1286 int err, ret;
1286 1287
1287 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) { 1288 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
1288 int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
1289 if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
1290 if (size > hid->urbin->transfer_buffer_length)
1291 hid->urbin->transfer_buffer_length = size;
1292 hid_submit_report(hid, report, USB_DIR_IN); 1289 hid_submit_report(hid, report, USB_DIR_IN);
1293 }
1294 1290
1295 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) 1291 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
1296 hid_submit_report(hid, report, USB_DIR_IN); 1292 hid_submit_report(hid, report, USB_DIR_IN);
@@ -1564,15 +1560,32 @@ static struct hid_blacklist {
1564 { 0, 0 } 1560 { 0, 0 }
1565}; 1561};
1566 1562
1563/*
1564 * Traverse the supplied list of reports and find the longest
1565 */
1566static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
1567{
1568 struct hid_report *report;
1569 int size;
1570
1571 list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
1572 size = ((report->size - 1) >> 3) + 1;
1573 if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
1574 size++;
1575 if (*max < size)
1576 *max = size;
1577 }
1578}
1579
1567static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) 1580static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
1568{ 1581{
1569 if (!(hid->inbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->inbuf_dma))) 1582 if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma)))
1570 return -1; 1583 return -1;
1571 if (!(hid->outbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->outbuf_dma))) 1584 if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma)))
1572 return -1; 1585 return -1;
1573 if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) 1586 if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma)))
1574 return -1; 1587 return -1;
1575 if (!(hid->ctrlbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->ctrlbuf_dma))) 1588 if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma)))
1576 return -1; 1589 return -1;
1577 1590
1578 return 0; 1591 return 0;
@@ -1581,13 +1594,13 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
1581static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) 1594static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
1582{ 1595{
1583 if (hid->inbuf) 1596 if (hid->inbuf)
1584 usb_buffer_free(dev, HID_BUFFER_SIZE, hid->inbuf, hid->inbuf_dma); 1597 usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma);
1585 if (hid->outbuf) 1598 if (hid->outbuf)
1586 usb_buffer_free(dev, HID_BUFFER_SIZE, hid->outbuf, hid->outbuf_dma); 1599 usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma);
1587 if (hid->cr) 1600 if (hid->cr)
1588 usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); 1601 usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma);
1589 if (hid->ctrlbuf) 1602 if (hid->ctrlbuf)
1590 usb_buffer_free(dev, HID_BUFFER_SIZE, hid->ctrlbuf, hid->ctrlbuf_dma); 1603 usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
1591} 1604}
1592 1605
1593static struct hid_device *usb_hid_configure(struct usb_interface *intf) 1606static struct hid_device *usb_hid_configure(struct usb_interface *intf)
@@ -1598,7 +1611,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
1598 struct hid_device *hid; 1611 struct hid_device *hid;
1599 unsigned quirks = 0, rsize = 0; 1612 unsigned quirks = 0, rsize = 0;
1600 char *buf, *rdesc; 1613 char *buf, *rdesc;
1601 int n; 1614 int n, insize = 0;
1602 1615
1603 for (n = 0; hid_blacklist[n].idVendor; n++) 1616 for (n = 0; hid_blacklist[n].idVendor; n++)
1604 if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && 1617 if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
@@ -1652,6 +1665,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
1652 kfree(rdesc); 1665 kfree(rdesc);
1653 hid->quirks = quirks; 1666 hid->quirks = quirks;
1654 1667
1668 hid->bufsize = HID_MIN_BUFFER_SIZE;
1669 hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize);
1670 hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize);
1671 hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize);
1672
1673 if (hid->bufsize > HID_MAX_BUFFER_SIZE)
1674 hid->bufsize = HID_MAX_BUFFER_SIZE;
1675
1676 hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
1677
1678 if (insize > HID_MAX_BUFFER_SIZE)
1679 insize = HID_MAX_BUFFER_SIZE;
1680
1655 if (hid_alloc_buffers(dev, hid)) { 1681 if (hid_alloc_buffers(dev, hid)) {
1656 hid_free_buffers(dev, hid); 1682 hid_free_buffers(dev, hid);
1657 goto fail; 1683 goto fail;
@@ -1682,7 +1708,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
1682 if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) 1708 if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
1683 goto fail; 1709 goto fail;
1684 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 1710 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
1685 usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, 1711 usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize,
1686 hid_irq_in, hid, interval); 1712 hid_irq_in, hid, interval);
1687 hid->urbin->transfer_dma = hid->inbuf_dma; 1713 hid->urbin->transfer_dma = hid->inbuf_dma;
1688 hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); 1714 hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index ca3e170ce0b3..d76bbc81f6a8 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -351,7 +351,8 @@ struct hid_report_enum {
351 351
352#define HID_REPORT_TYPES 3 352#define HID_REPORT_TYPES 3
353 353
354#define HID_BUFFER_SIZE 64 /* use 64 for compatibility with all possible packetlen */ 354#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */
355#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */
355#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ 356#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
356#define HID_OUTPUT_FIFO_SIZE 64 357#define HID_OUTPUT_FIFO_SIZE 64
357 358
@@ -389,6 +390,8 @@ struct hid_device { /* device report descriptor */
389 390
390 unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ 391 unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
391 392
393 unsigned int bufsize; /* URB buffer size */
394
392 struct urb *urbin; /* Input URB */ 395 struct urb *urbin; /* Input URB */
393 char *inbuf; /* Input buffer */ 396 char *inbuf; /* Input buffer */
394 dma_addr_t inbuf_dma; /* Input buffer dma */ 397 dma_addr_t inbuf_dma; /* Input buffer dma */