summaryrefslogtreecommitdiff
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.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c958cf42a1bb..eb2625b48ba1 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -21,6 +21,7 @@
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
+#include <linux/usb/otg-fsm.h>
#include <linux/usb/quirks.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
@@ -1134,6 +1135,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
need_debounce_delay = true;
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
+#ifdef CONFIG_USB_OTG
+ if (hdev->bus->is_b_host)
+ usb_bus_start_enum(hdev->bus, port1);
+#endif
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
need_debounce_delay = true;
@@ -2224,9 +2229,9 @@ static inline void announce_device(struct usb_device *udev) { }
*/
static int usb_enumerate_device_otg(struct usb_device *udev)
{
+#ifdef CONFIG_USB_OTG
int err = 0;
-#ifdef CONFIG_USB_OTG
/*
* 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
@@ -2267,6 +2272,12 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
err);
bus->b_hnp_enable = 0;
}
+
+ if (bus->otg_fsm) {
+ bus->otg_fsm->b_hnp_enable = 1;
+ if (bus->b_hnp_enable)
+ bus->otg_fsm->a_set_b_hnp_en = 1;
+ }
} else if (desc->bLength == sizeof
(struct usb_otg_descriptor)) {
/* Set a_alt_hnp_support for legacy otg device */
@@ -2283,7 +2294,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
}
}
#endif
- return err;
+ return 0;
}
@@ -2305,6 +2316,7 @@ static int usb_enumerate_device(struct usb_device *udev)
{
int err;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct otg_fsm *fsm = udev->bus->otg_fsm;
if (udev->config == NULL) {
err = usb_get_configuration(udev);
@@ -2336,8 +2348,10 @@ static int usb_enumerate_device(struct usb_device *udev)
err = usb_port_suspend(udev, PMSG_AUTO_SUSPEND);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ return -ENOTSUPP;
+ } else if (!fsm || !fsm->b_hnp_enable || !fsm->hnp_polling) {
+ return -ENOTSUPP;
}
- return -ENOTSUPP;
}
usb_detect_interface_quirks(udev);
@@ -4387,6 +4401,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
enum usb_device_speed oldspeed = udev->speed;
const char *speed;
int devnum = udev->devnum;
+ const char *driver_name;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -4454,11 +4469,23 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
else
speed = usb_speed_string(udev->speed);
+ /*
+ * The controller driver may be NULL if the controller device
+ * is the middle device between platform device and roothub.
+ * This middle device may not need a device driver due to
+ * all hardware control can be at platform device driver, this
+ * platform device is usually a dual-role USB controller device.
+ */
+ if (udev->bus->controller->driver)
+ driver_name = udev->bus->controller->driver->name;
+ else
+ driver_name = udev->bus->sysdev->driver->name;
+
if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
- devnum, udev->bus->controller->driver->name);
+ devnum, driver_name);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -4560,7 +4587,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (r) {
if (r != -ENODEV)
- dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+ dev_err(&udev->dev,
+ "device no response, device descriptor read/64, error %d\n",
r);
retval = -EMSGSIZE;
continue;
@@ -4592,7 +4620,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
"%s SuperSpeed%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
(udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
- devnum, udev->bus->controller->driver->name);
+ devnum, driver_name);
}
/* cope with hardware quirkiness: