diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-04-18 11:12:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-04-20 16:36:26 -0400 |
commit | e10a9dfc35ae6bd62bbb83df08297ea06b54d9ce (patch) | |
tree | 482bc2177b5c825661a8a0847b534b5944816195 /drivers/net | |
parent | 18aaab15f9a9cd4f20dc596aa38408c5e5d208ed (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')
-rw-r--r-- | drivers/net/wireless/ar9170/usb.c | 110 |
1 files changed, 90 insertions, 20 deletions
diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ar9170/usb.c index c9e422ead925..fddda477095c 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 | ||
626 | static 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 | |||
652 | err_unrx: | ||
653 | ar9170_usb_cancel_urbs(aru); | ||
654 | |||
655 | err_out: | ||
656 | return err; | ||
657 | } | ||
658 | |||
626 | static int ar9170_usb_probe(struct usb_interface *intf, | 659 | static 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 | ||
706 | err_unlock: | 723 | err_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 | ||
751 | static 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 | |||
765 | static 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 | |||
791 | err_unrx: | ||
792 | aru->common.state = AR9170_IDLE; | ||
793 | ar9170_usb_cancel_urbs(aru); | ||
794 | |||
795 | return err; | ||
796 | } | ||
797 | #endif /* CONFIG_PM */ | ||
798 | |||
733 | static struct usb_driver ar9170_driver = { | 799 | static 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 | ||
741 | static int __init ar9170_init(void) | 811 | static int __init ar9170_init(void) |