作为选项,常规用途 I/O (GPIO) 控制器的驱动程序可以为 GPIO 中断提供支持。 为了支持 GPIO 中断,GPIO 控制器驱动程序实现一组回调函数来管理这些中断。 驱动程序在将自身注册为 GPIO 框架扩展客户端(GpioClx)时,在注册数据包中包含指向这些回调函数的指针。 有关此注册数据包的详细信息,请参阅 GPIO_CLIENT_REGISTRATION_PACKET。
通常情况下,作为芯片系统 (SoC) 集成部分的 GPIO 控制器具有内存映射的硬件寄存器,可以被 SoC 芯片中的处理器直接访问。 但是,单独的 GPIO 控制器设备可以通过串行总线在外部连接到 SoC 芯片,如下图所示。
在此图中,外部 GPIO 控制器已连接到 I IoC 总线。 此总线由属于 SoC 芯片的集成部分的 I IoC 总线控制器控制。 来自外部 GPIO 控制器的中断请求行连接到集成 GPIO 控制器上的引脚。 在此示例中, GpioClx DDI 可以同时容纳集成的 GPIO 控制器和外部 GPIO 控制器。
如果 GPIO 控制器设备是内存映射的,GPIO 控制器驱动程序可以直接在 DIRQL 上访问控制器的硬件寄存器。 但是,如果 GPIO 控制器是串行连接的,则 GPIO 控制器驱动程序只能访问硬件注册在 IRQL = PASSIVE_LEVEL,如 Passive-Level ISR 中所述。
具有内存映射硬件寄存器的 GPIO 控制器的驱动程序应在驱动程序提供给 GpioClx 的设备信息中设置 MemoryMappedController 标志位。 否则,GpioClx 假定这些硬件寄存器不是内存映射的,并且驱动程序只能在 IRQL = PASSIVE_LEVEL 访问这些寄存器。 有关此标志位的详细信息,请参阅 CONTROLLER_ATTRIBUTE_FLAGS。
GpioClx 实现中断服务例程(ISR),以服务来自 GPIO 控制器的中断请求。 此 ISR 调用以下与中断相关的回调函数:
CLIENT_ClearActiveInterruptsCLIENT_MaskInterruptsCLIENT_QueryActiveInterruptsCLIENT_QueryEnabledInterruptsCLIENT_UnmaskInterrupt 这些函数根据 GpioClx 中的 ISR 是在 DIRQL 还是在 PASSIVE_LEVEL 运行,可以在 DIRQL 或 PASSIVE_LEVEL 调用。 如果 MemoryMappedController = 1,则 ISR 在 DIRQL 级别调用这些函数;如果 MemoryMappedController = 0,则在 PASSIVE_LEVEL 级别调用。 在任一情况下,ISR 都会自动序列化其回调,以便对其中一个函数的调用不会在调用其中另一个函数的中间发生。
GPIO 框架扩展仅在 PASSIVE_LEVEL 调用以下与中断有关的回调函数,而不考虑是否设置了 MemoryMappedController 标志:
CLIENT_DisableInterruptCLIENT_EnableInterrupt 如果未设置 MemoryMappedController 标志,则会在PASSIVE_LEVEL调用与中断相关的所有回调函数。 GpioClx 自动序列化对这些函数的调用,以便调用其中一个函数不会在调用其中另一个函数时发生。
但是,如果设置了 MemoryMappedController 标志, 则CLIENT_EnableInterrupt 和 CLIENT_DisableInterrupt 函数必须将中断启用和禁用作显式同步到 GpioClx ISR,后者在 DIRQL 上调用其他四个与中断相关的回调函数。
通常,其他 CLIENT_Xxx 回调函数(其名称不包含“中断”)不执行与中断相关的处理,因此不需要同步到 GpioClx ISR。 但是,如果在PASSIVE_LEVEL调用这些函数中的任何一个,并且代码包含访问由DIRQL层中断相关函数所访问的中断设置,则必须将此代码与ISR同步。
为了支持中断同步,GpioClx 实现一组中断锁。 在PASSIVE_LEVEL运行的回调函数可以调用 GPIO_CLX_AcquireInterruptLock 方法来获取中断锁,并调用 GPIO_CLX_ReleaseInterruptLock 方法来释放锁。 当函数保存中断锁时,GpioClx ISR 无法运行,并且此 ISR 无法调用任何与中断相关的回调函数。 若要使 GPIO 中断能够及时处理,驱动程序应将中断锁保留的时间不超过必要时间。
有关详细信息,请参阅 GPIO 控制器驱动程序的中断同步。