*/
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
+#include <linux/device.h>
#include <net/mac80211.h>
#include "ar9170.h"
#include "cmd.h"
{ USB_DEVICE(0x0cf3, 0x9170) },
/* Atheros TG121N */
{ USB_DEVICE(0x0cf3, 0x1001) },
+ /* TP-Link TL-WN821N v2 */
+ { USB_DEVICE(0x0cf3, 0x1002) },
+ /* 3Com Dual Band 802.11n USB Adapter */
+ { USB_DEVICE(0x0cf3, 0x1010) },
+ /* H3C Dual Band 802.11n USB Adapter */
+ { USB_DEVICE(0x0cf3, 0x1011) },
/* Cace Airpcap NX */
{ USB_DEVICE(0xcace, 0x0300) },
- /* D-Link DWA 160A */
+ /* D-Link DWA 160 A1 */
{ USB_DEVICE(0x07d1, 0x3c10) },
+ /* D-Link DWA 160 A2 */
+ { USB_DEVICE(0x07d1, 0x3a09) },
+ /* Netgear WNA1000 */
+ { USB_DEVICE(0x0846, 0x9040) },
/* Netgear WNDA3100 */
{ USB_DEVICE(0x0846, 0x9010) },
/* Netgear WN111 v2 */
{ USB_DEVICE(0x0846, 0x9001) },
/* Zydas ZD1221 */
{ USB_DEVICE(0x0ace, 0x1221) },
+ /* Proxim ORiNOCO 802.11n USB */
+ { USB_DEVICE(0x1435, 0x0804) },
+ /* WNC Generic 11n USB Dongle */
+ { USB_DEVICE(0x1435, 0x0326) },
/* ZyXEL NWD271N */
{ USB_DEVICE(0x0586, 0x3417) },
/* Z-Com UB81 BG */
{ USB_DEVICE(0x0cde, 0x0023) },
/* Z-Com UB82 ABG */
{ USB_DEVICE(0x0cde, 0x0026) },
+ /* Sphairon Homelink 1202 */
+ { USB_DEVICE(0x0cde, 0x0027) },
/* Arcadyan WN7512 */
{ USB_DEVICE(0x083a, 0xf522) },
/* Planex GWUS300 */
{ USB_DEVICE(0x04bb, 0x093f) },
/* AVM FRITZ!WLAN USB Stick N */
{ USB_DEVICE(0x057C, 0x8401) },
+ /* NEC WL300NU-G */
+ { USB_DEVICE(0x0409, 0x0249) },
/* AVM FRITZ!WLAN USB Stick N 2.4 */
{ USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
return ;
spin_lock_irqsave(&aru->tx_urb_lock, flags);
- if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
+ if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
}
- aru->tx_submitted_urbs++;
+ atomic_inc(&aru->tx_submitted_urbs);
urb = usb_get_from_anchor(&aru->tx_pending);
if (!urb) {
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
err);
usb_unanchor_urb(urb);
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, urb->context);
}
return ;
}
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, skb);
spin_unlock_irqrestore(&aru->common.cmdlock, flags);
usb_fill_int_urb(urb, aru->udev,
- usb_sndbulkpipe(aru->udev, AR9170_EP_CMD),
+ usb_sndintpipe(aru->udev, AR9170_EP_CMD),
aru->common.cmdbuf, plen + 4,
ar9170_usb_tx_urb_complete, NULL, 1);
return 0;
}
-static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
-{
- int err = 0;
-
- err = request_firmware(&aru->firmware, "ar9170.fw",
- &aru->udev->dev);
- if (!err) {
- aru->init_values = NULL;
- return 0;
- }
-
- if (aru->req_one_stage_fw) {
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found and is required for this device\n");
- return -EINVAL;
- }
-
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found, trying old firmware...\n");
-
- err = request_firmware(&aru->init_values, "ar9170-1.fw",
- &aru->udev->dev);
- if (err) {
- dev_err(&aru->udev->dev, "file with init values not found.\n");
- return err;
- }
-
- err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
- if (err) {
- release_firmware(aru->init_values);
- dev_err(&aru->udev->dev, "firmware file not found.\n");
- return err;
- }
-
- return err;
-}
-
static int ar9170_usb_reset(struct ar9170_usb *aru)
{
int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING);
return err;
}
+static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
+{
+ struct device *parent = aru->udev->dev.parent;
+
+ complete(&aru->firmware_loading_complete);
+
+ /* unbind anything failed */
+ if (parent)
+ device_lock(parent);
+ device_release_driver(&aru->udev->dev);
+ if (parent)
+ device_unlock(parent);
+
+ usb_put_dev(aru->udev);
+}
+
+static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ aru->firmware = fw;
+
+ if (!fw) {
+ dev_err(&aru->udev->dev, "firmware file not found.\n");
+ goto err_freefw;
+ }
+
+ err = ar9170_usb_init_device(aru);
+ if (err)
+ goto err_freefw;
+
+ err = ar9170_usb_open(&aru->common);
+ if (err)
+ goto err_unrx;
+
+ err = ar9170_register(&aru->common, &aru->udev->dev);
+
+ ar9170_usb_stop(&aru->common);
+ if (err)
+ goto err_unrx;
+
+ complete(&aru->firmware_loading_complete);
+ usb_put_dev(aru->udev);
+ return;
+
+ err_unrx:
+ ar9170_usb_cancel_urbs(aru);
+
+ err_freefw:
+ ar9170_usb_firmware_failed(aru);
+}
+
+static void ar9170_usb_firmware_inits(const struct firmware *fw,
+ void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ if (!fw) {
+ dev_err(&aru->udev->dev, "file with init values not found.\n");
+ ar9170_usb_firmware_failed(aru);
+ return;
+ }
+
+ aru->init_values = fw;
+
+ /* ok so we have the init values -- get code for two-stage */
+
+ err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_finish);
+ if (err)
+ ar9170_usb_firmware_failed(aru);
+}
+
+static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context)
+{
+ struct ar9170_usb *aru = context;
+ int err;
+
+ if (fw) {
+ ar9170_usb_firmware_finish(fw, context);
+ return;
+ }
+
+ if (aru->req_one_stage_fw) {
+ dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+ "not found and is required for this device\n");
+ ar9170_usb_firmware_failed(aru);
+ return;
+ }
+
+ dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+ "not found, trying old firmware...\n");
+
+ err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_inits);
+ if (err)
+ ar9170_usb_firmware_failed(aru);
+}
+
static bool ar9170_requires_one_stage(const struct usb_device_id *id)
{
if (!id->driver_info)
init_usb_anchor(&aru->tx_pending);
init_usb_anchor(&aru->tx_submitted);
init_completion(&aru->cmd_wait);
+ init_completion(&aru->firmware_loading_complete);
spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0;
- aru->tx_submitted_urbs = 0;
+ atomic_set(&aru->tx_submitted_urbs, 0);
aru->common.stop = ar9170_usb_stop;
aru->common.flush = ar9170_usb_flush;
if (err)
goto err_freehw;
- err = ar9170_usb_request_firmware(aru);
- if (err)
- goto err_freehw;
-
- err = ar9170_usb_init_device(aru);
- if (err)
- goto err_freefw;
-
- err = ar9170_usb_open(ar);
- if (err)
- goto err_unrx;
-
- err = ar9170_register(ar, &udev->dev);
-
- ar9170_usb_stop(ar);
- if (err)
- goto err_unrx;
-
- return 0;
-
-err_unrx:
- ar9170_usb_cancel_urbs(aru);
-
-err_freefw:
- release_firmware(aru->init_values);
- release_firmware(aru->firmware);
-
+ usb_get_dev(aru->udev);
+ return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
+ &aru->udev->dev, GFP_KERNEL, aru,
+ ar9170_usb_firmware_step2);
err_freehw:
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
return;
aru->common.state = AR9170_IDLE;
+
+ wait_for_completion(&aru->firmware_loading_complete);
+
ar9170_unregister(&aru->common);
ar9170_usb_cancel_urbs(aru);
- release_firmware(aru->init_values);
- release_firmware(aru->firmware);
-
usb_put_dev(aru->udev);
usb_set_intfdata(intf, NULL);
ieee80211_free_hw(aru->common.hw);
+
+ release_firmware(aru->init_values);
+ release_firmware(aru->firmware);
}
#ifdef CONFIG_PM