windows 驱动实例分析系列: libusb驱动分析-驱动层源码篇(一)
2026/9/1 7:40:09 网站建设 项目流程

libusb-win32 内核驱动源码分析(第一篇):驱动框架、PnP 与电源管理

1. 驱动概述

src/driver/目录包含 libusb-win32 的内核模式驱动程序libusb0.sys的完整实现。该驱动是一个 WDM(Windows 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_OBJECTMajorFunction数组,将所有 IRP 主功能码指向统一的派发函数dispatch
  • 设置DriverExtension->AddDeviceadd_device
  • 设置DriverUnloadunload
  • 检测操作系统版本:通过RtlGetVersion获取版本信息,若为 Windows 8 及以上(版本号 > 6.1),则使用NonPagedPoolNx作为内存池类型,否则使用NonPagedPool。这保证了驱动能通过 Windows 8 及更高版本的驱动验证测试(要求非可执行分页池)。

3. 设备添加AddDevicelibusb_driver.c

add_device是驱动为每个物理设备创建功能设备对象(FDO)并附加到设备栈的入口。

3.1 硬件过滤

  • 读取硬件 ID(reg_get_hardware_id)和兼容 ID。
  • 仅处理 USB 设备(包含usb\且包含vid_pid_),跳过 USB 集线器(含hubclass_09)。
  • 检查已附加的设备驱动,若存在picopplibusb0则跳过(避免重复绑定)。
  • 检查是否存在 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。
  • 设置初始电源状态PowerDeviceD0PowerSystemWorking
  • 调用reg_get_properties从注册表读取关键配置:
    • SurpriseRemovalOK:若为 DWORD 1,则驱动作为功能驱动is_filter = FALSE),否则作为过滤驱动is_filter = TRUE)。
    • InitialConfigValue:指定初始配置值(默认SET_CONFIG_ACTIVE_CONFIG,即自动选择活动配置)。
    • DeviceInterfaceGUIDs:用户指定的设备接口 GUID,若不存在则使用默认 GUID(Libusb0DeviceGuidLibusb0FilterGuid)。
  • 若检测到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_602(Win8+),调用USBD_CreateHandleUSBD_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物理设备对象(PDO)
next_stack_device栈中的下层设备
target_device实际发送 URB 的目标设备
handle(USBD_HANDLE)USBD 句柄(Win8+)
remove_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/Super)
pending_sequence/pending_busy用于保证端点传输顺序的原子变量

5. IRP 分发dispatchdispatch.c

所有 IRP 首先进入dispatch函数,根据主功能码和当前设备状态分流:

  • IRP_MJ_PNPdispatch_pnp
  • IRP_MJ_POWERdispatch_power(若没有下层设备,直接返回STATUS_INVALID_DEVICE_STATE
  • 对于其他 IRP,检查是否属于本驱动(accept_irp):
    • IRP_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.c

dispatch_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->DeviceStatedev->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_t):

  • usage_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 提交、端点管理、描述符缓存等核心功能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询