diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
| -rw-r--r-- | drivers/usb/core/hub.c | 26 | 
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b98efae6a1c..d041c6826e4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -676,6 +676,8 @@ static void hub_init_func3(struct work_struct *ws);  static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  {  	struct usb_device *hdev = hub->hdev; +	struct usb_hcd *hcd; +	int ret;  	int port1;  	int status;  	bool need_debounce_delay = false; @@ -714,6 +716,25 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			usb_autopm_get_interface_no_resume(  					to_usb_interface(hub->intfdev));  			return;		/* Continues at init2: below */ +		} else if (type == HUB_RESET_RESUME) { +			/* The internal host controller state for the hub device +			 * may be gone after a host power loss on system resume. +			 * Update the device's info so the HW knows it's a hub. +			 */ +			hcd = bus_to_hcd(hdev->bus); +			if (hcd->driver->update_hub_device) { +				ret = hcd->driver->update_hub_device(hcd, hdev, +						&hub->tt, GFP_NOIO); +				if (ret < 0) { +					dev_err(hub->intfdev, "Host not " +							"accepting hub info " +							"update.\n"); +					dev_err(hub->intfdev, "LS/FS devices " +							"and hubs may not work " +							"under this hub\n."); +				} +			} +			hub_power_on(hub, true);  		} else {  			hub_power_on(hub, true);  		} @@ -2732,6 +2753,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		udev->ttport = hdev->ttport;  	} else if (udev->speed != USB_SPEED_HIGH  			&& hdev->speed == USB_SPEED_HIGH) { +		if (!hub->tt.hub) { +			dev_err(&udev->dev, "parent hub has no TT\n"); +			retval = -EINVAL; +			goto fail; +		}  		udev->tt = &hub->tt;  		udev->ttport = port1;  	}  |