+ /* deallocate hcd/hardware state ... nuking all pending urbs and
+ * cleaning up all state associated with the current configuration
+ * so that the hardware is now fully quiesced.
+ */
+ usb_disable_device(udev, 0);
+
+ usb_notify_remove_device(udev);
+
+ /* Free the device number, remove the /proc/bus/usb entry and
+ * the sysfs attributes, and delete the parent's children[]
+ * (or root_hub) pointer.
+ */
+ dev_dbg (&udev->dev, "unregistering device\n");
+ release_address(udev);
+ usb_remove_sysfs_dev_files(udev);
+
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+ spin_lock_irq(&device_state_lock);
+ *pdev = NULL;
+ spin_unlock_irq(&device_state_lock);
+
+ usb_unlock_device(udev);
+
+ device_unregister(&udev->dev);
+}
+
+static inline const char *plural(int n)
+{
+ return (n == 1 ? "" : "s");
+}
+
+static int choose_configuration(struct usb_device *udev)
+{
+ int i;
+ int num_configs;
+ int insufficient_power = 0;
+ struct usb_host_config *c, *best;
+
+ best = NULL;
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ /* It's possible that a config has no interfaces! */
+ if (c->desc.bNumInterfaces > 0)
+ desc = &c->intf_cache[0]->altsetting->desc;
+
+ /*
+ * HP's USB bus-powered keyboard has only one configuration
+ * and it claims to be self-powered; other devices may have
+ * similar errors in their descriptors. If the next test
+ * were allowed to execute, such configurations would always
+ * be rejected and the devices would not work as expected.
+ * In the meantime, we run the risk of selecting a config
+ * that requires external power at a time when that power
+ * isn't available. It seems to be the lesser of two evils.
+ *
+ * Bugzilla #6448 reports a device that appears to crash
+ * when it receives a GET_DEVICE_STATUS request! We don't
+ * have any other way to tell whether a device is self-powered,
+ * but since we don't use that information anywhere but here,
+ * the call has been removed.
+ *
+ * Maybe the GET_DEVICE_STATUS call and the test below can
+ * be reinstated when device firmwares become more reliable.
+ * Don't hold your breath.
+ */
+#if 0
+ /* Rule out self-powered configs for a bus-powered device */
+ if (bus_powered && (c->desc.bmAttributes &
+ USB_CONFIG_ATT_SELFPOWER))
+ continue;
+#endif
+
+ /*
+ * The next test may not be as effective as it should be.
+ * Some hubs have errors in their descriptor, claiming
+ * to be self-powered when they are really bus-powered.
+ * We will overestimate the amount of current such hubs
+ * make available for each port.
+ *
+ * This is a fairly benign sort of failure. It won't
+ * cause us to reject configurations that we should have
+ * accepted.
+ */
+
+ /* Rule out configs that draw too much bus current */
+ if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+ insufficient_power++;
+ continue;
+ }
+
+ /* If the first config's first interface is COMM/2/0xff
+ * (MSFT RNDIS), rule it out unless Linux has host-side
+ * RNDIS support. */
+ if (i == 0 && desc
+ && desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff) {
+#ifndef CONFIG_USB_NET_RNDIS_HOST
+ continue;
+#else
+ best = c;
+#endif
+ }
+
+ /* From the remaining configs, choose the first one whose
+ * first interface is for a non-vendor-specific class.
+ * Reason: Linux is more likely to have a class driver
+ * than a vendor-specific driver. */
+ else if (udev->descriptor.bDeviceClass !=
+ USB_CLASS_VENDOR_SPEC &&
+ (!desc || desc->bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC)) {
+ best = c;
+ break;
+ }
+
+ /* If all the remaining configs are vendor-specific,
+ * choose the first one. */
+ else if (!best)
+ best = c;
+ }
+
+ if (insufficient_power > 0)
+ dev_info(&udev->dev, "rejected %d configuration%s "
+ "due to insufficient available bus power\n",
+ insufficient_power, plural(insufficient_power));
+
+ if (best) {
+ i = best->desc.bConfigurationValue;
+ dev_info(&udev->dev,
+ "configuration #%d chosen from %d choice%s\n",
+ i, num_configs, plural(num_configs));
+ } else {
+ i = -1;
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
+ }
+ return i;
+}
+
+#ifdef DEBUG
+static void show_string(struct usb_device *udev, char *id, char *string)
+{
+ if (!string)
+ return;
+ dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
+}
+
+#else
+static inline void show_string(struct usb_device *udev, char *id, char *string)
+{}
+#endif
+
+
+#ifdef CONFIG_USB_OTG
+#include "otg_whitelist.h"
+#endif
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * Returns 0 for success (device is configured and listed, with its
+ * interfaces, in sysfs); else a negative errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+ int err;
+ int c;
+
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+
+ /* Tell the world! */
+ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
+
+#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
+ * "host" to "peripheral". The OTG descriptor helps figure this out.
+ */
+ if (!udev->bus->is_b_host
+ && udev->config
+ && udev->parent == udev->bus->root_hub) {
+ struct usb_otg_descriptor *desc = 0;
+ struct usb_bus *bus = udev->bus;
+
+ /* descriptor may appear anywhere in config */
+ if (__usb_get_extra_descriptor (udev->rawdescriptors[0],
+ le16_to_cpu(udev->config[0].desc.wTotalLength),
+ USB_DT_OTG, (void **) &desc) == 0) {
+ if (desc->bmAttributes & USB_OTG_HNP) {
+ unsigned port1 = udev->portnum;
+ struct usb_device *root = udev->parent;
+
+ dev_info(&udev->dev,
+ "Dual-Role OTG device on %sHNP port\n",
+ (port1 == bus->otg_port)
+ ? "" : "non-");
+
+ /* enable HNP before suspend, it's simpler */
+ if (port1 == bus->otg_port)
+ bus->b_hnp_enable = 1;
+ err = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, 0,
+ bus->b_hnp_enable
+ ? USB_DEVICE_B_HNP_ENABLE
+ : USB_DEVICE_A_ALT_HNP_SUPPORT,
+ 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
+ /* OTG MESSAGE: report errors here,
+ * customize to match your product.
+ */
+ dev_info(&udev->dev,
+ "can't set HNP mode; %d\n",
+ err);
+ bus->b_hnp_enable = 0;
+ }
+ }
+ }
+ }
+
+ if (!is_targeted(udev)) {
+
+ /* Maybe it can talk to us, though we can't talk to it.
+ * (Includes HNP test device.)
+ */
+ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
+ static int __usb_suspend_device(struct usb_device *,
+ int port1);
+ err = __usb_suspend_device(udev, udev->bus->otg_port);
+ if (err < 0)
+ dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ }
+ err = -ENODEV;
+ goto fail;
+ }
+#endif
+
+ /* put device-specific files into sysfs */
+ err = device_add (&udev->dev);
+ if (err) {
+ dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ goto fail;
+ }
+ usb_create_sysfs_dev_files (udev);
+
+ usb_lock_device(udev);
+
+ /* choose and set the configuration. that registers the interfaces
+ * with the driver core, and lets usb device drivers bind to them.
+ */
+ c = choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ c, err);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+
+ /* USB device state == configured ... usable */
+ usb_notify_add_device(udev);
+
+ usb_unlock_device(udev);
+
+ return 0;
+
+fail:
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ return err;
+}
+
+
+static int hub_port_status(struct usb_hub *hub, int port1,
+ u16 *status, u16 *change)
+{
+ int ret;
+
+ ret = get_port_status(hub->hdev, port1, &hub->status->port);
+ if (ret < 0)
+ dev_err (hub->intfdev,
+ "%s failed (err = %d)\n", __FUNCTION__, ret);
+ else {
+ *status = le16_to_cpu(hub->status->port.wPortStatus);
+ *change = le16_to_cpu(hub->status->port.wPortChange);
+ ret = 0;
+ }
+ return ret;
+}
+
+#define PORT_RESET_TRIES 5
+#define SET_ADDRESS_TRIES 2
+#define GET_DESCRIPTOR_TRIES 2
+#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
+#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first)
+
+#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
+#define HUB_SHORT_RESET_TIME 10
+#define HUB_LONG_RESET_TIME 200
+#define HUB_RESET_TIMEOUT 500
+
+static int hub_port_wait_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay)
+{
+ int delay_time, ret;
+ u16 portstatus;
+ u16 portchange;
+
+ for (delay_time = 0;
+ delay_time < HUB_RESET_TIMEOUT;
+ delay_time += delay) {
+ /* wait to give the device a chance to reset */
+ msleep(delay);
+
+ /* read and decode port status */
+ ret = hub_port_status(hub, port1, &portstatus, &portchange);
+ if (ret < 0)
+ return ret;
+
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return -ENOTCONN;
+
+ /* bomb out completely if something weird happened */
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ return -EINVAL;
+
+ /* if we`ve finished resetting, then break out of the loop */
+ if (!(portstatus & USB_PORT_STAT_RESET) &&
+ (portstatus & USB_PORT_STAT_ENABLE)) {
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ udev->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ udev->speed = USB_SPEED_LOW;
+ else
+ udev->speed = USB_SPEED_FULL;
+ return 0;
+ }
+
+ /* switch to the long delay after two short delay failures */
+ if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
+ delay = HUB_LONG_RESET_TIME;
+
+ dev_dbg (hub->intfdev,
+ "port %d not reset yet, waiting %dms\n",
+ port1, delay);
+ }
+
+ return -EBUSY;
+}
+
+static int hub_port_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay)
+{
+ int i, status;
+
+ /* Reset the port */
+ for (i = 0; i < PORT_RESET_TRIES; i++) {
+ status = set_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_RESET);
+ if (status)
+ dev_err(hub->intfdev,
+ "cannot reset port %d (err = %d)\n",
+ port1, status);
+ else {
+ status = hub_port_wait_reset(hub, port1, udev, delay);
+ if (status && status != -ENOTCONN)
+ dev_dbg(hub->intfdev,
+ "port_wait_reset: err = %d\n",
+ status);
+ }
+
+ /* return on disconnect or reset */
+ switch (status) {
+ case 0:
+ /* TRSTRCY = 10 ms; plus some extra */
+ msleep(10 + 40);
+ /* FALL THROUGH */
+ case -ENOTCONN:
+ case -ENODEV:
+ clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_C_RESET);
+ /* FIXME need disconnect() for NOTATTACHED device */
+ usb_set_device_state(udev, status
+ ? USB_STATE_NOTATTACHED
+ : USB_STATE_DEFAULT);
+ return status;
+ }
+
+ dev_dbg (hub->intfdev,
+ "port %d not enabled, trying reset again...\n",
+ port1);
+ delay = HUB_LONG_RESET_TIME;
+ }
+
+ dev_err (hub->intfdev,
+ "Cannot enable port %i. Maybe the USB cable is bad?\n",
+ port1);
+
+ return status;
+}
+
+/*
+ * Disable a port and mark a logical connnect-change event, so that some
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+{
+ dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
+ hub_port_disable(hub, port1, 1);
+
+ /* FIXME let caller ask to power down the port:
+ * - some devices won't enumerate without a VBUS power cycle
+ * - SRP saves power that way
+ * - ... new call, TBD ...
+ * That's easy if this hub can switch power per-port, and
+ * khubd reactivates the port later (timer, SRP, etc).
+ * Powerdown must be optional, because of reset/DFU.
+ */
+
+ set_bit(port1, hub->change_bits);
+ kick_khubd(hub);
+}
+
+
+#ifdef CONFIG_USB_SUSPEND
+
+/*
+ * Selective port suspend reduces power; most suspended devices draw
+ * less than 500 uA. It's also used in OTG, along with remote wakeup.
+ * All devices below the suspended port are also suspended.
+ *
+ * Devices leave suspend state when the host wakes them up. Some devices
+ * also support "remote wakeup", where the device can activate the USB
+ * tree above them to deliver data, such as a keypress or packet. In
+ * some cases, this wakes the USB host.
+ */
+static int hub_port_suspend(struct usb_hub *hub, int port1,
+ struct usb_device *udev)
+{
+ int status;
+
+ // dev_dbg(hub->intfdev, "suspend port %d\n", port1);
+
+ /* enable remote wakeup when appropriate; this lets the device
+ * wake up the upstream hub (including maybe the root hub).
+ *
+ * NOTE: OTG devices may issue remote wakeup (or SRP) even when
+ * we don't explicitly enable it here.
+ */
+ if (device_may_wakeup(&udev->dev)) {
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (status)
+ dev_dbg(&udev->dev,
+ "won't remote wakeup, status %d\n",
+ status);
+ }
+
+ /* see 7.1.7.6 */
+ status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
+ if (status) {
+ dev_dbg(hub->intfdev,
+ "can't suspend port %d, status %d\n",
+ port1, status);
+ /* paranoia: "should not happen" */
+ (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ /* device has up to 10 msec to fully suspend */
+ dev_dbg(&udev->dev, "usb suspend\n");
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ msleep(10);
+ }
+ return status;
+}
+
+/*
+ * Devices on USB hub ports have only one "suspend" state, corresponding
+ * to ACPI D2, "may cause the device to lose some context".
+ * State transitions include:
+ *
+ * - suspend, resume ... when the VBUS power link stays live
+ * - suspend, disconnect ... VBUS lost
+ *
+ * Once VBUS drop breaks the circuit, the port it's using has to go through
+ * normal re-enumeration procedures, starting with enabling VBUS power.
+ * Other than re-initializing the hub (plug/unplug, except for root hubs),
+ * Linux (2.6) currently has NO mechanisms to initiate that: no khubd
+ * timer, no SRP, no requests through sysfs.
+ *
+ * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
+ */
+static int __usb_suspend_device (struct usb_device *udev, int port1)
+{
+ int status = 0;
+
+ /* caller owns the udev device lock */
+ if (port1 < 0)
+ return port1;
+
+ if (udev->state == USB_STATE_SUSPENDED
+ || udev->state == USB_STATE_NOTATTACHED) {
+ return 0;
+ }
+
+ /* all interfaces must already be suspended */
+ if (udev->actconfig) {
+ int i;
+
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf;
+
+ intf = udev->actconfig->interface[i];
+ if (is_active(intf)) {
+ dev_dbg(&intf->dev, "nyet suspended\n");
+ return -EBUSY;
+ }
+ }
+ }
+
+ /* we only change a device's upstream USB link.
+ * root hubs have no upstream USB link.
+ */
+ if (udev->parent)
+ status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
+ udev);
+
+ if (status == 0)
+ udev->dev.power.power_state = PMSG_SUSPEND;
+ return status;
+}
+
+#endif
+
+/*
+ * usb_suspend_device - suspend a usb device
+ * @udev: device that's no longer in active use
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * Suspends a USB device that isn't in active use, conserving power.
+ * Devices may wake out of a suspend, if anything important happens,
+ * using the remote wakeup mechanism. They may also be taken out of
+ * suspend by the host, using usb_resume_device(). It's also routine
+ * to disconnect devices while they are suspended.
+ *
+ * This only affects the USB hardware for a device; its interfaces
+ * (and, for hubs, child devices) must already have been suspended.
+ *
+ * Suspending OTG devices may trigger HNP, if that's been enabled
+ * between a pair of dual-role devices. That will change roles, such
+ * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_suspend_device(struct usb_device *udev)
+{
+#ifdef CONFIG_USB_SUSPEND
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+ return __usb_suspend_device(udev, udev->portnum);
+#else
+ /* NOTE: udev->state unchanged, it's not lying ... */
+ udev->dev.power.power_state = PMSG_SUSPEND;
+ return 0;
+#endif
+}
+
+/*
+ * If the USB "suspend" state is in use (rather than "global suspend"),
+ * many devices will be individually taken out of suspend state using
+ * special" resume" signaling. These routines kick in shortly after
+ * hardware resume signaling is finished, either because of selective
+ * resume (by host) or remote wakeup (by device) ... now see what changed
+ * in the tree that's rooted at this device.
+ */
+static int finish_device_resume(struct usb_device *udev)
+{
+ int status;
+ u16 devstatus;
+
+ /* caller owns the udev device lock */
+ dev_dbg(&udev->dev, "finish resume\n");
+
+ /* usb ch9 identifies four variants of SUSPENDED, based on what
+ * state the device resumes to. Linux currently won't see the
+ * first two on the host side; they'd be inside hub_port_init()
+ * during many timeouts, but khubd can't suspend until later.
+ */
+ usb_set_device_state(udev, udev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
+ udev->dev.power.power_state = PMSG_ON;
+
+ /* 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.
+ */
+ status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
+ if (status >= 0)
+ status = (status == 2 ? 0 : -ENODEV);
+
+ if (status)
+ dev_dbg(&udev->dev,
+ "gone after usb resume? status %d\n",
+ status);
+ else if (udev->actconfig) {
+ unsigned i;
+ int (*resume)(struct device *);
+
+ le16_to_cpus(&devstatus);
+ if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
+ && udev->parent) {
+ status = usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ if (status) {
+ dev_dbg(&udev->dev, "disable remote "
+ "wakeup, status %d\n", status);
+ status = 0;
+ }
+ }
+
+ /* resume interface drivers; if this is a hub, it
+ * may have a child resume event to deal with soon
+ */
+ resume = udev->dev.bus->resume;
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ struct device *dev =
+ &udev->actconfig->interface[i]->dev;
+
+ down(&dev->sem);
+ (void) resume(dev);
+ up(&dev->sem);
+ }
+ status = 0;
+
+ } else if (udev->devnum <= 0) {
+ dev_dbg(&udev->dev, "bogus resume!\n");
+ status = -EINVAL;
+ }
+ return status;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+
+static int
+hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+{
+ int status;
+
+ // dev_dbg(hub->intfdev, "resume port %d\n", port1);
+
+ /* see 7.1.7.7; affects power usage, but not budgeting */
+ status = clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_SUSPEND);
+ if (status) {
+ dev_dbg(hub->intfdev,
+ "can't resume port %d, status %d\n",
+ port1, status);
+ } else {
+ u16 devstatus;
+ u16 portchange;
+
+ /* drive resume for at least 20 msec */
+ if (udev)
+ dev_dbg(&udev->dev, "RESUME\n");
+ msleep(25);
+
+#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
+ | USB_PORT_STAT_ENABLE \
+ | USB_PORT_STAT_CONNECTION)
+
+ /* Virtual root hubs can trigger on GET_PORT_STATUS to
+ * stop resume signaling. Then finish the resume
+ * sequence.
+ */
+ devstatus = portchange = 0;
+ status = hub_port_status(hub, port1,
+ &devstatus, &portchange);
+ if (status < 0
+ || (devstatus & LIVE_FLAGS) != LIVE_FLAGS
+ || (devstatus & USB_PORT_STAT_SUSPEND) != 0
+ ) {
+ dev_dbg(hub->intfdev,
+ "port %d status %04x.%04x after resume, %d\n",
+ port1, portchange, devstatus, status);
+ if (status >= 0)
+ status = -ENODEV;
+ } else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ if (udev)
+ status = finish_device_resume(udev);
+ }
+ }
+ if (status < 0)
+ hub_port_logical_disconnect(hub, port1);