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 | 47 +++++++++++++++++++++++++++++++++++++
 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, 143 insertions(+), 1 deletion(-)

diff --git a/libusb/core.c b/libusb/core.c
index 72faac4..aa06288 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,
+       int num_streams, unsigned char *endpoints, int num_endpoints)
+{
+       usbi_dbg("streams %d eps %d", num_streams, num_endpoints);
+
+       if (!dev->dev->attached)
+               return LIBUSB_ERROR_NO_DEVICE;
+
+       if (usbi_backend->free_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..d3c8afd 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,
+       int 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..762e644 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,
+               int 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..8783a46 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1482,6 +1482,50 @@ out:
        return ret;
 }
 
+static int do_streams_ioctl(struct libusb_device_handle *handle, int req,
+       int num_streams, unsigned char *endpoints, int num_endpoints)
+{
+       int r, fd = _device_handle_priv(handle)->fd;
+       struct usbfs_streams streams = {
+               .num_streams = num_streams,
+               .num_eps = num_endpoints,
+       };
+
+       if (num_endpoints > sizeof(streams.eps))
+               return LIBUSB_ERROR_INVALID_PARAM;
+
+       memcpy(streams.eps, endpoints, num_endpoints);
+
+       r = ioctl(fd, req, &streams);
+       if (r) {
+               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 LIBUSB_SUCCESS;
+}
+
+static int op_alloc_streams(struct libusb_device_handle *handle,
+       int 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 +2627,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..113d23f 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[30]; /* This has size 0 in the offical header */
+};
+
 #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 995c478..da8a87c 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10834
+#define LIBUSB_NANO 10835
-- 
1.8.3.1


------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=51271111&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