aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/usb/core/hub.c
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c60
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);