Windows 驱动示例(Windows-driver-samples)GPIO 开发实战:基于 GpioClx 的控制器驱动与外围设备驱动
发布时间:2026/9/27 9:01:34来源:尧图网络
示例工程【免费下载链接】Windows-driver-samplesThis repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.项目地址https://gitcode.com/gh_mirrors/wi/Windows-driver-samples点击查看免费下载GPIO通用输入/输出驱动是 Windows SoC 平台上最常见的驱动类型之一本文以微软 Windows-driver-samples 仓库gpio/samples目录下的四组官方示例为核心系统讲解如何编写与 GPIO 框架扩展GpioClx协作的 GPIO 控制器驱动controller driver以及消费 GPIO 资源的外围设备驱动peripheral driver。读完本文你将掌握 GpioClx DDI 的注册回调机制、内存映射与 I2C 两类 GPIO 控制器的驱动实现差异、内核态与用户态 GPIO I/O 与中断的消费方式以及 ACPI 固件中 GPIO 中断/IO 描述符ASL的编写方法。示例集全景四个示例的分工与定位根据 gpio/samples/README.md该示例集包含四个独立示例全部采用带详细注释的代码编写目的“纯粹用于教学”purely instructional。它们覆盖了 GPIO 驱动栈的两端——控制器驱动供 GpioClx 使用与外围设备驱动消费 GPIO 资源示例说明SimGpioGPIO 控制器驱动通过 GpioClx 设备驱动接口DDI与 GpioClx 通信面向一个假想的内存映射GPIO 控制器simgpio。随附 ASL 文件演示如何在 ACPI 固件中描述 GPIO 中断与 I/O 描述符。SimGpio_I2CGPIO 控制器驱动同样通过 GpioClx DDI 与 GpioClx 通信但控制器并非内存映射而是挂在 I2C 总线上的假想设备simgpio_i2c。随附 ASL 文件演示 ACPI 固件中的 GPIO 描述符。SimDevice\kmdf演示内核态驱动如何打开设备、对 GPIO 控制器执行 I/O 操作并连接 GPIO 中断资源。SimDevice\umdf演示用户态驱动如何打开设备、对 GPIO 控制器执行 I/O 操作并连接 GPIO 中断资源。四个示例被组织在一个解决方案文件 sim.sln 中目录结构如下simgpio内存映射 GPIO 控制器驱动simgpio.c、simgpio.inx、simgpio.vcxprojsimgpio_i2cI2C 总线 GPIO 控制器驱动simgpio_i2c.c、simgpio_i2c.h、spb_i2c.c、trace.h等simdevice外围设备驱动同一份simdevice.ccommon.h通过条件编译同时产出 KMDF 与 UMDF 两个版本GpioClx 架构控制器驱动与类扩展的分工Windows 的 GPIO 驱动支持体系分为三层参见 GpioClx 驱动支持概述GPIO 类扩展GpioClx由系统提供的类驱动程序负责处理 GPIO I/O 控制请求、中断管理、电源管理框架交互等通用逻辑向上对操作系统暴露统一接口GPIO 控制器驱动client driver由厂商实现通过 GpioClx DDIgpioclx.h注册一组回调函数操作真实的控制器寄存器外围设备驱动peripheral driver消费 GPIO 引脚的外设驱动通过 Resource Hub / GPIO 抽象gpio.h、reshub.h打开 GPIO 引脚并执行读写或连接中断。SimGpio 与 SimGpio_I2C 属于第 2 层SimDevice 属于第 3 层四者合起来构成一条完整的教学链路。SimGpio内存映射 GPIO 控制器驱动假想的寄存器模型simgpio.c 的文件头注释完整定义了 simgpio 控制器的硬件模型4 个 bank每个 bank 32 个引脚共 128 个引脚任意引脚可配置为中断、输入或输出。每个 bank 的寄存器在物理内存中相邻排布偏移与大小如下寄存器偏移大小语义ModeRegister0x04 字节中断模式Level 0x1 或 Edge 0x0PolarityRegister0x48 字节电平触发ActiveLow 0x0 / ActiveHigh 0x1边沿触发Falling 0x0 / Rising 0x1 / Both-Edges 0x3每引脚占 2 位EnableRegister0xC4 字节中断使能位掩码StatusRegister0x104 字节当前正在产生中断的引脚位图任一位置位即触发控制器中断DirectionRegister0x144 字节方向input 0x1 / output 0x0LevelRegister0x184 字节引脚电平值位图高 0x1 / 低 0x0对应到代码中的结构体SIM_GPIO_REGISTERSsimgpio.c其中PolarityRegister是长度为 2 的 ULONG 数组以容纳每引脚 2 位的极性字段。宏定义SIM_GPIO_TOTAL_PINS (4 * 32)、SIM_GPIO_PINS_PER_BANK (32)、SIM_GPIO_TOTAL_BANKS (4)simgpio.c与寄存器模型一一对应。DriverEntry 与注册包GPIO_CLIENT_REGISTRATION_PACKET控制器驱动与 GpioClx 协作的第一步是在DriverEntry中填充并提交GPIO_CLIENT_REGISTRATION_PACKETsimgpio.c设置Version GPIO_CLIENT_VERSION、Size并指定ControllerContextSize sizeof(SIM_GPIO_CONTEXT)由类扩展为设备扩展上下文分配内存注册通用接口回调CLIENT_PrepareController、CLIENT_QueryControllerBasicInformation、CLIENT_StartController、CLIENT_StopController、CLIENT_ReleaseController注册中断回调CLIENT_EnableInterrupt、CLIENT_DisableInterrupt、CLIENT_MaskInterrupts、CLIENT_UnmaskInterrupt、CLIENT_ReconfigureInterrupt、CLIENT_QueryActiveInterrupts、CLIENT_QueryEnabledInterrupts、CLIENT_ClearActiveInterrupts注册 I/O 回调CLIENT_ConnectIoPins、CLIENT_DisconnectIoPins、CLIENT_ReadGpioPinsUsingMask、CLIENT_WriteGpioPinsUsingMask最后调用GPIO_CLX_RegisterClient(Driver, RegistrationPacket, RegistryPath)完成注册。设备创建走“前后两段式”流程EvtDeviceAdd中先调GPIO_CLX_ProcessAddDevicePreDeviceCreate再WdfDeviceCreate最后调GPIO_CLX_ProcessAddDevicePostDeviceCreatesimgpio.c。卸载时在SimGpioEvtDriverUnload中调用GPIO_CLX_UnregisterClientsimgpio.c。资源解析与控制器准备SimGpioPrepareControllersimgpio.c遍历WdfCmResourceListGetDescriptor得到的翻译后资源列表CmResourceTypeMemory将第一个内存资源作为寄存器基址用MmMapIoSpaceEx(..., PAGE_NOCACHE | PAGE_READWRITE)映射为虚拟地址并要求长度至少为4 * sizeof(SIM_GPIO_REGISTERS)CmResourceTypeInterrupt仅计数控制器中断的实际连接由类扩展完成但驱动必须确保至少描述了 4 个中断资源对应 4 个 bank 的中断CmResourceTypePort意外的 IO 端口资源会直接导致初始化失败。需要注意代码中有一段显式标注的SIMGPIO HACKsimgpio.c由于 simgpio 不是真实硬件当没有内存资源时驱动会把寄存器“映射”到一个软件全局结构体GlobalGpioRegisters上用于测试真实控制器驱动绝不能这样做。同理SimGpioQueryActiveInterrupts中会把使能寄存器值复制到状态寄存器来“伪造”中断发生simgpio.c注释同样强调真实硬件不可如此。控制器基本信息与关键标志位SimGpioQueryControllerBasicInformationsimgpio.c向类扩展报告控制器属性各标志位的含义与影响是学习重点TotalPins 128、NumberOfPinsPerBank 32Flags.MemoryMappedController TRUE声明控制器可被直接内存访问因此中断回调可在 DIRQL 运行若控制器挂在串行总线上则必须为 FALSE对比 SimGpio_I2CFlags.IndependentIoHwSupported TRUE声明 I/O 寄存器与中断处理寄存器可独立访问类扩展会跳过 I/O 路径上的中断锁获取以优化性能——注释特别警告若硬件不支持 I/O 与中断并行处理会引发不可预测的竞态条件Flags.ActiveInterruptsAutoClearOnRead 0状态寄存器必须在读后显式清除Flags.FormatIoRequestsAsMasks 1驱动希望以位掩码形式接收 I/O 请求直接映射寄存器操作Flags.DeviceIdlePowerMgmtSupported FALSE控制器不支持设备级 D-state 电源管理Flags.BankIdlePowerMgmtSupported由ENABLE_F_STATE_POWER_MGMT宏控制开启时置 TRUEFlags.EmulateActiveBoth TRUE驱动希望由类扩展模拟 ActiveBoth 中断语义因此驱动自身的 Enable/Reconfigure 回调只需处理 ActiveHigh 与 ActiveLow见 simgpio.c。中断回调的实现要点内存映射控制器的中断回调遵循“DIRQL 与 PASSIVE_LEVEL 分层”的同步规则SimGpioEnableInterrupt/SimGpioDisableInterrupt在 PASSIVE_LEVEL 被调用线程上下文必须通过GPIO_CLX_AcquireInterruptLock/GPIO_CLX_ReleaseInterruptLock显式获取中断锁后再读写寄存器simgpio.cSimGpioMaskInterrupts/SimGpioUnmaskInterrupt/SimGpioQueryActiveInterrupts/SimGpioClearActiveInterrupts/SimGpioReconfigureInterrupt在 DIRQL中断上下文被调用此时类扩展已持有中断锁驱动不得重复加锁。Mask 对 simgpio 而言等价于清 EnableRegister 对应位且内存映射控制器必然成功故FailedMask恒为 0simgpio.c使能流程的寄存器操作顺序值得借鉴先写 ModeRegister电平/边沿、再写 PolarityRegister极性每引脚 2 位、清除状态寄存器中的陈旧位、最后置位 EnableRegistersimgpio.c。F-state 电源管理演示通过ENABLE_F_STATE_POWER_MGMT宏simgpio.c可开启 bank 级 F-state 电源管理这是本示例独有的教学点宏开启时注册CLIENT_QuerySetControllerInformation、CLIENT_SaveBankHardwareContext、CLIENT_RestoreBankHardwareContextsimgpio.cSimGpioQuerySetControllerInformation响应QueryBankPowerInformation请求报告F1StateSupported TRUE及 F1 状态参数NominalPower 0、ResidencyRequirement 8 小时、TransitionLatency 1 小时simgpio.c注释说明这些“极大”的驻留/延迟值用于防止 mini-PEP 在系统进入 Connected Standby 之外做运行时空闲电源管理若确实需要 bank 级运行时电源管理应改为合理数值StartController/StopController根据RestoreContext/SaveContext参数决定是恢复已保存的 bank 上下文还是先把 EnableRegister 清零以防未注册驱动的中断造成中断风暴simgpio.c。SimGpio_I2C串行总线上的 GPIO 控制器驱动SimGpio_I2C 与 SimGpio 共享同一套回调骨架DriverEntry 中注册的回调几乎一致差异完全源于“控制器不是内存映射的”这一事实寄存器模型与访问方式simgpio_i2c.c 的硬件模型为2 个 bank × 8 引脚 16 个引脚见 simgpio_i2c.h寄存器全部为 1 字节宽地址 0x0–0x5 对应引脚 0–7 的一组寄存器0x6–0xB 对应引脚 8–15simgpio_i2c.c寄存器引脚 0–7 / 引脚 8–15地址大小ModeRegister1 / ModeRegister20x0 / 0x61 字节PolarityRegister1 / PolarityRegister20x1 / 0x71 字节EnableRegister1 / EnableRegister20x2 / 0x81 字节StatusRegister1 / StatusRegister20x3 / 0x91 字节DirectionRegister1 / DirectionRegister20x4 / 0xA1 字节LevelRegister1 / LevelRegister20x5 / 0xB1 字节由于控制器在 I2C 总线上驱动无法用READ_REGISTER_ULONG直读而是在设备扩展中保存SpbIoTarget、SpbConnectionId、SpbRequestsimgpio_i2c.h通过 SPB简单外设总线连接以SimGpioSpbReadByte/SimGpioSpbWriteByte逐个字节地访问寄存器声明见 simgpio_i2c.h。驱动还启用了 WPP 软件跟踪WPP_INIT_TRACING及trace.h便于调试。与内存映射版本的关键差异SimGpioQueryControllerBasicInformationsimgpio_i2c.c中的标志位设置完整呈现了两类控制器的差异Flags.MemoryMappedController FALSE控制器在 SoC 之外、位于 I2C 总线之后只能在 PASSIVE_LEVEL 被服务——因此所有中断回调都在 PASSIVE_LEVEL 运行且由类扩展保证与其他回调的同步Flags.ActiveInterruptsAutoClearOnRead FALSE状态寄存器需显式清除Flags.FormatIoRequestsAsMasks TRUE仍以位掩码形式接收 I/O 请求Flags.DeviceIdlePowerMgmtSupported FALSE、Flags.BankIdlePowerMgmtSupported FALSE注释明确指出F-state 管理仅支持片上on-SoCGPIO 控制器所以本示例完全不注册 F-state 相关回调Flags.EmulateActiveBoth TRUE同样请求类扩展模拟 ActiveBoth该控制器硬件本身不支持 ActiveBoth见 simgpio_i2c.c。SimDevice内核态/用户态外围设备驱动SimDevice 站在 GPIO 资源消费端展示外围驱动如何从系统拿到 GPIO 引脚并操作。同一份 simdevice.c 通过_KERNEL_MODE宏同时编译出 KMDF 与 UMDF 两个版本common.h 根据宏选择windows.h或ntddk.hsimdevice.c 中 KMDF 版本注册 DPCUMDF 版本传 NULL因为 UMDF 的 ISR 在 PASSIVE_LEVEL 运行。解析 GPIO 连接资源SampleDrvEvtDevicePrepareHardwaresimdevice.c遍历资源列表识别类型为CmResourceTypeConnection、且Class CM_RESOURCE_CONNECTION_CLASS_GPIO、Type CM_RESOURCE_CONNECTION_TYPE_GPIO_IO的描述符把其中的IdLowPart/IdHighPart保存为连接 ID同时统计CmResourceTypeInterrupt数量并要求至少 1 个中断资源。示例外围设备最多消费 2 个 GPIO IO 连接MAX_NUMBER_IO_RESOURCES第一个用于输入、第二个用于输出。通过 IOCTL 读写 GPIO 引脚SampleDrvEvtDeviceD0Entrysimdevice.c演示了完整的 I/O 流程用RESOURCE_HUB_CREATE_PATH_FROM_ID把连接 ID 构造成设备路径字符串创建 WDF I/O 目标WdfIoTargetOpen以FILE_GENERIC_READ或FILE_GENERIC_WRITE打开用WdfIoTargetFormatRequestForIoctl构造IOCTL_GPIO_READ_PINS或IOCTL_GPIO_WRITE_PINS请求WdfRequestSend同步发送超时 60 秒WDF_REL_TIMEOUT_IN_SEC(60)。其中TestReadWrite工具函数simdevice.c集中展示了 WDF 内存对象、请求对象、I/O 目标的创建与清理规范。ISRSampleDrvInterruptIsr恒定返回 TRUE 声明中断示例假设中断线不与其它设备共享DPC 回调保留为空并在注释中说明了真实驱动应在 ISR 中消除中断源、需要时调度 DPC 的处理方式simdevice.c。ACPI 固件描述GPIO 中断与 I/O 描述符ASL示例随附两份几乎相同的 DSDT 片段用于在 ACPI 固件中描述 GPIO 控制器和外围设备分别是 GpioSampleKMDF.asl 与 GpioSampleUMDF.asl其差异仅在于外围设备的 PNP ID 与所用引脚号。GPIO 控制器设备_HID TEST0001的_CRS描述了两个关键资源以 KMDF 版为例GpioSampleKMDF.asl中断资源4 个共享的 Level、ActiveHigh 中断——bank 0/1 共享中断 50bank 2/3 共享中断 51与驱动PrepareController中“至少 4 个中断资源”的校验对应内存资源Memory32Fixed(ReadWrite, 0x00100000, 0x18)即控制器寄存器基址 0x100000、长度 0x18对应 4 个 bank 的寄存器组大小。外围设备TDEV的_CRS则演示了 GPIO 资源宏的用法GpioSampleKMDF.asl// GPIO 中断资源边沿触发、ActiveHigh、共享、上拉 GpioInt(Edge, ActiveHigh, Shared, PullUp, 0, \_SB.GPIO, 0, ResourceConsumer,, RawDataBuffer() {1}) {1} // GPIO IO 资源独占、上拉 GpioIo(Exclusive, PullUp, 0, 0,, \_SB.GPIO,0, ResourceConsumer, , RawDataBuffer() {1}) {10} GpioIo(Exclusive, PullUp, 0, 0,, \_SB.GPIO,0, ResourceConsumer, , RawDataBuffer() {1}) {11}其中RawDataBuffer() {1}是传给驱动EnableParameters-VendorData的厂商自定义数据在 simgpio.c 的注释中有说明。UMDF 版对应改用引脚 2中断、12 和 13I/OPNP ID 为TEST0004KMDF 版为TEST0003并与各自的 .inx 文件配对。ASL 头部注释特别提醒内存与中断描述、PNP ID 均为演示用途实际平台必须按真实 GIC 与内存布局修改。构建与安装构建所有示例均为 Visual Studio Windows Driver KitWDK工程.vcxproj可直接在 Visual Studio 中打开 sim.sln 生成。SimGpio、SimGpio_I2C 为内核驱动SimDevice 的 kmdf/umdf 子目录分别产出内核态与用户态版本。安装 INF每个驱动都带有一个.inx文件WDK 构建时处理为.inf。以 simgpio.inx 为例它声明ClassSystem、ClassGuid{4d36e97d-e325-11ce-bfc1-08002be10318}通过硬件 IDACPI\TEST0001与 ASL 中的_HID匹配完成设备绑定并将simgpio.sys注册为内核服务SERVICE_DEMAND_START按需启动。固件配合SimGpio / SimGpio_I2C 依赖 ACPI 固件中的_CRS描述见上一节 ASL 片段SimDevice 则依赖 GPIO 控制器设备下的外围设备节点TEST0003/TEST0004来获得 GPIO 连接与中断资源。小结四步掌握 Windows GPIO 驱动开发通过这组示例可以提炼出可复用的学习路径理解分层GpioClx 负责通用逻辑控制器驱动只实现寄存器级回调GPIO_CLIENT_*函数指针族外围驱动通过 Resource Hub 与IOCTL_GPIO_READ_PINS/IOCTL_GPIO_WRITE_PINS消费引脚区分总线类型内存映射控制器SimGpio支持 DIRQL 回调与 F-state 电源管理串行总线控制器SimGpio_I2C所有回调降到 PASSIVE_LEVEL 且不支持 F-state——这一差异完全由MemoryMappedController标志位驱动掌握同步规则PASSIVE_LEVEL 回调需显式获取中断锁GPIO_CLX_AcquireInterruptLockDIRQL 回调由类扩展持锁调用驱动不得重复加锁补齐固件视角通过 ASL 的GpioInt/GpioIo资源宏将控制器、中断、引脚号与驱动代码对应起来形成“固件 → 类扩展 → 控制器驱动 → 外围驱动”的完整闭环。后续深入时建议对照simgpio.c的注册包GPIO_CLIENT_REGISTRATION_PACKET、simgpio_i2c.c的 SPB 读写实现与simdevice.c的 WDF I/O 目标管理逐函数比对两个控制器版本之间的回调实现差异这是理解 GpioClx 行为模型最有效的方式。赞分享示例工程【免费下载链接】Windows-driver-samplesThis repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.项目地址https://gitcode.com/gh_mirrors/wi/Windows-driver-samples点击查看免费下载相关推荐TADS-Boilerplate进阶教程使用Jinja2模板定制Docker Swarm服务配置TADS Boilerplate进阶教程使用Jinja2模板定制Docker Swarm服务配置 想要快速部署和管理Docker Swarm集群吗TADSLaravel-Acl缓存策略终极指南提升权限检查性能的10个实用技巧Laravel Acl缓存策略终极指南提升权限检查性能的10个实用技巧 Laravel Acl是一个轻量级的基于角色的权限系统专为Laravel 6设计。Windows 驱动开发实战基于 KMDF 编写 Non-PnP 驱动并处理四种 IOCTLWindows-driver-samples 的 ioctl/kmdf 示例深度解析Windows 驱动开发实战基于 KMDF 编写 Non PnP 驱动并处理四种 IOCTLWindows driver samples 的 ioctl/k示例工程上一篇Windows 12 网页版终极主题编辑器开发指南打造个性化桌面体验下一篇FontForge完全指南如何用这款免费开源字体编辑器打造专业级字体创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网