首先在获得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 [in]
Caller-supplied pointer to a KDPC structure, which represents the DPC object that is associated with this CustomDpc routine.
DeferredContext [in, optional]
Caller-supplied pointer to driver-defined context information that was specified in a previous call to KeInitializeDpc.
SystemArgument1 [in, optional]
Caller-supplied pointer to driver-supplied information that was specified in a previous call to KeInsertQueueDpc.
SystemArgument2 [in, optional]
Caller-supplied pointer to driver-supplied information that was specified in a previous call to KeInsertQueueDpc.
这里DPC可以这样设计:
VOID DPCForISR(IN PKDPC Dpc,IN PVOID Context,IN PVOID fdo,IN PVOID pIrp)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)
((PDEVICE_OBJECT)fdo)->DeviceExtension;
KeAcquireSpinLock(&pdx->spinLock,&pdx->oldIrql);
//Int_stat 寄存器由硬件填写的
int_status = READ_REGISTER_ULONG((PULONG) &pdx->pHBARegs->Int_stat);
KdPrint(("interrupt!int status is 0x%0x\n",int_status));
while(int_status) //循环处理中断,直到处理完
{
if(int_status >= INT_RECV_0 && int_status <= INT_RECV_23)
{
RecvTask(pdx,int_status-1);
pdx->recint_cnt[int_status-1]++;
}
if(int_status >= INT_LINK0_BUILD && int_status <= INT_LINK3_BUILD)
{
pdx->rx_fc_desc_buf_virt[int_status-25]->link_state=1;
pdx->bldint_cnt[int_status-25]++;
KdPrint(("Build!int status is 0x%0x\n",int_status));
}
if(int_status >= INT_LINK0_BREAK && int_status <= INT_LINK3_BREAK)
{
pdx->rx_fc_desc_buf_virt[int_status-29]->link_state=0;
pdx->brkint_cnt[int_status-29]++;
}
pdx->intsw_cnt++;
int_status = READ_REGISTER_ULONG((PULONG) &pdx->pHBARegs->Int_stat);
KdPrint(("interrupt!int status is 0x%0x\n",int_status));
}
return ;
}
在DPC中完成具体的操作,这样中断处理就结束了。