diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-09-11 13:06:38 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2014-04-22 14:31:35 +0200 |
commit | 0504375ea965dd25f00d4828a19c329b7e7525d4 (patch) | |
tree | e207b92c7e777046288be44de2c344b51068906e | |
parent | c59d574b211bedcab951b2f19de58bb03a04d671 (diff) | |
download | libusb-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.c | 62 | ||||
-rw-r--r-- | libusb/libusb.h | 5 | ||||
-rw-r--r-- | libusb/libusbi.h | 8 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.c | 53 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.h | 8 | ||||
-rw-r--r-- | libusb/os/netbsd_usb.c | 3 | ||||
-rw-r--r-- | libusb/os/openbsd_usb.c | 3 | ||||
-rw-r--r-- | libusb/os/wince_usb.c | 3 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 3 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 |
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 |