In order to make xhci_hub_control() easier to read,
let's break it into smaller functions. This will aid
maintainability and readability of the code. There
are no functional changes here, just shuffling code
around.

Signed-off-by: Felipe Balbi <felipe.ba...@linux.intel.com>
---
 drivers/usb/host/xhci-hub.c | 652 ++++++++++++++++++++++++--------------------
 1 file changed, 363 insertions(+), 289 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index dd6de282e48f..b99f06f4c421 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -873,17 +873,97 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
        return status;
 }
 
-int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+static int xhci_ctrl_get_hub_status(struct usb_hcd *hcd, u16 wValue,
                u16 wIndex, char *buf, u16 wLength)
 {
+       /* No power source, over-current reported per port */
+       memset(buf, 0, 4);
+       return 0;
+}
+
+static int xhci_ctrl_get_hub_descriptor(struct usb_hcd *hcd, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       /* Check to make sure userspace is asking for the USB 3.0 hub
+        * descriptor for the USB 3.0 roothub.  If not, we stall the
+        * endpoint, like external hubs do.
+        */
+       if (hcd->speed >= HCD_USB3 &&
+                       (wLength < USB_DT_SS_HUB_SIZE ||
+                                       wValue != (USB_DT_SS_HUB << 8))) {
+               xhci_dbg(xhci, "Wrong hub descriptor type for "
+                               "USB 3.0 roothub.\n");
+               return -EPIPE;
+       }
+       xhci_hub_descriptor(hcd, xhci,
+                       (struct usb_hub_descriptor *) buf);
+
+       return 0;
+}
+
+static int xhci_ctrl_get_port_status(struct usb_hcd *hcd, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength, unsigned long flags)
+{
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct xhci_bus_state *bus_state;
+
+       u32 status;
+       u32 temp;
+
        int max_ports;
-       unsigned long flags;
-       u32 temp, status;
-       int retval = 0;
+
        __le32 __iomem **port_array;
-       int slot_id;
+
+       max_ports = xhci_get_ports(hcd, &port_array);
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
+
+       if (!wIndex || wIndex > max_ports)
+               return -EINVAL;
+
+       wIndex--;
+       temp = readl(port_array[wIndex]);
+       if (temp == 0xffffffff)
+               return -ENODEV;
+       status = xhci_get_port_status(hcd, bus_state, port_array,
+                       wIndex, temp, flags);
+       if (status == 0xffffffff)
+               return -ENODEV;
+
+       xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n",
+                       wIndex, temp);
+       xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+
+       put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+       /* if USB 3.1 extended port status return additional 4 bytes */
+       if (wValue == 0x02) {
+               u32 port_li;
+
+               if (hcd->speed < HCD_USB31 || wLength != 8) {
+                       xhci_err(xhci, "get ext port status invalid 
parameter\n");
+                       return -EINVAL;
+               }
+               port_li = readl(port_array[wIndex] + PORTLI);
+               status = xhci_get_ext_port_status(temp, port_li);
+               put_unaligned_le32(cpu_to_le32(status), &buf[4]);
+       }
+
+       return 0;
+}
+
+static int xhci_ctrl_set_port_feature(struct usb_hcd *hcd, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength, unsigned long flags)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        struct xhci_bus_state *bus_state;
+
+       int max_ports;
+       int slot_id;
+       u32 temp;
+
+       __le32 __iomem **port_array;
+
        u16 link_state = 0;
        u16 wake_mask = 0;
        u16 timeout = 0;
@@ -891,328 +971,322 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, 
u16 wValue,
        max_ports = xhci_get_ports(hcd, &port_array);
        bus_state = &xhci->bus_state[hcd_index(hcd)];
 
-       spin_lock_irqsave(&xhci->lock, flags);
-       switch (typeReq) {
-       case GetHubStatus:
-               /* No power source, over-current reported per port */
-               memset(buf, 0, 4);
-               break;
-       case GetHubDescriptor:
-               /* Check to make sure userspace is asking for the USB 3.0 hub
-                * descriptor for the USB 3.0 roothub.  If not, we stall the
-                * endpoint, like external hubs do.
+       if (wValue == USB_PORT_FEAT_LINK_STATE)
+               link_state = (wIndex & 0xff00) >> 3;
+       if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
+               wake_mask = wIndex & 0xff00;
+       /* The MSB of wIndex is the U1/U2 timeout */
+       timeout = (wIndex & 0xff00) >> 8;
+       wIndex &= 0xff;
+       if (!wIndex || wIndex > max_ports)
+               return -EPIPE;
+
+       wIndex--;
+       temp = readl(port_array[wIndex]);
+       if (temp == 0xffffffff)
+               return -ENODEV;
+
+       temp = xhci_port_state_to_neutral(temp);
+       /* FIXME: What new port features do we need to support? */
+       switch (wValue) {
+       case USB_PORT_FEAT_SUSPEND:
+               temp = readl(port_array[wIndex]);
+               if ((temp & PORT_PLS_MASK) != XDEV_U0) {
+                       /* Resume the port to U0 first */
+                       xhci_set_link_state(xhci, port_array, wIndex,
+                                       XDEV_U0);
+                       spin_unlock_irqrestore(&xhci->lock, flags);
+                       msleep(10);
+                       spin_lock_irqsave(&xhci->lock, flags);
+               }
+               /* In spec software should not attempt to suspend
+                * a port unless the port reports that it is in the
+                * enabled (PED = ‘1’,PLS < ‘3’) state.
                 */
-               if (hcd->speed >= HCD_USB3 &&
-                               (wLength < USB_DT_SS_HUB_SIZE ||
-                                wValue != (USB_DT_SS_HUB << 8))) {
-                       xhci_dbg(xhci, "Wrong hub descriptor type for "
-                                       "USB 3.0 roothub.\n");
-                       goto error;
+               temp = readl(port_array[wIndex]);
+               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
+                               || (temp & PORT_PLS_MASK) >= XDEV_U3) {
+                       xhci_warn(xhci, "USB core suspending device "
+                                       "not in U0/U1/U2.\n");
+                       return -EPIPE;
                }
-               xhci_hub_descriptor(hcd, xhci,
-                               (struct usb_hub_descriptor *) buf);
-               break;
-       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-               if ((wValue & 0xff00) != (USB_DT_BOS << 8))
-                       goto error;
 
-               if (hcd->speed < HCD_USB3)
-                       goto error;
-
-               retval = xhci_create_usb3_bos_desc(xhci, buf, wLength);
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return retval;
-       case GetPortStatus:
-               if (!wIndex || wIndex > max_ports)
-                       goto error;
-               wIndex--;
-               temp = readl(port_array[wIndex]);
-               if (temp == 0xffffffff) {
-                       retval = -ENODEV;
-                       break;
+               slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+                               wIndex + 1);
+               if (!slot_id) {
+                       xhci_warn(xhci, "slot_id is zero\n");
+                       return -EPIPE;
                }
-               status = xhci_get_port_status(hcd, bus_state, port_array,
-                               wIndex, temp, flags);
-               if (status == 0xffffffff)
-                       goto error;
+               /* unlock to execute stop endpoint commands */
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_stop_device(xhci, slot_id, 1);
+               spin_lock_irqsave(&xhci->lock, flags);
 
-               xhci_dbg(xhci, "get port status, actual port %d status  = 
0x%x\n",
-                               wIndex, temp);
-               xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+               xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
 
-               put_unaligned(cpu_to_le32(status), (__le32 *) buf);
-               /* if USB 3.1 extended port status return additional 4 bytes */
-               if (wValue == 0x02) {
-                       u32 port_li;
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               msleep(10); /* wait device to enter */
+               spin_lock_irqsave(&xhci->lock, flags);
 
-                       if (hcd->speed < HCD_USB31 || wLength != 8) {
-                               xhci_err(xhci, "get ext port status invalid 
parameter\n");
-                               retval = -EINVAL;
-                               break;
-                       }
-                       port_li = readl(port_array[wIndex] + PORTLI);
-                       status = xhci_get_ext_port_status(temp, port_li);
-                       put_unaligned_le32(cpu_to_le32(status), &buf[4]);
-               }
+               temp = readl(port_array[wIndex]);
+               bus_state->suspended_ports |= 1 << wIndex;
                break;
-       case SetPortFeature:
-               if (wValue == USB_PORT_FEAT_LINK_STATE)
-                       link_state = (wIndex & 0xff00) >> 3;
-               if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
-                       wake_mask = wIndex & 0xff00;
-               /* The MSB of wIndex is the U1/U2 timeout */
-               timeout = (wIndex & 0xff00) >> 8;
-               wIndex &= 0xff;
-               if (!wIndex || wIndex > max_ports)
-                       goto error;
-               wIndex--;
+       case USB_PORT_FEAT_LINK_STATE:
                temp = readl(port_array[wIndex]);
-               if (temp == 0xffffffff) {
-                       retval = -ENODEV;
+
+               /* Disable port */
+               if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
+                       xhci_dbg(xhci, "Disable port %d\n", wIndex);
+                       temp = xhci_port_state_to_neutral(temp);
+                       /*
+                        * Clear all change bits, so that we get a new
+                        * connection event.
+                        */
+                       temp |= PORT_CSC | PORT_PEC | PORT_WRC |
+                               PORT_OCC | PORT_RC | PORT_PLC |
+                               PORT_CEC;
+                       writel(temp | PORT_PE, port_array[wIndex]);
+                       temp = readl(port_array[wIndex]);
                        break;
                }
-               temp = xhci_port_state_to_neutral(temp);
-               /* FIXME: What new port features do we need to support? */
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       temp = readl(port_array[wIndex]);
-                       if ((temp & PORT_PLS_MASK) != XDEV_U0) {
-                               /* Resume the port to U0 first */
-                               xhci_set_link_state(xhci, port_array, wIndex,
-                                                       XDEV_U0);
-                               spin_unlock_irqrestore(&xhci->lock, flags);
-                               msleep(10);
-                               spin_lock_irqsave(&xhci->lock, flags);
-                       }
-                       /* In spec software should not attempt to suspend
-                        * a port unless the port reports that it is in the
-                        * enabled (PED = ‘1’,PLS < ‘3’) state.
-                        */
+
+               /* Put link in RxDetect (enable port) */
+               if (link_state == USB_SS_PORT_LS_RX_DETECT) {
+                       xhci_dbg(xhci, "Enable port %d\n", wIndex);
+                       xhci_set_link_state(xhci, port_array, wIndex,
+                                       link_state);
                        temp = readl(port_array[wIndex]);
-                       if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
-                               || (temp & PORT_PLS_MASK) >= XDEV_U3) {
-                               xhci_warn(xhci, "USB core suspending device "
-                                         "not in U0/U1/U2.\n");
-                               goto error;
-                       }
+                       break;
+               }
+
+               /* Software should not attempt to set
+                * port link state above '3' (U3) and the port
+                * must be enabled.
+                */
+               if ((temp & PORT_PE) == 0 ||
+                               (link_state > USB_SS_PORT_LS_U3)) {
+                       xhci_warn(xhci, "Cannot set link state.\n");
+                       return -EPIPE;
+               }
 
+               if (link_state == USB_SS_PORT_LS_U3) {
                        slot_id = xhci_find_slot_id_by_port(hcd, xhci,
                                        wIndex + 1);
-                       if (!slot_id) {
-                               xhci_warn(xhci, "slot_id is zero\n");
-                               goto error;
+                       if (slot_id) {
+                               /* unlock to execute stop endpoint
+                                * commands */
+                               spin_unlock_irqrestore(&xhci->lock,
+                                               flags);
+                               xhci_stop_device(xhci, slot_id, 1);
+                               spin_lock_irqsave(&xhci->lock, flags);
                        }
-                       /* unlock to execute stop endpoint commands */
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       xhci_stop_device(xhci, slot_id, 1);
-                       spin_lock_irqsave(&xhci->lock, flags);
+               }
 
-                       xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
+               xhci_set_link_state(xhci, port_array, wIndex,
+                               link_state);
 
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       msleep(10); /* wait device to enter */
-                       spin_lock_irqsave(&xhci->lock, flags);
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               msleep(20); /* wait device to enter */
+               spin_lock_irqsave(&xhci->lock, flags);
 
-                       temp = readl(port_array[wIndex]);
+               temp = readl(port_array[wIndex]);
+               if (link_state == USB_SS_PORT_LS_U3)
                        bus_state->suspended_ports |= 1 << wIndex;
-                       break;
-               case USB_PORT_FEAT_LINK_STATE:
-                       temp = readl(port_array[wIndex]);
+               break;
+       case USB_PORT_FEAT_POWER:
+               /*
+                * Turn on ports, even if there isn't per-port switching.
+                * HC will report connect events even before this is set.
+                * However, hub_wq will ignore the roothub events until
+                * the roothub is registered.
+                */
+               writel(temp | PORT_POWER, port_array[wIndex]);
 
-                       /* Disable port */
-                       if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
-                               xhci_dbg(xhci, "Disable port %d\n", wIndex);
-                               temp = xhci_port_state_to_neutral(temp);
-                               /*
-                                * Clear all change bits, so that we get a new
-                                * connection event.
-                                */
-                               temp |= PORT_CSC | PORT_PEC | PORT_WRC |
-                                       PORT_OCC | PORT_RC | PORT_PLC |
-                                       PORT_CEC;
-                               writel(temp | PORT_PE, port_array[wIndex]);
-                               temp = readl(port_array[wIndex]);
-                               break;
-                       }
+               temp = readl(port_array[wIndex]);
+               xhci_dbg(xhci, "set port power, actual port %d status  = 
0x%x\n", wIndex, temp);
 
-                       /* Put link in RxDetect (enable port) */
-                       if (link_state == USB_SS_PORT_LS_RX_DETECT) {
-                               xhci_dbg(xhci, "Enable port %d\n", wIndex);
-                               xhci_set_link_state(xhci, port_array, wIndex,
-                                               link_state);
-                               temp = readl(port_array[wIndex]);
-                               break;
-                       }
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               temp = usb_acpi_power_manageable(hcd->self.root_hub,
+                               wIndex);
+               if (temp)
+                       usb_acpi_set_power_state(hcd->self.root_hub,
+                                       wIndex, true);
+               spin_lock_irqsave(&xhci->lock, flags);
+               break;
+       case USB_PORT_FEAT_RESET:
+               temp = (temp | PORT_RESET);
+               writel(temp, port_array[wIndex]);
 
-                       /* Software should not attempt to set
-                        * port link state above '3' (U3) and the port
-                        * must be enabled.
-                        */
-                       if ((temp & PORT_PE) == 0 ||
-                               (link_state > USB_SS_PORT_LS_U3)) {
-                               xhci_warn(xhci, "Cannot set link state.\n");
-                               goto error;
-                       }
+               temp = readl(port_array[wIndex]);
+               xhci_dbg(xhci, "set port reset, actual port %d status  = 
0x%x\n", wIndex, temp);
+               break;
+       case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+               xhci_set_remote_wake_mask(xhci, port_array,
+                               wIndex, wake_mask);
+               temp = readl(port_array[wIndex]);
+               xhci_dbg(xhci, "set port remote wake mask, "
+                               "actual port %d status  = 0x%x\n",
+                               wIndex, temp);
+               break;
+       case USB_PORT_FEAT_BH_PORT_RESET:
+               temp |= PORT_WR;
+               writel(temp, port_array[wIndex]);
 
-                       if (link_state == USB_SS_PORT_LS_U3) {
-                               slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                               wIndex + 1);
-                               if (slot_id) {
-                                       /* unlock to execute stop endpoint
-                                        * commands */
-                                       spin_unlock_irqrestore(&xhci->lock,
-                                                               flags);
-                                       xhci_stop_device(xhci, slot_id, 1);
-                                       spin_lock_irqsave(&xhci->lock, flags);
-                               }
-                       }
+               temp = readl(port_array[wIndex]);
+               break;
+       case USB_PORT_FEAT_U1_TIMEOUT:
+               if (hcd->speed < HCD_USB3)
+                       return -EPIPE;
+               temp = readl(port_array[wIndex] + PORTPMSC);
+               temp &= ~PORT_U1_TIMEOUT_MASK;
+               temp |= PORT_U1_TIMEOUT(timeout);
+               writel(temp, port_array[wIndex] + PORTPMSC);
+               break;
+       case USB_PORT_FEAT_U2_TIMEOUT:
+               if (hcd->speed < HCD_USB3)
+                       return -EPIPE;
+               temp = readl(port_array[wIndex] + PORTPMSC);
+               temp &= ~PORT_U2_TIMEOUT_MASK;
+               temp |= PORT_U2_TIMEOUT(timeout);
+               writel(temp, port_array[wIndex] + PORTPMSC);
+               break;
+       default:
+               return -EPIPE;
+       }
+       /* unblock any posted writes */
+       temp = readl(port_array[wIndex]);
 
-                       xhci_set_link_state(xhci, port_array, wIndex,
-                                               link_state);
+       return 0;
+}
 
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       msleep(20); /* wait device to enter */
-                       spin_lock_irqsave(&xhci->lock, flags);
+static int xhci_ctrl_clear_port_feature(struct usb_hcd *hcd, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength, unsigned long flags)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct xhci_bus_state *bus_state;
 
-                       temp = readl(port_array[wIndex]);
-                       if (link_state == USB_SS_PORT_LS_U3)
-                               bus_state->suspended_ports |= 1 << wIndex;
-                       break;
-               case USB_PORT_FEAT_POWER:
-                       /*
-                        * Turn on ports, even if there isn't per-port 
switching.
-                        * HC will report connect events even before this is 
set.
-                        * However, hub_wq will ignore the roothub events until
-                        * the roothub is registered.
-                        */
-                       writel(temp | PORT_POWER, port_array[wIndex]);
+       int max_ports;
+       int slot_id;
+       u32 temp;
 
-                       temp = readl(port_array[wIndex]);
-                       xhci_dbg(xhci, "set port power, actual port %d status  
= 0x%x\n", wIndex, temp);
+       __le32 __iomem **port_array;
+
+       max_ports = xhci_get_ports(hcd, &port_array);
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
+
+       if (!wIndex || wIndex > max_ports)
+               return -EPIPE;
 
+       wIndex--;
+       temp = readl(port_array[wIndex]);
+       if (temp == 0xffffffff)
+               return -ENODEV;
+
+       /* FIXME: What new port features do we need to support? */
+       temp = xhci_port_state_to_neutral(temp);
+       switch (wValue) {
+       case USB_PORT_FEAT_SUSPEND:
+               temp = readl(port_array[wIndex]);
+               xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
+               xhci_dbg(xhci, "PORTSC %04x\n", temp);
+               if (temp & PORT_RESET)
+                       return -EPIPE;
+               if ((temp & PORT_PLS_MASK) == XDEV_U3) {
+                       if ((temp & PORT_PE) == 0)
+                               return -EPIPE;
+
+                       set_bit(wIndex, &bus_state->resuming_ports);
+                       xhci_set_link_state(xhci, port_array, wIndex,
+                                       XDEV_RESUME);
                        spin_unlock_irqrestore(&xhci->lock, flags);
-                       temp = usb_acpi_power_manageable(hcd->self.root_hub,
-                                       wIndex);
-                       if (temp)
-                               usb_acpi_set_power_state(hcd->self.root_hub,
-                                               wIndex, true);
+                       msleep(20);
                        spin_lock_irqsave(&xhci->lock, flags);
-                       break;
-               case USB_PORT_FEAT_RESET:
-                       temp = (temp | PORT_RESET);
-                       writel(temp, port_array[wIndex]);
-
-                       temp = readl(port_array[wIndex]);
-                       xhci_dbg(xhci, "set port reset, actual port %d status  
= 0x%x\n", wIndex, temp);
-                       break;
-               case USB_PORT_FEAT_REMOTE_WAKE_MASK:
-                       xhci_set_remote_wake_mask(xhci, port_array,
-                                       wIndex, wake_mask);
-                       temp = readl(port_array[wIndex]);
-                       xhci_dbg(xhci, "set port remote wake mask, "
-                                       "actual port %d status  = 0x%x\n",
-                                       wIndex, temp);
-                       break;
-               case USB_PORT_FEAT_BH_PORT_RESET:
-                       temp |= PORT_WR;
-                       writel(temp, port_array[wIndex]);
+                       xhci_set_link_state(xhci, port_array, wIndex,
+                                       XDEV_U0);
+                       clear_bit(wIndex, &bus_state->resuming_ports);
+               }
+               bus_state->port_c_suspend |= 1 << wIndex;
 
-                       temp = readl(port_array[wIndex]);
-                       break;
-               case USB_PORT_FEAT_U1_TIMEOUT:
-                       if (hcd->speed < HCD_USB3)
-                               goto error;
-                       temp = readl(port_array[wIndex] + PORTPMSC);
-                       temp &= ~PORT_U1_TIMEOUT_MASK;
-                       temp |= PORT_U1_TIMEOUT(timeout);
-                       writel(temp, port_array[wIndex] + PORTPMSC);
-                       break;
-               case USB_PORT_FEAT_U2_TIMEOUT:
-                       if (hcd->speed < HCD_USB3)
-                               goto error;
-                       temp = readl(port_array[wIndex] + PORTPMSC);
-                       temp &= ~PORT_U2_TIMEOUT_MASK;
-                       temp |= PORT_U2_TIMEOUT(timeout);
-                       writel(temp, port_array[wIndex] + PORTPMSC);
-                       break;
-               default:
-                       goto error;
+               slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+                               wIndex + 1);
+               if (!slot_id) {
+                       xhci_dbg(xhci, "slot_id is zero\n");
+                       return -EPIPE;
                }
-               /* unblock any posted writes */
-               temp = readl(port_array[wIndex]);
+               xhci_ring_device(xhci, slot_id);
                break;
-       case ClearPortFeature:
-               if (!wIndex || wIndex > max_ports)
-                       goto error;
-               wIndex--;
-               temp = readl(port_array[wIndex]);
-               if (temp == 0xffffffff) {
-                       retval = -ENODEV;
-                       break;
-               }
-               /* FIXME: What new port features do we need to support? */
-               temp = xhci_port_state_to_neutral(temp);
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       temp = readl(port_array[wIndex]);
-                       xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
-                       xhci_dbg(xhci, "PORTSC %04x\n", temp);
-                       if (temp & PORT_RESET)
-                               goto error;
-                       if ((temp & PORT_PLS_MASK) == XDEV_U3) {
-                               if ((temp & PORT_PE) == 0)
-                                       goto error;
+       case USB_PORT_FEAT_C_SUSPEND:
+               bus_state->port_c_suspend &= ~(1 << wIndex);
+       case USB_PORT_FEAT_C_RESET:
+       case USB_PORT_FEAT_C_BH_PORT_RESET:
+       case USB_PORT_FEAT_C_CONNECTION:
+       case USB_PORT_FEAT_C_OVER_CURRENT:
+       case USB_PORT_FEAT_C_ENABLE:
+       case USB_PORT_FEAT_C_PORT_LINK_STATE:
+       case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+               xhci_clear_port_change_bit(xhci, wValue, wIndex,
+                               port_array[wIndex], temp);
+               break;
+       case USB_PORT_FEAT_ENABLE:
+               xhci_disable_port(hcd, xhci, wIndex,
+                               port_array[wIndex], temp);
+               break;
+       case USB_PORT_FEAT_POWER:
+               writel(temp & ~PORT_POWER, port_array[wIndex]);
 
-                               set_bit(wIndex, &bus_state->resuming_ports);
-                               xhci_set_link_state(xhci, port_array, wIndex,
-                                                       XDEV_RESUME);
-                               spin_unlock_irqrestore(&xhci->lock, flags);
-                               msleep(USB_RESUME_TIMEOUT);
-                               spin_lock_irqsave(&xhci->lock, flags);
-                               xhci_set_link_state(xhci, port_array, wIndex,
-                                                       XDEV_U0);
-                               clear_bit(wIndex, &bus_state->resuming_ports);
-                       }
-                       bus_state->port_c_suspend |= 1 << wIndex;
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               temp = usb_acpi_power_manageable(hcd->self.root_hub,
+                               wIndex);
+               if (temp)
+                       usb_acpi_set_power_state(hcd->self.root_hub,
+                                       wIndex, false);
+               spin_lock_irqsave(&xhci->lock, flags);
+               break;
+       default:
+               return -EPIPE;
+       }
 
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                       wIndex + 1);
-                       if (!slot_id) {
-                               xhci_dbg(xhci, "slot_id is zero\n");
-                               goto error;
-                       }
-                       xhci_ring_device(xhci, slot_id);
-                       break;
-               case USB_PORT_FEAT_C_SUSPEND:
-                       bus_state->port_c_suspend &= ~(1 << wIndex);
-               case USB_PORT_FEAT_C_RESET:
-               case USB_PORT_FEAT_C_BH_PORT_RESET:
-               case USB_PORT_FEAT_C_CONNECTION:
-               case USB_PORT_FEAT_C_OVER_CURRENT:
-               case USB_PORT_FEAT_C_ENABLE:
-               case USB_PORT_FEAT_C_PORT_LINK_STATE:
-               case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
-                       xhci_clear_port_change_bit(xhci, wValue, wIndex,
-                                       port_array[wIndex], temp);
-                       break;
-               case USB_PORT_FEAT_ENABLE:
-                       xhci_disable_port(hcd, xhci, wIndex,
-                                       port_array[wIndex], temp);
-                       break;
-               case USB_PORT_FEAT_POWER:
-                       writel(temp & ~PORT_POWER, port_array[wIndex]);
+       return 0;
+}
 
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       temp = usb_acpi_power_manageable(hcd->self.root_hub,
-                                       wIndex);
-                       if (temp)
-                               usb_acpi_set_power_state(hcd->self.root_hub,
-                                               wIndex, false);
-                       spin_lock_irqsave(&xhci->lock, flags);
-                       break;
-               default:
+int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       unsigned long flags;
+       int retval = 0;
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       switch (typeReq) {
+       case GetHubStatus:
+               retval = xhci_ctrl_get_hub_status(hcd, wValue, wIndex, buf,
+                               wLength);
+               break;
+       case GetHubDescriptor:
+               retval = xhci_ctrl_get_hub_descriptor(hcd, wValue, wIndex, buf,
+                               wLength);
+               break;
+       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+               if ((wValue & 0xff00) != (USB_DT_BOS << 8))
                        goto error;
-               }
+
+               if (hcd->speed < HCD_USB3)
+                       goto error;
+
+               retval = xhci_create_usb3_bos_desc(xhci, buf, wLength);
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               return retval;
+       case GetPortStatus:
+               retval = xhci_ctrl_get_port_status(hcd, wValue, wIndex, buf,
+                               wLength, flags);
+               break;
+       case SetPortFeature:
+               retval = xhci_ctrl_set_port_feature(hcd, wValue, wIndex, buf,
+                               wLength, flags);
+               break;
+       case ClearPortFeature:
+               retval = xhci_ctrl_clear_port_feature(hcd, wValue, wIndex, buf,
+                               wLength, flags);
                break;
        default:
 error:
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to