123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- From d4806e4f103895387dc679fe53e1f4a5d41391bf Mon Sep 17 00:00:00 2001
- From: Peter Chen <[email protected]>
- Date: Thu, 18 Jan 2018 11:03:24 +0800
- Subject: [PATCH] MLK-17380-3 usb: move EH SINGLE_STEP_SET_FEATURE implement to
- core
- Since other USB 2.0 host may need it, like USB2 for XHCI. We move
- this design to HCD core.
- Acked-by: Jun Li <[email protected]>
- Signed-off-by: Peter Chen <[email protected]>
- (cherry picked from commit 035a27e1a3088261f40f77534aaccfe5825c2f96)
- ---
- drivers/usb/core/hcd.c | 134 ++++++++++++++++++++++++++++++++++++++++++
- drivers/usb/host/ehci-hcd.c | 4 ++
- drivers/usb/host/ehci-hub.c | 139 --------------------------------------------
- drivers/usb/host/ehci-q.c | 2 +-
- include/linux/usb/hcd.h | 13 ++++-
- 5 files changed, 151 insertions(+), 141 deletions(-)
- --- a/drivers/usb/core/hcd.c
- +++ b/drivers/usb/core/hcd.c
- @@ -2104,6 +2104,140 @@ int usb_hcd_get_frame_number (struct usb
- }
-
- /*-------------------------------------------------------------------------*/
- +#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
-
- --- a/drivers/usb/host/ehci-hcd.c
- +++ b/drivers/usb/host/ehci-hcd.c
- @@ -1245,6 +1245,10 @@ static const struct hc_driver ehci_hc_dr
- * 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,
- --- a/drivers/usb/host/ehci-hub.c
- +++ b/drivers/usb/host/ehci-hub.c
- @@ -727,145 +727,6 @@ ehci_hub_descriptor (
- }
-
- /*-------------------------------------------------------------------------*/
- -#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(
- struct usb_hcd *hcd,
- --- a/drivers/usb/host/ehci-q.c
- +++ b/drivers/usb/host/ehci-q.c
- @@ -1165,7 +1165,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
- --- a/include/linux/usb/hcd.h
- +++ b/include/linux/usb/hcd.h
- @@ -409,7 +409,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)
- @@ -474,6 +477,14 @@ int usb_hcd_setup_local_mem(struct usb_h
-
- 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_USB_PCI
- struct pci_dev;
|