Installable ISRs and Device Drivers

Other versions of this page are also available for the following:
Windows Mobile Not SupportedWindows Embedded CE Supported
8/28/2008

Installable interrupt service routines (ISRs) allow multiple devices to share interrupts and to share a single hardware platform interrupt request (IRQ). ISRs also extend the ability of the OS to process the device in the ISR in addition to the interrupt service thread (IST). If you want to allow interrupt sharing, you should update the ISRs for your device driver. If an installable ISR must recognize the device generating the input, you can usually use the generic installable ISR sample, GIISR.dll.

Because most devices indicate interrupt activity in a single register that is possibly masked, the sample installable ISR handler, GIISR.dll, is adequate for many devices. If necessary, you can write a custom installable ISR handler to implement complex interrupt detection.

You might choose to install an ISR to handle interrupts for the device. This is required if the interrupt is shared between two or more devices, which is a common occurrence with PCI devices. The installed ISR can be a generic routine that simply checks to see if the device is the one requesting service, or it can be a custom design. Giisr.dll is the generic installable ISR. If the IsrHandler and IsrDll values are provided in the device's registry key, then the driver should load the ISR DLL through the LoadIntChainHandler call.

After the ISR is loaded with LoadIntChainHandler, GIISR_INFO, defined in Giisr.h, is filled in and passed to the ISR through KernelLibIoControl IntChainHandlerIoControl with IOCTL_GIISR_INFO. The interrupt handler is unloaded with FreeIntChainHandler.

The following code example shows how to load the ISR DLL with LoadIntChainHandler.

#include <mkfuncs.h>
#include <giisr.h>
// InstallIsr is a flag that indicates that there is an ISR to be installed.
//        IsrDll is the ISR DLL name, obtained from the registry.
//        IsrHandler is the ISR function name, obtained from the registry.
//        IfcType is the bus interface type, obtained from the registry.
//        BusNumber is the PCI bus number, obtained from the registry.

// Install ISR handler if there is one.
if (InstallIsr) {
    // Install ISR handler
    g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);

    if (!g_IsrHandle) {
        DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: Couldn't install ISR handler\r\n"));
    } else {
        GIISR_INFO Info;
        PVOID PhysAddr;
        DWORD inIoSpace = 1;    // io space
        PHYSICAL_ADDRESS PortAddress = {ulIoBase, 0}; 

        if (!TransBusAddrToStatic(PCIBus, 0, PortAddress, ulIoLen, &inIoSpace, &PhysAddr)) {
            DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: Failed TransBusAddrToStatic\r\n"));
            return FALSE;
        }

        DEBUGMSG(ZONE_PDD, (L"WAVEDEV: Installed ISR handler, Dll = '%s', Handler = '%s', Irq = %d, PhysAddr = 0x%x\r\n", IsrDll, IsrHandler, Irq, PhysAddr));

        // Set up ISR handler
        Info.SysIntr = ulSysIntr;
        Info.CheckPort = TRUE;
        Info.PortIsIO = TRUE;
        Info.UseMaskReg = FALSE;
        Info.PortAddr = (DWORD)PhysAddr + ES1371_dSTATUS_OFF;
        Info.PortSize = sizeof(DWORD);
        Info.Mask = ES1371_INTSTAT_PENDING;

        if (!KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &Info, sizeof(Info), NULL, 0, NULL)) {
            DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: KernelLibIoControl call failed.\r\n"));
        }
    }
}
Show: