版权声明:本文采用【DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE】协议
由于PCI设备的多样化,而系统的中断数量是有限的。所以采用多个设备共用一个中断号。在获取到中断后,操作系统会询问这条中断线上的所以设备。设备通过查询中断寄存器就可以知道是不是自己的中断,如果不是则在中断处理例程中返回FALSE,如果是则处理并返回TRUE。
在操作系统收到IRP_MN_START_DEVICE请求时,PDO会获取到中断相关的资源。参考例子如下:
NTSTATUS GetPciResource(IN PDEVICE_EXTENSION pExtension, IN PCM_PARTIAL_RESOURCE_LIST list)
{
PDEVICE_OBJECT fdo = pExtension->fdo;
KINTERRUPT_MODE mode;
BOOLEAN irqshare;
BOOLEAN gotinterrupt = FALSE;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &list->PartialDescriptors[0];
ULONG nres = list->Count;
for (ULONG i = 0; i < nres; ++i, ++resource)
{ // for each resource
switch (resource->Type)
{ // switch on resource type
case CmResourceTypeInterrupt:
{
KdPrint(("resource->Type = CmResourceTypeInterrupt\n"));
pExtension->Irql = (KIRQL)resource->u.Interrupt.Level;
pExtension->Vector = resource->u.Interrupt.Vector;
pExtension->Affinity = resource->u.Interrupt.Affinity;
mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
irqshare = (resource->ShareDisposition == CmResourceShareShared);
gotinterrupt = TRUE;
}break;
default:
KdPrint(("Unexpected I/O resource type %d\n", resource->Type));
break;
} // switch on resource type
} // for each resource
return STATUS_SUCCESS;
}
- 3
获取到中断资源后,驱动程序可以使用IoConnectInterrupt将中断与中断处理函数挂接。IoConnectInterrupt的原型如下:
NTSTATUS IoConnectInterrupt(
_Out_ PKINTERRUPT *InterruptObject, //输出一个INTERRUPT结构的中断对象
_In_ PKSERVICE_ROUTINE ServiceRoutine, //中断处理例程
_In_opt_ PVOID ServiceContext, //中断处理例程的参数
_In_opt_ PKSPIN_LOCK SpinLock, //用于同步的自旋锁
_In_ ULONG Vector, //中断向量号,在PDO获得
_In_ KIRQL Irql, //中断优先级,在PDO获得
_In_ KIRQL SynchronizeIrql, //同IRQL
_In_ KINTERRUPT_MODE InterruptMode, //中断模式,Latched(电平触发),LevelSensitive (边沿触发)
_In_ BOOLEAN ShareVector, //是否与其他设备共享中断向量,设为TRUE
_In_ KAFFINITY ProcessorEnableMask,//CPU屏蔽位,在PDO获得
_In_ BOOLEAN FloatingSave //X86平台默认为FALSE
);
- 1
NTSTATUS status = IoConnectInterrupt(&pExtension->pInterruptObject, (PKSERVICE_ROUTINE)OnInterrupt,
(PVOID)pExtension, NULL, pExtension->Vector, pExtension->Irql, pExtension->Irql, LevelSensitive, TRUE, pExtension->Affinity, FALSE);
if (!NT_SUCCESS(status))
{
KdPrint(("IoConnectInterrupt failed - %X\n", status));
return status;
}
中断处理例程原型如下:
KSERVICE_ROUTINE InterruptService;
BOOLEAN InterruptService(
_In_ struct _KINTERRUPT *Interrupt,
_In_ PVOID ServiceContext
)
{ ... }
值得注意的是,如果不是自己设备产生的中断,一定要返回FALSE,如果是自己设备的中断,则必须清除掉中断。