usb: host: move EH SINGLE_STEP_SET_FEATURE implementation to core
Subsystems (3)
PATCH v4 1/3 usb: host: move EH SINGLE_STEP_SET_FEATURE implementation to core
From: Peter Chen <[email protected]>
It is needed at USB Certification test for Embedded Host 2.0, and the detail is at CH6.4.1.1 of On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. Since other USB 2.0 capable host like XHCI also need it, so move it to HCD core.
---
Change for v4:
- No change.
Change for v3:
- Add Alan's A-b tag.
Change for v2:
- No change.
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(-)
drivers/usb/core/hcd.c +134 -0
@@ -2110,6 +2110,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
drivers/usb/host/ehci-hcd.c +4 -0
@@ -1238,6 +1238,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,
drivers/usb/host/ehci-hub.c +0 -139
145 lines not on this page · raw message
drivers/usb/host/ehci-q.c +1 -1
@@ -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
include/linux/usb/hcd.h +12 -1
@@ -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_hcd *hcd, phys_addr_t phys_addr,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 ;
Signature · 1 line
2.25.1
PATCH v4 2/3 usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2
From: Peter Chen <[email protected]>
This function is similar with EHCI's, but implemented using XHCI. The USB2 host needs to send SETUP packet first, then wait 15 seconds before DATA (IN) + STATUS stage.
---
No change since v1.
drivers/usb/host/xhci-hub.c | 10 +++ drivers/usb/host/xhci-ring.c | 123 +++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 1 + drivers/usb/host/xhci.h | 10 +++ 4 files changed, 144 insertions(+)
drivers/usb/host/xhci-hub.c +10 -0
@@ -1511,6 +1511,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,/* 4.19.6 Port Test Modes (USB2 Test Mode) */ if (hcd->speed !=HCD_USB2 ) goto error; + +#ifdef CONFIG_USB_HCD_TEST_MODE +if (test_mode ==EHSET_TEST_SINGLE_STEP_SET_FEATURE ) { +spin_unlock_irqrestore (&xhci->lock, flags); + retval =ehset_single_step_set_feature (hcd, + wIndex +1 ); +spin_lock_irqsave (&xhci->lock, flags); +break ; + } +#endif if (test_mode >USB_TEST_FORCE_ENABLE || test_mode <USB_TEST_J ) goto error;
drivers/usb/host/xhci-ring.c +123 -0
129 lines not on this page · raw message
drivers/usb/host/xhci.c +1 -0
@@ -5426,6 +5426,7 @@ static const struct hc_driver xhci_hc_driver = { .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, .find_raw_port_number = xhci_find_raw_port_number, .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete, + .submit_single_step_set_feature = xhci_submit_single_step_set_feature, }; void xhci_init_driver(struct hc_driver *drv,
drivers/usb/host/xhci.h +10 -0
@@ -2165,6 +2165,16 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);struct xhci_hub *xhci_get_rhub (struct usb_hcd *hcd);void xhci_hc_died (struct xhci_hcd *xhci); +#ifdef CONFIG_USB_HCD_TEST_MODE +int xhci_submit_single_step_set_feature (struct usb_hcd *hcd, +struct urb *urb,int is_setup); +#else +static inline int xhci_submit_single_step_set_feature (struct usb_hcd *hcd, +struct urb *urb,int is_setup) +{ +return 0 ; +} +#endif #ifdef CONFIG_PM int xhci_bus_suspend (struct usb_hcd *hcd);
Signature · 1 line
2.25.1
Re: [PATCH v4 2/3] usb: host: xhci: add EH SINGLE_STEP_SET_FEATURE Test for USB2
Quoted 10 lines · Li Jun
From: Peter Chen <[email protected]>
This function is similar with EHCI's, but implemented using XHCI. The USB2 host needs to send SETUP packet first, then wait 15 seconds before DATA (IN) + STATUS stage.
Signed-off-by Peter Chen <[email protected]>Signed-off-by Li Jun <[email protected]>---
No change since v1.
I've applied patches 1 and 3 here, and am waiting for Mathias to review this before accepting patch 2.
thanks,
greg k-h
PATCH v4 3/3 usb: core: hcd: use map_urb_for_dma for single step set feature urb
In reply to Li JunUse map_urb_for_dma() to improve the dma map code for single step set feature request urb in test mode.
---
Change for v4:
- Add missing usb_free_urb() to balance refcount to be 0.
Change for v3:
- Correct the error handling if map_urb_for_dma() fails.
change for v2:
- Add this new patch to use map_urb_for_dma API to replace both of dma_map_single() calls, suggested by Jack Pham.
drivers/usb/core/hcd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
drivers/usb/core/hcd.c +6 -10
@@ -2159,16 +2159,12 @@ static struct urb *request_single_step_set_feature_urb(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 ); +if (map_urb_for_dma (hcd, urb,GFP_KERNEL )) { +usb_put_urb (urb); +usb_free_urb (urb); +return NULL ; + } + urb->context = done;return urb; }
Signature · 1 line
2.25.1
Re: [PATCH v4 3/3] usb: core: hcd: use map_urb_for_dma for single step set feature urb
Quoted 5 lines · Li Jun
Use
map_urb_for_dma()to improve the dma map code for single step set feature request urb in test mode.Signed-off-by Li Jun <[email protected]>---
Quoted 44 lines
Change for v4:
- Add missingusb_free_urb()to balance refcount to be 0.Change for v3:
- Correct the error handling ifmap_urb_for_dma()fails.change for v2:
- Add this new patch to usemap_urb_for_dmaAPI to replace both ofdma_map_single()calls, suggested by Jack Pham.drivers/usb/core/hcd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)drivers/usb/core/hcd.c +6
-10@@ -2159,16 +2159,12 @@ static struct urb *request_single_step_set_feature_urb(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 ); +if (map_urb_for_dma (hcd, urb,GFP_KERNEL )) { +usb_put_urb (urb); +usb_free_urb (urb); +return NULL ; + } + urb->context = done;return urb; }Signature · 1 line
2.25.1