aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-11-18 12:06:34 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-04 16:48:34 -0500
commit7d069b7d80933004282c48edbe62526e4cb0aecc (patch)
treec18d1e04366bee64b62b28d4953fed3c83e85fcc /drivers/usb
parent9ad3d6ccf5eee285e233dbaf186369b8d477a666 (diff)
[PATCH] USB: Disconnect children during hub unbind
This patch (as606b) is an updated version of my earlier patch to disconnect children from a hub device when the hub driver is unbound. Thanks to the changes in the driver core locking, we now know that the entire hub device (and not just the interface) is locked whenever the hub driver's disconnect method runs. Hence it is safe to disconnect the child device structures immediately instead of deferring the job. The earlier version of the patch neglected to disable the hub's ports. We don't want to forget that; otherwise we'd end up with live devices using addresses that have been recycled. This update adds the necessary code. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-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);