diff --git a/IMX6ULL/doc_pic/12_USB/06_libusb的使用.md b/IMX6ULL/doc_pic/12_USB/06_libusb的使用.md index 0c26573..52f1bcb 100644 --- a/IMX6ULL/doc_pic/12_USB/06_libusb的使用.md +++ b/IMX6ULL/doc_pic/12_USB/06_libusb的使用.md @@ -45,8 +45,8 @@ unsigned char data[4]; int actual_length; int r = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_IN, data, sizeof(data), &actual_length, 0); if (r == 0 && actual_length == sizeof(data)) { - // results of the transaction can now be found in the data buffer - // parse them here and report button press + // 接收到的数据保存在data数组里 + // 解析这些数据就可以知道按键状态 } else { error(); } @@ -61,18 +61,17 @@ if (r == 0 && actual_length == sizeof(data)) { ### 2.2 初始化 ```c -/** \ingroup libusb_lib - * Initialize libusb. This function must be called before calling any other - * libusb function. +/** + * 初始化libusb,这个函数必须先与其他libusb的函数执行 * - * If you do not provide an output location for a context pointer, a default - * context will be created. If there was already a default context, it will - * be reused (and nothing will be initialized/reinitialized). + * 如果传入NULL,那么函数内部会穿件一个默认的context + * 如果已经创建过默认的context,这个context会被重新使用(不会重新初始化它) * - * \param ctx Optional output location for context pointer. - * Only valid on return code 0. - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see libusb_contexts + * 参数: + * ctx : context pointer的位置,也可以传入NULL + * 返回值 + * 0 - 成功 + * 负数 - 失败 */ int API_EXPORTED libusb_init(libusb_context **ctx); ``` @@ -87,24 +86,18 @@ int API_EXPORTED libusb_init(libusb_context **ctx); ```c /** @ingroup libusb_dev - * Returns a list of USB devices currently attached to the system. This is - * your entry point into finding a USB device to operate. + * 返回一个list,list里含有当前系统中所有的USB设备 * - * You are expected to unreference all the devices when you are done with - * them, and then free the list with libusb_free_device_list(). Note that - * libusb_free_device_list() can unref all the devices for you. Be careful - * not to unreference a device you are about to open until after you have - * opened it. + * 我们一般会在list里寻找需要访问的设备,找到之后使用libusb_open函数打开它 + * 然后调用libusb_free_device_list释放list * - * This return value of this function indicates the number of devices in - * the resultant list. The list is actually one element larger, as it is - * NULL-terminated. + * 这个函数的返回值表示list中有多少个设备 + * list的最后一项是NULL * - * \param ctx the context to operate on, or NULL for the default context - * \param list output location for a list of devices. Must be later freed with - * libusb_free_device_list(). - * \returns the number of devices in the outputted list, or any - * \ref libusb_error according to errors encountered by the backend. + * 参数: + * ctx : context + * list : output location for a list of devices, 最后必须调用libusb_free_device_list()来释放它 + * 返回值: list中设备的个数, 或错误值 */ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, libusb_device ***list); @@ -114,11 +107,12 @@ ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, ```c /** \ingroup libusb_dev - * Frees a list of devices previously discovered using - * libusb_get_device_list(). If the unref_devices parameter is set, the - * reference count of each device in the list is decremented by 1. - * \param list the list to free - * \param unref_devices whether to unref the devices in the list + * 前面使用libusb_get_device_list()获得了设备list, + * 使用完后要调用libusb_free_device_list()释放这个list + * 如果参数unref_devices为1, 则list中每个设备的引用计数值减小1 + * 参数: + * list : 要释放的设备list + * unref_devices : 是否要将设备的引用计数减1 */ void API_EXPORTED libusb_free_device_list(libusb_device **list, int unref_devices); @@ -130,23 +124,21 @@ void API_EXPORTED libusb_free_device_list(libusb_device **list, ```c /** \ingroup libusb_dev - * Open a device and obtain a device handle. A handle allows you to perform - * I/O on the device in question. + * 打开一个设备并得到它的句柄, 以后进行IO操作时都是使用句柄 * - * Internally, this function adds a reference to the device and makes it - * available to you through libusb_get_device(). This reference is removed - * during libusb_close(). + * 使用libusb_get_device()函数可以得到设备的list, + * 从list里确定你要访问的设备后, 使用libusb_open()去打开它。 + * libusb_open()函数内部会增加此设备的引用计数, 使用完毕后要调用libusb_close()减小引用计数。 * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev the device to open - * \param dev_handle output location for the returned device handle pointer. Only - * populated when the return code is 0. - * \returns 0 on success - * \returns \ref LIBUSB_ERROR_NO_MEM on memory allocation failure - * \returns \ref LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure + * 参数: + * dev : 要打开的设备 + * dev_handle : 输出参数, 用来保存句柄 + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NO_MEM : 缺少内存 + * LIBUSB_ERROR_ACCESS : 权限不足 + * LIBUSB_ERROR_NO_DEVICE : 这个设备未连接 + * 其他错误 : 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_open(libusb_device *dev, libusb_device_handle **dev_handle); @@ -158,15 +150,12 @@ int API_EXPORTED libusb_open(libusb_device *dev, ```c /** \ingroup libusb_dev - * Close a device handle. Should be called on all open handles before your - * application exits. + * 关闭设备句柄, 在程序退出之前应该使用它去关闭已经打开的句柄 * - * Internally, this function destroys the reference that was added by - * libusb_open() on the given device. + * 设备的引用计数在前面被libusb_open()函数增加了。 + * 在libusb_close()函数的内部,它会减小设备的引用计数。 * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev_handle the device handle to close + * 参数: dev_handle - 句柄 */ void API_EXPORTED libusb_close(libusb_device_handle *dev_handle); ``` @@ -181,21 +170,23 @@ libusb_open_device_with_vid_pid函数原型如下: ```c /** \ingroup libusb_dev - * Convenience function for finding a device with a particular - * idVendor/idProduct combination. This function is intended - * for those scenarios where you are using libusb to knock up a quick test - * application - it allows you to avoid calling libusb_get_device_list() and - * worrying about traversing/freeing the list. + * 打开设备的常规做法是使用libusb_get_device_list()得到设备list, + * 然后遍历list,找到设备 + * 接着使用libusb_open()函数得到句柄 + * + * 如果知道USB设备的VID、PID,那么可以使用libusb_open_device_with_vid_pid()函数快速打开它,得到句柄。 + * + * 这个函数有一个缺点: 如果系统中有多个ID相同的设备,你只能打开第1个设备 * - * This function has limitations and is hence not intended for use in real - * applications: if multiple devices have the same IDs it will only - * give you the first one, etc. - * - * \param ctx the context to operate on, or NULL for the default context - * \param vendor_id the idVendor value to search for - * \param product_id the idProduct value to search for - * \returns a device handle for the first found device, or NULL on error - * or if the device could not be found. */ + * 参数: + * ctx : context, 或者传入NULL以使用默认的context + * vendor_id : 厂家ID + * product_id : 产品ID + * + * 返回值: + * 句柄 - 找到的第1个设备的句柄 + * NULL - 没有找到设备 + */ DEFAULT_VISIBILITY libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); @@ -205,6 +196,8 @@ libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( ### 2.6 detach/attach驱动 +#### 2.6.1 两种方法 + 使用libusb访问USB设备时,需要先移除(detach)设备原来的驱动程序,然后安装(attach)libusb专用的驱动程序。有两种办法: * 方法1: @@ -230,28 +223,30 @@ libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( +#### 2.6.2 函数原型 + 函数`libusb_detach_kernel_driver`原型如下: ```c - * Detach a kernel driver from an interface. If successful, you will then be - * able to claim the interface and perform I/O. +/** \ingroup libusb_dev + * 给USB设备的接口(interface)移除驱动程序. If successful, you will then be + * 移除原来的驱动后才能"claim the interface"、执行IO操作 * - * This functionality is not available on Windows. + * 实际上libusb会给这个接口安装一个特殊的内核驱动, + * 所以本函数"移除驱动"是移除其他驱动,不是移除这个特殊的驱动。 + * 若干这个接口已经安装了这个特殊的驱动,本函数会返回LIBUSB_ERROR_NOT_FOUND. * - * Note that libusb itself also talks to the device through a special kernel - * driver, if this driver is already attached to the device, this call will - * not detach it and return \ref LIBUSB_ERROR_NOT_FOUND. - * - * \param dev_handle a device handle - * \param interface_number the interface to detach the driver from - * \returns 0 on success - * \returns \ref LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_kernel_driver_active() + * 参数: + * dev_handle - 设备句柄 + * interface_number - 哪一个接口 + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NOT_FOUND - 这个接口没有安装其他驱动 + * LIBUSB_ERROR_INVALID_PARAM - 没有这个接口 + * LIBUSB_ERROR_NO_DEVICE - 这个设备未连接 + * LIBUSB_ERROR_NOT_SUPPORTED - 系统不支持此操作, 比如Windows + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number); @@ -263,32 +258,27 @@ int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev_handle, ```c /** \ingroup libusb_dev - * Claim an interface on a given device handle. You must claim the interface - * you wish to use before you can perform I/O on any of its endpoints. + * libusb使用内核里一个特殊的驱动程序, + * libusb_claim_interface()函数就是给某个usb接口安装这个特殊的驱动程序, + * 在使用libusb的函数执行IO操作之前必须调用本函数。 * - * It is legal to attempt to claim an already-claimed interface, in which - * case libusb just returns 0 without doing anything. + * 你可以给"已经claim过的接口"再次调用本函数,它直接返回0。 * - * If auto_detach_kernel_driver is set to 1 for dev, the kernel driver - * will be detached if necessary, on failure the detach error is returned. + * 如果这个接口的auto_detach_kernel_driver被设置为1, + * libusb_claim_interface()函数会先移除其他驱动。 * - * Claiming of interfaces is a purely logical operation; it does not cause - * any requests to be sent over the bus. Interface claiming is used to - * instruct the underlying operating system that your application wishes - * to take ownership of the interface. + * 本函数时纯粹的逻辑操作:只是替换接口的驱动程序而已,不会导致USB硬件传输。 * - * This is a non-blocking function. + * 参数: + * dev_handle - 句柄, 表示USB设备 + * interface_number - 接口 * - * \param dev_handle a device handle - * \param interface_number the bInterfaceNumber of the interface you - * wish to claim - * \returns 0 on success - * \returns \ref LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist - * \returns \ref LIBUSB_ERROR_BUSY if another program or driver has claimed the - * interface - * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns a LIBUSB_ERROR code on other failure - * \see libusb_set_auto_detach_kernel_driver() + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NOT_FOUND - 没有这个接口 + * LIBUSB_ERROR_BUSY - 其他APP或者驱动正在使用这个接口 + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number); @@ -300,23 +290,23 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle, ```c /** \ingroup libusb_dev - * Release an interface previously claimed with libusb_claim_interface(). You - * should release all claimed interfaces before closing a device handle. + * 前面使用libusb_claim_interface()给接口安装了给libusb使用的特殊驱动程序, + * 使用完毕后,在调用libusb_close()关闭句柄之前, + * 可以调用libusb_release_interface()卸载特殊驱动程序 + * 如果设备的auto_detach_kernel_driver为1,还会重新安装普通驱动程序 + * + * 这是一个阻塞函数, 它会给USB设备发送一个请求: SET_INTERFACE control, + * 用来把接口的状态复位到第1个setting(the first alternate setting) * - * This is a blocking function. A SET_INTERFACE control request will be sent - * to the device, resetting interface state to the first alternate setting. - * - * If auto_detach_kernel_driver is set to 1 for dev, the kernel - * driver will be re-attached after releasing the interface. - * - * \param dev_handle a device handle - * \param interface_number the bInterfaceNumber of the - * previously-claimed interface - * \returns 0 on success - * \returns \ref LIBUSB_ERROR_NOT_FOUND if the interface was not claimed - * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_set_auto_detach_kernel_driver() + * 参数: + * dev_handle - 设备句柄 + * interface_number - 哪个接口 + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NOT_FOUND - 这个接口没有被claim(没有安装特殊的驱动程序) + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle, int interface_number); @@ -326,54 +316,46 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle, ### 2.7 描述符相关函数 -**获得设备描述符**: +#### 2.7.1 获得设备描述符 ```c /** \ingroup libusb_desc - * Get the USB device descriptor for a given device. + * 获得设备描述符 * - * This is a non-blocking function; the device descriptor is cached in memory. + * 参数: + * dev - 哪个设备 + * desc - 输出参数, 用来保存设备描述符 * - * Note since libusb-1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, this - * function always succeeds. - * - * \param dev the device - * \param desc output location for the descriptor data - * \returns 0 on success or a LIBUSB_ERROR code on failure + * 返回值: + * 0 - 成功, 或其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc); ``` -**获得/释放配置描述符**: +#### 2.7.2 获得/释放配置描述符 ```c /** \ingroup libusb_desc - * Get a USB configuration descriptor based on its index. - * This is a non-blocking function which does not involve any requests being - * sent to the device. + * 获得指定的配置描述符 * - * \param dev a device - * \param config_index the index of the configuration you wish to retrieve - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_active_config_descriptor() - * \see libusb_get_config_descriptor_by_value() + * 参数: + * dev - 哪个设备 + * config_index - 哪个配置 + * config - 输出参数, 用来保存配置描述符, 使用完毕要调用libusb_free_config_descriptor()释放掉 + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NOT_FOUND - 没有这个配置 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config); /** \ingroup libusb_desc * Free a configuration descriptor obtained from - * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). - * It is safe to call this function with a NULL config parameter, in which - * case the function simply returns. - * - * \param config the configuration descriptor to free + * 前面使用libusb_get_active_config_descriptor()或libusb_get_config_descriptor()获得配置描述符, + * 用完后调用libusb_free_config_descriptor()释放掉 */ void API_EXPORTED libusb_free_config_descriptor( struct libusb_config_descriptor *config); @@ -387,35 +369,30 @@ void API_EXPORTED libusb_free_config_descriptor( ```c /** \ingroup libusb_syncio - * Perform a USB control transfer. + * 启动控制传输 * - * The direction of the transfer is inferred from the bmRequestType field of - * the setup packet. + * 传输方向在bmRequestType里 + * wValue,wIndex和wLength是host-endian字节序 * - * The wValue, wIndex and wLength fields values should be given in host-endian - * byte order. - * - * \param dev_handle a handle for the device to communicate with - * \param bmRequestType the request type field for the setup packet - * \param bRequest the request field for the setup packet - * \param wValue the value field for the setup packet - * \param wIndex the index field for the setup packet - * \param data a suitably-sized data buffer for either input or output - * (depending on direction bits within bmRequestType) - * \param wLength the length field for the setup packet. The data buffer should - * be at least this size. - * \param timeout timeout (in milliseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * \returns on success, the number of bytes actually transferred - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the - * device - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than + * 参数: + * dev_handle - 设备句柄 + * bmRequestType - setup数据包的bmRequestType域 + * bRequest - setup数据包的bRequest域 + * wValue - setup数据包的wValue域 + * wIndex - setup数据包的wIndex域 + * data - 保存数据的buffer, 可以是in、out数据 + * wLength - setup数据包的wLength域 + * timeout - 超时时间(单位ms),就是这个函数能等待的最大时间; 0表示一直等待直到成功 + * + * 返回值: + * 正整数 - 成功传输的数据的长度 + * LIBUSB_ERROR_TIMEOUT - 超时 + * LIBUSB_ERROR_PIPE - 设备不支持该请求 + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * LIBUSB_ERROR_BUSY - 如果这个函数时在事件处理上下文(event handling context)里则返回这个错误 + * LIBUSB_ERROR_INVALID_PARAM - 传输的字节超过OS或硬件的支持 * the operating system and/or hardware can support (see \ref asynclimits) - * \returns another LIBUSB_ERROR code on other failures + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, @@ -428,49 +405,34 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, ```c /** \ingroup libusb_syncio - * Perform a USB bulk transfer. The direction of the transfer is inferred from - * the direction bits of the endpoint address. + * 启动批量传输 + * 传输方向在endpoint的"方向位"里表示 * - * For bulk reads, the length field indicates the maximum length of - * data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * transferred output parameter. + * 对于批量读,参数length表示"期望读到的数据最大长度", 实际读到的长度保存在transferred参数里 * - * You should also check the transferred parameter for bulk writes. - * Not all of the data may have been written. + * 对于批量写, transferred参数表示实际发送出去的数据长度 * - * Also check transferred when dealing with a timeout error code. - * libusb may have to split your transfer into a number of chunks to satisfy - * underlying O/S requirements, meaning that the timeout may expire after - * the first few chunks have completed. libusb is careful not to lose any data - * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. See \ref asynctimeout for more details. + * 发生超时错误时,也应该检查transferred参数。 + * libusb会根据硬件的特点把数据拆分为一小段一小段地发送出去, + * 这意味着发送满某段数据后可能就发生超时错误,需要根据transferred参数判断传输了多少数据。 * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), - * it is legal to pass a NULL pointer if you do not wish to receive this - * information. - * \param timeout timeout (in milliseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. + * 参数: + * dev_handle - 设备句柄 + * endpoint - 端点 + * data - 保存数据的buffer, 可以是in、out数据 + * length - 对于批量写,它表示要发送的数据长度; 对于批量读,它表示"要读的数据的最大长度" + * transferred - 输出参数,表示实际传输的数据长度 + * timeout - 超时时间(单位ms),就是这个函数能等待的最大时间; 0表示一直等待直到成功 * - * \returns 0 on success (and populates transferred) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates - * transferred) - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref libusb_packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than - * the operating system and/or hardware can support (see \ref asynclimits) - * \returns another LIBUSB_ERROR code on other failures + * 返回值: + * 0 - 成功,根据transferred参数判断传输了多少长度的数据 + * LIBUSB_ERROR_TIMEOUT - 超时, 根据transferred参数判断传输了多少长度的数据 + * LIBUSB_ERROR_PIPE - 端点错误,端点被挂起了 + * LIBUSB_ERROR_OVERFLOW - 溢出,设备提供的数据太多了 + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * LIBUSB_ERROR_BUSY - 如果这个函数时在事件处理上下文(event handling context)里则返回这个错误 + * LIBUSB_ERROR_INVALID_PARAM - 传输的字节超过OS或硬件的支持 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, @@ -483,50 +445,34 @@ int API_EXPORTED libusb_bulk_transfer(libusb_device_handle *dev_handle, ```c /** \ingroup libusb_syncio - * Perform a USB interrupt transfer. The direction of the transfer is inferred - * from the direction bits of the endpoint address. + * 启动中断传输 + * 传输方向在endpoint的"方向位"里表示 * - * For interrupt reads, the length field indicates the maximum length - * of data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * transferred output parameter. + * 对于中断读,参数length表示"期望读到的数据最大长度", 实际读到的长度保存在transferred参数里 * - * You should also check the transferred parameter for interrupt - * writes. Not all of the data may have been written. + * 对于中断写, transferred参数表示实际发送出去的数据长度,不一定能发送完全部数据。 * - * Also check transferred when dealing with a timeout error code. - * libusb may have to split your transfer into a number of chunks to satisfy - * underlying O/S requirements, meaning that the timeout may expire after - * the first few chunks have completed. libusb is careful not to lose any data - * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. See \ref asynctimeout for more details. + * 发生超时错误时,也应该检查transferred参数。 + * libusb会根据硬件的特点把数据拆分为一小段一小段地发送出去, + * 这意味着发送满某段数据后可能就发生超时错误,需要根据transferred参数判断传输了多少数据。 * - * The default endpoint bInterval value is used as the polling interval. + * 参数: + * dev_handle - 设备句柄 + * endpoint - 端点 + * data - 保存数据的buffer, 可以是in、out数据 + * length - 对于批量写,它表示要发送的数据长度; 对于批量读,它表示"要读的数据的最大长度" + * transferred - 输出参数,表示实际传输的数据长度 + * timeout - 超时时间(单位ms),就是这个函数能等待的最大时间; 0表示一直等待直到成功 * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105), - * it is legal to pass a NULL pointer if you do not wish to receive this - * information. - * \param timeout timeout (in milliseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * - * \returns 0 on success (and populates transferred) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref libusb_packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if called from event handling context - * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than - * the operating system and/or hardware can support (see \ref asynclimits) - * \returns another LIBUSB_ERROR code on other error + * 返回值: + * 0 - 成功,根据transferred参数判断传输了多少长度的数据 + * LIBUSB_ERROR_TIMEOUT - 超时, 根据transferred参数判断传输了多少长度的数据 + * LIBUSB_ERROR_PIPE - 端点错误,端点被挂起了 + * LIBUSB_ERROR_OVERFLOW - 溢出,设备提供的数据太多了 + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * LIBUSB_ERROR_BUSY - 如果这个函数时在事件处理上下文(event handling context)里则返回这个错误 + * LIBUSB_ERROR_INVALID_PARAM - 传输的字节超过OS或硬件的支持 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_interrupt_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, @@ -553,27 +499,28 @@ int API_EXPORTED libusb_interrupt_transfer(libusb_device_handle *dev_handle, ```c /** \ingroup libusb_asyncio - * Allocate a libusb transfer with a specified number of isochronous packet - * descriptors. The returned transfer is pre-initialized for you. When the new - * transfer is no longer needed, it should be freed with - * libusb_free_transfer(). + * 分配一个libusb_transfer结构体, + * 如果iso_packets不为0,还会分配iso_packets个libusb_iso_packet_descriptor结构体 + * 使用完毕后需要调用libusb_free_transfer()函数释放掉 * - * Transfers intended for non-isochronous endpoints (e.g. control, bulk, - * interrupt) should specify an iso_packets count of zero. + * 对于控制传输、批量传输、中断传输,iso_packets参数需要设置为0 * - * For transfers intended for isochronous endpoints, specify an appropriate - * number of packet descriptors to be allocated as part of the transfer. - * The returned transfer is not specially initialized for isochronous I/O; - * you are still required to set the - * \ref libusb_transfer::num_iso_packets "num_iso_packets" and - * \ref libusb_transfer::type "type" fields accordingly. + * 对于实时传输,需要指定iso_packets参数, + * 这个函数会一起分配iso_packets个libusb_iso_packet_descriptor结构体。 + * 这个函数返回的libusb_transfer结构体并未初始化, + * 你还需要初始化它的这些成员: + * libusb_transfer::num_iso_packets + * libusb_transfer::type * - * It is safe to allocate a transfer with some isochronous packets and then - * use it on a non-isochronous endpoint. If you do this, ensure that at time - * of submission, num_iso_packets is 0 and that type is set appropriately. + * 你可以指定iso_packets参数,意图给实时传输分配结构体, + * 但是你可以把这个结构题用于其他类型的传输, + * 在这种情况下,只要确保num_iso_packets为0就可以。 * - * \param iso_packets number of isochronous packet descriptors to allocate. Must be non-negative. - * \returns a newly allocated transfer, or NULL on error + * 参数: + * iso_packets - 分配多少个isochronous packet descriptors to allocate + * + * 返回值: + * 返回一个libusb_transfer结构体或NULL */ DEFAULT_VISIBILITY struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( @@ -585,32 +532,31 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( #### 2.9.3 填充控制传输 ```c - * Helper function to populate the required \ref libusb_transfer fields - * for a control transfer. +/** \ingroup libusb_asyncio + * 构造控制传输结构体 * - * If you pass a transfer buffer to this function, the first 8 bytes will - * be interpreted as a control setup packet, and the wLength field will be - * used to automatically populate the \ref libusb_transfer::length "length" - * field of the transfer. Therefore the recommended approach is: - * -# Allocate a suitably sized data buffer (including space for control setup) - * -# Call libusb_fill_control_setup() - * -# If this is a host-to-device transfer with a data stage, put the data - * in place after the setup packet - * -# Call this function - * -# Call libusb_submit_transfer() + * 如果你传入buffer参数,那么buffer的前面8字节会被当做"control setup packet"来解析, + * buffer的最后2字节表示wLength,它也会被用来设置libusb_transfer::length + * 所以,建议使用流程如下: + * 1. 分配buffer,这个buffer的前面8字节对应"control setup packet",后面的空间可以用来保存其他数据 + * 2. 设置"control setup packet",通过调用libusb_fill_control_setup()函数来设置 + * 3. 如果是要把数据发送个设备,把要发送的数据放在buffer的后面(从buffer[8]开始放) + * 4. 调用libusb_fill_bulk_transfer + * 5. 提交传输: 调用libusb_submit_transfer() * - * It is also legal to pass a NULL buffer to this function, in which case this - * function will not attempt to populate the length field. Remember that you - * must then populate the buffer and length fields later. + * 也可以让buffer参数为NULL, + * 这种情况下libusb_transfer::length就不会被设置, + * 需要手工去设置ibusb_transfer::buffer、ibusb_transfer::length * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param buffer data buffer. If provided, this function will interpret the - * first 8 bytes as a setup packet and infer the transfer length from that. - * This pointer must be aligned to at least 2 bytes boundary. - * \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 + * 参数: + * transfer - 要设置的libusb_transfer结构体 + * dev_handle - 设备句柄 + * buffer - 数据buffer,如果不是NULL的话,它前面8直接会被当做"control setup packet"来处理, + * 也会从buffer[6], buffer[7]把length提取出来,用来设置libusb_transfer::length + * 这个buffer必须是2字节对齐 + * callback - 传输完成时的回调函数 + * user_data - 传给回调函数的参数 + * timeout - 超时时间(单位: ms) */ static inline void libusb_fill_control_transfer( struct libusb_transfer *transfer, libusb_device_handle *dev_handle, @@ -624,17 +570,17 @@ static inline void libusb_fill_control_transfer( ```c /** \ingroup libusb_asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a bulk transfer. + * 构造批量传输结构体 * - * \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 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 + * 参数: + * transfer - 要设置的libusb_transfer结构体 + * dev_handle - 设备句柄 + * endpoint - 端点 + * buffer - 数据buffer + * length - buffer的数据长度 + * callback - 传输完成时的回调函数 + * user_data - 传给回调函数的参数 + * timeout - 超时时间(单位: ms) */ static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, @@ -648,17 +594,17 @@ static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, ```c /** \ingroup libusb_asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an interrupt transfer. + * 构造中断传输结构体 * - * \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 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 + * 参数: + * transfer - 要设置的libusb_transfer结构体 + * dev_handle - 设备句柄 + * endpoint - 端点 + * buffer - 数据buffer + * length - buffer的数据长度 + * callback - 传输完成时的回调函数 + * user_data - 传给回调函数的参数 + * timeout - 超时时间(单位: ms) */ static inline void libusb_fill_interrupt_transfer( struct libusb_transfer *transfer, libusb_device_handle *dev_handle, @@ -672,18 +618,18 @@ static inline void libusb_fill_interrupt_transfer( ```c /** \ingroup libusb_asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an isochronous transfer. + * 构造实时传输结构体 * - * \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 buffer data buffer - * \param length length of data buffer - * \param num_iso_packets the number of isochronous packets - * \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 + * 参数: + * transfer - 要设置的libusb_transfer结构体 + * dev_handle - 设备句柄 + * endpoint - 端点 + * buffer - 数据buffer + * length - buffer的数据长度 + * num_iso_packets - 实时传输包的个数 + * callback - 传输完成时的回调函数 + * user_data - 传给回调函数的参数 + * timeout - 超时时间(单位: ms) */ static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, @@ -697,18 +643,18 @@ static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, ```c /** \ingroup libusb_asyncio - * Submit a transfer. This function will fire off the USB transfer and then - * return immediately. + * 提交传输Submit,这个函数会启动传输,然后立刻返回 * - * \param transfer the transfer to submit - * \returns 0 on success - * \returns \ref LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns \ref LIBUSB_ERROR_BUSY if the transfer has already been submitted. - * \returns \ref LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported - * by the operating system. - * \returns \ref LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than - * the operating system and/or hardware can support (see \ref asynclimits) - * \returns another LIBUSB_ERROR code on other failure + * 参数: + * transfer - 要传输的libusb_transfer结构体 + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_NO_DEVICE - 设备未连接 + * LIBUSB_ERROR_BUSY - 这个传输已经提交过了 + * LIBUSB_ERROR_NOT_SUPPORTED - 不支持这个传输 + * LIBUSB_ERROR_INVALID_PARAM - 传输的字节超过OS或硬件的支持 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer); ``` @@ -717,41 +663,96 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer); #### 2.9.8 处理事件 -有2个函数: +有4个函数,其中2个没有`completed`后缀的函数过时了: ```c /** \ingroup libusb_poll - * Handle any pending events + * 处理任何"pengding的事件" * - * Like libusb_handle_events_timeout_completed(), but without the completed - * parameter, calling this function is equivalent to calling - * libusb_handle_events_timeout_completed() with a NULL completed parameter. + * 使用异步传输函数时,提交的tranfer结构体后就返回了。 + * 可以使用本函数处理这些传输的返回结果。 * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. + * 如果timeval参数为0,本函数会处理"当前、已经pending的事件",然后马上返回。 * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or an all zero - * timeval struct for non-blocking mode - * \returns 0 on success, or a LIBUSB_ERROR code on failure + * 如果timeval参数不为0,并且当前没有待处理的事件,本函数会阻塞以等待事件,直到超时。 + * 在等待过程中,如果事件发生了、或者得到了信号(signal),那么这个函数会提前返回。 + * + * completed参数用来避免竞争,如果它不为NULL: + * 本函数获得"event handling lock"后,会判断completed指向的数值, + * 如果这个数值非0(表示别的线程已经处理了、已经completed了), + * 则本函数会立刻返回(既然都completed了,当然无需再处理) + * + * 参数: + * ctx - context(如果传入NULL则使用默认context) + * tv - 等待事件的最大时间,0表示不等待 + * completed - 指针,可以传入NULL + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_INVALID_PARAM - timeval参数无效 + * 其他LIBUSB_ERROR错误码 + */ +int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, + struct timeval *tv, int *completed); + +/** \ingroup libusb_poll + * 处理任何"pengding的事件" + * + * 跟libusb_handle_events_timeout_completed()类似, + * 就是调用"libusb_handle_events_timeout_completed(ctx, tv, NULL);" + * 最后的completed参数为NULL。 + * + * 这个函数只是为了保持向后兼容,新的代码建议使用libusb_handle_events_completed()或 + * libusb_handle_events_timeout_completed(), + * 这2个新函数可以处理竞争。 + * + * 参数: + * ctx - context(如果传入NULL则使用默认context) + * tv - 等待事件的最大时间,0表示不等待 + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_INVALID_PARAM - timeval参数无效 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv); /** \ingroup libusb_poll - * Handle any pending events in blocking mode. There is currently a timeout - * hard-coded at 60 seconds but we plan to make it unlimited in future. For - * finer control over whether this function is blocking or non-blocking, or - * for control over the timeout, use libusb_handle_events_timeout_completed() - * instead. + * 处理任何"pengding的事件",以阻塞方式处理(blocking mode) * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. + * 本函数的内部实现就是调用: libusb_handle_events_timeout_completed(ctx, &tv, completed); + * 超时时间设置为60秒 * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 on success, or a LIBUSB_ERROR code on failure + * 参数: + * ctx - context(如果传入NULL则使用默认context) + * completed - 指针,可以传入NULL + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_INVALID_PARAM - timeval参数无效 + * 其他LIBUSB_ERROR错误码 + */ +int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, + int *completed); + +/** \ingroup libusb_poll + * 处理任何"pengding的事件",以阻塞方式处理(blocking mode) + * + * 本函数的内部实现就是调用: libusb_handle_events_timeout_completed(ctx, &tv, NULL); + * 超时时间设置为60秒 + * + * 这个函数只是为了保持向后兼容,新的代码建议使用libusb_handle_events_completed()或 + * libusb_handle_events_timeout_completed(), + * 这2个新函数可以处理竞争。 + * + * 参数: + * ctx - context(如果传入NULL则使用默认context) + * + * 返回值: + * 0 - 成功 + * LIBUSB_ERROR_INVALID_PARAM - timeval参数无效 + * 其他LIBUSB_ERROR错误码 */ int API_EXPORTED libusb_handle_events(libusb_context *ctx); ``` @@ -764,31 +765,20 @@ int API_EXPORTED libusb_handle_events(libusb_context *ctx); ```c /** \ingroup libusb_asyncio - * Free a transfer structure. This should be called for all transfers - * allocated with libusb_alloc_transfer(). + * 释放libusb_transfer结构体 + * 前面使用libusb_alloc_transfer()分配的结构体,要使用本函数来释放。 * - * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER - * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is - * non-NULL, this function will also free the transfer buffer using the - * standard system memory allocator (e.g. free()). - * - * It is legal to call this function with a NULL transfer. In this case, - * the function will simply return safely. - * - * It is not legal to free an active transfer (one which has been submitted - * and has not yet completed). - * - * \param transfer the transfer to free + * 如果libusb_transfer::flags的LIBUSB_TRANSFER_FREE_BUFFER位非0, + * 那么会使用free()函数释放ibusb_transfer::buffer + * + * 不能使用本函数释放一个活动的传输结构体(active, 已经提交尚未结束) + * */ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer); ``` - - - - ## 3. 使用示例 在libusb源码的examples目录下有示例程序,我们也有一些真实的案列。