summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ar9170/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ar9170/usb.c')
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c172
1 files changed, 105 insertions, 67 deletions
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e0799d924057..4e30197afff6 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
{ 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 */
@@ -580,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data,
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);
@@ -755,6 +720,103 @@ err_out:
return err;
}
+static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
+{
+ struct device *parent = aru->udev->dev.parent;
+
+ /* unbind anything failed */
+ if (parent)
+ down(&parent->sem);
+ device_release_driver(&aru->udev->dev);
+ if (parent)
+ up(&parent->sem);
+}
+
+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;
+
+ 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)
@@ -812,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf,
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);
-
+ 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);
@@ -858,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
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