From patchwork Fri Jul 30 06:28:15 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sujith X-Patchwork-Id: 115408 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6U6KtH5009840 for ; Fri, 30 Jul 2010 06:22:08 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755093Ab0G3GWA (ORCPT ); Fri, 30 Jul 2010 02:22:00 -0400 Received: from mail.atheros.com ([12.36.123.2]:38985 "EHLO mail.atheros.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752326Ab0G3GV7 (ORCPT ); Fri, 30 Jul 2010 02:21:59 -0400 Received: from mail.atheros.com ([10.10.20.105]) by sidewinder.atheros.com for ; Thu, 29 Jul 2010 23:21:35 -0700 Received: from CHEXHC-01.global.atheros.com (10.12.0.100) by SC1EXHC-01.global.atheros.com (10.10.20.104) with Microsoft SMTP Server (TLS) id 8.2.213.0; Thu, 29 Jul 2010 23:21:59 -0700 Received: from neuromancer (10.12.4.25) by CHEXHC-01.global.atheros.com (10.12.0.100) with Microsoft SMTP Server (TLS) id 8.2.176.0; Fri, 30 Jul 2010 11:51:55 +0530 From: Sujith MIME-Version: 1.0 Message-ID: <19538.28927.259256.23273@gargle.gargle.HOWL> Date: Fri, 30 Jul 2010 11:58:15 +0530 To: CC: , Subject: [PATCH] ath9k_htc: Fix Bulk endpoint issue Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Fri, 30 Jul 2010 06:22:08 +0000 (UTC) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 61c1bee..6efc46f 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -92,10 +92,19 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - usb_fill_int_urb(urb, hif_dev->udev, - usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), - skb->data, skb->len, - hif_usb_regout_cb, cmd, 1); + if (hif_dev->flags & HIF_USB_AR9271) { + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_sndbulkpipe(hif_dev->udev, + USB_REG_OUT_PIPE), + skb->data, skb->len, + hif_usb_regout_cb, cmd); + } else { + usb_fill_int_urb(urb, hif_dev->udev, + usb_sndintpipe(hif_dev->udev, + USB_REG_OUT_PIPE), + skb->data, skb->len, + hif_usb_regout_cb, cmd, 1); + } usb_anchor_urb(urb, &hif_dev->regout_submitted); ret = usb_submit_urb(urb, GFP_KERNEL); @@ -540,10 +549,19 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) return; } - usb_fill_int_urb(urb, hif_dev->udev, - usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), - nskb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, nskb, 1); + if (hif_dev->flags & HIF_USB_AR9271) { + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, + USB_REG_IN_PIPE), + nskb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, nskb); + } else { + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, + USB_REG_IN_PIPE), + nskb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, nskb, 1); + } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { @@ -719,10 +737,17 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) if (!skb) goto err; - usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev, - usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), - skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb, 1); + if (hif_dev->flags & HIF_USB_AR9271) { + usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, skb); + } else { + usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, skb, 1); + } if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) goto err; @@ -822,7 +847,9 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) { - int ret; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i, ret; /* Request firmware */ ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name, @@ -833,14 +860,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) goto err_fw_req; } - /* Alloc URBs */ - ret = ath9k_hif_usb_alloc_urbs(hif_dev); - if (ret) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Unable to allocate URBs\n"); - goto err_urb; - } - /* Download firmware */ ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) { @@ -850,11 +869,46 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) goto err_fw_download; } + /* + * If any of the endpoints have been configured as Interrupt, + * reset the device to trigger re-enumeration. + * + * Re-enumeration changes the endpoints from Interrupt to Bulk, + * since the firmware 'patches' the USB descriptors. + * + * For now, do this only for AR9271. AR7010 based devices + * also need this hack, but until the corresponding FW is fixed, + * keep using EP3 and EP4 as Interrupt endpoints for AR7010. + */ + + if (hif_dev->flags & HIF_USB_AR9271) { + iface_desc = hif_dev->interface->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(endpoint) || + usb_endpoint_is_int_out(endpoint)) { + ret = usb_reset_device(hif_dev->udev); + if (ret) + return ret; + } + } + } + + /* Alloc URBs */ + ret = ath9k_hif_usb_alloc_urbs(hif_dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Unable to allocate URBs\n"); + goto err_urb; + } + return 0; -err_fw_download: - ath9k_hif_usb_dealloc_urbs(hif_dev); err_urb: + ath9k_hif_usb_dealloc_urbs(hif_dev); +err_fw_download: release_firmware(hif_dev->firmware); err_fw_req: hif_dev->firmware = NULL; @@ -909,6 +963,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, break; default: hif_dev->fw_name = FIRMWARE_AR9271; + hif_dev->flags |= HIF_USB_AR9271; break; } @@ -995,6 +1050,16 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface, ath9k_hif_usb_dealloc_urbs(hif_dev); + /* + * Issue a reboot to the target, since it + * has be powered down. + * + * The 0xffffff command is a special case that + * is handled in the firmware. + */ + if (hif_dev->flags & HIF_USB_AR9271) + ath9k_hif_usb_reboot(hif_dev->udev); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 2daf97b..ced63cb 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -62,6 +62,7 @@ struct tx_buf { }; #define HIF_USB_TX_STOP BIT(0) +#define HIF_USB_AR9271 BIT(1) struct hif_usb_tx { u8 flags;