此部分内容参考《Windows驱动开发技术详解》第16章 16.6.2
首先在获得PCI配置空间资源的时候,就要获得中断资源,根据CM_PARTIAL_RESOURCE_DESCRIPTOR 结构的 Type 域来区分需要获得什么样的中断资源的时候,如果Type类型为:CmResourceTypeInterrupt,此时需要将中断资源从CM_PARTIAL_RESOURCE_DESCRIPTOR中取出:
irql = (KIRQL) resource->u.Interrupt.Level; //中断级别
vector = resource->u.Interrupt.Vector; // 中断向量
affinity = resource->u.Interrupt.Affinity;
mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
? Latched : LevelSensitive;
irqshare = resource->ShareDisposition == CmResourceShareShared;
gotinterrupt = TRUE;
获取以上这些信息之后我们就可以注册中断,通过IoConnectInterrupt()函数来实现:
函数定义如下:
IoConnectInterrupt(
OUT PKINTERRUPT *InterruptObject,//指向驱动程序提供的中断对象存储地址,该参数随后
//要传递给KeSynchronizeExecution。
OUT PKSERVICE_ROUTINE ServiceRoutine,//中断服务例程的入口
IN PVOID ServiceContext, //指向驱动指定的即将传递给ISR的参数,ServiceContext必须在
//常驻内存中,可以是驱动程序创建的设备驱动的设备扩展,也可
//以是驱动创建的控制对象的控制拓展,还可以是设备驱动分配的
//非分页内存。
IN PKSPIN_LOCK SpinLock OPTIONAL,//指向已经初始化的自旋所,驱动程序负责自旋所的存
//储,并且该自旋所将用来同步被驱动程序其它例程共
//享的数据的访问,该参数在ISR处理多个中断向量或
//者驱动程序包含不止一个ISR时需要设置,否则,驱
//动程序不需要为中断自旋所分配存储空间,参数设置
//为NULL。
IN ULONG Vector, //输入获取的中断向量
IN KIRQL Irql, //输入获取的中断优先级DIRQL
IN KIRQL SynchronizeIrql, //指明ISR执行所在的DIRQL,当ISR需要处理多个中断
//向量或者驱动程序有多个ISR的时候,该值选择全部中
//断资源的u.Interrupt.Level中的最高值,否则和上面的
//Irql变量相等。
IN KINTERRUPT_MODE InterruptMode,//电平触发或者边沿触发
IN BOOLEAN ShareVector, //指明中断向量是否是可共享的。
IN KAFFINITY ProcessorEnableMask,//指定一个KAFFINITY值,用来说明设备中断可以在什
//么样的处理器平台上发生。
IN BOOLEAN FloatingSave //指明是否需要保存设备中断时的浮点堆栈,在X86平
//台下,该值必须是FALSE。
);
实际使用时:
status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE)
ISRInterrupt,(PVOID)pdx, NULL, vector, irql, irql, mode,
irqshare, affinity, FALSE);
第二个参数为我们自定义的中断服务例程,当驱动通过这个函数接收中断,之后调用相应的DPC(deferred procedure calls,延迟过程调用)处理函数,DPC的使用主要是为了提高处理效率。但是首先要注册DPC处理函数,通过:
VOID KeInitializeDpc(
__out PRKDPC Dpc,
__in PKDEFERRED_ROUTINE DeferredRoutine,
__in_opt PVOID DeferredContext
);
来实现注册DPC处理函数。
实际应用:
KeInitializeDpc(&pdx->fdo->Dpc,DPCForISR,NULL);
BOOLEAN ISRInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx)
{
//中断响应,通知硬件该中断已经处理,不用再发该中断
WRITE_REGISTER_ULONG((PULONG) &pdx->pHBARegs->IntrMask,0x00000001);
pdx->inthw_cnt++;
KeInsertQueueDpc(&pdx->fdo->Dpc,pdx->fdo,pdx->fdo->CurrentIrp );
return TRUE;
}
在该函数中,将中断请求插入到中断处理队列中,交由DPC来处理
BOOLEAN KeInsertQueueDpc(
__inout PRKDPC Dpc,
__in_opt PVOID SystemArgument1,
__in_opt PVOID SystemArgument2
);
DPC的标准格式为:
KDEFERRED_ROUTINE CustomDpc;
VOID CustomDpc(
__in struct _KDPC *Dpc,
__in_opt PVOID DeferredContext,
__in_opt PVOID SystemArgument1,
__in_opt PVOID SystemArgument2
)
{ ... }
这里DPC可以这样设计:
VOID DPCForISR(IN PKDPC Dpc,IN PVOID Context,IN PVOID fdo,IN PVOID pIrp)
{
KdPrint(("DPCForISR"));
}