Signed-off-by: Hans de Goede <hdego...@redhat.com>
---
 libusb/core.c           | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
 libusb/libusb.h         |  5 ++++
 libusb/libusbi.h        |  8 +++++++
 libusb/os/linux_usbfs.c | 53 ++++++++++++++++++++++++++++++++++++++++++
 libusb/os/linux_usbfs.h |  8 +++++++
 libusb/os/netbsd_usb.c  |  3 +++
 libusb/os/openbsd_usb.c |  3 +++
 libusb/os/wince_usb.c   |  3 +++
 libusb/os/windows_usb.c |  3 +++
 libusb/version_nano.h   |  2 +-
 10 files changed, 149 insertions(+), 1 deletion(-)

diff --git a/libusb/core.c b/libusb/core.c
index 72faac4..ea6adcb 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1615,6 +1615,68 @@ int API_EXPORTED 
libusb_reset_device(libusb_device_handle *dev)
        return usbi_backend->reset_device(dev);
 }
 
+/** \ingroup asyncio
+ * Allocate up to num_streams usb bulk streams on the specified endpoints. This
+ * function takes an array of endpoints rather then a single endpoint because
+ * some protocols require that endpoints are setup with similar stream ids.
+ * All endpoints passed in must belong to the same interface.
+ *
+ * Note this function may return less streams then requested.
+ *
+ * Stream id 0 is reserved, and should not be used to communicate with devices.
+ * If libusb_alloc_streams() returns with a value of N, you may use stream ids
+ * 1 to N.
+ *
+ * Since version 1.0.18, \ref LIBUSBX_API_VERSION >= 0x01000103
+ *
+ * \param dev a device handle
+ * \param num_streams number of streams to try to allocate
+ * \param endpoints array of endpoints to allocate streams on
+ * \param num_endpoints length of the endpoints array
+ * \returns number of streams allocated, or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev,
+       uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
+{
+       usbi_dbg("streams %u eps %d", (unsigned) num_streams, num_endpoints);
+
+       if (!dev->dev->attached)
+               return LIBUSB_ERROR_NO_DEVICE;
+
+       if (usbi_backend->alloc_streams)
+               return usbi_backend->alloc_streams(dev, num_streams, endpoints,
+                                                  num_endpoints);
+       else
+               return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup asyncio
+ * Free usb bulk streams allocated with libusb_alloc_streams().
+ *
+ * Note streams are automatically free-ed when releasing an interface.
+ *
+ * Since version 1.0.18, \ref LIBUSBX_API_VERSION >= 0x01000103
+ *
+ * \param dev a device handle
+ * \param endpoints array of endpoints to allocate streams on
+ * \param num_endpoints length of the endpoints array
+ * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_free_streams(libusb_device_handle *dev,
+       unsigned char *endpoints, int num_endpoints)
+{
+       usbi_dbg("eps %d", num_endpoints);
+
+       if (!dev->dev->attached)
+               return LIBUSB_ERROR_NO_DEVICE;
+
+       if (usbi_backend->free_streams)
+               return usbi_backend->free_streams(dev, endpoints,
+                                                 num_endpoints);
+       else
+               return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
 /** \ingroup dev
  * Determine if a kernel driver is active on an interface. If a kernel driver
  * is active, you cannot claim the interface, and libusbx will be unable to
diff --git a/libusb/libusb.h b/libusb/libusb.h
index da3f1ef..2802095 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1384,6 +1384,11 @@ int LIBUSB_CALL libusb_clear_halt(libusb_device_handle 
*dev,
        unsigned char endpoint);
 int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev);
 
+int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev,
+       uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
+int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev,
+       unsigned char *endpoints, int num_endpoints);
+
 int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev,
        int interface_number);
 int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev,
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index a4d74f6..5c19b76 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -834,6 +834,14 @@ struct usbi_os_backend {
         */
        int (*reset_device)(struct libusb_device_handle *handle);
 
+       /* Alloc num_streams usb3 bulk streams on the passed in endpoints */
+       int (*alloc_streams)(struct libusb_device_handle *handle,
+               uint32_t num_streams, unsigned char *endpoints, int 
num_endpoints);
+
+       /* Free usb3 bulk streams allocated with alloc_streams */
+       int (*free_streams)(struct libusb_device_handle *handle,
+               unsigned char *endpoints, int num_endpoints);
+
        /* Determine if a kernel driver is active on an interface. Optional.
         *
         * The presence of a kernel driver on an interface indicates that any
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index f8defb8..f007ab3 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1482,6 +1482,56 @@ out:
        return ret;
 }
 
+static int do_streams_ioctl(struct libusb_device_handle *handle, long req,
+       uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
+{
+       int r, fd = _device_handle_priv(handle)->fd;
+       struct usbfs_streams *streams;
+
+       if (num_endpoints > 30) /* Max 15 in + 15 out eps */
+               return LIBUSB_ERROR_INVALID_PARAM;
+
+       streams = malloc(sizeof(struct usbfs_streams) + num_endpoints);
+       if (!streams)
+               return LIBUSB_ERROR_NO_MEM;
+
+       streams->num_streams = num_streams;
+       streams->num_eps = num_endpoints;
+       memcpy(streams->eps, endpoints, num_endpoints);
+
+       r = ioctl(fd, req, streams);
+
+       free(streams);
+
+       if (r < 0) {
+               if (errno == ENOTTY)
+                       return LIBUSB_ERROR_NOT_SUPPORTED;
+               else if (errno == EINVAL)
+                       return LIBUSB_ERROR_INVALID_PARAM;
+               else if (errno == ENODEV)
+                       return LIBUSB_ERROR_NO_DEVICE;
+
+               usbi_err(HANDLE_CTX(handle),
+                       "streams-ioctl failed error %d errno %d", r, errno);
+               return LIBUSB_ERROR_OTHER;
+       }
+       return r;
+}
+
+static int op_alloc_streams(struct libusb_device_handle *handle,
+       uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
+{
+       return do_streams_ioctl(handle, IOCTL_USBFS_ALLOC_STREAMS,
+                               num_streams, endpoints, num_endpoints);
+}
+
+static int op_free_streams(struct libusb_device_handle *handle,
+               unsigned char *endpoints, int num_endpoints)
+{
+       return do_streams_ioctl(handle, IOCTL_USBFS_FREE_STREAMS, 0,
+                               endpoints, num_endpoints);
+}
+
 static int op_kernel_driver_active(struct libusb_device_handle *handle,
        int interface)
 {
@@ -2583,6 +2633,9 @@ const struct usbi_os_backend linux_usbfs_backend = {
        .clear_halt = op_clear_halt,
        .reset_device = op_reset_device,
 
+       .alloc_streams = op_alloc_streams,
+       .free_streams = op_free_streams,
+
        .kernel_driver_active = op_kernel_driver_active,
        .detach_kernel_driver = op_detach_kernel_driver,
        .attach_kernel_driver = op_attach_kernel_driver,
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index 1f5b191..de5186f 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -132,6 +132,12 @@ struct usbfs_disconnect_claim {
        char driver[USBFS_MAXDRIVERNAME + 1];
 };
 
+struct usbfs_streams {
+       unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
+       unsigned int num_eps;
+       unsigned char eps[0];
+};
+
 #define IOCTL_USBFS_CONTROL    _IOWR('U', 0, struct usbfs_ctrltransfer)
 #define IOCTL_USBFS_BULK               _IOWR('U', 2, struct usbfs_bulktransfer)
 #define IOCTL_USBFS_RESETEP    _IOR('U', 3, unsigned int)
@@ -155,6 +161,8 @@ struct usbfs_disconnect_claim {
 #define IOCTL_USBFS_RELEASE_PORT       _IOR('U', 25, unsigned int)
 #define IOCTL_USBFS_GET_CAPABILITIES   _IOR('U', 26, __u32)
 #define IOCTL_USBFS_DISCONNECT_CLAIM   _IOR('U', 27, struct 
usbfs_disconnect_claim)
+#define IOCTL_USBFS_ALLOC_STREAMS      _IOR('U', 28, struct usbfs_streams)
+#define IOCTL_USBFS_FREE_STREAMS       _IOR('U', 29, struct usbfs_streams)
 
 extern usbi_mutex_static_t linux_hotplug_lock;
 
diff --git a/libusb/os/netbsd_usb.c b/libusb/os/netbsd_usb.c
index 1da9e1e..3493dfa 100644
--- a/libusb/os/netbsd_usb.c
+++ b/libusb/os/netbsd_usb.c
@@ -112,6 +112,9 @@ const struct usbi_os_backend netbsd_backend = {
        netbsd_clear_halt,
        netbsd_reset_device,
 
+       NULL,                           /* alloc_streams */
+       NULL,                           /* free_streams */
+
        NULL,                           /* kernel_driver_active() */
        NULL,                           /* detach_kernel_driver() */
        NULL,                           /* attach_kernel_driver() */
diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c
index 01934ef..b9fc7fa 100644
--- a/libusb/os/openbsd_usb.c
+++ b/libusb/os/openbsd_usb.c
@@ -115,6 +115,9 @@ const struct usbi_os_backend openbsd_backend = {
        obsd_clear_halt,
        obsd_reset_device,
 
+       NULL,                           /* alloc_streams */
+       NULL,                           /* free_streams */
+
        NULL,                           /* kernel_driver_active() */
        NULL,                           /* detach_kernel_driver() */
        NULL,                           /* attach_kernel_driver() */
diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c
index c7ab7f6..819a208 100644
--- a/libusb/os/wince_usb.c
+++ b/libusb/os/wince_usb.c
@@ -1005,6 +1005,9 @@ const struct usbi_os_backend wince_backend = {
         wince_clear_halt,
         wince_reset_device,
 
+       NULL,                           /* alloc_streams */
+       NULL,                           /* free_streams */
+
         wince_kernel_driver_active,
         wince_detach_kernel_driver,
         wince_attach_kernel_driver,
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index fdc60c7..043e125 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -2303,6 +2303,9 @@ const struct usbi_os_backend windows_backend = {
        windows_clear_halt,
        windows_reset_device,
 
+       NULL,                           /* alloc_streams */
+       NULL,                           /* free_streams */
+
        windows_kernel_driver_active,
        windows_detach_kernel_driver,
        windows_attach_kernel_driver,
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index da8a87c..85260ed 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10835
+#define LIBUSB_NANO 10836
-- 
1.8.3.1


------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to