Alan, do you have any more feedback on this patchset? Sarah Sharp On Wed, Oct 09, 2013 at 05:19:31PM +0200, Hans de Goede wrote: > Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> > --- > drivers/usb/core/devio.c | 118 ++++++++++++++++++++++++++++++++++++++ > include/uapi/linux/usbdevice_fs.h | 7 +++ > 2 files changed, 125 insertions(+) > > diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c > index bfb2821..4ca7e86 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, > return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; > } > > +static int parse_usbdevfs_streams(struct dev_state *ps, > + struct usbdevfs_streams __user *streams, > + unsigned int *num_streams_ret, > + unsigned int *num_eps_ret, > + struct usb_host_endpoint ***eps_ret, > + struct usb_interface **intf_ret) > +{ > + unsigned int i, num_streams, num_eps; > + struct usb_host_endpoint **eps; > + struct usb_interface *intf = NULL; > + unsigned char ep; > + int ifnum, ret; > + > + if (get_user(num_streams, &streams->num_streams) || > + get_user(num_eps, &streams->num_eps)) > + return -EFAULT; > + > + if (num_eps < 1 || num_eps > USB_MAXENDPOINTS) > + return -EINVAL; > + > + /* The XHCI controller allows max 1024 streams */ > + if (num_streams_ret && (num_streams < 2 || num_streams > 1024)) > + return -EINVAL; > + > + eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); > + if (!eps) > + return -ENOMEM; > + > + for (i = 0; i < num_eps; i++) { > + if (get_user(ep, &streams->eps[i])) { > + ret = -EFAULT; > + goto error; > + } > + eps[i] = ep_to_host_endpoint(ps->dev, ep); > + if (!eps[i]) { > + ret = -EINVAL; > + goto error; > + } > + > + /* usb_alloc/free_streams operate on an usb_interface */ > + ifnum = findintfep(ps->dev, ep); > + if (ifnum < 0) { > + ret = ifnum; > + goto error; > + } > + > + if (i == 0) { > + ret = checkintf(ps, ifnum); > + if (ret < 0) > + goto error; > + intf = usb_ifnum_to_if(ps->dev, ifnum); > + } else { > + /* Verify all eps belong to the same interface */ > + if (ifnum != intf->altsetting->desc.bInterfaceNumber) { > + ret = -EINVAL; > + goto error; > + } > + } > + } > + > + if (num_streams_ret) > + *num_streams_ret = num_streams; > + *num_eps_ret = num_eps; > + *eps_ret = eps; > + *intf_ret = intf; > + > + return 0; > + > +error: > + kfree(eps); > + return ret; > +} > + > static int match_devt(struct device *dev, void *data) > { > return dev->devt == (dev_t) (unsigned long) data; > @@ -1992,6 +2065,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) > return claimintf(ps, dc.interface); > } > > +static int proc_alloc_streams(struct dev_state *ps, void __user *arg) > +{ > + unsigned num_streams, num_eps; > + struct usb_host_endpoint **eps; > + struct usb_interface *intf; > + int r; > + > + r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps, > + &eps, &intf); > + if (r) > + return r; > + > + destroy_async_on_interface(ps, > + intf->altsetting[0].desc.bInterfaceNumber); > + > + r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL); > + kfree(eps); > + return r; > +} > + > +static int proc_free_streams(struct dev_state *ps, void __user *arg) > +{ > + unsigned num_eps; > + struct usb_host_endpoint **eps; > + struct usb_interface *intf; > + int r; > + > + r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf); > + if (r) > + return r; > + > + destroy_async_on_interface(ps, > + intf->altsetting[0].desc.bInterfaceNumber); > + > + r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL); > + kfree(eps); > + return r; > +} > + > /* > * NOTE: All requests here that have interface numbers as parameters > * are assuming that somehow the configuration has been prevented from > @@ -2168,6 +2280,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, > case USBDEVFS_DISCONNECT_CLAIM: > ret = proc_disconnect_claim(ps, p); > break; > + case USBDEVFS_ALLOC_STREAMS: > + ret = proc_alloc_streams(ps, p); > + break; > + case USBDEVFS_FREE_STREAMS: > + ret = proc_free_streams(ps, p); > + break; > } > usb_unlock_device(dev); > if (ret >= 0) > diff --git a/include/uapi/linux/usbdevice_fs.h b/include/uapi/linux/usbdevice_fs.h > index cbf122d..abe5f4b 100644 > --- a/include/uapi/linux/usbdevice_fs.h > +++ b/include/uapi/linux/usbdevice_fs.h > @@ -147,6 +147,11 @@ struct usbdevfs_disconnect_claim { > char driver[USBDEVFS_MAXDRIVERNAME + 1]; > }; > > +struct usbdevfs_streams { > + unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */ > + unsigned int num_eps; > + unsigned char eps[0]; > +}; > > #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) > #define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32) > @@ -179,5 +184,7 @@ struct usbdevfs_disconnect_claim { > #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) > #define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) > #define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) > +#define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams) > +#define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams) > > #endif /* _UAPI_LINUX_USBDEVICE_FS_H */ > -- > 1.8.3.1 > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html