Allow user space applications such as LIBUSB, to request streams alloc/dealloc from HCD that implements XHCI. Signed-off-by: Amit Blay <ablay@xxxxxxxxxxxx> Signed-off-by: Tatyana Brokhman <tlinder@xxxxxxxxxxxxxx> --- drivers/usb/core/devio.c | 128 +++++++++++++++++++++++++++++++++++++++++- include/linux/usbdevice_fs.h | 5 ++ 2 files changed, 132 insertions(+), 1 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 37518df..7e73e35 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -943,6 +943,115 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg) return usb_clear_halt(ps->dev, pipe); } +static int proc_allocstreams(struct dev_state *ps, void __user *arg) +{ + unsigned int ep_map; + int ret; + int intf_num; + struct usb_interface *intf = NULL; + const int max_eps = 32; + int max_streams = 0; + struct usb_host_endpoint *eps[max_eps]; + int num_eps = 0; + int i; + unsigned int ep; + + if (get_user(ep_map, (unsigned int __user *)arg)) + return -EFAULT; + + for (i = 0; i < max_eps; i++) { + if (ep_map & (0x1 << i)) { + /* Convert from i to ep address */ + if (i < 16) /* IN EP */ + ep = i | USB_ENDPOINT_DIR_MASK; + else /* OUT EP */ + ep = (i - 16); + + intf_num = findintfep(ps->dev, ep); + if (intf_num < 0) + return intf_num; + ret = checkintf(ps, intf_num); + if (ret) + return ret; + intf = usb_ifnum_to_if(ps->dev, intf_num); + if (!intf) + return -ENOENT; + + if (ep & USB_ENDPOINT_DIR_MASK) + eps[num_eps] = ps->dev->ep_in[ep & + USB_ENDPOINT_NUMBER_MASK]; + else + eps[num_eps] = ps->dev->ep_out[ep & + USB_ENDPOINT_NUMBER_MASK]; + + if (!max_streams) + max_streams = USB_SS_MAX_STREAMS( + eps[num_eps]->ss_ep_comp.bmAttributes); + + num_eps++; + } + } + + if (!intf || !max_streams) + return -ENOENT; + + ret = usb_alloc_streams(intf, eps, num_eps, max_streams, GFP_KERNEL); + if (ret > 0) + return 0; + return ret; +} + +static int proc_freestreams(struct dev_state *ps, void __user *arg) +{ + unsigned int ep_map; + int ret; + int intf_num; + struct usb_interface *intf = NULL; + const int max_eps = 32; + struct usb_host_endpoint *eps[max_eps]; + int num_eps = 0; + int i; + unsigned int ep; + + if (get_user(ep_map, (unsigned int __user *)arg)) + return -EFAULT; + + for (i = 0; i < max_eps; i++) { + if (ep_map & (0x1 << i)) { + /* Convert from i to ep address */ + if (i < 16) /* IN EP */ + ep = i | USB_ENDPOINT_DIR_MASK; + else /* OUT EP */ + ep = (i - 16); + + intf_num = findintfep(ps->dev, ep); + if (intf_num < 0) + return intf_num; + ret = checkintf(ps, intf_num); + if (ret) + return ret; + intf = usb_ifnum_to_if(ps->dev, intf_num); + if (!intf) + return -ENOENT; + + if (ep & USB_ENDPOINT_DIR_MASK) + eps[num_eps] = ps->dev->ep_in[ep & + USB_ENDPOINT_NUMBER_MASK]; + else + eps[num_eps] = ps->dev->ep_out[ep & + USB_ENDPOINT_NUMBER_MASK]; + + num_eps++; + } + } + + if (!intf) + return -ENOENT; + + usb_free_streams(intf, eps, num_eps, GFP_KERNEL); + return 0; +} + static int proc_getdriver(struct dev_state *ps, void __user *arg) { struct usbdevfs_getdriver gd; @@ -1236,6 +1345,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, u |= URB_NO_INTERRUPT; as->urb->transfer_flags = u; + as->urb->stream_id = (uurb->type == USBDEVFS_URB_TYPE_BULK) ? + uurb->stream_id : 0; as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; as->urb->start_frame = uurb->start_frame; @@ -1491,7 +1602,8 @@ static int get_urb32(struct usbdevfs_urb *kurb, __get_user(kurb->start_frame, &uurb->start_frame) || __get_user(kurb->number_of_packets, &uurb->number_of_packets) || __get_user(kurb->error_count, &uurb->error_count) || - __get_user(kurb->signr, &uurb->signr)) + __get_user(kurb->signr, &uurb->signr) || + __get_user(kurb->stream_id, &uurb->stream_id)) return -EFAULT; if (__get_user(uptr, &uurb->buffer)) @@ -1795,6 +1907,20 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, inode->i_mtime = CURRENT_TIME; break; + case USBDEVFS_ALLOC_STREAMS: + snoop(&dev->dev, "%s: ALLOC_STREAMS\n", __func__); + ret = proc_allocstreams(ps, p); + if (ret >= 0) + inode->i_mtime = CURRENT_TIME; + break; + + case USBDEVFS_FREE_STREAMS: + snoop(&dev->dev, "%s: FREE_STREAMS\n", __func__); + ret = proc_freestreams(ps, p); + if (ret >= 0) + inode->i_mtime = CURRENT_TIME; + break; + case USBDEVFS_GETDRIVER: snoop(&dev->dev, "%s: GETDRIVER\n", __func__); ret = proc_getdriver(ps, p); diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h index 15591d2..133c216 100644 --- a/include/linux/usbdevice_fs.h +++ b/include/linux/usbdevice_fs.h @@ -108,6 +108,7 @@ struct usbdevfs_urb { or 0 if none should be sent. */ void __user *usercontext; struct usbdevfs_iso_packet_desc iso_frame_desc[0]; + unsigned int stream_id; }; /* ioctls for talking directly to drivers */ @@ -165,6 +166,7 @@ struct usbdevfs_urb32 { compat_uint_t signr; compat_caddr_t usercontext; /* unused */ struct usbdevfs_iso_packet_desc iso_frame_desc[0]; + compat_uint_t stream_id; }; struct usbdevfs_ioctl32 { @@ -204,4 +206,7 @@ struct usbdevfs_ioctl32 { #define USBDEVFS_CONNECT _IO('U', 23) #define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) +#define USBDEVFS_ALLOC_STREAMS _IOR('U', 26, unsigned int) +#define USBDEVFS_FREE_STREAMS _IOR('U', 27, unsigned int) + #endif /* _LINUX_USBDEVICE_FS_H */ -- 1.7.3.3 -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- 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