diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 78 |
1 files changed, 29 insertions, 49 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c4cdb69a6e9..50e79010401 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -596,27 +596,18 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) | |||
596 | kick_khubd(hub); | 596 | kick_khubd(hub); |
597 | } | 597 | } |
598 | 598 | ||
599 | static void disconnect_all_children(struct usb_hub *hub, int logical) | ||
600 | { | ||
601 | struct usb_device *hdev = hub->hdev; | ||
602 | int port1; | ||
603 | |||
604 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { | ||
605 | if (hdev->children[port1-1]) { | ||
606 | if (logical) | ||
607 | hub_port_logical_disconnect(hub, port1); | ||
608 | else | ||
609 | usb_disconnect(&hdev->children[port1-1]); | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | |||
614 | /* caller has locked the hub device */ | 599 | /* caller has locked the hub device */ |
615 | static int hub_pre_reset(struct usb_interface *intf) | 600 | static int hub_pre_reset(struct usb_interface *intf) |
616 | { | 601 | { |
617 | struct usb_hub *hub = usb_get_intfdata(intf); | 602 | struct usb_hub *hub = usb_get_intfdata(intf); |
603 | struct usb_device *hdev = hub->hdev; | ||
604 | int i; | ||
618 | 605 | ||
619 | disconnect_all_children(hub, 0); | 606 | /* Disconnect all the children */ |
607 | for (i = 0; i < hdev->maxchild; ++i) { | ||
608 | if (hdev->children[i]) | ||
609 | usb_disconnect(&hdev->children[i]); | ||
610 | } | ||
620 | hub_quiesce(hub); | 611 | hub_quiesce(hub); |
621 | return 0; | 612 | return 0; |
622 | } | 613 | } |
@@ -1872,50 +1863,39 @@ static int hub_resume(struct usb_interface *intf) | |||
1872 | return 0; | 1863 | return 0; |
1873 | } | 1864 | } |
1874 | 1865 | ||
1875 | #ifdef CONFIG_USB_PERSIST | 1866 | static int hub_reset_resume(struct usb_interface *intf) |
1876 | |||
1877 | /* For "persistent-device" resets we must mark the child devices for reset | ||
1878 | * and turn off a possible connect-change status (so khubd won't disconnect | ||
1879 | * them later). | ||
1880 | */ | ||
1881 | static void mark_children_for_reset_resume(struct usb_hub *hub) | ||
1882 | { | 1867 | { |
1868 | struct usb_hub *hub = usb_get_intfdata(intf); | ||
1883 | struct usb_device *hdev = hub->hdev; | 1869 | struct usb_device *hdev = hub->hdev; |
1884 | int port1; | 1870 | int port1; |
1885 | 1871 | ||
1872 | hub_power_on(hub); | ||
1873 | |||
1886 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { | 1874 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { |
1887 | struct usb_device *child = hdev->children[port1-1]; | 1875 | struct usb_device *child = hdev->children[port1-1]; |
1888 | 1876 | ||
1889 | if (child) { | 1877 | if (child) { |
1890 | child->reset_resume = 1; | 1878 | |
1891 | clear_port_feature(hdev, port1, | 1879 | /* For "USB_PERSIST"-enabled children we must |
1892 | USB_PORT_FEAT_C_CONNECTION); | 1880 | * mark the child device for reset-resume and |
1881 | * turn off the connect-change status to prevent | ||
1882 | * khubd from disconnecting it later. | ||
1883 | */ | ||
1884 | if (USB_PERSIST && child->persist_enabled) { | ||
1885 | child->reset_resume = 1; | ||
1886 | clear_port_feature(hdev, port1, | ||
1887 | USB_PORT_FEAT_C_CONNECTION); | ||
1888 | |||
1889 | /* Otherwise we must disconnect the child, | ||
1890 | * but as we may not lock the child device here | ||
1891 | * we have to do a "logical" disconnect. | ||
1892 | */ | ||
1893 | } else { | ||
1894 | hub_port_logical_disconnect(hub, port1); | ||
1895 | } | ||
1893 | } | 1896 | } |
1894 | } | 1897 | } |
1895 | } | ||
1896 | |||
1897 | #else | ||
1898 | |||
1899 | static inline void mark_children_for_reset_resume(struct usb_hub *hub) | ||
1900 | { } | ||
1901 | |||
1902 | #endif /* CONFIG_USB_PERSIST */ | ||
1903 | |||
1904 | static int hub_reset_resume(struct usb_interface *intf) | ||
1905 | { | ||
1906 | struct usb_hub *hub = usb_get_intfdata(intf); | ||
1907 | 1898 | ||
1908 | hub_power_on(hub); | ||
1909 | if (USB_PERSIST) | ||
1910 | mark_children_for_reset_resume(hub); | ||
1911 | else { | ||
1912 | /* Reset-resume doesn't call pre_reset, so we have to | ||
1913 | * disconnect the children here. But we may not lock | ||
1914 | * the child devices, so we have to do a "logical" | ||
1915 | * disconnect. | ||
1916 | */ | ||
1917 | disconnect_all_children(hub, 1); | ||
1918 | } | ||
1919 | hub_activate(hub); | 1899 | hub_activate(hub); |
1920 | return 0; | 1900 | return 0; |
1921 | } | 1901 | } |