diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r-- | drivers/usb/core/hcd.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6a05e693445..3aaee2811f0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1814,6 +1814,75 @@ void usb_hcd_reset_endpoint(struct usb_device *udev, | |||
1814 | } | 1814 | } |
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | /** | ||
1818 | * usb_alloc_streams - allocate bulk endpoint stream IDs. | ||
1819 | * @interface: alternate setting that includes all endpoints. | ||
1820 | * @eps: array of endpoints that need streams. | ||
1821 | * @num_eps: number of endpoints in the array. | ||
1822 | * @num_streams: number of streams to allocate. | ||
1823 | * @mem_flags: flags hcd should use to allocate memory. | ||
1824 | * | ||
1825 | * Sets up a group of bulk endpoints to have num_streams stream IDs available. | ||
1826 | * Drivers may queue multiple transfers to different stream IDs, which may | ||
1827 | * complete in a different order than they were queued. | ||
1828 | */ | ||
1829 | int usb_alloc_streams(struct usb_interface *interface, | ||
1830 | struct usb_host_endpoint **eps, unsigned int num_eps, | ||
1831 | unsigned int num_streams, gfp_t mem_flags) | ||
1832 | { | ||
1833 | struct usb_hcd *hcd; | ||
1834 | struct usb_device *dev; | ||
1835 | int i; | ||
1836 | |||
1837 | dev = interface_to_usbdev(interface); | ||
1838 | hcd = bus_to_hcd(dev->bus); | ||
1839 | if (!hcd->driver->alloc_streams || !hcd->driver->free_streams) | ||
1840 | return -EINVAL; | ||
1841 | if (dev->speed != USB_SPEED_SUPER) | ||
1842 | return -EINVAL; | ||
1843 | |||
1844 | /* Streams only apply to bulk endpoints. */ | ||
1845 | for (i = 0; i < num_eps; i++) | ||
1846 | if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) | ||
1847 | return -EINVAL; | ||
1848 | |||
1849 | return hcd->driver->alloc_streams(hcd, dev, eps, num_eps, | ||
1850 | num_streams, mem_flags); | ||
1851 | } | ||
1852 | EXPORT_SYMBOL_GPL(usb_alloc_streams); | ||
1853 | |||
1854 | /** | ||
1855 | * usb_free_streams - free bulk endpoint stream IDs. | ||
1856 | * @interface: alternate setting that includes all endpoints. | ||
1857 | * @eps: array of endpoints to remove streams from. | ||
1858 | * @num_eps: number of endpoints in the array. | ||
1859 | * @mem_flags: flags hcd should use to allocate memory. | ||
1860 | * | ||
1861 | * Reverts a group of bulk endpoints back to not using stream IDs. | ||
1862 | * Can fail if we are given bad arguments, or HCD is broken. | ||
1863 | */ | ||
1864 | void usb_free_streams(struct usb_interface *interface, | ||
1865 | struct usb_host_endpoint **eps, unsigned int num_eps, | ||
1866 | gfp_t mem_flags) | ||
1867 | { | ||
1868 | struct usb_hcd *hcd; | ||
1869 | struct usb_device *dev; | ||
1870 | int i; | ||
1871 | |||
1872 | dev = interface_to_usbdev(interface); | ||
1873 | hcd = bus_to_hcd(dev->bus); | ||
1874 | if (dev->speed != USB_SPEED_SUPER) | ||
1875 | return; | ||
1876 | |||
1877 | /* Streams only apply to bulk endpoints. */ | ||
1878 | for (i = 0; i < num_eps; i++) | ||
1879 | if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) | ||
1880 | return; | ||
1881 | |||
1882 | hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); | ||
1883 | } | ||
1884 | EXPORT_SYMBOL_GPL(usb_free_streams); | ||
1885 | |||
1817 | /* Protect against drivers that try to unlink URBs after the device | 1886 | /* Protect against drivers that try to unlink URBs after the device |
1818 | * is gone, by waiting until all unlinks for @udev are finished. | 1887 | * is gone, by waiting until all unlinks for @udev are finished. |
1819 | * Since we don't currently track URBs by device, simply wait until | 1888 | * Since we don't currently track URBs by device, simply wait until |