aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ar9170/usb.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-04-18 11:12:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-20 16:36:26 -0400
commite10a9dfc35ae6bd62bbb83df08297ea06b54d9ce (patch)
tree482bc2177b5c825661a8a0847b534b5944816195 /drivers/net/wireless/ar9170/usb.c
parent18aaab15f9a9cd4f20dc596aa38408c5e5d208ed (diff)
ar9170usb: fix hang on resume
This patch fixes a hang on resume when the filesystem is not available and request_firmware blocks. However, the device does not accept the firmware on resume. and it will exit with: > firmware part 1 upload failed (-71). > device is in a bad state. please reconnect it! Reported-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ar9170/usb.c')
-rw-r--r--drivers/net/wireless/ar9170/usb.c110
1 files changed, 90 insertions, 20 deletions
diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ar9170/usb.c
index c9e422ead92..fddda477095 100644
--- a/drivers/net/wireless/ar9170/usb.c
+++ b/drivers/net/wireless/ar9170/usb.c
@@ -623,6 +623,39 @@ static int ar9170_usb_open(struct ar9170 *ar)
623 return 0; 623 return 0;
624} 624}
625 625
626static int ar9170_usb_init_device(struct ar9170_usb *aru)
627{
628 int err;
629
630 err = ar9170_usb_alloc_rx_irq_urb(aru);
631 if (err)
632 goto err_out;
633
634 err = ar9170_usb_alloc_rx_bulk_urbs(aru);
635 if (err)
636 goto err_unrx;
637
638 err = ar9170_usb_upload_firmware(aru);
639 if (err) {
640 err = ar9170_echo_test(&aru->common, 0x60d43110);
641 if (err) {
642 /* force user invention, by disabling the device */
643 err = usb_driver_set_configuration(aru->udev, -1);
644 dev_err(&aru->udev->dev, "device is in a bad state. "
645 "please reconnect it!\n");
646 goto err_unrx;
647 }
648 }
649
650 return 0;
651
652err_unrx:
653 ar9170_usb_cancel_urbs(aru);
654
655err_out:
656 return err;
657}
658
626static int ar9170_usb_probe(struct usb_interface *intf, 659static int ar9170_usb_probe(struct usb_interface *intf,
627 const struct usb_device_id *id) 660 const struct usb_device_id *id)
628{ 661{
@@ -658,32 +691,16 @@ static int ar9170_usb_probe(struct usb_interface *intf,
658 691
659 err = ar9170_usb_reset(aru); 692 err = ar9170_usb_reset(aru);
660 if (err) 693 if (err)
661 goto err_unlock; 694 goto err_freehw;
662 695
663 err = ar9170_usb_request_firmware(aru); 696 err = ar9170_usb_request_firmware(aru);
664 if (err) 697 if (err)
665 goto err_unlock; 698 goto err_freehw;
666 699
667 err = ar9170_usb_alloc_rx_irq_urb(aru); 700 err = ar9170_usb_init_device(aru);
668 if (err) 701 if (err)
669 goto err_freefw; 702 goto err_freefw;
670 703
671 err = ar9170_usb_alloc_rx_bulk_urbs(aru);
672 if (err)
673 goto err_unrx;
674
675 err = ar9170_usb_upload_firmware(aru);
676 if (err) {
677 err = ar9170_echo_test(&aru->common, 0x60d43110);
678 if (err) {
679 /* force user invention, by disabling the device */
680 err = usb_driver_set_configuration(aru->udev, -1);
681 dev_err(&aru->udev->dev, "device is in a bad state. "
682 "please reconnect it!\n");
683 goto err_unrx;
684 }
685 }
686
687 err = ar9170_usb_open(ar); 704 err = ar9170_usb_open(ar);
688 if (err) 705 if (err)
689 goto err_unrx; 706 goto err_unrx;
@@ -703,7 +720,7 @@ err_freefw:
703 release_firmware(aru->init_values); 720 release_firmware(aru->init_values);
704 release_firmware(aru->firmware); 721 release_firmware(aru->firmware);
705 722
706err_unlock: 723err_freehw:
707 usb_set_intfdata(intf, NULL); 724 usb_set_intfdata(intf, NULL);
708 usb_put_dev(udev); 725 usb_put_dev(udev);
709 ieee80211_free_hw(ar->hw); 726 ieee80211_free_hw(ar->hw);
@@ -730,12 +747,65 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
730 ieee80211_free_hw(aru->common.hw); 747 ieee80211_free_hw(aru->common.hw);
731} 748}
732 749
750#ifdef CONFIG_PM
751static int ar9170_suspend(struct usb_interface *intf,
752 pm_message_t message)
753{
754 struct ar9170_usb *aru = usb_get_intfdata(intf);
755
756 if (!aru)
757 return -ENODEV;
758
759 aru->common.state = AR9170_IDLE;
760 ar9170_usb_cancel_urbs(aru);
761
762 return 0;
763}
764
765static int ar9170_resume(struct usb_interface *intf)
766{
767 struct ar9170_usb *aru = usb_get_intfdata(intf);
768 int err;
769
770 if (!aru)
771 return -ENODEV;
772
773 usb_unpoison_anchored_urbs(&aru->rx_submitted);
774 usb_unpoison_anchored_urbs(&aru->tx_submitted);
775
776 /*
777 * FIXME: firmware upload will fail on resume.
778 * but this is better than a hang!
779 */
780
781 err = ar9170_usb_init_device(aru);
782 if (err)
783 goto err_unrx;
784
785 err = ar9170_usb_open(&aru->common);
786 if (err)
787 goto err_unrx;
788
789 return 0;
790
791err_unrx:
792 aru->common.state = AR9170_IDLE;
793 ar9170_usb_cancel_urbs(aru);
794
795 return err;
796}
797#endif /* CONFIG_PM */
798
733static struct usb_driver ar9170_driver = { 799static struct usb_driver ar9170_driver = {
734 .name = "ar9170usb", 800 .name = "ar9170usb",
735 .probe = ar9170_usb_probe, 801 .probe = ar9170_usb_probe,
736 .disconnect = ar9170_usb_disconnect, 802 .disconnect = ar9170_usb_disconnect,
737 .id_table = ar9170_usb_ids, 803 .id_table = ar9170_usb_ids,
738 .soft_unbind = 1, 804 .soft_unbind = 1,
805#ifdef CONFIG_PM
806 .suspend = ar9170_suspend,
807 .resume = ar9170_resume,
808#endif /* CONFIG_PM */
739}; 809};
740 810
741static int __init ar9170_init(void) 811static int __init ar9170_init(void)