diff options
| author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2011-05-30 03:15:47 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2011-05-31 14:47:26 -0400 |
| commit | 59342f6a6bc35df623fb44784daa5e1077063b8f (patch) | |
| tree | 612d3ec8c09d18fb0a97f841a535de8b25e46ada | |
| parent | 66870b1ccd5c1460e437c18b0026e2dcaab1ece9 (diff) | |
zd1211rw: fix to work on OHCI
zd1211 devices register 'EP 4 OUT' endpoint as Interrupt type on USB 2.0:
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
However on USB 1.1 endpoint becomes Bulk:
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Commit 37939810b937aba830dd751291fcdc51cae1a6cb assumed that endpoint is
always interrupt type and changed usb_bulk_msg() calls to usb_interrupt_msg().
Problem here is that usb_bulk_msg() on interrupt endpoint selfcorrects the
call and changes requested pipe to interrupt type (see usb_bulk_msg).
However with usb_interrupt_msg() on bulk endpoint does not correct the
pipe type to bulk, but instead URB is submitted with interrupt type pipe.
So pre-2.6.39 used usb_bulk_msg() and therefore worked with both endpoint
types, however in 2.6.39 usb_interrupt_msg() with bulk endpoint causes
ohci_hcd to fail submitted URB instantly with -ENOSPC and preventing zd1211rw
from working with OHCI.
Fix this by detecting endpoint type and using correct endpoint/pipe types
for URB. Also fix asynchronous zd_usb_iowrite16v_async() to use right
URB type on 'EP 4 OUT'.
Cc: stable@kernel.org
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 0e819943b9e4..631194d49828 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
| @@ -1533,6 +1533,31 @@ static void __exit usb_exit(void) | |||
| 1533 | module_init(usb_init); | 1533 | module_init(usb_init); |
| 1534 | module_exit(usb_exit); | 1534 | module_exit(usb_exit); |
| 1535 | 1535 | ||
| 1536 | static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len, | ||
| 1537 | int *actual_length, int timeout) | ||
| 1538 | { | ||
| 1539 | /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in | ||
| 1540 | * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint | ||
| 1541 | * descriptor. | ||
| 1542 | */ | ||
| 1543 | struct usb_host_endpoint *ep; | ||
| 1544 | unsigned int pipe; | ||
| 1545 | |||
| 1546 | pipe = usb_sndintpipe(udev, EP_REGS_OUT); | ||
| 1547 | ep = usb_pipe_endpoint(udev, pipe); | ||
| 1548 | if (!ep) | ||
| 1549 | return -EINVAL; | ||
| 1550 | |||
| 1551 | if (usb_endpoint_xfer_int(&ep->desc)) { | ||
| 1552 | return usb_interrupt_msg(udev, pipe, data, len, | ||
| 1553 | actual_length, timeout); | ||
| 1554 | } else { | ||
| 1555 | pipe = usb_sndbulkpipe(udev, EP_REGS_OUT); | ||
| 1556 | return usb_bulk_msg(udev, pipe, data, len, actual_length, | ||
| 1557 | timeout); | ||
| 1558 | } | ||
| 1559 | } | ||
| 1560 | |||
| 1536 | static int usb_int_regs_length(unsigned int count) | 1561 | static int usb_int_regs_length(unsigned int count) |
| 1537 | { | 1562 | { |
| 1538 | return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data); | 1563 | return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data); |
| @@ -1648,15 +1673,14 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, | |||
| 1648 | 1673 | ||
| 1649 | udev = zd_usb_to_usbdev(usb); | 1674 | udev = zd_usb_to_usbdev(usb); |
| 1650 | prepare_read_regs_int(usb); | 1675 | prepare_read_regs_int(usb); |
| 1651 | r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT), | 1676 | r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); |
| 1652 | req, req_len, &actual_req_len, 50 /* ms */); | ||
| 1653 | if (r) { | 1677 | if (r) { |
| 1654 | dev_dbg_f(zd_usb_dev(usb), | 1678 | dev_dbg_f(zd_usb_dev(usb), |
| 1655 | "error in usb_interrupt_msg(). Error number %d\n", r); | 1679 | "error in zd_ep_regs_out_msg(). Error number %d\n", r); |
| 1656 | goto error; | 1680 | goto error; |
| 1657 | } | 1681 | } |
| 1658 | if (req_len != actual_req_len) { | 1682 | if (req_len != actual_req_len) { |
| 1659 | dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()\n" | 1683 | dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n" |
| 1660 | " req_len %d != actual_req_len %d\n", | 1684 | " req_len %d != actual_req_len %d\n", |
| 1661 | req_len, actual_req_len); | 1685 | req_len, actual_req_len); |
| 1662 | r = -EIO; | 1686 | r = -EIO; |
| @@ -1818,9 +1842,17 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | |||
| 1818 | rw->value = cpu_to_le16(ioreqs[i].value); | 1842 | rw->value = cpu_to_le16(ioreqs[i].value); |
| 1819 | } | 1843 | } |
| 1820 | 1844 | ||
| 1821 | usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), | 1845 | /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode |
| 1822 | req, req_len, iowrite16v_urb_complete, usb, | 1846 | * endpoint is bulk. Select correct type URB by endpoint descriptor. |
| 1823 | ep->desc.bInterval); | 1847 | */ |
| 1848 | if (usb_endpoint_xfer_int(&ep->desc)) | ||
| 1849 | usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), | ||
| 1850 | req, req_len, iowrite16v_urb_complete, usb, | ||
| 1851 | ep->desc.bInterval); | ||
| 1852 | else | ||
| 1853 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT), | ||
| 1854 | req, req_len, iowrite16v_urb_complete, usb); | ||
| 1855 | |||
| 1824 | urb->transfer_flags |= URB_FREE_BUFFER; | 1856 | urb->transfer_flags |= URB_FREE_BUFFER; |
| 1825 | 1857 | ||
| 1826 | /* Submit previous URB */ | 1858 | /* Submit previous URB */ |
| @@ -1924,15 +1956,14 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) | |||
| 1924 | } | 1956 | } |
| 1925 | 1957 | ||
| 1926 | udev = zd_usb_to_usbdev(usb); | 1958 | udev = zd_usb_to_usbdev(usb); |
| 1927 | r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT), | 1959 | r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); |
| 1928 | req, req_len, &actual_req_len, 50 /* ms */); | ||
| 1929 | if (r) { | 1960 | if (r) { |
| 1930 | dev_dbg_f(zd_usb_dev(usb), | 1961 | dev_dbg_f(zd_usb_dev(usb), |
| 1931 | "error in usb_interrupt_msg(). Error number %d\n", r); | 1962 | "error in zd_ep_regs_out_msg(). Error number %d\n", r); |
| 1932 | goto out; | 1963 | goto out; |
| 1933 | } | 1964 | } |
| 1934 | if (req_len != actual_req_len) { | 1965 | if (req_len != actual_req_len) { |
| 1935 | dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()" | 1966 | dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()" |
| 1936 | " req_len %d != actual_req_len %d\n", | 1967 | " req_len %d != actual_req_len %d\n", |
| 1937 | req_len, actual_req_len); | 1968 | req_len, actual_req_len); |
| 1938 | r = -EIO; | 1969 | r = -EIO; |
