diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 210e359..c0c8644 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -863,7 +863,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * If any port-status changes do occur during this delay, khubd * will see them later and handle them normally. */ +#if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB) + if (need_debounce_delay && type != HUB_RESET_RESUME) { +#else if (need_debounce_delay) { +#endif delay = HUB_DEBOUNCE_STABLE; /* Don't do a long sleep inside a workqueue routine */ @@ -1640,20 +1644,22 @@ void usb_disconnect(struct usb_device **pdev) { struct usb_device *udev = *pdev; int i; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_hcd *hcd; if (!udev) { pr_debug ("%s nodev\n", __func__); return; } + hcd = bus_to_hcd(udev->bus); + /* mark the device as inactive, so any further urb submissions for * this device (and any of its children) will fail immediately. * this quiesces everything except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); - dev_info(&udev->dev, "USB disconnect, device number %d\n", - udev->devnum); + dev_info(&udev->dev, "USB disconnect, device number %d by %pF\n", + udev->devnum, __builtin_return_address(0)); usb_lock_device(udev); @@ -2424,6 +2430,9 @@ static int finish_port_resume(struct usb_device *udev) retry_reset_resume: status = usb_reset_and_verify_device(udev); + if (udev->quirks & USB_QUIRK_NO_GET_STATUS) + goto done; + /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, * and device drivers will know about any resume quirks. @@ -2462,6 +2471,7 @@ static int finish_port_resume(struct usb_device *udev) } status = 0; } +done: return status; } @@ -2530,7 +2540,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* drive resume for at least 20 msec */ dev_dbg(&udev->dev, "usb %sresume\n", (msg.event & PM_EVENT_AUTO ? "auto-" : "")); - msleep(25); + + /* Add the 5msec delay for XMM6260 resume fail case*/ + if (udev->quirks & USB_QUIRK_HSIC_TUNE) + msleep(30); + else + msleep(25); /* Virtual root hubs can trigger on GET_PORT_STATUS to * stop resume signaling. Then finish the resume @@ -2540,9 +2555,20 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* TRSMRCY = 10 msec */ msleep(10); + + /* If portstatus's still resuming, retry GET_PORT_STATUS */ + if (udev->quirks & USB_QUIRK_HSIC_TUNE) + if (portstatus & USB_PORT_STAT_SUSPEND) { + usleep_range(5000, 10000); + status = hub_port_status(hub, port1, + &portstatus, &portchange); + } } SuspendCleared: +#if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB) + pr_debug("mif: %s: %d, %d\n", __func__, portstatus, portchange); +#endif if (status == 0) { if (hub_is_superspeed(hub->hdev)) { if (portchange & USB_PORT_STAT_C_LINK_STATE) @@ -2955,9 +2981,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, buf->bMaxPacketSize0; kfree(buf); - retval = hub_port_reset(hub, port1, udev, delay); - if (retval < 0) /* error or disconnect */ - goto fail; + if (!(udev->quirks & USB_QUIRK_HSIC_TUNE)) { + retval = + hub_port_reset(hub, port1, udev, delay); + if (retval < 0) /* error or disconnect */ + goto fail; + } + if (oldspeed != udev->speed) { dev_dbg(&udev->dev, "device reset changed speed!\n"); @@ -4049,3 +4079,19 @@ void usb_queue_reset_device(struct usb_interface *iface) schedule_work(&iface->reset_ws); } EXPORT_SYMBOL_GPL(usb_queue_reset_device); + +void usb_force_disconnect(struct usb_device *udev) +{ + struct usb_hub *parent_hub; + int port1 = udev->portnum; + + if (!udev->parent) + return; + + parent_hub = hdev_to_hub(udev->parent); + if (!parent_hub) + return; + + hub_port_logical_disconnect(parent_hub, port1); +} +EXPORT_SYMBOL_GPL(usb_force_disconnect); |