windows 驱动实例分析系列: libusb驱动分析-驱动层源码篇(一)
libusb-win32 内核驱动源码分析第一篇驱动框架、PnP 与电源管理1. 驱动概述src/driver/目录包含 libusb-win32 的内核模式驱动程序libusb0.sys的完整实现。该驱动是一个 WDMWindows Driver Model或 KMDF内核模式驱动框架风格的驱动程序主要职责包括作为 USB 设备的功能驱动或过滤驱动与用户态 DLL 交互。处理 PnP即插即用和电源管理 IRP。接收来自用户态的 IOCTL 请求并将其转换为 USB 请求块URB提交给 USB 主机控制器驱动USBD。管理设备配置、接口声明、端点管道等 USB 资源。提供设备接口Device Interface供用户态程序通过 SetupAPI 发现设备。驱动采用单二进制双模式设计通过注册表项SurpriseRemovalOK判断是作为功能驱动非过滤还是过滤驱动Upper/Lower Filter。2. 入口函数DriverEntrylibusb_driver.c驱动入口按照标准 WDM 驱动实现填充DRIVER_OBJECT的MajorFunction数组将所有 IRP 主功能码指向统一的派发函数dispatch。设置DriverExtension-AddDevice为add_device。设置DriverUnload为unload。检测操作系统版本通过RtlGetVersion获取版本信息若为 Windows 8 及以上版本号 6.1则使用NonPagedPoolNx作为内存池类型否则使用NonPagedPool。这保证了驱动能通过 Windows 8 及更高版本的驱动验证测试要求非可执行分页池。3. 设备添加AddDevicelibusb_driver.cadd_device是驱动为每个物理设备创建功能设备对象FDO并附加到设备栈的入口。3.1 硬件过滤读取硬件 IDreg_get_hardware_id和兼容 ID。仅处理 USB 设备包含usb\且包含vid_和pid_跳过 USB 集线器含hub或class_09。检查已附加的设备驱动若存在picopp或libusb0则跳过避免重复绑定。检查是否存在 WDF 驱动如 WinUSB、WUDF若存在则设置has_wdf TRUE后续将禁止该设备成为电源策略拥有者防止蓝屏。3.2 创建设备对象与符号链接尝试创建设备名\Device\libusb0-xxxx循环 1 到LIBUSB_MAX_NUMBER_OF_DEVICES找到未使用的编号。创建符号链接\DosDevices\libusb0-xxxx供用户态CreateFile打开。设备扩展大小固定为sizeof(libusb_device_t)。3.3 初始化设备扩展libusb_device_t保存物理设备对象physical_device_object、设备编号、设备 ID。设置初始电源状态PowerDeviceD0和PowerSystemWorking。调用reg_get_properties从注册表读取关键配置SurpriseRemovalOK若为 DWORD 1则驱动作为功能驱动is_filter FALSE否则作为过滤驱动is_filter TRUE。InitialConfigValue指定初始配置值默认SET_CONFIG_ACTIVE_CONFIG即自动选择活动配置。DeviceInterfaceGUIDs用户指定的设备接口 GUID若不存在则使用默认 GUIDLibusb0DeviceGuid或Libusb0FilterGuid。若检测到has_wdf设置disallow_power_control TRUE禁止该驱动成为电源策略拥有者。调用clear_pipe_info清空端点缓存。初始化移除锁remove_lock_initialize。若设备接口启用调用IoRegisterDeviceInterface注册设备接口并在设备接口注册表中写入LUsb0值设备编号便于用户态快速打开。3.4 附着到设备栈调用IoAttachDeviceToDeviceStack将新创建的设备对象附着到物理设备对象之上。若成功则dev-next_stack_device指向下层设备。根据is_filter决定target_device过滤驱动target_device physical_device_object直接向 PDO 发送 URB。功能驱动target_device next_stack_device向栈中的下一设备发送。若支持LIBUSB_ENABLE_CONTRACT_VERSION_602Win8调用USBD_CreateHandle和USBD_QueryUsbCapability检测设备速度SuperSpeed/HighSpeed/FullSpeed。复制下层设备的标志DO_BUFFERED_IO、DO_DIRECT_IO、DO_POWER_PAGABLE确保兼容。最后清除DO_DEVICE_INITIALIZING标志设备可被打开。4. 设备扩展结构libusb_device_tlibusb_driver.h该结构是每个设备实例的上下文包含丰富的成员成员用途self本设备对象physical_device_object物理设备对象PDOnext_stack_device栈中的下层设备target_device实际发送 URB 的目标设备handleUSBD_HANDLEUSBD 句柄Win8remove_lock移除锁保护并发 PnP 操作is_filter/is_started驱动模式标志和设备启动状态surprise_removal_ok是否支持意外移除id设备编号用于符号链接device_descriptor缓存的设备描述符config当前配置信息句柄、值、索引、描述符缓存、接口数组power_state当前电源状态系统/设备device_power_states支持的各系统状态对应的设备状态initial_config_value初始配置值device_id硬件 ID 字符串disallow_power_control是否禁止成为电源策略拥有者device_interface_guid/device_interface_name设备接口 GUID 和名称control_read/write_timeout控制传输超时可由用户态设置speedUSB 速度Low/Full/High/Superpending_sequence/pending_busy用于保证端点传输顺序的原子变量5. IRP 分发dispatchdispatch.c所有 IRP 首先进入dispatch函数根据主功能码和当前设备状态分流IRP_MJ_PNP→dispatch_pnpIRP_MJ_POWER→dispatch_power若没有下层设备直接返回STATUS_INVALID_DEVICE_STATE对于其他 IRP检查是否属于本驱动accept_irpIRP_MJ_DEVICE_CONTROL若设备已启动调用dispatch_ioctl否则返回错误。IRP_MJ_CREATE若设备已启动若电源状态非 D0 且允许电源控制则调用power_set_device_state上电然后返回成功。IRP_MJ_CLOSE释放该文件对象绑定的所有接口release_all_interfaces。IRP_MJ_CLEANUP直接完成。其他 → 返回STATUS_NOT_SUPPORTED。若 IRP 不属于本驱动即发往下层设备则调用pass_irp_down向下传递。accept_irp判断依据若OriginalFileObject-DeviceObject dev-self或非过滤模式且设备接口启用且DeviceObject physical_device_object则接受。6. PnP 处理pnp.cdispatch_pnp处理各 PnP 子功能码IRP_MN_START_DEVICE调用PoSetPowerState通知电源管理器设备已进入 D0若设备接口启用调用IoSetDeviceInterfaceState(TRUE)启用接口最后将 IRP 向下传递并设置完成例程on_start_complete。在完成例程中若非过滤模式且尚未启动则根据initial_config_value调用set_configuration设置配置若配置值为SET_CONFIG_ACTIVE_CONFIG则尝试设置为活动配置。标记is_started TRUE。IRP_MN_REMOVE_DEVICE禁用设备接口设置is_started FALSE调用remove_lock_release_and_wait等待所有未决请求完成关闭 USBD 句柄向下传递 IRP最后删除符号链接、释放设备接口名称、释放缓存的配置描述符、分离设备对象并删除本设备对象。IRP_MN_SURPRISE_REMOVAL禁用设备接口释放接口名称清除配置缓存标记is_started FALSE。IRP_MN_STOP_DEVICE仅标记is_started FALSE不执行特殊操作直接向下传递。IRP_MN_DEVICE_USAGE_NOTIFICATION根据下层设备的DO_POWER_PAGABLE标志设置本设备对象标志向下传递并设置完成例程在完成后恢复标志。IRP_MN_QUERY_CAPABILITIES若非过滤模式将Capabilities-SurpriseRemovalOK设置为dev-surprise_removal_ok向下传递在完成例程中保存Capabilities-DeviceState到dev-device_power_states。其他 PnP IRP 直接向下传递。7. 电源管理power.c电源管理处理IRP_MJ_POWER特别是IRP_MN_SET_POWER。若设备为过滤驱动或disallow_power_control为真则设置完成例程on_filter_power_state_complete该例程仅记录电源状态变化并调用PoSetPowerState同步设备状态。若为功能驱动且允许电源控制则设置完成例程on_power_state_complete该例程在系统电源状态变化时根据dev-device_power_states映射表调用power_set_device_state更改设备状态非阻塞。对于设备电源状态变化若新状态低于当前状态如进入 D3在发送 IRP 前先调用PoSetPowerState通知电源管理器。power_set_device_state函数通过PoRequestPowerIrp发出设备电源设置 IRP可选择阻塞等待完成。该设计允许过滤驱动不干预电源策略而功能驱动可完全控制设备电源。8. 设备接口与注册表键值驱动在add_device阶段从注册表设备硬件键读取若干值SurpriseRemovalOK决定是否为功能驱动。InitialConfigValue决定启动后自动设置的配置。DeviceInterfaceGUIDs用户可指定设备接口 GUID否则使用默认值过滤驱动用Libusb0FilterGuid功能驱动用Libusb0DeviceGuid。驱动在启动/移除时调用IoSetDeviceInterfaceState启用/禁用接口使用户态程序可通过 SetupAPI 发现设备。9. 移除锁机制为防止设备在 PnP 移除过程中仍有 I/O 请求正在处理驱动实现了自定义移除锁libusb_remove_lock_tusage_count原子计数表示当前活跃的 I/O 请求数。remove_pending标记设备正在被移除。event事件对象用于等待所有请求完成。所有 IOCTL 处理函数在开始处理前调用remove_lock_acquire递增计数完成时调用remove_lock_release递减计数。当收到IRP_MN_REMOVE_DEVICE时调用remove_lock_release_and_wait将remove_pending设为 TRUE释放两次使计数可能减为 0然后等待事件直到所有请求释放。10. 总结第一篇文档涵盖了 libusb-win32 内核驱动的基础骨架入口与添加驱动如何初始化、创建设备对象、读取注册表配置并附着到设备栈。IRP 分发统一的派发函数根据 IRP 类型和驱动程序模式进行分发。PnP 处理完整响应启动、停止、移除、查询能力等关键 PnP 事件并自动配置设备。电源管理区分功能驱动与过滤驱动实现不同的电源策略处理。设备接口与移除锁保障设备可被用户态发现并安全处理并发移除。后续文档将深入分析IOCTL 处理、USB 传输、URB 提交、端点管理、描述符缓存等核心功能。

相关新闻

最新新闻

日新闻

周新闻

月新闻