Using the CONNECT_FULLY_SPECIFIED Version of IoConnectInterruptEx

A driver can use the CONNECT_FULLY_SPECIFIED version of IoConnectInterruptEx to register an InterruptService routine for a specific interrupt. A driver can use the CONNECT_FULLY_SPECIFIED version starting with Windows Vista. By linking to the Iointex.lib library, the driver can use the CONNECT_FULLY_SPECIFIED version in Windows 2000, Windows XP, and Windows Server 2003. For more information, see Using IoConnectInterruptEx Prior to Windows Vista.

The driver specifies a value of CONNECT_FULLY_SPECIFIED for Parameters->Version and uses the members of Parameters->FullySpecified to specify the other parameters of the operation:

  • Parameters->FullySpecified.PhysicalDeviceObject specifies the PDO for the device that the ISR services.

  • Parameters->FullySpecified.ServiceRoutine points to the InterruptService routine, while Parameters->FullySpecified.ServiceContext specifies the value that the system passes as the ServiceContext parameter to InterruptService. The driver can use this to pass context information. For more information about passing context information, see Providing ISR Context Information.

  • The driver provides a pointer to a PKINTERRUPT variable in Parameters->FullySpecified.InterruptObject. The IoConnectInterruptEx routine sets this variable to point to the interrupt object for the interrupt, which can be used when removing the ISR.

  • Drivers can optionally specify a spin lock in Parameters->FullySpecified.SpinLock for the system to use when synchronizing with the ISR. Most drivers can just specify NULL to enable the system to allocate a spin lock on behalf of the driver. For more information about synchronizing with an ISR, see Synchronizing Access to Device Data.

The driver must specify the key properties of the interrupt in other members of Parameters->FullySpecified. The system provides the necessary information in the array of CM_PARTIAL_RESOURCE_DESCRIPTOR structures when it sends the IRP_MN_START_DEVICE IRP to the driver.

The system provides for each interrupt a CM_PARTIAL_RESOURCE_DESCRIPTOR structure with Type member equal to CmResourceTypeInterrupt. For a message-signaled interrupt, the CM_RESOURCE_INTERRUPT_MESSAGE bit of the Flags member is set; otherwise, it is cleared.

The u.Interrupt member of CM_PARTIAL_RESOURCE_DESCRIPTOR contains the description of a line-based interrupt, while the u.MessageInterrupt.Translated member contains the description of a message-signaled interrupt. The following table indicates where, in the CM_PARTIAL_RESOURCE_DESCRIPTOR structure, to find the information required to set the members of Parameters->FullySpecified for both types of interrupt. For more information, see the code example that follows the table.

Member Line-based interrupt Message-signaled interrupt

ShareVector

ShareDisposition

ShareDisposition

Vector

u.Interrupt.Vector

u.MessageInterrupt.Translated.Vector

Irql

u.Interrupt.Level

u.MessageInterrupt.Translated.Level

InterruptMode

Flags & CM_RESOURCE_INTERRUPT_LATCHED

Flags & CM_RESOURCE_INTERRUPT_LATCHED

ProcessorEnableMask

u.Interrupt.Affinity

u.MessageInterrupt.Translated.Affinity

A driver will only receive CM_PARTIAL_RESOURCE_DESCRIPTOR structures for message-signaled interrupts on Windows Vista and later versions of Windows.

The following code example demonstrates how to register an InterruptService routine using CONNECT_FULLY_SPECIFIED.

IO_CONNECT_INTERRUPT_PARAMETERS params;

// deviceExtension is a pointer to the driver's device extension. 
//     deviceExtension->IntObj is a PKINTERRUPT.
// deviceInterruptService is a pointer to the driver's InterruptService routine.
// IntResource is a CM_PARTIAL_RESOURCE_DESCRIPTOR structure of either type CmResourceTypeInterrupt or CmResourceTypeMessageInterrupt.
// PhysicalDeviceObject is a pointer to the device's PDO. 
// ServiceContext is a pointer to driver-specified context for the ISR.

RtlZeroMemory( &params, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS) );
params.Version = CONNECT_FULLY_SPECIFIED;
params.FullySpecified.PhysicalDeviceObject = PhysicalDeviceObject;
params.FullySpecified.InterruptObject = &devExt->IntObj;
params.FullySpecified.ServiceRoutine = deviceInterruptService;
params.FullySpecified.ServiceContext = ServiceContext;
params.FullySpecified.FloatingSave = FALSE;
params.FullySpecified.SpinLock = NULL;

if (IntResource->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
    // The resource is for a message-signaled interrupt. Use the u.MessageInterrupt.Translated member of IntResource.
 
    params.FullySpecified.Vector = IntResource->u.MessageInterrupt.Translated.Vector;
    params.FullySpecified.Irql = (KIRQL)IntResource->u.MessageInterrupt.Translated.Level;
    params.FullySpecified.SynchronizeIrql = (KIRQL)IntResource->u.MessageInterrupt.Translated.Level;
    params.FullySpecified.ProcessorEnableMask = IntResource->u.MessageInterrupt.Translated.Affinity;
} else {
    // The resource is for a line-based interrupt. Use the u.Interrupt member of IntResource.
 
    params.FullySpecified.Vector = IntResource->u.Interrupt.Vector;
    params.FullySpecified.Irql = (KIRQL)IntResource->u.Interrupt.Level;
    params.FullySpecified.SynchronizeIrql = (KIRQL)IntResource->u.Interrupt.Level;
    params.FullySpecified.ProcessorEnableMask = IntResource->u.Interrupt.Affinity;
}

params.FullySpecified.InterruptMode = (IntResource->Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive);
params.FullySpecified.ShareVector = (BOOLEAN)(IntResource->ShareDisposition == CmResourceShareShared);

status = IoConnectInterruptEx(&params);

if (!NT_SUCCESS(status)) {
    ...
}