]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/wireless/ath/ar9170/usb.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[net-next-2.6.git] / drivers / net / wireless / ath / ar9170 / usb.c
index 0f361186b78ffb0dca6e03fdf799493fba0b595d..0b0d2dc2f38c6409394138137e2ccaaae7755d2c 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
@@ -582,43 +583,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);
@@ -757,6 +721,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)
@@ -814,33 +875,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);
@@ -860,12 +897,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