From patchwork Mon May 30 07:15:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jussi Kivilinna X-Patchwork-Id: 829282 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p4U7LU7b019622 for ; Mon, 30 May 2011 07:21:30 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754807Ab1E3HV0 (ORCPT ); Mon, 30 May 2011 03:21:26 -0400 Received: from sd-mail-sa-01.sanoma.fi ([158.127.18.161]:41463 "EHLO sd-mail-sa-01.sanoma.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754690Ab1E3HVZ (ORCPT ); Mon, 30 May 2011 03:21:25 -0400 X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 30 May 2011 07:21:30 +0000 (UTC) X-Greylist: delayed 336 seconds by postgrey-1.27 at vger.kernel.org; Mon, 30 May 2011 03:21:25 EDT Received: from localhost (localhost [127.0.0.1]) by sd-mail-sa-01.sanoma.fi (Postfix) with ESMTP id 9933EF01CA; Mon, 30 May 2011 10:15:48 +0300 (EEST) X-Virus-Scanned: Debian amavisd-new at sd-mail-sa-01.sanoma.fi Received: from sd-mail-sa-01.sanoma.fi ([127.0.0.1]) by localhost (sd-mail-sa-01.sanoma.fi [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id H-tf8CN45zev; Mon, 30 May 2011 10:15:47 +0300 (EEST) Received: from hayate.81.fi (dyn2-85-23-163-147.psoas.suomi.net [85.23.163.147]) by sd-mail-sa-01.sanoma.fi (Postfix) with ESMTPSA id A3770F018B; Mon, 30 May 2011 10:15:47 +0300 (EEST) Received: from fate.lan ([10.0.0.10] helo=fate) by hayate.81.fi with esmtp (Exim 4.72) (envelope-from ) id 1QQwhX-0004jS-Cx; Mon, 30 May 2011 10:15:47 +0300 Received: from localhost6.localdomain6 (unknown [127.0.0.1]) by fate (Postfix) with ESMTP id 5B61F5A247; Mon, 30 May 2011 10:15:47 +0300 (EEST) Subject: [PATCH wireless-2.6] zd1211rw: fix to work on OHCI To: "John W. Linville" From: Jussi Kivilinna Cc: linux-wireless@vger.kernel.org, stable@kernel.org Date: Mon, 30 May 2011 10:15:47 +0300 Message-ID: <20110530071547.1834.38429.stgit@localhost6.localdomain6> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org 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 --- drivers/net/wireless/zd1211rw/zd_usb.c | 53 +++++++++++++++++++++++++------- 1 files changed, 42 insertions(+), 11 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 0e81994..631194d 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) module_init(usb_init); module_exit(usb_exit); +static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len, + int *actual_length, int timeout) +{ + /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in + * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint + * descriptor. + */ + struct usb_host_endpoint *ep; + unsigned int pipe; + + pipe = usb_sndintpipe(udev, EP_REGS_OUT); + ep = usb_pipe_endpoint(udev, pipe); + if (!ep) + return -EINVAL; + + if (usb_endpoint_xfer_int(&ep->desc)) { + return usb_interrupt_msg(udev, pipe, data, len, + actual_length, timeout); + } else { + pipe = usb_sndbulkpipe(udev, EP_REGS_OUT); + return usb_bulk_msg(udev, pipe, data, len, actual_length, + timeout); + } +} + static int usb_int_regs_length(unsigned int count) { 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, udev = zd_usb_to_usbdev(usb); prepare_read_regs_int(usb); - r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 50 /* ms */); + r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error in usb_interrupt_msg(). Error number %d\n", r); + "error in zd_ep_regs_out_msg(). Error number %d\n", r); goto error; } if (req_len != actual_req_len) { - dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()\n" + dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n" " req_len %d != actual_req_len %d\n", req_len, actual_req_len); r = -EIO; @@ -1818,9 +1842,17 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, rw->value = cpu_to_le16(ioreqs[i].value); } - usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), - req, req_len, iowrite16v_urb_complete, usb, - ep->desc.bInterval); + /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode + * endpoint is bulk. Select correct type URB by endpoint descriptor. + */ + if (usb_endpoint_xfer_int(&ep->desc)) + usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), + req, req_len, iowrite16v_urb_complete, usb, + ep->desc.bInterval); + else + usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT), + req, req_len, iowrite16v_urb_complete, usb); + urb->transfer_flags |= URB_FREE_BUFFER; /* Submit previous URB */ @@ -1924,15 +1956,14 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) } udev = zd_usb_to_usbdev(usb); - r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 50 /* ms */); + r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error in usb_interrupt_msg(). Error number %d\n", r); + "error in zd_ep_regs_out_msg(). Error number %d\n", r); goto out; } if (req_len != actual_req_len) { - dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()" + dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()" " req_len %d != actual_req_len %d\n", req_len, actual_req_len); r = -EIO;