MLK-17380-3 usb: move EH SINGLE_STEP_SET_FEATURE implement to core
authorPeter Chen <peter.chen@nxp.com>
Thu, 18 Jan 2018 03:03:24 +0000 (11:03 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Tue, 20 Mar 2018 19:55:22 +0000 (14:55 -0500)
Since other USB 2.0 host may need it, like USB2 for XHCI. We move
this design to HCD core.

Acked-by: Jun Li <jun.li@nxp.com>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
drivers/usb/core/hcd.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-q.c
include/linux/usb/hcd.h

index cc41216..8b4ad24 100644 (file)
@@ -2232,6 +2232,140 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
        return hcd->driver->get_frame_number (hcd);
 }
 
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+static void usb_ehset_completion(struct urb *urb)
+{
+       struct completion  *done = urb->context;
+
+       complete(done);
+}
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+       struct usb_device       *udev,
+       void                    *dr,
+       void                    *buf,
+       struct completion       *done
+) {
+       struct urb *urb;
+       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+       struct usb_host_endpoint *ep;
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return NULL;
+
+       urb->pipe = usb_rcvctrlpipe(udev, 0);
+       ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+                               [usb_pipeendpoint(urb->pipe)];
+       if (!ep) {
+               usb_free_urb(urb);
+               return NULL;
+       }
+
+       urb->ep = ep;
+       urb->dev = udev;
+       urb->setup_packet = (void *)dr;
+       urb->transfer_buffer = buf;
+       urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+       urb->complete = usb_ehset_completion;
+       urb->status = -EINPROGRESS;
+       urb->actual_length = 0;
+       urb->transfer_flags = URB_DIR_IN;
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       urb->setup_dma = dma_map_single(
+                       hcd->self.sysdev,
+                       urb->setup_packet,
+                       sizeof(struct usb_ctrlrequest),
+                       DMA_TO_DEVICE);
+       urb->transfer_dma = dma_map_single(
+                       hcd->self.sysdev,
+                       urb->transfer_buffer,
+                       urb->transfer_buffer_length,
+                       DMA_FROM_DEVICE);
+       urb->context = done;
+       return urb;
+}
+
+int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+       int retval = -ENOMEM;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       struct usb_device *udev;
+       struct usb_device_descriptor *buf;
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       /* Obtain udev of the rhub's child port */
+       udev = usb_hub_find_child(hcd->self.root_hub, port);
+       if (!udev) {
+               dev_err(hcd->self.controller, "No device attached to the RootHub\n");
+               return -ENODEV;
+       }
+       buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+       if (!dr) {
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       /* Fill Setup packet for GetDescriptor */
+       dr->bRequestType = USB_DIR_IN;
+       dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+       dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+       dr->wIndex = 0;
+       dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+       urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+       if (!urb)
+               goto cleanup;
+
+       /* Submit just the SETUP stage */
+       retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
+       if (retval)
+               goto out1;
+       if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+               usb_kill_urb(urb);
+               retval = -ETIMEDOUT;
+               dev_err(hcd->self.controller,
+                       "%s SETUP stage timed out on ep0\n", __func__);
+               goto out1;
+       }
+       msleep(15 * 1000);
+
+       /* Complete remaining DATA and STATUS stages using the same URB */
+       urb->status = -EINPROGRESS;
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
+       if (!retval && !wait_for_completion_timeout(&done,
+                                               msecs_to_jiffies(2000))) {
+               usb_kill_urb(urb);
+               retval = -ETIMEDOUT;
+               dev_err(hcd->self.controller,
+                       "%s IN stage timed out on ep0\n", __func__);
+       }
+out1:
+       usb_free_urb(urb);
+cleanup:
+       kfree(dr);
+       kfree(buf);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_PM
index a36fded..f754236 100644 (file)
@@ -1244,6 +1244,10 @@ static const struct hc_driver ehci_hc_driver = {
         * device support
         */
        .free_dev =             ehci_remove_device,
+#ifdef CONFIG_USB_HCD_TEST_MODE
+       /* EH SINGLE_STEP_SET_FEATURE test support */
+       .submit_single_step_set_feature = ehci_submit_single_step_set_feature,
+#endif
 };
 
 void ehci_init_driver(struct hc_driver *drv,
index 56effc0..9de4122 100644 (file)
@@ -721,145 +721,6 @@ ehci_hub_descriptor (
        desc->wHubCharacteristics = cpu_to_le16(temp);
 }
 
-/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_HCD_TEST_MODE
-
-#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
-
-static void usb_ehset_completion(struct urb *urb)
-{
-       struct completion  *done = urb->context;
-
-       complete(done);
-}
-static int submit_single_step_set_feature(
-       struct usb_hcd  *hcd,
-       struct urb      *urb,
-       int             is_setup
-);
-
-/*
- * Allocate and initialize a control URB. This request will be used by the
- * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
- * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
- * Return NULL if failed.
- */
-static struct urb *request_single_step_set_feature_urb(
-       struct usb_device       *udev,
-       void                    *dr,
-       void                    *buf,
-       struct completion       *done
-) {
-       struct urb *urb;
-       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-       struct usb_host_endpoint *ep;
-
-       urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!urb)
-               return NULL;
-
-       urb->pipe = usb_rcvctrlpipe(udev, 0);
-       ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
-                               [usb_pipeendpoint(urb->pipe)];
-       if (!ep) {
-               usb_free_urb(urb);
-               return NULL;
-       }
-
-       urb->ep = ep;
-       urb->dev = udev;
-       urb->setup_packet = (void *)dr;
-       urb->transfer_buffer = buf;
-       urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
-       urb->complete = usb_ehset_completion;
-       urb->status = -EINPROGRESS;
-       urb->actual_length = 0;
-       urb->transfer_flags = URB_DIR_IN;
-       usb_get_urb(urb);
-       atomic_inc(&urb->use_count);
-       atomic_inc(&urb->dev->urbnum);
-       urb->setup_dma = dma_map_single(
-                       hcd->self.sysdev,
-                       urb->setup_packet,
-                       sizeof(struct usb_ctrlrequest),
-                       DMA_TO_DEVICE);
-       urb->transfer_dma = dma_map_single(
-                       hcd->self.sysdev,
-                       urb->transfer_buffer,
-                       urb->transfer_buffer_length,
-                       DMA_FROM_DEVICE);
-       urb->context = done;
-       return urb;
-}
-
-static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
-{
-       int retval = -ENOMEM;
-       struct usb_ctrlrequest *dr;
-       struct urb *urb;
-       struct usb_device *udev;
-       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-       struct usb_device_descriptor *buf;
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       /* Obtain udev of the rhub's child port */
-       udev = usb_hub_find_child(hcd->self.root_hub, port);
-       if (!udev) {
-               ehci_err(ehci, "No device attached to the RootHub\n");
-               return -ENODEV;
-       }
-       buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
-       if (!dr) {
-               kfree(buf);
-               return -ENOMEM;
-       }
-
-       /* Fill Setup packet for GetDescriptor */
-       dr->bRequestType = USB_DIR_IN;
-       dr->bRequest = USB_REQ_GET_DESCRIPTOR;
-       dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
-       dr->wIndex = 0;
-       dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
-       urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
-       if (!urb)
-               goto cleanup;
-
-       /* Submit just the SETUP stage */
-       retval = submit_single_step_set_feature(hcd, urb, 1);
-       if (retval)
-               goto out1;
-       if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
-               usb_kill_urb(urb);
-               retval = -ETIMEDOUT;
-               ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
-               goto out1;
-       }
-       msleep(15 * 1000);
-
-       /* Complete remaining DATA and STATUS stages using the same URB */
-       urb->status = -EINPROGRESS;
-       usb_get_urb(urb);
-       atomic_inc(&urb->use_count);
-       atomic_inc(&urb->dev->urbnum);
-       retval = submit_single_step_set_feature(hcd, urb, 0);
-       if (!retval && !wait_for_completion_timeout(&done,
-                                               msecs_to_jiffies(2000))) {
-               usb_kill_urb(urb);
-               retval = -ETIMEDOUT;
-               ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
-       }
-out1:
-       usb_free_urb(urb);
-cleanup:
-       kfree(dr);
-       kfree(buf);
-       return retval;
-}
-#endif /* CONFIG_USB_HCD_TEST_MODE */
 /*-------------------------------------------------------------------------*/
 
 int ehci_hub_control(
index 1b0251e..27b53f4 100644 (file)
@@ -1169,7 +1169,7 @@ submit_async (
  * performed; TRUE - SETUP and FALSE - IN+STATUS
  * Returns 0 if success
  */
-static int submit_single_step_set_feature(
+static int ehci_submit_single_step_set_feature(
        struct usb_hcd  *hcd,
        struct urb      *urb,
        int             is_setup
index b21ca44..4f5d7b2 100644 (file)
@@ -398,7 +398,10 @@ struct hc_driver {
        int     (*find_raw_port_number)(struct usb_hcd *, int);
        /* Call for power on/off the port if necessary */
        int     (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
-
+       /* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */
+#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+       int     (*submit_single_step_set_feature)(struct usb_hcd *,
+                       struct urb *, int);
 };
 
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
@@ -456,6 +459,14 @@ extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+extern int ehset_single_step_set_feature(struct usb_hcd *hcd, int port);
+#else
+static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+       return 0;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
 
 #ifdef CONFIG_PCI
 struct pci_dev;