This new version looks fine, thanks Andiry. I'll apply these to the for-linux-next branch and get them sent to Greg by end-of-week after I test them. Sarah Sharp On Wed, Apr 27, 2011 at 06:07:43PM +0800, 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 | 41 ++++++++++++++++++++++++---------- > 2 files changed, 66 insertions(+), 27 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 93720bd..dcd78c1 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); > @@ -2160,11 +2151,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. > @@ -2174,7 +2194,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; > } > @@ -2439,7 +2461,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); > @@ -3147,7 +3169,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) > diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c > index c93fc66..4b76b83 100644 > --- a/drivers/usb/host/xhci-hub.c > +++ b/drivers/usb/host/xhci-hub.c > @@ -431,9 +431,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, > } > xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); > > - /* FIXME - should we return a port status value like the USB > - * 3.0 external hubs do? > - */ > /* wPortChange bits */ > if (temp & PORT_CSC) > status |= USB_PORT_STAT_C_CONNECTION << 16; > @@ -441,13 +438,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, > status |= USB_PORT_STAT_C_ENABLE << 16; > if ((temp & PORT_OCC)) > status |= USB_PORT_STAT_C_OVERCURRENT << 16; > - /* > - * FIXME ignoring reset and USB 2.1/3.0 specific > - * changes > - */ > - if ((temp & PORT_PLS_MASK) == XDEV_U3 > - && (temp & PORT_POWER)) > - status |= 1 << USB_PORT_FEAT_SUSPEND; > + if ((temp & PORT_RC)) > + status |= USB_PORT_STAT_C_RESET << 16; > + /* USB3.0 only */ > + if (hcd->speed == HCD_USB3) { > + if ((temp & PORT_PLC)) > + status |= USB_PORT_STAT_C_LINK_STATE << 16; > + if ((temp & PORT_WRC)) > + status |= USB_PORT_STAT_C_BH_RESET << 16; > + } > + > + if (hcd->speed != HCD_USB3) { > + if ((temp & PORT_PLS_MASK) == XDEV_U3 > + && (temp & PORT_POWER)) > + status |= USB_PORT_STAT_SUSPEND; > + } > if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { > if ((temp & PORT_RESET) || !(temp & PORT_PE)) > goto error; > @@ -490,8 +495,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, > status |= USB_PORT_STAT_OVERCURRENT; > if (temp & PORT_RESET) > status |= USB_PORT_STAT_RESET; > - if (temp & PORT_POWER) > - status |= USB_PORT_STAT_POWER; > + if (temp & PORT_POWER) { > + if (hcd->speed == HCD_USB3) > + status |= USB_SS_PORT_STAT_POWER; > + else > + status |= USB_PORT_STAT_POWER; > + } > + /* Port Link State */ > + if (hcd->speed == HCD_USB3) { > + /* resume state is a xHCI internal state. > + * Do not report it to usb core. > + */ > + if ((temp & PORT_PLS_MASK) != XDEV_RESUME) > + status |= (temp & PORT_PLS_MASK); > + } > if (bus_state->port_c_suspend & (1 << wIndex)) > status |= 1 << USB_PORT_FEAT_C_SUSPEND; > xhci_dbg(xhci, "Get port status returned 0x%x\n", status); > -- > 1.7.1 > > > -- 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