@@ -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;
}
@@ -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;