diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 94 |
1 files changed, 31 insertions, 63 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dd3bcfb2bcb6..02601f412f9d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -515,6 +515,31 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | |||
515 | return ret; | 515 | return ret; |
516 | } | 516 | } |
517 | 517 | ||
518 | |||
519 | /* caller has locked the hub device */ | ||
520 | static void hub_pre_reset(struct usb_hub *hub, int disable_ports) | ||
521 | { | ||
522 | struct usb_device *hdev = hub->hdev; | ||
523 | int port1; | ||
524 | |||
525 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { | ||
526 | if (hdev->children[port1 - 1]) { | ||
527 | usb_disconnect(&hdev->children[port1 - 1]); | ||
528 | if (disable_ports) | ||
529 | hub_port_disable(hub, port1, 0); | ||
530 | } | ||
531 | } | ||
532 | hub_quiesce(hub); | ||
533 | } | ||
534 | |||
535 | /* caller has locked the hub device */ | ||
536 | static void hub_post_reset(struct usb_hub *hub) | ||
537 | { | ||
538 | hub_activate(hub); | ||
539 | hub_power_on(hub); | ||
540 | } | ||
541 | |||
542 | |||
518 | static int hub_configure(struct usb_hub *hub, | 543 | static int hub_configure(struct usb_hub *hub, |
519 | struct usb_endpoint_descriptor *endpoint) | 544 | struct usb_endpoint_descriptor *endpoint) |
520 | { | 545 | { |
@@ -750,29 +775,10 @@ fail: | |||
750 | 775 | ||
751 | static unsigned highspeed_hubs; | 776 | static unsigned highspeed_hubs; |
752 | 777 | ||
753 | /* Called after the hub driver is unbound from a hub with children */ | ||
754 | static void hub_remove_children_work(void *__hub) | ||
755 | { | ||
756 | struct usb_hub *hub = __hub; | ||
757 | struct usb_device *hdev = hub->hdev; | ||
758 | int i; | ||
759 | |||
760 | kfree(hub); | ||
761 | |||
762 | usb_lock_device(hdev); | ||
763 | for (i = 0; i < hdev->maxchild; ++i) { | ||
764 | if (hdev->children[i]) | ||
765 | usb_disconnect(&hdev->children[i]); | ||
766 | } | ||
767 | usb_unlock_device(hdev); | ||
768 | usb_put_dev(hdev); | ||
769 | } | ||
770 | |||
771 | static void hub_disconnect(struct usb_interface *intf) | 778 | static void hub_disconnect(struct usb_interface *intf) |
772 | { | 779 | { |
773 | struct usb_hub *hub = usb_get_intfdata (intf); | 780 | struct usb_hub *hub = usb_get_intfdata (intf); |
774 | struct usb_device *hdev; | 781 | struct usb_device *hdev; |
775 | int n, port1; | ||
776 | 782 | ||
777 | usb_set_intfdata (intf, NULL); | 783 | usb_set_intfdata (intf, NULL); |
778 | hdev = hub->hdev; | 784 | hdev = hub->hdev; |
@@ -780,7 +786,9 @@ static void hub_disconnect(struct usb_interface *intf) | |||
780 | if (hdev->speed == USB_SPEED_HIGH) | 786 | if (hdev->speed == USB_SPEED_HIGH) |
781 | highspeed_hubs--; | 787 | highspeed_hubs--; |
782 | 788 | ||
783 | hub_quiesce(hub); | 789 | /* Disconnect all children and quiesce the hub */ |
790 | hub_pre_reset(hub, 1); | ||
791 | |||
784 | usb_free_urb(hub->urb); | 792 | usb_free_urb(hub->urb); |
785 | hub->urb = NULL; | 793 | hub->urb = NULL; |
786 | 794 | ||
@@ -800,27 +808,7 @@ static void hub_disconnect(struct usb_interface *intf) | |||
800 | hub->buffer = NULL; | 808 | hub->buffer = NULL; |
801 | } | 809 | } |
802 | 810 | ||
803 | /* If there are any children then this is an unbind only, not a | 811 | kfree(hub); |
804 | * physical disconnection. The active ports must be disabled | ||
805 | * and later on we must call usb_disconnect(). We can't call | ||
806 | * it now because we may not hold the hub's device lock. | ||
807 | */ | ||
808 | n = 0; | ||
809 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { | ||
810 | if (hdev->children[port1 - 1]) { | ||
811 | ++n; | ||
812 | hub_port_disable(hub, port1, 1); | ||
813 | } | ||
814 | } | ||
815 | |||
816 | if (n == 0) | ||
817 | kfree(hub); | ||
818 | else { | ||
819 | /* Reuse the hub->leds work_struct for our own purposes */ | ||
820 | INIT_WORK(&hub->leds, hub_remove_children_work, hub); | ||
821 | schedule_work(&hub->leds); | ||
822 | usb_get_dev(hdev); | ||
823 | } | ||
824 | } | 812 | } |
825 | 813 | ||
826 | static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) | 814 | static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) |
@@ -917,26 +905,6 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) | |||
917 | } | 905 | } |
918 | } | 906 | } |
919 | 907 | ||
920 | /* caller has locked the hub device */ | ||
921 | static void hub_pre_reset(struct usb_hub *hub) | ||
922 | { | ||
923 | struct usb_device *hdev = hub->hdev; | ||
924 | int i; | ||
925 | |||
926 | for (i = 0; i < hdev->maxchild; ++i) { | ||
927 | if (hdev->children[i]) | ||
928 | usb_disconnect(&hdev->children[i]); | ||
929 | } | ||
930 | hub_quiesce(hub); | ||
931 | } | ||
932 | |||
933 | /* caller has locked the hub device */ | ||
934 | static void hub_post_reset(struct usb_hub *hub) | ||
935 | { | ||
936 | hub_activate(hub); | ||
937 | hub_power_on(hub); | ||
938 | } | ||
939 | |||
940 | 908 | ||
941 | /* grab device/port lock, returning index of that port (zero based). | 909 | /* grab device/port lock, returning index of that port (zero based). |
942 | * protects the upstream link used by this device from concurrent | 910 | * protects the upstream link used by this device from concurrent |
@@ -2682,7 +2650,7 @@ static void hub_events(void) | |||
2682 | 2650 | ||
2683 | /* If the hub has died, clean up after it */ | 2651 | /* If the hub has died, clean up after it */ |
2684 | if (hdev->state == USB_STATE_NOTATTACHED) { | 2652 | if (hdev->state == USB_STATE_NOTATTACHED) { |
2685 | hub_pre_reset(hub); | 2653 | hub_pre_reset(hub, 0); |
2686 | goto loop; | 2654 | goto loop; |
2687 | } | 2655 | } |
2688 | 2656 | ||
@@ -2997,7 +2965,7 @@ int usb_reset_device(struct usb_device *udev) | |||
2997 | udev->actconfig->interface[0]->dev.driver == | 2965 | udev->actconfig->interface[0]->dev.driver == |
2998 | &hub_driver.driver && | 2966 | &hub_driver.driver && |
2999 | (hub = hdev_to_hub(udev)) != NULL) { | 2967 | (hub = hdev_to_hub(udev)) != NULL) { |
3000 | hub_pre_reset(hub); | 2968 | hub_pre_reset(hub, 0); |
3001 | } | 2969 | } |
3002 | 2970 | ||
3003 | set_bit(port1, parent_hub->busy_bits); | 2971 | set_bit(port1, parent_hub->busy_bits); |