Allow user space applications such as LIBUSB, to request
streams alloc/dealloc from HCD that implements XHCI.

Signed-off-by: Amit Blay <[email protected]>
Signed-off-by: Tatyana Brokhman <[email protected]>

---
 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-arm-msm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to