)
libusb-win32 应用层源码分析第二篇同步与异步数据传输1. 数据传输总览libusb-win32 应用层支持两类传输接口同步阻塞传输函数调用后阻塞直至传输完成或超时。包括usb_bulk_read/write、usb_interrupt_read/write、usb_control_msg。异步非阻塞传输需调用*_setup_async创建上下文usb_submit_async提交usb_reap_async等待完成。支持批量、中断、等时传输。实际实现中同步传输是异步传输的封装内部创建上下文、提交、等待完成然后释放。所有传输最终通过DeviceIoControl发送IOCTL给内核驱动libusb0.sys。2. 核心 IO 辅助函数2.1_usb_io_sync()位于windows.c。用于执行同步 DeviceIoControl请求。内部创建OVERLAPPED和事件对象。调用DeviceIoControl若返回ERROR_IO_PENDING则WaitForSingleObject等待完成。成功时返回TRUE并通过ret参数返回实际传输字节数。这是所有同步传输控制、版本查询、调试设置的底层工具。2.2_usb_setup_async()创建异步传输上下文usb_context_t。参数设备句柄、控制码、端点地址、等时包大小。校验端点方向与控制码匹配如读端点不能用于写控制码。分配内存初始化OVERLAPPED事件。返回上下文指针。2.3_usb_transfer_sync()同步传输的通用实现。调用_usb_setup_async创建上下文。调用usb_submit_async提交。调用usb_reap_async等待完成超时timeout若为 0 则视为INFINITE。调用usb_free_async释放。返回实际传输字节数或错误码。3. 同步传输函数3.1usb_bulk_read/writeintusb_bulk_read(usb_dev_handle*dev,intep,char*bytes,intsize,inttimeout){return_usb_transfer_sync(dev,LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,ep,0,bytes,size,timeout);}控制码读LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ写LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITEpktsize参数为 0由内核驱动根据端点描述符自动确定。3.2usb_interrupt_read/write与 bulk 使用相同的控制码LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ/WRITE。内核驱动会根据端点类型区分。3.3usb_control_msg特殊处理这是最复杂的传输函数因为 Windows 不直接支持标准 USB 控制请求需映射到不同的 IOCTL。流程解析requesttype和request若为USB_TYPE_STANDARD根据request值映射到对应的 IOCTL如USB_REQ_GET_STATUS-LIBUSB_IOCTL_GET_STATUS。若为USB_TYPE_VENDOR或USB_TYPE_CLASS映射到LIBUSB_IOCTL_VENDOR_READ或LIBUSB_IOCTL_VENDOR_WRITE。对于OUT请求requesttype不带USB_ENDPOINT_IN将用户数据附加在libusb_request结构之后通过_usb_io_sync发送in_size为 0。对于IN请求_usb_io_sync将数据填充到用户缓冲区返回实际读取字节数。超时参数通过req.timeout传递。4. 异步传输框架4.1 上下文创建usb_bulk_setup_async(dev, context, ep)usb_interrupt_setup_async(dev, context, ep)usb_isochronous_setup_async(dev, context, ep, pktsize)这些函数调用_usb_setup_async传入对应的控制码Bulk/InterruptLIBUSB_IOCTL_INTERRUPT_OR_BULK_READ/WRITEIsochronousLIBUSB_IOCTL_ISOCHRONOUS_READ/WRITE等时传输需指定pktsize包大小批量/中断则传 0。4.2 提交传输usb_submit_async检查上下文有效性、设备打开状态、配置有效、接口已声明。重置OVERLAPPED事件。调用DeviceIoControllpInBuffer指向c-reqlibusb_request结构nInBufferSizesizeof(libusb_request)lpOutBufferc-bytes用户数据缓冲区nOutBufferSizec-sizelpOverlapped指向c-ol若返回ERROR_IO_PENDING则传输已后台进行其他错误则立即返回错误码。4.3 等待完成4.3.1usb_reap_async(context, timeout)内部调用_usb_reap_async(context, timeout, TRUE)。WaitForSingleObject(c-ol.hEvent, timeout)。若超时调用_usb_cancel_io(c)取消传输返回-ETRANSFER_TIMEDOUT。若完成调用GetOverlappedResult获取实际传输字节数。4.3.2usb_reap_async_nocancel(context, timeout)与reap_async唯一区别超时时不取消传输仅返回超时错误。适用于流水线场景调用者希望保留传输继续执行。4.4 取消传输usb_cancel_async(context)调用_usb_cancel_io(c)。_usb_cancel_io通过_usb_abort_ep发送LIBUSB_IOCTL_ABORT_ENDPOINT给内核同步等待原传输的事件对象完成WaitForSingleObject(ol.hEvent, INFINITE)。原因必须确保用户缓冲区不再被内核访问防止栈溢出如局部数组被异步访问。文档注释中明确指出此行为。4.5 释放上下文usb_free_async关闭事件句柄CloseHandle。释放上下文内存。4.6 异步流水线示例参考benchmark.c可同时保持多个进行中的传输通过多个上下文。提交 N 个传输后使用usb_reap_async_nocancel等待最旧的完成立即重新提交形成环形队列。5. 端点控制函数5.1usb_resetep(dev, ep)发送两个 IOCTLLIBUSB_IOCTL_ABORT_ENDPOINT中止该端点上所有待处理 URB。LIBUSB_IOCTL_RESET_ENDPOINT复位端点数据翻转位清除 halt 状态。实际上是usb_clear_halt的超集。5.2usb_clear_halt(dev, ep)仅发送LIBUSB_IOCTL_RESET_ENDPOINT。根据 USB 规范清除端点 halt 条件。5.3 内部_usb_abort_ep发送LIBUSB_IOCTL_ABORT_ENDPOINT同步等待完成。6. 设备重置6.1usb_reset(dev)发送LIBUSB_IOCTL_RESET_DEVICE执行完整复位端口复位 端口循环。6.2usb_reset_ex(dev, reset_type)V1.2.4.8 新增扩展接口。reset_type可选USB_RESET_TYPE_RESET_PORT仅端口复位。USB_RESET_TYPE_CYCLE_PORT仅端口循环逻辑移除再重新枚举。USB_RESET_TYPE_FULL_RESET两者组合默认。通过LIBUSB_IOCTL_RESET_DEVICE_EX传递reset_type给驱动。7. 版本查询与调试控制7.1usb_get_version()返回全局静态变量_usb_version。在usb_os_init()中已通过 IOCTL 填充驱动版本号。7.2usb_set_debug(level)调用usb_log_set_level(level)。找到第一个可用的 libusb0 设备通过CreateFile试探发送LIBUSB_IOCTL_SET_DEBUG_LEVEL。驱动收到后更新内部调试级别。8. DLL 生命周期管理DllMainwindows.cDLL_PROCESS_ATTACH无操作。DLL_PROCESS_DETACH调用_usb_deinit()递归释放所有总线、设备和虚拟根集线器。确保进程退出时无内存泄漏。9. 关键技术点总结同步基于异步所有传输最终都使用OVERLAPPEDWaitForSingleObject。取消安全性usb_cancel_async同步等待OVERLAPPED完成防止用户栈被破坏。控制传输的复杂映射将标准 USB 请求拆分为多个 Windows 专用 IOCTL。超时处理超时值 0 被解释为INFINITE符合 libusb 语义。设备枚举优化在usb_os_init时尝试打开任意设备以获取驱动版本但实际枚举在usb_find_devices中独立完成。10. 与内核驱动交互的 IOCTL 清单IOCTL 名称用途LIBUSB_IOCTL_GET_VERSION获取驱动版本LIBUSB_IOCTL_SET_DEBUG_LEVEL设置驱动日志级别LIBUSB_IOCTL_GET_CACHED_CONFIGURATION获取缓存配置无 I/OLIBUSB_IOCTL_SET_CONFIGURATION设置配置LIBUSB_IOCTL_CLAIM_INTERFACE声明接口LIBUSB_IOCTL_RELEASE_INTERFACE释放接口LIBUSB_IOCTL_SET_INTERFACE设置备用接口LIBUSB_IOCTL_GET_INTERFACE获取当前备用设置LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ/WRITE批量/中断传输LIBUSB_IOCTL_ISOCHRONOUS_READ/WRITE等时传输LIBUSB_IOCTL_VENDOR_READ/WRITE厂商/类控制传输LIBUSB_IOCTL_GET_DESCRIPTOR获取描述符驱动可缓存LIBUSB_IOCTL_GET_STATUS获取状态LIBUSB_IOCTL_CLEAR_FEATURE清除特性LIBUSB_IOCTL_SET_FEATURE设置特性LIBUSB_IOCTL_RESET_ENDPOINT复位端点LIBUSB_IOCTL_ABORT_ENDPOINT中止端点传输LIBUSB_IOCTL_RESET_DEVICE复位设备LIBUSB_IOCTL_RESET_DEVICE_EX扩展复位LIBUSB_IOCTL_GET_DEVICE_PROPERTY获取设备属性PnPLIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY获取自定义注册表属性LIBUSB_IOCTL_GET_OBJECT_NAME获取设备对象名称后续文档将详细分析安装工具与注册表操作install.c,registry.c以及动态加载模块libusb_dyn.c。