aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c78
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
599static 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 */
615static int hub_pre_reset(struct usb_interface *intf) 600static 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 1866static 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 */
1881static 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
1899static inline void mark_children_for_reset_resume(struct usb_hub *hub)
1900{ }
1901
1902#endif /* CONFIG_USB_PERSIST */
1903
1904static 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}