summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-09-11 13:06:38 +0200
committerHans de Goede <hdegoede@redhat.com>2014-04-22 14:31:35 +0200
commit0504375ea965dd25f00d4828a19c329b7e7525d4 (patch)
treee207b92c7e777046288be44de2c344b51068906e
parentc59d574b211bedcab951b2f19de58bb03a04d671 (diff)
downloadlibusb-0504375ea965dd25f00d4828a19c329b7e7525d4.tar.gz
Add API for allocating / freeing usb3 bulk streams + Linux implementation
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--libusb/core.c62
-rw-r--r--libusb/libusb.h5
-rw-r--r--libusb/libusbi.h8
-rw-r--r--libusb/os/linux_usbfs.c53
-rw-r--r--libusb/os/linux_usbfs.h8
-rw-r--r--libusb/os/netbsd_usb.c3
-rw-r--r--libusb/os/openbsd_usb.c3
-rw-r--r--libusb/os/wince_usb.c3
-rw-r--r--libusb/os/windows_usb.c3
-rw-r--r--libusb/version_nano.h2
10 files changed, 149 insertions, 1 deletions
diff --git a/libusb/core.c b/libusb/core.c
index af92854..f766e62 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.19, \ref LIBUSB_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.19, \ref LIBUSB_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 libusb will be unable to
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 409b510..ccbad44 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -1387,6 +1387,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 3d21406..225c273 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -843,6 +843,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 5ad6129..2f6b4af 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1495,6 +1495,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)
{
@@ -2596,6 +2646,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 d43eea3..988d3c0 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 ef0b27b..d56c1af 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 c48d27d..656b1de 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 e130bc9..1a25d37 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -2317,6 +2317,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 ce329f2..f37c06f 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10878
+#define LIBUSB_NANO 10879