uint8_t endpoint, unsigned char *data, int length,
int *transferred, unsigned int timeout);
+/* Async IO */
+
+/**
+ * @brief Asynchronous transfer callback function
+ */
+typedef void (*libhusb_transfer_cb_fn)(int status, unsigned char *buffer, int len, void *user_data);
+
+/**
+ * @brief Asynchronous transfer handler
+ */
+struct libhusb_transfer;
+
+typedef struct libhusb_transfer libhusb_transfer;
+
+/**
+ * @brief Create an asynchronous transfer handler
+ * @details To perform asynchronous transfer, we need a handler structure which will
+ * be later passed to libhusb_submit_transfer(). This function allocate memory for the handler,
+ * but it will be uninitialized until libhusb_fill_* function will be called.
+ *
+ * For isochronous transfer, iso_packets should be set to appropriate number of packet descriptors.
+ * If you do not intend to use isochronous transfer, it should be set to 0.
+ *
+ * @param transfer Pointer to be filled with pointer to newly allocated transfer structure
+ * @param iso_packets Number of iso packets descriptors to be allocated.
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_create_transfer(libhusb_transfer **transfer, int iso_packets);
+
+/**
+ * @brief Submit an asynchronous transfer1
+ * @details The transfer structure should be initialized with transfer parameters and
+ * callback function. When transfer is completed, the callback function is called.
+ *
+ * @param transfer Transfer handler to be submited
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_submit_transfer(libhusb_transfer *transfer);
+
+/**
+ * @brief Cancel a submited asynchronous transfer
+ * @details If transfer was submitted, this will cancel it. Callback function will be
+ * called with CANCEL status
+ *
+ * @param transfer Transfer handler to be canceled
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_cancel_transfer(libhusb_transfer *transfer);
+
+/**
+ * @brief Destroy asynchronous transfer handler
+ * @details Deallocate memory allocated by libhusb_create_transfer
+ *
+ * @param transfer Transfer handler to be destroyed
+ */
+void libhusb_destroy_transfer(libhusb_transfer *transfer);
+
+/**
+ * @brief Fill an interrupt asynchronous transfer
+ * @details Before submitting transfer it should be initialized. This function initialize it with
+ * values required for interrupt transfer.
+ *
+ * @param transfer Transfer handle
+ * @param dev_handle Device handle
+ * @param callback Function to be called when transfer is finished
+ * @param endpoint Number of endpoint
+ * @param buffer Data buffer
+ * @param length Length of data buffer
+ * @param user_data Pointer to additional user data that will be passed to callback function
+ * @param timeout Timeout for the transfer in miliseconds
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_fill_interrupt_transfer(libhusb_transfer *transfer, libhusb_device_handle *dev_handle,
+ libhusb_transfer_cb_fn callback, uint8_t endpoint, unsigned char *buffer, int length,
+ void *user_data, unsigned int timeout);
+
+/**
+ * @brief Fill a bulk asynchronous transfer
+ * @details Before submitting transfer it should be initialized. This funtion initialize it with
+ * values required for bulk transfer.
+ *
+ * @param transfer Transfer handle
+ * @param dev_handle Device handle
+ * @param callback Function to be called when transfer is finished
+ * @param endpoint Number of endpoint
+ * @param buffer Data buffer
+ * @param length Length of data buffer
+ * @param user_data Pointer to additional user data that will be passed to callback function
+ * @param timeout Timeout for the transfer in miliseconds
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_fill_bulk_transfer(libhusb_transfer *transfer, libhusb_device_handle *dev_handle,
+ libhusb_transfer_cb_fn callback, uint8_t endpoint, unsigned char *buffer, int length,
+ void *user_data, unsigned int timeout);
+
+/**
+ * @brief Fill setup packet for a control transfer
+ * @details This is helper function to populate first 8 bytes of control transfer buffer
+ * with given setup values.
+ *
+ * @param buffer Buffer to write the setup packet into
+ * @param bmRequestType Request type
+ * @param bRequest Request
+ * @param wValue Value
+ * @param wIndex Index
+ * @param wLength Length
+ */
+void libhusb_fill_control_setup(unsigned char *buffer, uint8_t bmRequestType,
+ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength);
+
+/**
+ * @brief Fill an interrupt asynchronous transfer
+ * @details Before submitting transfer it should be initialized. This funtion initialize it with
+ * values required for control transfer.
+ *
+ * The first 8 bytes of buffer is interpreted as control setup packet. It contains information about
+ * length of the buffer. Use libhusb_fill_control_setup() function to initialize setup packet.
+ *
+ * @param transfer Transfer handle
+ * @param dev_handle Device handle
+ * @param callback Function to be called when transfer is finished
+ * @param buffer Data buffer
+ * @param user_data Pointer to additional user data that will be passed to callback function
+ * @param timeout Timeout for the transfer in miliseconds
+ *
+ * @par Example
+ * @code
+ * ...
+ *
+ * r = libhusb_create_transfer(&transfer);
+ * if (r < 0) {
+ * printf("Failed to create transfer)\n";
+ * exit(1);
+ * }
+ *
+ * ...
+ *
+ * libhusb_fill_control_setup(buffer, request_type, request, value, index, length);
+ * r = libhusb_fill_control_transfer(transfer, dev_handle, buffer, callback, user_data, timeout);
+ * if (r < 0) {
+ * printf("Failed to fill control transfer\n");
+ * libhusb_destroy_transfer(transfer);
+ * exit(1);
+ * }
+ *
+ * ...
+ * @endcode
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_fill_control_transfer(libhusb_transfer *transfer, libhusb_device_handle *dev_handle,
+ libhusb_transfer_cb_fn callback, unsigned char *buffer, void *user_data, unsigned int timeout);
+
+/**
+ * @brief Fill an interrupt asynchronous transfer
+ * @details Before submitting transfer it should be initialized. This funtion initialize it with
+ * values required for isochronous transfer.
+ *
+ * @param transfer Transfer handle
+ * @param dev_handle Device handle
+ * @param callback Function to be called when transfer is finished
+ * @param endpoint Number of endpoint
+ * @param buffer Buffer to store data
+ * @param length Length of data buffer
+ * @param iso_packets Number of iso packets
+ * @param user_data Pointer to additional user data that will be passed to callback function
+ * @param timeout Timeout for the transfer in miliseconds
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_fill_iso_transfer(libhusb_transfer *transfer, libhusb_device_handle *dev_handle,
+ libhusb_transfer_cb_fn callback, uint8_t endpoint, unsigned char *buffer, int length,
+ int iso_packets, void *user_data, unsigned int timeout);
+/**
+ * @brief Handle all pending events
+ * @param ctx Library context
+ * @param completed Pointer to completion integer check, or NULL
+ * @return 0 on success, negative error code otherwise
+ */
+int libhusb_handle_events(libhusb_context *ctx, int *completed);
+
/**
* @brief Translate error name
* @details Translates error code to NULL terminated libhusb
return ret;
}
+struct async_transfer_data {
+ libhusb_transfer_cb_fn cb;
+ void *user_data;
+};
+
+static void generic_transfer_cb(struct libusb_transfer *transfer)
+{
+ struct async_transfer_data *data;
+
+ data = transfer->user_data;
+ data->cb(translate_error(transfer->status), transfer->buffer, transfer->actual_length, data->user_data);
+}
+
+int libhusb_create_transfer(libhusb_transfer **transfer, int iso_packets)
+{
+ libhusb_transfer *rtransfer;
+
+ assert(transfer);
+
+ rtransfer = malloc(sizeof(*rtransfer));
+ if (!rtransfer) {
+ _E("Failed to alloc transfer structure");
+ return LIBHUSB_ERROR_NO_MEM;
+ }
+
+ rtransfer->lusb_transfer = libusb_alloc_transfer(iso_packets);
+ rtransfer->lusb_transfer->user_data = NULL;
+ *transfer = rtransfer;
+
+ return 0;
+}
+
+int libhusb_submit_transfer(libhusb_transfer *transfer)
+{
+ int ret;
+
+ ret = libusb_submit_transfer(transfer->lusb_transfer);
+ if (ret < 0) {
+ _E("Failed to submit async transfer: %d", ret);
+ ret = translate_error(ret);
+ }
+
+ return ret;
+}
+
+int libhusb_cancel_transfer(libhusb_transfer *transfer)
+{
+ int ret;
+
+ ret = libusb_cancel_transfer(transfer->lusb_transfer);
+ if (ret < 0) {
+ _E("Failed to cancel async transfer: %d", ret);
+ ret = translate_error(ret);
+ }
+
+ return ret;
+}
+
+void libhusb_destroy_transfer(libhusb_transfer *transfer)
+{
+ libusb_free_transfer(transfer->lusb_transfer);
+ free(transfer->lusb_transfer->user_data);
+ free(transfer);
+}
+
+void libhusb_fill_control_setup(unsigned char *buffer, uint8_t bmRequestType,
+ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength)
+{
+ assert(buffer);
+
+ libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength);
+}
+
+int libhusb_fill_interrupt_transfer(libhusb_transfer *transfer, libhusb_device_handle *handle,
+ libhusb_transfer_cb_fn callback, uint8_t endpoint, unsigned char *buffer, int length,
+ void *user_data, unsigned int timeout)
+{
+ struct async_transfer_data *data;
+ assert(transfer);
+ assert(transfer->lsusb_transfer);
+ assert(handle);
+
+ data = malloc(sizeof(*data));
+ if (!data) {
+ _E("malloc failed");
+ return LIBHUSB_ERROR_NO_MEM;
+ }
+
+ data->cb = callback;
+ data->user_data = user_data;
+
+ /* it's either NULL, or was allocated by library */
+ free(transfer->lusb_transfer->user_data);
+ libusb_fill_interrupt_transfer(transfer->lusb_transfer, handle->lusb_dev_handle, endpoint, buffer, length, generic_transfer_cb, data, timeout);
+
+ return 0;
+}
+
+int libhusb_fill_bulk_transfer(libhusb_transfer *transfer, libhusb_device_handle *handle,
+ libhusb_transfer_cb_fn callback, uint8_t endpoint, unsigned char *buffer, int length,
+ void *user_data, unsigned int timeout)
+{
+ struct async_transfer_data *data;
+ assert(transfer);
+ assert(transfer->lsusb_transfer);
+ assert(handle);
+
+ data = malloc(sizeof(*data));
+ if (!data) {
+ _E("malloc failed");
+ return LIBHUSB_ERROR_NO_MEM;
+ }
+
+ data->cb = callback;
+ data->user_data = user_data;
+
+ /* it's either NULL, or was allocated by library */
+ free(transfer->lusb_transfer->user_data);
+ libusb_fill_bulk_transfer(transfer->lusb_transfer, handle->lusb_dev_handle, endpoint, buffer, length, generic_transfer_cb, data, timeout);
+
+ return 0;
+}
+
+int libhusb_fill_control_transfer(libhusb_transfer *transfer, libhusb_device_handle *handle,
+ libhusb_transfer_cb_fn callback, unsigned char *buffer, void *user_data, unsigned int timeout)
+{
+ struct async_transfer_data *data;
+ assert(transfer);
+ assert(transfer->lsusb_transfer);
+ assert(handle);
+
+ data = malloc(sizeof(*data));
+ if (!data) {
+ _E("malloc failed");
+ return LIBHUSB_ERROR_NO_MEM;
+ }
+
+ data->cb = callback;
+ data->user_data = user_data;
+
+ /* it's either NULL, or was allocated by library */
+ free(transfer->lusb_transfer->user_data);
+ libusb_fill_control_transfer(transfer->lusb_transfer, handle->lusb_dev_handle, buffer, generic_transfer_cb, data, timeout);
+
+ return 0;
+}
+
+int libhusb_handle_events(libhusb_context *ctx, int *completed)
+{
+ int ret;
+
+ ret = libusb_handle_events_completed(ctx->lusb_ctx, completed);
+ return translate_error(ret);
+}
+
const char *libhusb_error_name(int error_code)
{
switch (error_code) {