aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/devio.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-10-09 11:19:31 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2014-03-04 18:38:05 -0500
commitbcf7f6e39335af4f03da8c26a98185fd49754fcc (patch)
tree61a8b40af9264409c66ced8ac324e3f3274f00ff /drivers/usb/core/devio.c
parent2fec32b06e374642802f7fb4f5350317cd14732b (diff)
usbfs: Add support for allocating / freeing streams
This allows userspace to use bulk-streams, just like in kernel drivers, see Documentation/usb/bulk-streams.txt for details on the in kernel API. This is exported pretty much one on one to userspace. To use streams an app must first make a USBDEVFS_ALLOC_STREAMS ioctl, on success this will return the number of streams available (which may be less then requested). If there are n streams the app can then submit usbdevfs_urb-s with their stream_id member set to 1-n to use a specific stream. IE if USBDEVFS_ALLOC_STREAMS returns 4 then stream_id 1-4 can be used. When the app is done using streams it should call USBDEVFS_FREE_STREAMS Note applications are advised to use libusb rather then using the usbdevfs api directly. The latest version of libusb has support for streams. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r--drivers/usb/core/devio.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 502974b4deb5..12401ee4ba0e 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -778,6 +778,79 @@ static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
778 return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; 778 return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
779} 779}
780 780
781static int parse_usbdevfs_streams(struct dev_state *ps,
782 struct usbdevfs_streams __user *streams,
783 unsigned int *num_streams_ret,
784 unsigned int *num_eps_ret,
785 struct usb_host_endpoint ***eps_ret,
786 struct usb_interface **intf_ret)
787{
788 unsigned int i, num_streams, num_eps;
789 struct usb_host_endpoint **eps;
790 struct usb_interface *intf = NULL;
791 unsigned char ep;
792 int ifnum, ret;
793
794 if (get_user(num_streams, &streams->num_streams) ||
795 get_user(num_eps, &streams->num_eps))
796 return -EFAULT;
797
798 if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
799 return -EINVAL;
800
801 /* The XHCI controller allows max 2 ^ 16 streams */
802 if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
803 return -EINVAL;
804
805 eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL);
806 if (!eps)
807 return -ENOMEM;
808
809 for (i = 0; i < num_eps; i++) {
810 if (get_user(ep, &streams->eps[i])) {
811 ret = -EFAULT;
812 goto error;
813 }
814 eps[i] = ep_to_host_endpoint(ps->dev, ep);
815 if (!eps[i]) {
816 ret = -EINVAL;
817 goto error;
818 }
819
820 /* usb_alloc/free_streams operate on an usb_interface */
821 ifnum = findintfep(ps->dev, ep);
822 if (ifnum < 0) {
823 ret = ifnum;
824 goto error;
825 }
826
827 if (i == 0) {
828 ret = checkintf(ps, ifnum);
829 if (ret < 0)
830 goto error;
831 intf = usb_ifnum_to_if(ps->dev, ifnum);
832 } else {
833 /* Verify all eps belong to the same interface */
834 if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
835 ret = -EINVAL;
836 goto error;
837 }
838 }
839 }
840
841 if (num_streams_ret)
842 *num_streams_ret = num_streams;
843 *num_eps_ret = num_eps;
844 *eps_ret = eps;
845 *intf_ret = intf;
846
847 return 0;
848
849error:
850 kfree(eps);
851 return ret;
852}
853
781static int match_devt(struct device *dev, void *data) 854static int match_devt(struct device *dev, void *data)
782{ 855{
783 return dev->devt == (dev_t) (unsigned long) data; 856 return dev->devt == (dev_t) (unsigned long) data;
@@ -2009,6 +2082,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
2009 return claimintf(ps, dc.interface); 2082 return claimintf(ps, dc.interface);
2010} 2083}
2011 2084
2085static int proc_alloc_streams(struct dev_state *ps, void __user *arg)
2086{
2087 unsigned num_streams, num_eps;
2088 struct usb_host_endpoint **eps;
2089 struct usb_interface *intf;
2090 int r;
2091
2092 r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
2093 &eps, &intf);
2094 if (r)
2095 return r;
2096
2097 destroy_async_on_interface(ps,
2098 intf->altsetting[0].desc.bInterfaceNumber);
2099
2100 r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
2101 kfree(eps);
2102 return r;
2103}
2104
2105static int proc_free_streams(struct dev_state *ps, void __user *arg)
2106{
2107 unsigned num_eps;
2108 struct usb_host_endpoint **eps;
2109 struct usb_interface *intf;
2110 int r;
2111
2112 r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
2113 if (r)
2114 return r;
2115
2116 destroy_async_on_interface(ps,
2117 intf->altsetting[0].desc.bInterfaceNumber);
2118
2119 r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
2120 kfree(eps);
2121 return r;
2122}
2123
2012/* 2124/*
2013 * NOTE: All requests here that have interface numbers as parameters 2125 * NOTE: All requests here that have interface numbers as parameters
2014 * are assuming that somehow the configuration has been prevented from 2126 * are assuming that somehow the configuration has been prevented from
@@ -2185,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2185 case USBDEVFS_DISCONNECT_CLAIM: 2297 case USBDEVFS_DISCONNECT_CLAIM:
2186 ret = proc_disconnect_claim(ps, p); 2298 ret = proc_disconnect_claim(ps, p);
2187 break; 2299 break;
2300 case USBDEVFS_ALLOC_STREAMS:
2301 ret = proc_alloc_streams(ps, p);
2302 break;
2303 case USBDEVFS_FREE_STREAMS:
2304 ret = proc_free_streams(ps, p);
2305 break;
2188 } 2306 }
2189 usb_unlock_device(dev); 2307 usb_unlock_device(dev);
2190 if (ret >= 0) 2308 if (ret >= 0)