aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/hub.c94
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 */
520static 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 */
536static void hub_post_reset(struct usb_hub *hub)
537{
538 hub_activate(hub);
539 hub_power_on(hub);
540}
541
542
518static int hub_configure(struct usb_hub *hub, 543static 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
751static unsigned highspeed_hubs; 776static unsigned highspeed_hubs;
752 777
753/* Called after the hub driver is unbound from a hub with children */
754static 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
771static void hub_disconnect(struct usb_interface *intf) 778static 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
826static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) 814static 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 */
921static 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 */
934static 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);