Being able to allocate bulk-streams is not really useful if the user cannot specify the stream ids when submitting transfers.
The actual stream id gets added to our private itransfer struct, and a setter + getter are added to get to it. Unfortunately this is the only way to add support for stream ids without breaking ABI. So this is another item to fix when we do break ABI in libusb-2.0. Bulk streams also use a separate transer type, to allow backends to determine if a transfer is a bulk stream transfer or an ordinary bulk transfer. This is added because there is no other reliable way to determine if a transfer is a stream as the stream_id is part of the private itransfer struct so apps re-using a transfer may not set it to 0. Adding a separate transfer-type for this was suggested (and coded) by Nathan Hjelm. Most users will likely use the new libusb_fill_bulk_stream_transfer() though, and will never know the difference. Signed-off-by: Hans de Goede <hdego...@redhat.com> --- libusb/io.c | 37 +++++++++++++++++++++++++++++++++++++ libusb/libusb.h | 39 +++++++++++++++++++++++++++++++++++++-- libusb/libusbi.h | 1 + libusb/os/linux_usbfs.c | 25 ++++++++++++++++++++----- libusb/os/linux_usbfs.h | 5 ++++- libusb/os/netbsd_usb.c | 3 +++ libusb/os/openbsd_usb.c | 3 +++ libusb/os/wince_usb.c | 4 ++++ libusb/os/windows_usb.c | 6 ++++++ libusb/version_nano.h | 2 +- 10 files changed, 116 insertions(+), 9 deletions(-) diff --git a/libusb/io.c b/libusb/io.c index 4f22963..982882e 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -1510,6 +1510,43 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) return r; } +/** \ingroup asyncio + * Set a transfers bulk stream id. Note users are advised to use + * libusb_fill_bulk_stream_transfer() instead of calling this function + * directly. + * + * Since version 1.0.18, \ref LIBUSBX_API_VERSION >= 0x01000103 + * + * \param transfer the transfer to set the stream id for + * \param stream_id the stream id to set + * \see libusb_alloc_streams() + */ +void API_EXPORTED libusb_transfer_set_stream_id( + struct libusb_transfer *transfer, uint32_t stream_id) +{ + struct usbi_transfer *itransfer = + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); + + itransfer->stream_id = stream_id; +} + +/** \ingroup asyncio + * Get a transfers bulk stream id. + * + * Since version 1.0.18, \ref LIBUSBX_API_VERSION >= 0x01000103 + * + * \param transfer the transfer to get the stream id for + * \returns the stream id for the transfer + */ +uint32_t API_EXPORTED libusb_transfer_get_stream_id( + struct libusb_transfer *transfer) +{ + struct usbi_transfer *itransfer = + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); + + return itransfer->stream_id; +} + /* Handle completion of a transfer (completion might be an error condition). * This will invoke the user-supplied callback function, which may end up * freeing the transfer. Therefore you cannot use the transfer structure diff --git a/libusb/libusb.h b/libusb/libusb.h index 2802095..91c7087 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -144,7 +144,7 @@ typedef unsigned __int32 uint32_t; * Internally, LIBUSBX_API_VERSION is defined as follows: * (libusbx major << 24) | (libusbx minor << 16) | (16 bit incremental) */ -#define LIBUSBX_API_VERSION 0x01000102 +#define LIBUSBX_API_VERSION 0x01000103 #ifdef __cplusplus extern "C" { @@ -340,7 +340,10 @@ enum libusb_transfer_type { LIBUSB_TRANSFER_TYPE_BULK = 2, /** Interrupt endpoint */ - LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 + LIBUSB_TRANSFER_TYPE_INTERRUPT = 3, + + /** Stream endpoint */ + LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4, }; /** \ingroup misc @@ -1475,6 +1478,10 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); +void LIBUSB_CALL libusb_transfer_set_stream_id( + struct libusb_transfer *transfer, uint32_t stream_id); +uint32_t LIBUSB_CALL libusb_transfer_get_stream_id( + struct libusb_transfer *transfer); /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields @@ -1552,6 +1559,34 @@ static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, /** \ingroup asyncio * Helper function to populate the required \ref libusb_transfer fields + * for a bulk transfer using bulk streams. + * + * Since version 1.0.18, \ref LIBUSBX_API_VERSION >= 0x01000103 + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param stream_id bulk stream id for this transfer + * \param buffer data buffer + * \param length length of data buffer + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_bulk_stream_transfer( + struct libusb_transfer *transfer, libusb_device_handle *dev_handle, + unsigned char endpoint, uint32_t stream_id, + unsigned char *buffer, int length, libusb_transfer_cb_fn callback, + void *user_data, unsigned int timeout) +{ + libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, + length, callback, user_data, timeout); + transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM; + libusb_transfer_set_stream_id(transfer, stream_id); +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields * for an interrupt transfer. * * \param transfer the transfer to populate diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 5c19b76..c9c8ddf 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -357,6 +357,7 @@ struct usbi_transfer { struct list_head list; struct timeval timeout; int transferred; + uint32_t stream_id; uint8_t flags; /* this lock is held during libusb_submit_transfer() and diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index f007ab3..e259380 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1739,8 +1739,7 @@ static void free_iso_urbs(struct linux_transfer_priv *tpriv) tpriv->iso_urbs = NULL; } -static int submit_bulk_transfer(struct usbi_transfer *itransfer, - unsigned char urb_type) +static int submit_bulk_transfer(struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); @@ -1828,7 +1827,19 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer, for (i = 0; i < num_urbs; i++) { struct usbfs_urb *urb = &urbs[i]; urb->usercontext = itransfer; - urb->type = urb_type; + switch (transfer->type) { + case LIBUSB_TRANSFER_TYPE_BULK: + urb->type = USBFS_URB_TYPE_BULK; + urb->stream_id = 0; + break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + urb->type = USBFS_URB_TYPE_BULK; + urb->stream_id = itransfer->stream_id; + break; + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + urb->type = USBFS_URB_TYPE_INTERRUPT; + break; + } urb->endpoint = transfer->endpoint; urb->buffer = transfer->buffer + (i * bulk_buffer_len); /* don't set the short not ok flag for the last URB */ @@ -2111,9 +2122,10 @@ static int op_submit_transfer(struct usbi_transfer *itransfer) case LIBUSB_TRANSFER_TYPE_CONTROL: return submit_control_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_BULK: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return submit_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT); + return submit_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return submit_iso_transfer(itransfer); default: @@ -2131,6 +2143,7 @@ static int op_cancel_transfer(struct usbi_transfer *itransfer) switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: if (tpriv->reap_action == ERROR) break; /* else, fall through */ @@ -2161,6 +2174,7 @@ static void op_clear_transfer_priv(struct usbi_transfer *itransfer) switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: case LIBUSB_TRANSFER_TYPE_INTERRUPT: usbi_mutex_lock(&itransfer->lock); if (tpriv->urbs) @@ -2529,6 +2543,7 @@ static int reap_for_handle(struct libusb_device_handle *handle) case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return handle_iso_completion(itransfer, urb); case LIBUSB_TRANSFER_TYPE_BULK: + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: case LIBUSB_TRANSFER_TYPE_INTERRUPT: return handle_bulk_completion(itransfer, urb); case LIBUSB_TRANSFER_TYPE_CONTROL: diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h index de5186f..f2404ab 100644 --- a/libusb/os/linux_usbfs.h +++ b/libusb/os/linux_usbfs.h @@ -94,7 +94,10 @@ struct usbfs_urb { int buffer_length; int actual_length; int start_frame; - int number_of_packets; + union { + int number_of_packets; /* Only used for isoc urbs */ + unsigned int stream_id; /* Only used with bulk streams */ + }; int error_count; unsigned int signr; void *usercontext; diff --git a/libusb/os/netbsd_usb.c b/libusb/os/netbsd_usb.c index 3493dfa..f32ac48 100644 --- a/libusb/os/netbsd_usb.c +++ b/libusb/os/netbsd_usb.c @@ -461,6 +461,9 @@ netbsd_submit_transfer(struct usbi_transfer *itransfer) } err = _sync_gen_transfer(itransfer); break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + err = LIBUSB_ERROR_NOT_SUPPORTED; + break; } if (err) diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c index b9fc7fa..a086f8d 100644 --- a/libusb/os/openbsd_usb.c +++ b/libusb/os/openbsd_usb.c @@ -507,6 +507,9 @@ obsd_submit_transfer(struct usbi_transfer *itransfer) } err = _sync_gen_transfer(itransfer); break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + err = LIBUSB_ERROR_NOT_SUPPORTED; + break; } if (err) diff --git a/libusb/os/wince_usb.c b/libusb/os/wince_usb.c index 819a208..f524d91 100644 --- a/libusb/os/wince_usb.c +++ b/libusb/os/wince_usb.c @@ -689,6 +689,8 @@ static int wince_submit_transfer( return wince_submit_control_or_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return wince_submit_iso_transfer(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; @@ -801,6 +803,8 @@ static void wince_handle_callback (struct usbi_transfer *itransfer, uint32_t io_ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: wince_transfer_callback (itransfer, io_result, io_size); break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); } diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index 043e125..05e166f 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -2005,6 +2005,8 @@ static int windows_submit_transfer(struct usbi_transfer *itransfer) return submit_bulk_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return submit_iso_transfer(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; @@ -2038,6 +2040,8 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer) case LIBUSB_TRANSFER_TYPE_INTERRUPT: case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return windows_abort_transfers(itransfer); + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; @@ -2097,6 +2101,8 @@ static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t i case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: windows_transfer_callback (itransfer, io_result, io_size); break; + case LIBUSB_TRANSFER_TYPE_BULK_STREAM: + return LIBUSB_ERROR_NOT_SUPPORTED; default: usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); } diff --git a/libusb/version_nano.h b/libusb/version_nano.h index 85260ed..736c9b6 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 10836 +#define LIBUSB_NANO 10837 -- 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