From baa8297456c878bba0bfcf5d6638c8ed32e185a7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Szewczyk?= Date: Fri, 7 Oct 2016 17:22:20 +0200 Subject: [PATCH] [5.0] api: Add asynchronous transfers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: I31b9773eee6cae0ec3cb935ef053d944cae0d619 Signed-off-by: Paweł Szewczyk --- doc/usb_host_doc.h | 141 +++++++++ include/usb_host.h | 449 +++++++++++++++++++++++++++ include/usb_host_internal.h | 2 + src/usb_host.c | 603 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1195 insertions(+) diff --git a/doc/usb_host_doc.h b/doc/usb_host_doc.h index e216bb2..6b83a8c 100755 --- a/doc/usb_host_doc.h +++ b/doc/usb_host_doc.h @@ -233,6 +233,147 @@ * Functions described here can be used to register callbacks to be called on events such as * device connection or disconnection. * + * @defgroup CAPI_USB_HOST_ASYNC_MODULE Asynchronous IO + * @brief This API is used to perform asynchronous operations + * @ingroup CAPI_USB_HOST_MODULE + * @section CAPI_USB_HOST_ASYNC_MODULE_OVERVIEW Overview + * Asynchronous transfers are performed by submitting previously prepared transfer handle (#usb_host_transfer_h). + * When the transfer is finished, the callback set by user is called. + * Transfer handle contains all transfer parameters and, when configured, can be submited multiple times. + * Most of parameters required for asynchronous transfers match those from synchronous transfer. + * + * Like in synchronous transfer, you must first obtain the endpoint handle. Then you can create a transfer handle with desired parameters. + * @code + * usb_host_transfer_h transfer; + * usb_host_endpoint_h ep; + * + * // Obtain the endpoint ep + * // ... + * + * // Create a transfer handle + * ret = usb_host_create_transfer(ep, transfer_callback, data, length, user_data, timeout, &transfer); + * if (ret < 0) + * error(); + * + * // Submit the transfer + * ret = usb_host_transfer_submit(transfer); + * if (ret < 0) + * error(); + * + * // ... + * // Destroy the transfer handle when no longer needed + * ret = usb_host_transfer_destroy(transfer); + * @endcode + * + * The transfer_callback() is a function which will be called when transfer is finished. It should match the usb_host_transfer_cb() type, e.g.: + * @code + * void transfer_callback(usb_host_transfer_h transfer, void user_data) + * { + * int status; + * int length; + * char *data; + * + * // Get the status value + * usb_host_get_transfer_status(transfer, &status); + * + * // Check the status value + * if (status != USB_HOST_TRANSFER_COMPLETED) { + * // Handle errors here + * } + * + * // Get the data buffer + * usb_host_get_data(transfer, &data, &length); + * + * // Handle received data + * // ... + * } + * @endcode + * + * + * Note, that not always successfully submitted transfer finishes with success. The callback function is called + * with status code set to value from #usb_host_transfer_status_e enum. It informs what happened with the transfer. + * + * Also remember, that received data length can be different than length of buffer (i.e. requested length). + * + * + * You can change the transfer handle parameters by using usb_host_transfer_set_* functions and resubmit the transfer multiple times. + * @code + * void transfer_callback(usb_host_transfer_h transfer, void user_data) + * { + * // Change parameters of the transfer if needed + * // ... + * + * usb_host_transfer_submit(transfer); + * } + * @endcode + * + * For passing additional data to callback function user_data pointer can be used. The user_data passed to callback + * is the same as was set for submitted transfer. + * + * After transfer is submitted, it can be canceled by calling usb_host_transfer_cancel(). This will cause the + * transfer callback function to be called with #USB_HOST_TRANSFER_CANCELLED status. + * + * @section CAPI_USB_HOST_ASYNC_MODULE_ISOCHRONOUS Isochronous transfers + * For creating isochronous transfers use usb_host_create_isochronous_transfer() function. + * It takes parameters similar to usb_host_create_transfer(), with addition of num_iso_packets. + * The data buffer is used to store all packets data and should be large enough to do so. + * + * @code + * ret = usb_host_create_isochronous_transfer(ep, transfer_callback, data, length, num_iso_packets, user_data, timeout, &transfer); + * @endcode + * + * Before submitting the transfer you must setup isochoronous packets lengths (and data, if making out transfer). + * @code + * for (i = 0; i < num_iso_packets; ++i) { + * ret = usb_host_set_iso_packet_length(transfer, i, packet_lenght); + * //... + * + * ret = usb_host_get_iso_packet_data(transfer, i, &data, &len); + * // fill received buffer with your data + * // ... + * } + * @endcode + * + * Similarly, you can obtain received data in callback function by calling usb_host_transfer_get_iso_packet_data(). Note, that + * length of received data can be different than length of buffer space set for an isochronous packet. + * + * Each packet has its own status code. Check them by calling usb_host_transfer_get_iso_packet_status(). + * + * @section CAPI_USB_HOST_ASYNC_MODULE_CONTROL Control transfers + * You can make asynchronous control transfers as well. They use the same data type as other asynchronous transfers (#usb_host_transfer_h) + * and can be handled in similar way. + * + * A control transfer need specific format of data in buffer, i.e. first 8 bytes of buffer need to contain a setup packet. + * You can find more informations about setup packets in usb protocol specification. + * This API provides functions helping with filling the setup packet. + * + * @code + * // Create a transfer handle + * ret = usb_host_create_control_transfer(dev, transfer_callback, data, length, user_data, timeout, &transfer); + * if (ret < 0) + * error(); + * + * // Set setup packet member values + * + * usb_host_control_transfer_set_request_type(transfer, bm_request_type); + * usb_host_control_transfer_set_request(transfer, b_request); + * usb_host_control_transfer_set_value(transfer, w_value); + * usb_host_control_transfer_set_index(transfer, w_index); + * + * // Submit the transfer + * ret = usb_host_transfer_submit(transfer); + * if (ret < 0) + * error(); + * + * // ... + * // Destroy the transfer handle when no longer needed + * ret = usb_host_transfer_destroy(transfer); + * + * @endcode + * + * When receiving data from control transfer, remember that first 8 bytes of buffer are filled with setup packet. + * To obtain pointer to actual data, use usb_host_control_transfer_get_data(). + * */ #endif /* __TIZEN_USB_HOST_DOC_H__ */ diff --git a/include/usb_host.h b/include/usb_host.h index 6c301ee..d0d3f3d 100755 --- a/include/usb_host.h +++ b/include/usb_host.h @@ -104,6 +104,22 @@ typedef enum { USB_HOST_HOTPLUG_EVENT_ANY, /**< Any event */ } usb_host_hotplug_event_e; +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Enumeration of transfer status codes. + * @since_tizen 5.0 + */ +typedef enum { + USB_HOST_TRANSFER_COMPLETED, /**< Transfer completed without error*/ + USB_HOST_TRANSFER_ERROR, /**< Transfer failed */ + USB_HOST_TRANSFER_TIMED_OUT, /**< Transfer timed out */ + USB_HOST_TRANSFER_CANCELLED, /**< Transfer cancelled */ + USB_HOST_TRANSFER_STALL, /**< Halt condition detected */ + USB_HOST_TRANSFER_NO_DEVICE, /**< Device was disconnected */ + USB_HOST_TRANSFER_OVERFLOW, /**< Device sent more data than requested */ + USB_HOST_TRANSFER_UNKNOWN, /**< Unknown status */ +} usb_host_transfer_status_e; + /** * @ingroup CAPI_USB_HOST_MODULE * @brief Context handle to USB host. @@ -180,6 +196,23 @@ typedef struct usb_host_hotplug_s *usb_host_hotplug_h; */ typedef void (*usb_host_hotplug_cb)(usb_host_device_h dev, void *user_data); +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief USB asynchronous transfer handle. + * @details This type represents an asynchronous USB transfer. + * @since_tizen 5.0 + */ +typedef struct usb_host_transfer_s *usb_host_transfer_h; + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Called when asynchronous transfers finishes. + * @since_tizen 5.0 + * @param[in] transfer Transfer for which this callback was set + * @param[in] user_data User data pointer passed on callback registration + */ +typedef void (*usb_host_transferred_cb)(usb_host_transfer_h transfer, void *user_data); + /* Library initialization and cleanup */ /** @@ -1045,6 +1078,422 @@ int usb_host_set_hotplug_cb(usb_host_context_h ctx, usb_host_hotplug_cb cb, usb_ */ int usb_host_unset_hotplug_cb(usb_host_hotplug_h handle); +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Prepares an asynchronous USB transfer. + * @details This function prepares transfer handle for asynchronous communication. + * Transfer handle can be used for multiple transfers after this initialization. + * @since_tizen 5.0 + * @param[in] ep Endpoint handle + * @param[in] callback Callback to be called when transfer is finished + * @param[in] data Suitably-sized data buffer, similar to synchronized transfer + * @param[in] length For writes, the number of bytes from data to be sent; for + * reads, the maximum number of bytes to receive into the data buffer + * @param[in] user_data Pointer to data which will be passed to callback function later on + * @param[in] timeout Timeout (in milliseconds) that transfer should wait before giving up + * due to no response being received (for an unlimited timeout use value of 0) + * @param[out] transfer Transfer handle + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_OUT_OF_MEMORY Out of memory + * @pre @a ep must be a valid endpoint received from usb_host_interface_get_endpoint(). + * @post @a transfer should be destroyed by calling usb_host_transfer_destroy() when it's no longer needed. + */ +int usb_host_create_transfer(usb_host_endpoint_h ep, usb_host_transferred_cb callback, + unsigned char *data, int length, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Prepares an asynchronous USB isochronous transfer. + * @details This function prepares transfer handle for asynchronous communication. + * Usage is similar to usb_host_create_transfer(), except this function is intended for + * isochronous endpoints. Transfer handle can be used for multiple transfers after this initialization. + * Note however, that this function needs to allocate memory for @a num_iso_packets isochronous packets and + * it will be the limit for number of them in this transfer. + * @since_tizen 5.0 + * @param[in] ep Endpoint handle + * @param[in] callback Callback to be called when transfer is finished + * @param[in] data Suitably-sized data buffer, similar to synchronized transfer + * @param[in] length For writes, the number of bytes from data to be sent; for + * reads, the maximum number of bytes to receive into the data buffer + * @param[in] num_iso_packets Number of isochronous packets + * @param[in] user_data Pointer to data which will be passed to callback function later on + * @param[in] timeout Timeout (in milliseconds) that transfer should wait before giving up + * due to no response being received (for an unlimited timeout use value of 0) + * @param[out] transfer Transfer handle + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_OUT_OF_MEMORY Out of memory + * @pre @a ep must be a valid endpoint received from usb_host_interface_get_endpoint(). + * @post @a transfer should be destroyed by calling usb_host_transfer_destroy() when it's no longer needed. + */ +int usb_host_create_isochronous_transfer(usb_host_endpoint_h ep, usb_host_transferred_cb callback, + unsigned char *data, int length, unsigned int num_iso_packets, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Prepares an asynchronous USB control transfer. + * @details This function prepares control transfer handle. Transfer handle can + * be used for multiple transfers after this initialization. Note, that first + * 8 bytes of data buffer are interpreted as control setup packet. You may use + * usb_host_control_transfer_set_* functions to set the setup packet fields. + * @since_tizen 5.0 + * @param[in] dev Device handle + * @param[in] callback Callback to be called when transfer is finished + * @param[in] data Suitably-sized data buffer + * @param[in] length For writes, the number of bytes from data to be sent, for + * reads, the maximum number of bytes to receive into the data buffer + * @param[in] user_data Pointer to data which will be passed to callback function later on + * @param[in] timeout Timeout (in milliseconds) that transfer should wait before giving up + * due to no response being received (for an unlimited timeout use value of 0) + * @param[out] transfer Transfer handle + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_OUT_OF_MEMORY Out of memory + * @pre @a dev must be an opened device handle + * @post @a transfer should be destroyed by calling usb_host_transfer_destroy() when it's no longer needed. + */ +int usb_host_create_control_transfer(usb_host_device_h dev, usb_host_transferred_cb callback, + unsigned char *data, int length, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets an endpoint for asynchronous transfer. + * @details This function changes the endpoint on which given transfer is performed. Next submissions will be + * performed on this endpoint. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] ep An endpoint handle + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_transfer() or usb_host_create_isochronous_transfer(). + */ +int usb_host_transfer_set_ep(usb_host_transfer_h transfer, usb_host_endpoint_h ep); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets a callback for asynchronous transfer. + * @details This function changes the callback to be called on transfer completion. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] callback A callback function + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_transfer() or usb_host_create_isochronous_transfer(). + */ +int usb_host_transfer_set_callback(usb_host_transfer_h transfer, usb_host_transferred_cb callback); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets data buffer for asynchronous transfer. + * @details This function changes the data buffer used for this transfer. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] data A data buffer + * @param[in] length Length of data buffer + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_transfer() or usb_host_create_isochronous_transfer(). + */ +int usb_host_transfer_set_data(usb_host_transfer_h transfer, unsigned char *data, int length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets timeout for asynchronous transfer. + * @details This function changes the timeout after which transfer will be stopped due to + * no response being received. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] timeout A timeout in milliseconds + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_transfer() or usb_host_create_isochronous_transfer(). + */ +int usb_host_transfer_set_timeout(usb_host_transfer_h transfer, unsigned int timeout); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets number of isochrnous packet for isochronous transfer. + * @details This function changes the number of isochronous packets in transfer. + * This parameter affects only isochronous transfers (i.e. transfers on isochronous endpoints). + * Use usb_host_endpoint_get_transfer_type() for checking types of your endpoints. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] num_iso_packets Number of isochronous packets in this transfer + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_OUT_OF_MEMORY Out of memory (too many packets) + * @pre @a transfer should be created by usb_host_create_transfer() or usb_host_create_isochronous_transfer(). + */ +int usb_host_transfer_set_num_iso_packets(usb_host_transfer_h transfer, unsigned int num_iso_packets); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets request type for control transfer setup packet. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] bm_request_type bmRequestType type field for the setup packet + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_control_transfer(). + */ +int usb_host_control_transfer_set_request_type(usb_host_transfer_h transfer, uint8_t bm_request_type); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets request field for control transfer setup packet. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] b_request bRequest field for the setup packet + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_control_transfer(). + */ +int usb_host_control_transfer_set_request(usb_host_transfer_h transfer, uint8_t b_request); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets w_value field for control transfer setup packet. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] w_value wValue field for the setup packet + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_control_transfer(). + */ +int usb_host_control_transfer_set_value(usb_host_transfer_h transfer, uint16_t w_value); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets w_index field for control transfer setup packet. + * @since_tizen 5.0 + * @param[in] transfer A transfer handle + * @param[in] w_index wIndex field for the setup packet + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be created by usb_host_create_control_transfer(). + */ +int usb_host_control_transfer_set_index(usb_host_transfer_h transfer, uint16_t w_index); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets the transfer status. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[out] status Status of this transfer + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_get_status(usb_host_transfer_h transfer, int *status); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets the transfer data. + * @since_tizen 5.0 + * @remarks @a data is part of the transfer object and should not be released + * separately. It should not be accessed after @a transfer is destroyed. + * @param[in] transfer Transfer handle + * @param[out] data Data buffer of this transfer + * @param[out] actual_length Actual length of transferred data + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_get_data(usb_host_transfer_h transfer, unsigned char **data, unsigned int *actual_length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets the *control* transfer data. + * @since_tizen 5.0 + * @remarks @a data is part of the transfer object and should not be released + * separately. It should not be accessed after @a transfer is destroyed. + * @param[in] transfer Control transfer handle + * @param[out] data Data buffer of this transfer + * @param[out] actual_length Actual length of transferred data + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_control_transfer_get_data(usb_host_transfer_h transfer, unsigned char **data, unsigned int *actual_length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets length of data buffer. + * @details This functions gets length that was set for data buffer, not the actual transferred data length. + * For length of transferred data see usb_host_transfer_get_data(). + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[out] length Length of data buffer for this transfer + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_get_length(usb_host_transfer_h transfer, unsigned int *length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets number of isochronous packets for this transfer. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[out] num_iso_packets Number of isochronous packets + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_get_num_iso_packets(usb_host_transfer_h transfer, unsigned int *num_iso_packets); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Sets an isochronous packet length. + * @details This function sets length of individual packet. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[in] packet_number Number of isochronous packet + * @param[in] length Length of the packet handle + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_NOT_FOUND Packet of given number not found + * @retval #USB_HOST_ERROR_OVERFLOW Not enough space for this packet in data buffer + */ +int usb_host_transfer_set_iso_packet_length(usb_host_transfer_h transfer, unsigned int packet_number, int length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets an isochronous packet status. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[in] packet_number Number of isochronous packet + * @param[out] status Status of selected packet + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_NOT_FOUND Packet of given number not found + */ +int usb_host_transfer_get_iso_packet_status(usb_host_transfer_h transfer, unsigned int packet_number, int *status); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets data buffer of isochronous packet. + * @since_tizen 5.0 + * @remarks @a data is part of the transfer object and should not be released + * separately. It should not be accessed after @a transfer is destroyed. + * @param[in] transfer Transfer handle + * @param[in] packet_number Number of isochronous packet + * @param[out] data Data buffer for this packet + * @param[out] actual_length Length of transferred data + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_NOT_FOUND Packet of given number not found + */ +int usb_host_transfer_get_iso_packet_data(usb_host_transfer_h transfer, unsigned int packet_number, unsigned char **data, int *actual_length); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Gets isochronous packet data buffer length. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[in] packet_number Number of isochronous packet + * @param[out] length Length of data buffer + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @retval #USB_HOST_ERROR_NOT_FOUND Packet of given number not found + */ +int usb_host_transfer_get_iso_packet_length(usb_host_transfer_h transfer, unsigned int packet_number, int *length); + +/** + * @ingroup CAPI_USB_HOST_ENDPOINT_MODULE + * @brief Gets type of a transfer. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle + * @param[out] transfer_type Transfer type (a value from enum #usb_host_transfer_type_e) + * @return 0 on success, otherwise a negative error value + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_get_type(usb_host_transfer_h transfer, usb_host_transfer_type_e *transfer_type); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Destroys an asynchronous transfer structure. + * @details When no longer needed, transfer should be destroyed by this function. + * It frees memory allocated for the transfer. You cannot destroy unfinished transfer, + * wait for its completion or cancel it. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle to be destroyed + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_destroy(usb_host_transfer_h transfer); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Submits an asynchronous USB transfer. + * @details Calling this will start actual transfer. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle to be submitted + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + * @pre @a transfer should be initialized by one of initialization functions: + * usb_host_create_transfer(), usb_host_create_isochronous_transfer() or usb_host_create_control_transfer(). + */ +int usb_host_transfer_submit(usb_host_transfer_h transfer); + +/** + * @ingroup CAPI_USB_HOST_ASYNC_MODULE + * @brief Cancels an asynchronous USB transfer. + * @details After calling this function the transfer will be cancelled, if only + * it was not finished already. The transfer callback will be called with #USB_HOST_TRANSFER_CANCELLED status. + * @since_tizen 5.0 + * @param[in] transfer Transfer handle to be cancelled + * @return 0 on success, negative error code on error + * @retval #USB_HOST_ERROR_NONE Successful + * @retval #USB_HOST_ERROR_NOT_SUPPORTED Not supported + * @retval #USB_HOST_ERROR_INVALID_PARAMETER Invalid parameter was passed + */ +int usb_host_transfer_cancel(usb_host_transfer_h transfer); + #ifdef __cplusplus } #endif diff --git a/include/usb_host_internal.h b/include/usb_host_internal.h index d7d76c1..f4f2736 100644 --- a/include/usb_host_internal.h +++ b/include/usb_host_internal.h @@ -44,6 +44,8 @@ struct usb_host_device_s { struct usb_host_transfer_s { struct libusb_transfer *lusb_transfer; + int allocated_iso_packets; + int iso_buffer_usage; }; /** diff --git a/src/usb_host.c b/src/usb_host.c index f3afb20..028f0c0 100644 --- a/src/usb_host.c +++ b/src/usb_host.c @@ -101,6 +101,28 @@ static int translate_error(int error_code) } } +static int translate_status(int status_code) +{ + switch (status_code) { + case LIBUSB_TRANSFER_COMPLETED: + return USB_HOST_TRANSFER_COMPLETED; + case LIBUSB_TRANSFER_ERROR: + return USB_HOST_TRANSFER_ERROR; + case LIBUSB_TRANSFER_TIMED_OUT: + return USB_HOST_TRANSFER_TIMED_OUT; + case LIBUSB_TRANSFER_CANCELLED: + return USB_HOST_TRANSFER_CANCELLED; + case LIBUSB_TRANSFER_STALL: + return USB_HOST_TRANSFER_STALL; + case LIBUSB_TRANSFER_NO_DEVICE: + return USB_HOST_TRANSFER_NO_DEVICE; + case LIBUSB_TRANSFER_OVERFLOW: + return USB_HOST_TRANSFER_OVERFLOW; + default: + return USB_HOST_TRANSFER_UNKNOWN; + } +} + static void free_device(struct uref *uref) { struct usb_host_device_s *dev = to_usb_host_device(uref); @@ -1835,3 +1857,584 @@ int usb_host_unset_hotplug_cb(usb_host_hotplug_h handle) return USB_HOST_ERROR_NONE; } + +struct async_transfer_data { + usb_host_transferred_cb cb; + usb_host_transfer_h transfer; + void *user_data; +}; + +static void generic_transfer_cb(struct libusb_transfer *lusb_transfer) +{ + struct async_transfer_data *data; + + data = lusb_transfer->user_data; + data->cb(data->transfer, data->user_data); +} + +int usb_host_create_isochronous_transfer(usb_host_endpoint_h ep, usb_host_transferred_cb callback, + unsigned char *data, int length, unsigned int num_iso_packets, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer) +{ + usb_host_transfer_h rtransfer = NULL; + struct async_transfer_data *transfer_data = NULL; + int type; + int ret = USB_HOST_ERROR_UNKNOWN; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!ep || !data || !transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + rtransfer = calloc(1, sizeof(*rtransfer)); + if (!rtransfer) { + _E("Failed to alloc transfer structure"); + return USB_HOST_ERROR_OUT_OF_MEMORY; + } + + transfer_data = calloc(1, sizeof(*transfer_data)); + if (!transfer_data) { + _E("Failed to alloc transfer data structure"); + ret = USB_HOST_ERROR_OUT_OF_MEMORY; + goto free_rtransfer; + } + + transfer_data->cb = callback; + transfer_data->transfer = rtransfer; + transfer_data->user_data = user_data; + + rtransfer->lusb_transfer = libusb_alloc_transfer(num_iso_packets); + rtransfer->allocated_iso_packets = num_iso_packets; + rtransfer->iso_buffer_usage = 0; + + type = usb_host_get_ep_type(ep); + switch (type) { + case USB_ENDPOINT_XFER_BULK: + libusb_fill_bulk_transfer(rtransfer->lusb_transfer, ep->dev->lusb_dev_handle, + ep->desc.bEndpointAddress, data, length, generic_transfer_cb, transfer_data, timeout); + break; + case USB_ENDPOINT_XFER_INT: + libusb_fill_interrupt_transfer(rtransfer->lusb_transfer, ep->dev->lusb_dev_handle, + ep->desc.bEndpointAddress, data, length, generic_transfer_cb, transfer_data, timeout); + break; + case USB_ENDPOINT_XFER_ISOC: + libusb_fill_iso_transfer(rtransfer->lusb_transfer, ep->dev->lusb_dev_handle, ep->desc.bEndpointAddress, data, + length, num_iso_packets, generic_transfer_cb, transfer_data, timeout); + break; + default: + ret = USB_HOST_ERROR_NOT_SUPPORTED; + goto free_transfer_data; + } + + *transfer = rtransfer; + + return USB_HOST_ERROR_NONE; + +free_transfer_data: + free(transfer_data); +free_rtransfer: + libusb_free_transfer(rtransfer->lusb_transfer); + free(rtransfer); + + return ret; +} + +int usb_host_create_transfer(usb_host_endpoint_h ep, usb_host_transferred_cb callback, + unsigned char *data, int length, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer) +{ + return usb_host_create_isochronous_transfer(ep, callback, data, length, 0, user_data, timeout, transfer); +} + +int usb_host_create_control_transfer(usb_host_device_h dev, usb_host_transferred_cb callback, + unsigned char *data, int length, void *user_data, unsigned int timeout, usb_host_transfer_h *transfer) +{ + usb_host_transfer_h rtransfer = NULL; + struct async_transfer_data *transfer_data = NULL; + int ret = USB_HOST_ERROR_UNKNOWN; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!dev || !data || !transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + rtransfer = calloc(1, sizeof(*rtransfer)); + if (!rtransfer) { + _E("Failed to alloc transfer structure"); + return USB_HOST_ERROR_OUT_OF_MEMORY; + } + + transfer_data = calloc(1, sizeof(*transfer_data)); + if (!transfer_data) { + _E("Failed to alloc transfer data structure"); + ret = USB_HOST_ERROR_OUT_OF_MEMORY; + goto free_rtransfer; + } + + transfer_data->cb = callback; + transfer_data->transfer = rtransfer; + transfer_data->user_data = user_data; + + rtransfer->lusb_transfer = libusb_alloc_transfer(0); + if (!rtransfer->lusb_transfer) { + _E("Failed to alloc libusb transfer"); + ret = USB_HOST_ERROR_OUT_OF_MEMORY; + goto out; + } + + rtransfer->allocated_iso_packets = 0; + rtransfer->iso_buffer_usage = 0; + + libusb_fill_control_setup(data, 0, 0, 0, 0, length - LIBUSB_CONTROL_SETUP_SIZE); + libusb_fill_control_transfer(rtransfer->lusb_transfer, dev->lusb_dev_handle, data, generic_transfer_cb, transfer_data, timeout); + + *transfer = rtransfer; + return USB_HOST_ERROR_NONE; + +out: + free(transfer_data); + libusb_free_transfer(rtransfer->lusb_transfer); +free_rtransfer: + free(rtransfer); + return ret; +} + +int usb_host_transfer_get_status(usb_host_transfer_h transfer, int *status) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !status || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + *status = translate_status(transfer->lusb_transfer->status); + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_data(usb_host_transfer_h transfer, unsigned char **data, unsigned int *actual_length) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !data || !actual_length || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + *data = transfer->lusb_transfer->buffer; + *actual_length = transfer->lusb_transfer->actual_length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_control_transfer_get_data(usb_host_transfer_h transfer, unsigned char **data, unsigned int *actual_length) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !data || !actual_length || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + *data = libusb_control_transfer_get_data(transfer->lusb_transfer); + *actual_length = transfer->lusb_transfer->actual_length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_length(usb_host_transfer_h transfer, unsigned int *length) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !length || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + *length = transfer->lusb_transfer->length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_num_iso_packets(usb_host_transfer_h transfer, unsigned int *num_iso_packets) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !num_iso_packets || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + *num_iso_packets = transfer->lusb_transfer->num_iso_packets; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_ep(usb_host_transfer_h transfer, usb_host_endpoint_h ep) +{ + int type; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer || !ep || !ep->dev) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + transfer->lusb_transfer->endpoint = ep->desc.bEndpointAddress; + transfer->lusb_transfer->dev_handle = ep->dev->lusb_dev_handle; + + type = usb_host_get_ep_type(ep); + switch (type) { + case USB_ENDPOINT_XFER_BULK: + transfer->lusb_transfer->type = LIBUSB_TRANSFER_TYPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + transfer->lusb_transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + break; + case USB_ENDPOINT_XFER_ISOC: + transfer->lusb_transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; + break; + default: + return USB_HOST_ERROR_NOT_SUPPORTED; + } + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_callback(usb_host_transfer_h transfer, usb_host_transferred_cb callback) +{ + struct async_transfer_data *transfer_data = NULL; + + if (!transfer || !transfer->lusb_transfer || !callback) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + transfer_data = transfer->lusb_transfer->user_data; + transfer_data->cb = callback; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_data(usb_host_transfer_h transfer, unsigned char *data, int length) +{ + struct libusb_control_setup *setup; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + transfer->lusb_transfer->buffer = data; + transfer->lusb_transfer->length = length; + + if (transfer->lusb_transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) { + setup = (struct libusb_control_setup *)(transfer->lusb_transfer->buffer); + setup->wLength = length; + } + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_timeout(usb_host_transfer_h transfer, unsigned int timeout) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + transfer->lusb_transfer->timeout = timeout; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_num_iso_packets(usb_host_transfer_h transfer, unsigned int num_iso_packets) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + if (num_iso_packets > transfer->allocated_iso_packets) { + _E("Too many packets"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + transfer->lusb_transfer->num_iso_packets = num_iso_packets; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_control_transfer_set_request_type(usb_host_transfer_h transfer, uint8_t bm_request_type) +{ + struct libusb_control_setup *setup; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer || !transfer->lusb_transfer->buffer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + setup = (struct libusb_control_setup *)(transfer->lusb_transfer->buffer); + setup->bmRequestType = bm_request_type; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_control_transfer_set_request(usb_host_transfer_h transfer, uint8_t b_request) +{ + struct libusb_control_setup *setup; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer || !transfer->lusb_transfer->buffer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + setup = (struct libusb_control_setup *)(transfer->lusb_transfer->buffer); + setup->bRequest = b_request; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_control_transfer_set_value(usb_host_transfer_h transfer, uint16_t w_value) +{ + struct libusb_control_setup *setup; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer || !transfer->lusb_transfer->buffer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + setup = (struct libusb_control_setup *)(transfer->lusb_transfer->buffer); + setup->wValue = w_value; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_control_transfer_set_index(usb_host_transfer_h transfer, uint16_t w_index) +{ + struct libusb_control_setup *setup; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer || !transfer->lusb_transfer->buffer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + setup = (struct libusb_control_setup *)(transfer->lusb_transfer->buffer); + setup->wIndex = w_index; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_set_iso_packet_length(usb_host_transfer_h transfer, unsigned int packet_number, int length) +{ + int buffer_usage; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + if (packet_number >= transfer->lusb_transfer->num_iso_packets) { + _E("No such packet\n"); + return USB_HOST_ERROR_NOT_FOUND; + } + + buffer_usage = transfer->iso_buffer_usage + length + - transfer->lusb_transfer->iso_packet_desc[packet_number].length; + if (buffer_usage > transfer->lusb_transfer->length) { + _E("Buffer too short"); + return USB_HOST_ERROR_OVERFLOW; + } + + transfer->iso_buffer_usage = buffer_usage; + transfer->lusb_transfer->iso_packet_desc[packet_number].length = length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_iso_packet_status(usb_host_transfer_h transfer, unsigned int packet_number, int *status) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !status || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + if (packet_number >= transfer->lusb_transfer->num_iso_packets) { + _E("No such packet\n"); + return USB_HOST_ERROR_NOT_FOUND; + } + + *status = transfer->lusb_transfer->iso_packet_desc[packet_number].status; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_iso_packet_data(usb_host_transfer_h transfer, unsigned int packet_number, unsigned char **data, int *actual_length) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !data || !actual_length || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + if (packet_number >= transfer->lusb_transfer->num_iso_packets) { + _E("No such packet\n"); + return USB_HOST_ERROR_NOT_FOUND; + } + + *data = libusb_get_iso_packet_buffer(transfer->lusb_transfer, packet_number); + if (!(*data)) { + _E("No such packet\n"); + return USB_HOST_ERROR_NOT_FOUND; + } + + *actual_length = transfer->lusb_transfer->iso_packet_desc[packet_number].actual_length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_iso_packet_length(usb_host_transfer_h transfer, unsigned int packet_number, int *length) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !length || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + if (packet_number >= transfer->lusb_transfer->num_iso_packets) { + _E("No such packet\n"); + return USB_HOST_ERROR_NOT_FOUND; + } + + *length = transfer->lusb_transfer->iso_packet_desc[packet_number].length; + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_get_type(usb_host_transfer_h transfer, usb_host_transfer_type_e *transfer_type) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer_type || !transfer->lusb_transfer) { + _E("Invalid parameter was passed"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + switch (transfer->lusb_transfer->type) { + case LIBUSB_TRANSFER_TYPE_CONTROL: + *transfer_type = USB_HOST_TRANSFER_TYPE_CONTROL; + break; + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: + *transfer_type = USB_HOST_TRANSFER_TYPE_ISOCHRONOUS; + break; + case LIBUSB_TRANSFER_TYPE_BULK: + *transfer_type = USB_HOST_TRANSFER_TYPE_BULK; + break; + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + *transfer_type = USB_HOST_TRANSFER_TYPE_INTERRUPT; + break; + default: + return USB_HOST_ERROR_NOT_SUPPORTED; + } + + return USB_HOST_ERROR_NONE; +} + +int usb_host_transfer_submit(usb_host_transfer_h transfer) +{ + int ret; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + ret = libusb_submit_transfer(transfer->lusb_transfer); + if (ret < 0) + _E("Failed to submit transfer: %d", ret); + + return translate_error(ret); +} + +int usb_host_transfer_cancel(usb_host_transfer_h transfer) +{ + int ret; + + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + ret = libusb_cancel_transfer(transfer->lusb_transfer); + if (ret < 0) + _E("Failed to cancel transfer: %d", ret); + + return translate_error(ret); +} + +int usb_host_transfer_destroy(usb_host_transfer_h transfer) +{ + if (!usb_host_feature_enabled()) + return USB_HOST_ERROR_NOT_SUPPORTED; + + if (!transfer || !transfer->lusb_transfer) { + _E("Invalid parameter"); + return USB_HOST_ERROR_INVALID_PARAMETER; + } + + free(transfer->lusb_transfer->user_data); + libusb_free_transfer(transfer->lusb_transfer); + free(transfer); + + return USB_HOST_ERROR_NONE; +} -- 2.34.1