On Tue, 29 Mar 2011, Andiry Xu wrote: > USB3.0 specification has different wPortStatus and wPortChange definitions > from USB2.0 specification. Since USB3 root hub and USB2 root hub are split > now and USB3 hub only has USB3 protocol ports, we should modify the > portstatus and portchange report of USB3 ports to comply with USB3.0 > specification. > > Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx> > --- > drivers/usb/core/hub.c | 52 ++++++++++++++++++++++++++++++------------ > drivers/usb/host/xhci-hub.c | 23 +++++++++++++++---- > 2 files changed, 55 insertions(+), 20 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 0968157..bc6f39c 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -379,15 +379,6 @@ static int hub_port_status(struct usb_hub *hub, int port1, > *status = le16_to_cpu(hub->status->port.wPortStatus); > *change = le16_to_cpu(hub->status->port.wPortChange); > > - if ((hub->hdev->parent != NULL) && > - hub_is_superspeed(hub->hdev)) { > - /* Translate the USB 3 port status */ > - u16 tmp = *status & USB_SS_PORT_STAT_MASK; > - if (*status & USB_SS_PORT_STAT_POWER) > - tmp |= USB_PORT_STAT_POWER; > - *status = tmp; > - } > - > ret = 0; > } > mutex_unlock(&hub->status_mutex); > @@ -2158,11 +2149,40 @@ static int hub_port_reset(struct usb_hub *hub, int port1, > return status; > } > > +/* Check if a port is power on */ > +static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) > +{ > + int ret = 0; > + > + if (hub_is_superspeed(hub->hdev)) { > + if (portstatus & USB_SS_PORT_STAT_POWER) > + ret = 1; > + } else { > + if (portstatus & USB_PORT_STAT_POWER) > + ret = 1; > + } > + > + return ret; > +} > + > #ifdef CONFIG_PM > > -#define MASK_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION | \ > - USB_PORT_STAT_SUSPEND) > -#define WANT_BITS (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION) > +/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ > +static int port_is_suspended(struct usb_hub *hub, unsigned portstatus) > +{ > + int ret = 0; > + > + if (hub_is_superspeed(hub->hdev)) { > + if ((portstatus & USB_PORT_STAT_LINK_STATE) > + == USB_SS_PORT_LS_U3) > + ret = 1; > + } else { > + if (portstatus & USB_PORT_STAT_SUSPEND) > + ret = 1; > + } > + > + return ret; > +} > > /* Determine whether the device on a port is ready for a normal resume, > * is ready for a reset-resume, or should be disconnected. > @@ -2172,7 +2192,9 @@ static int check_port_resume_type(struct usb_device *udev, > int status, unsigned portchange, unsigned portstatus) > { > /* Is the device still present? */ > - if (status || (portstatus & MASK_BITS) != WANT_BITS) { > + if (status || port_is_suspended(hub, portstatus) || > + !port_is_power_on(hub, portstatus) || > + !(portstatus & USB_PORT_STAT_CONNECTION)) { > if (status >= 0) > status = -ENODEV; > } > @@ -2427,7 +2449,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) > > /* Skip the initial Clear-Suspend step for a remote wakeup */ > status = hub_port_status(hub, port1, &portstatus, &portchange); > - if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND)) > + if (status == 0 && !port_is_suspended(hub, portstatus)) > goto SuspendCleared; > > // dev_dbg(hub->intfdev, "resume port %d\n", port1); > @@ -3139,7 +3161,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, > > /* maybe switch power back on (e.g. root hub was reset) */ > if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 > - && !(portstatus & USB_PORT_STAT_POWER)) > + && !port_is_power_on(hub, portstatus)) > set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); > > if (portstatus & USB_PORT_STAT_ENABLE) This part is now indeed a lot cleaner. Thanks. Acked-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html