diff options
| author | Johannes Berg <johannes@sipsolutions.net> | 2009-12-23 13:15:30 +0100 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-03-02 14:31:50 -0500 | 
| commit | 535765179fd4e8af26b69d2240d7ec33702a370a (patch) | |
| tree | a21ca3bdc1b4b5f40e233672f16ec618aab604fa /drivers/net/wireless/ath/ar9170/usb.c | |
| parent | 6e93d7195e75741e9ebe23ca5591977d0b39ecc0 (diff) | |
ar9170: load firmware asynchronously
This converts ar9170 to load firmware asynchronously
out of ->probe() and only register with mac80211 when
all firmware has been loaded successfully. If, on the
other hand, any firmware fails to load, it will now
unbind from the device.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ar9170/usb.c')
| -rw-r--r-- | drivers/net/wireless/ath/ar9170/usb.c | 170 | 
1 files changed, 103 insertions, 67 deletions
| diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 0f361186b78f..4e30197afff6 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -582,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); @@ -757,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) @@ -814,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); @@ -860,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 | 
