USB: core: Add support for OTG automated compliance tests
1. Add OTG PET device to TPL. OTG device shall support this
device for allowing compliance automated testing.
2. Add otg_srp_reqd filed to gadget. OTG B-device shall enable
this flag when OTG PET (Protocol and Electrical Tester) that
acts as A-device sends Set Feature TEST_MODE with wIndex high
byte value = 0x06. OTG PET expects B-device to initiate SRP
after the end of current session.
3. Add otg_vbus_off to usb_bus. USB core enables this flag
when OTG PET enumerates with bcdDevice[0] field in its Device
Descriptor is equal to 1. OTG PET expects A-device to turn off
the VBUS with in 5 sec of its disconnection which allows it to
initiate SRP.
3. Add support to identify OTG PET and start HNP quickly.
Change-Id: Ib1f4d835d00ca29ff8f980c94d75a3890507dedc
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 97c5690..5cd6bb1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1285,10 +1285,20 @@
struct usb_bus *bus =
container_of(work, struct usb_bus, hnp_polling.work);
struct usb_device *udev = bus->root_hub->children[bus->otg_port - 1];
- u8 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+ u8 *status = NULL;
+ /*
+ * The OTG-B device must hand back the host role to OTG PET
+ * within 100 msec irrespective of host_request flag.
+ */
+ if (bus->quick_hnp) {
+ bus->quick_hnp = 0;
+ goto start_hnp;
+ }
+
+ status = kmalloc(sizeof(*status), GFP_KERNEL);
if (!status)
- return;
+ goto reschedule;
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE,
@@ -1300,17 +1310,20 @@
goto out;
}
- /* Spec says host must suspend the bus with in 2 sec. */
- if (*status & (1 << HOST_REQUEST_FLAG)) {
- do_unbind_rebind(udev, DO_UNBIND);
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
- ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
- if (ret)
- dev_info(&udev->dev, "suspend failed\n");
- } else {
- schedule_delayed_work(&bus->hnp_polling,
- msecs_to_jiffies(THOST_REQ_POLL));
- }
+ if (!(*status & (1 << HOST_REQUEST_FLAG)))
+ goto reschedule;
+
+start_hnp:
+ do_unbind_rebind(udev, DO_UNBIND);
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+ ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
+ if (ret)
+ dev_info(&udev->dev, "suspend failed\n");
+ goto out;
+
+reschedule:
+ schedule_delayed_work(&bus->hnp_polling,
+ msecs_to_jiffies(THOST_REQ_POLL));
out:
kfree(status);
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4a37dc2..7347c3d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1778,6 +1778,7 @@
int err = 0;
#ifdef CONFIG_USB_OTG
+ bool old_otg = false;
/*
* OTG-aware devices on OTG-capable root hubs may be able to use SRP,
* to wake us after we've powered off VBUS; and HNP, switching roles
@@ -1822,6 +1823,7 @@
* a_hnp_support or b_hnp_enable before
* selecting configuration.
*/
+ old_otg = true;
/* enable HNP before suspend, it's simpler */
err = usb_control_msg(udev,
@@ -1842,6 +1844,14 @@
}
}
out:
+ if ((udev->quirks & USB_QUIRK_OTG_PET)) {
+ if (le16_to_cpu(udev->descriptor.bcdDevice) &
+ OTG_TTST_VBUS_OFF)
+ udev->bus->otg_vbus_off = 1;
+ if (udev->bus->is_b_host || old_otg)
+ udev->bus->quick_hnp = 1;
+ }
+
if (!is_targeted(udev)) {
otg_send_event(OTG_EVENT_DEV_NOT_SUPPORTED);
@@ -1862,8 +1872,12 @@
* re-armed if device returns STALL. B-Host also perform
* HNP polling.
*/
- schedule_delayed_work(&udev->bus->hnp_polling,
- msecs_to_jiffies(THOST_REQ_POLL));
+ if (udev->bus->quick_hnp)
+ schedule_delayed_work(&udev->bus->hnp_polling,
+ msecs_to_jiffies(OTG_TTST_SUSP));
+ else
+ schedule_delayed_work(&udev->bus->hnp_polling,
+ msecs_to_jiffies(THOST_REQ_POLL));
}
#endif
return err;
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index cec4167..7bb6747 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -59,6 +59,11 @@
le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
return 0;
+ /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+ return 1;
+
/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 81ce6a8..d5a29b3 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -96,6 +96,9 @@
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Protocol and OTG Electrical Test Device */
+ { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_OTG_PET },
+
{ } /* terminating entry must be last */
};