USB: xhci: Allow roothub ports to be disabled.
Add the hub emulation code to allow ports on an xHCI root hub to be
disabled. Add the code to clear the port enabled/disabled bit, and clear
the port enabled/disabled change bit. Like EHCI, the port cannot be
enabled by setting the port enabled/disabled bit. Instead, a port is
enabled by the host controller after a reset.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5850e8b..208b805 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -129,6 +129,16 @@
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
+static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
+ u32 __iomem *addr, u32 port_status)
+{
+ /* Write 1 to disable the port */
+ xhci_writel(xhci, port_status | PORT_PE, addr);
+ port_status = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
+ wIndex, port_status);
+}
+
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
u16 wIndex, u32 __iomem *addr, u32 port_status)
{
@@ -148,6 +158,10 @@
status = PORT_OCC;
port_change_bit = "over-current";
break;
+ case USB_PORT_FEAT_C_ENABLE:
+ status = PORT_PEC;
+ port_change_bit = "enable/disable";
+ break;
default:
/* Should never happen */
return;
@@ -260,9 +274,13 @@
case USB_PORT_FEAT_C_RESET:
case USB_PORT_FEAT_C_CONNECTION:
case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_ENABLE:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
addr, temp);
break;
+ case USB_PORT_FEAT_ENABLE:
+ xhci_disable_port(xhci, wIndex, addr, temp);
+ break;
default:
goto error;
}