static int hs_host_port_suspend_resume(struct usb_hcd *hcd, u8 port) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct usb_device *hdev = hcd->self.root_hub; int retval = 0; xhci_info(xhci, "Testing SUSPEND & RESUME\n"); /* Sending SOF for 15 seconds */ schedule_timeout_uninterruptible(msecs_to_jiffies(15000)); /* Suspend for 15 seconds */ xhci_info(xhci, "Supend Root Hub for 15 seconds\n"); /* set_port_feature in hub.c */ retval = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_SUSPEND, port+1, NULL, 0, 1000); if (retval < 0) return retval; schedule_timeout_uninterruptible(msecs_to_jiffies(15000)); /* After 15 seconds, resume */ xhci_info(xhci, "Resume Root Hub\n"); /* clear_port_feature in hub.c */ retval = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_SUSPEND, port+1, NULL, 0, 1000); return retval; }
static int xhci_port_test(struct usb_hcd *hcd, u8 selector, u8 port, unsigned long flags) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_portpmsc; __le32 __iomem **portpmsc_array; u32 temp; int retval = 0; xhci_info(xhci, "TEST MODE !!! selector = 0x%x\n", selector); xhci_info(xhci, "running XHCI test %x on port %x\n", selector, port); max_portpmsc = xhci_get_portpmsc(hcd, &portpmsc_array); temp = xhci_readl(xhci, portpmsc_array[port]); temp &= ~PORT_TEST(0xf); xhci_writel(xhci, temp, portpmsc_array[port]); switch (selector) { case USB_PORT_TEST_J: xhci_info(xhci, "Port Test J State\n"); /* * For J/K/SE0_NAK/TEST_PACKET/FORCE_ENABLE * 1. Set the Run/Stop bit in the USBCMD register * to a '0' and wait for the HCHalted bit * in the USBSTS regster, to transitio to a '1' * 2. Set the Port Test Control field in the port * under test PORTPMSC register */ retval = xhci_halt(xhci); if (retval < 0) goto error; temp = xhci_readl(xhci, portpmsc_array[port]); temp |= PORT_TEST_J; xhci_writel(xhci, temp, portpmsc_array[port]); break; case USB_PORT_TEST_K: xhci_info(xhci, "Port Test K State\n"); retval = xhci_halt(xhci); if (retval < 0) goto error; temp = xhci_readl(xhci, portpmsc_array[port]); temp |= PORT_TEST_K; xhci_writel(xhci, temp, portpmsc_array[port]); break; case USB_PORT_TEST_SE0_NAK: xhci_info(xhci, "Port Test SE0_NAK\n"); retval = xhci_halt(xhci); if (retval < 0) goto error; temp = xhci_readl(xhci, portpmsc_array[port]); temp |= PORT_TEST_SE0_NAK; xhci_writel(xhci, temp, portpmsc_array[port]); break; case USB_PORT_TEST_PACKET: xhci_info(xhci, "Port Test Packet\n"); retval = xhci_halt(xhci); if (retval < 0) goto error; temp = xhci_readl(xhci, portpmsc_array[port]); temp |= PORT_TEST_PKT; xhci_writel(xhci, temp, portpmsc_array[port]); break; case USB_PORT_TEST_FORCE_ENABLE: xhci_info(xhci, "Port Test Force Enable\n"); retval = xhci_halt(xhci); if (retval < 0) goto error; temp = xhci_readl(xhci, portpmsc_array[port]); temp |= PORT_TEST_FORCE; xhci_writel(xhci, temp, portpmsc_array[port]); break; case (EHSET_HS_HOST_PORT_SUSPEND_RESUME & 0xFF): xhci_info(xhci, "HS Host Port Suspend Resume\n"); spin_unlock_irqrestore(&xhci->lock, flags); retval = hs_host_port_suspend_resume(hcd, port); spin_lock_irqsave(&xhci->lock, flags); if (retval < 0) goto error; break; case (EHSET_SINGLE_STEP_GET_DEV_DESC & 0xFF): xhci_info(xhci, "EHSET Single Step Get Device Descriptor\n"); spin_unlock_irqrestore(&xhci->lock, flags); retval = single_step_get_dev_desc(hcd, port); spin_lock_irqsave(&xhci->lock, flags); if (retval < 0) goto error; break; case (EHSET_SINGLE_STEP_SET_FEATURE & 0xFF): xhci_info(xhci, "EHSET Single Step Get Device Descriptor\n"); spin_unlock_irqrestore(&xhci->lock, flags); retval = single_step_set_feature(hcd, port); spin_lock_irqsave(&xhci->lock, flags); if (retval < 0) goto error; break; default: xhci_err(xhci, "Unknown Test Mode : %d\n", selector); retval = -EINVAL; goto error; } temp = xhci_readl(xhci, portpmsc_array[port]); xhci_info(xhci, "PORTPMSC: actual port %d status & control = 0x%x\n", port, temp); xhci_info(xhci, "USB2.0 Port Test Done !!!\n"); return retval; error: xhci_err(xhci, "USB2.0 Port Test Error : %d\n", retval); return retval; }
static int single_step_get_dev_desc(struct usb_hcd *hcd, u8 port) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct urb *urb; struct usb_device *hdev; struct usb_device *udev = NULL; struct usb_hub *hub = NULL; struct usb_ctrlrequest setup_packet; char data_buffer[USB_DT_DEVICE_SIZE]; int ret = 0; xhci_info(xhci, "Testing SINGLE_STEP_GET_DEV_DESC\n"); hdev = hcd->self.root_hub; if (!hdev) { xhci_err(xhci, "EHSET: root_hub pointer is NULL\n"); ret = -EPIPE; goto error; } hub = usb_hub_to_struct_hub(hdev); if (hub == NULL) { xhci_err(xhci, "EHSET: hub pointer is NULL\n"); ret = -EPIPE; goto error; } if (hub->ports[port]->child != NULL) udev = hub->ports[port]->child; if (!udev) { xhci_err(xhci, "EHSET: device available is NOT found\n"); ret = -EPIPE; goto error; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { xhci_err(xhci, "urb : get alloc failed\n"); ret = -ENOMEM; goto error; } setup_packet.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR; setup_packet.wValue = (USB_DT_DEVICE << 8); setup_packet.wIndex = 0; setup_packet.wLength = USB_DT_DEVICE_SIZE; urb->dev = udev; urb->hcpriv = udev->ep0.hcpriv; urb->setup_packet = (unsigned char *)&setup_packet; urb->transfer_buffer = data_buffer; urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; urb->actual_length = 0; urb->transfer_flags = URB_DIR_IN | URB_HCD_DRIVER_TEST; urb->pipe = usb_rcvctrlpipe(udev, 0); urb->ep = usb_pipe_endpoint(udev, urb->pipe); if (!urb->ep) { xhci_err(xhci, "urb->ep is NULL\n"); ret = -ENOENT; goto error_urb_ep; } urb->setup_dma = dma_map_single( hcd->self.controller, urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); if (dma_mapping_error(hcd->self.controller, urb->setup_dma)) { xhci_err(xhci, "setup : dma_map_single failed\n"); ret = -EBUSY; goto error_setup_dma; } urb->transfer_dma = dma_map_single( hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, DMA_TO_DEVICE); if (dma_mapping_error(hcd->self.controller, urb->transfer_dma)) { xhci_err(xhci, "xfer : dma_map_single failed\n"); ret = -EBUSY; goto error_xfer_dma; } ret = xhci_urb_enqueue_single_step(hcd, urb, GFP_ATOMIC, 1); dma_unmap_single(hcd->self.controller, urb->transfer_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); error_xfer_dma: dma_unmap_single(hcd->self.controller, urb->setup_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); error_setup_dma: error_urb_ep: usb_free_urb(urb); error: return ret; }
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); int max_ports, max_portpmsc; unsigned long flags; u32 temp, status; int retval = 0; __le32 __iomem **port_array; __le32 __iomem **portpmsc_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 selector; max_ports = xhci_get_ports(hcd, &port_array); max_portpmsc = xhci_get_portpmsc(hcd, &portpmsc_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 (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; } 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; memcpy(buf, &usb_bos_descriptor, USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); buf[12] = HCS_U1_LATENCY(temp); put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); spin_unlock_irqrestore(&xhci->lock, flags); return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; case GetPortStatus: if (!wIndex || wIndex > max_ports) goto error; wIndex--; status = 0; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); /* wPortChange bits */ if (temp & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (temp & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; if ((temp & PORT_OCC)) status |= USB_PORT_STAT_C_OVERCURRENT << 16; 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 && !DEV_SUPERSPEED(temp)) { if ((temp & PORT_RESET) || !(temp & PORT_PE)) goto error; if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", wIndex + 1); 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); bus_state->port_c_suspend |= 1 << wIndex; bus_state->suspended_ports &= ~(1 << wIndex); } else { /* * The resume has been signaling for less than * 20ms. Report the port status as SUSPEND, * let the usbcore check port status again * and clear resume signaling later. */ status |= USB_PORT_STAT_SUSPEND; } } if ((temp & PORT_PLS_MASK) == XDEV_U0 && (temp & PORT_POWER) && (bus_state->suspended_ports & (1 << wIndex))) { bus_state->suspended_ports &= ~(1 << wIndex); if (hcd->speed != HCD_USB3) bus_state->port_c_suspend |= 1 << wIndex; } if (temp & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; status |= xhci_port_speed(temp); } if (temp & PORT_PE) status |= USB_PORT_STAT_ENABLE; if (temp & PORT_OC) status |= USB_PORT_STAT_OVERCURRENT; if (temp & PORT_RESET) status |= USB_PORT_STAT_RESET; if (temp & PORT_POWER) { if (hcd->speed == HCD_USB3) status |= USB_SS_PORT_STAT_POWER; else status |= USB_PORT_STAT_POWER; } /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { xhci_hub_report_link_state(&status, temp); /* * Verify if all USB3 Ports Have entered U0 already. * Delete Compliance Mode Timer if so. */ xhci_del_comp_mod_timer(xhci, temp, wIndex); } 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); put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: selector = wIndex >> 8; if (wValue == USB_PORT_FEAT_LINK_STATE) link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; wIndex--; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; 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 = xhci_readl(xhci, 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. */ temp = xhci_readl(xhci, 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; } 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; } /* 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); spin_unlock_irqrestore(&xhci->lock, flags); msleep(10); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, port_array[wIndex]); bus_state->suspended_ports |= 1 << wIndex; break; case USB_PORT_FEAT_LINK_STATE: temp = xhci_readl(xhci, 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; xhci_writel(xhci, temp | PORT_PE, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); break; } /* 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 = xhci_readl(xhci, port_array[wIndex]); 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"); goto error; } 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); } } xhci_set_link_state(xhci, port_array, wIndex, link_state); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, 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, khubd will ignore the roothub events until * the roothub is registered. */ xhci_writel(xhci, temp | PORT_POWER, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); xhci_writel(xhci, temp, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); break; /* * For downstream facing ports (these): one hub port is put * into test mode according to USB2 11.24.2.13, then the hub * must be reset (which for root hub now means rmmod+modprobe, * or else system reboot). See EHCI 2.3.9 and 4.14 for info * about the EHCI-specific stuff. */ #ifdef CONFIG_HOST_COMPLIANT_TEST case USB_PORT_FEAT_TEST: xhci_info(xhci, "TEST MODE !!! selector = 0x%x\n", selector); xhci_info(xhci, "running XHCI test %x on port %x\n", selector, wIndex); /* * Set the Port Test Control field in the port * under test PORTPMSC register */ temp = xhci_readl(xhci, portpmsc_array[wIndex]); xhci_info(xhci, "PORTPMSC: actual port %d status" "& control = 0x%x\n", wIndex, temp); temp |= PORT_TEST_PKT; xhci_writel(xhci, temp, portpmsc_array[wIndex]); temp = xhci_readl(xhci, portpmsc_array[wIndex]); xhci_info(xhci, "PORTPMSC: Test Packet, actual port %d" "status = 0x%x\n", wIndex, temp); break; #endif/* CONFIG_HOST_COMPLIANT_TEST */ case USB_PORT_FEAT_REMOTE_WAKE_MASK: xhci_set_remote_wake_mask(xhci, port_array, wIndex, wake_mask); temp = xhci_readl(xhci, 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; xhci_writel(xhci, temp, port_array[wIndex]); temp = xhci_readl(xhci, port_array[wIndex]); break; default: goto error; } /* unblock any posted writes */ temp = xhci_readl(xhci, port_array[wIndex]); break; case ClearPortFeature: if (!wIndex || wIndex > max_ports) goto error; wIndex--; temp = xhci_readl(xhci, 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 = xhci_readl(xhci, 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; xhci_set_link_state(xhci, port_array, wIndex, XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); msleep(20); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); } bus_state->port_c_suspend |= 1 << wIndex; 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: 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; default: goto error; } break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&xhci->lock, flags); return retval; }