WDF驅動中處理消息中斷(MSI)

I have been struggling with something similar in the last week. My application is slightly different because I am trying to get plain MSI interrupts rather than MSI-X interrupts to work. But I am using the WDF framework in pretty much the same way.
I realize you posted your original question around April of 2013, but there are no updates. Have you solved your original problem? If so, I would like to see your own solution.
In my WDF driver, I am mapping an incoming hardware resource list and parsing it using the WdfCmResourceListGetDescriptor() function to examine each PCM_PARTIAL_RESOURCE_DESCRIPTOR item in the WDFCMRESLIST list. I was able to obtain a single CmResourceTypeInterrupt descriptor, but it was always for a legacy interrupt instead of MSI interrupt. My device does support MSI. I did not understand why the MSI descriptor was not in the resource list, even after setting up the extra registry entries in my .inf file as you described.
It turns out I had a typo in my .inf file. I had forgotten to append the “.HW” suffix in my device install section. Adding this suffix allows the Bus manager to modify the pcie config addresses in the device and create the appropriate MSI interrupt resource descriptor, which must be hooked by the driver.
[Standard.NTARCH ]
%tdvr.DeviceDesc%=tdvr_Device, PCI\VEN_104C&DEV_B800

[tdvr_Device.NT]
CopyFiles=Drivers_Dir

[tdvr_Device.NT.HW]
AddReg=MSI_Interrupts

[Drivers_Dir]
tdvr.sys

;http://msdn.microsoft.com/en-us/library/windows/hardware/ff544246(v=vs.85).aspx
;To receive message-signaled interrupts (MSIs), a driver’s INF file must enable MSIs in the
;registry during installation. Use the Interrupt Management\MessageSignaledInterruptProperties
;subkey of the device’s hardware key to enable MSI support.

[MSI_Interrupts]
HKR,Interrupt Management,,0x00000010
HKR,Interrupt Management\MessageSignaledInterruptProperties,,0x00000010
HKR,Interrupt Management\MessageSignaledInterruptProperties,MSISupported,0x00010001,1
When the MSI interrupt resource descriptor is found in the resource list (for example in a evtMapHWResources callback), the descriptor is used as an input to the WdfInterruptCreate() function. The “tdvr” prefixes here are for my own driver naming convention.

NTSTATUS
tdvrConfigureInterrupts(
    _Inout_ PDEVICE_CONTEXT deviceContext,
    _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR interruptDescRaw,
    _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR interruptDescTranslated
    )
{
    NTSTATUS status;
    PAGED_CODE();
    FuncEntry();

    // What kind of interrupt has been provided?
    if (CM_RESOURCE_INTERRUPT_MESSAGE & interruptDescTranslated->Flags)
    {
        TraceInterrupt(TRACE_LEVEL_INFORMATION, 
            "Message Interrupt level 0x%0x, Vector 0x%0x, MessageCount %u\n"
            ,interruptDescTranslated->u.MessageInterrupt.Translated.Level
            ,interruptDescTranslated->u.MessageInterrupt.Translated.Vector
            ,interruptDescTranslated->u.MessageInterrupt.Raw.MessageCount
            );
    }
    else
    {
        TraceInterrupt(TRACE_LEVEL_INFORMATION,
            "Legacy Interrupt level: 0x%0x, Vector: 0x%0x\n"
            ,interruptDescTranslated->u.Interrupt.Level
            ,interruptDescTranslated->u.Interrupt.Vector
            );
    }

    //
    // Create WDFINTERRUPT object.
    //
    WDF_INTERRUPT_CONFIG interruptConfig;
    WDF_INTERRUPT_CONFIG_INIT(
        &interruptConfig,
        tdvrEvtInterruptIsr,
        tdvrEvtInterruptDpc
        );

    // Each interrupt has some context data
    WDF_OBJECT_ATTRIBUTES interruptAttributes;
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
        &interruptAttributes,
        INTERRUPT_CONTEXT
        );

    //
    // These first two callbacks will be called at DIRQL.  Their job is to
    // enable and disable interrupts.
    //
    interruptConfig.EvtInterruptEnable  = tdvrEvtInterruptEnable;
    interruptConfig.EvtInterruptDisable = tdvrEvtInterruptDisable;

    // If the driver calls WdfInterruptCreate from EvtDriverDeviceAdd, the InterruptRaw and
    // InterruptTranslated members of the WDF_INTERRUPT_CONFIG structure must be NULL. 
    // the driver calls WdfInterruptCreate from EvtDevicePrepareHardware, these members must both be valid.
    interruptConfig.InterruptTranslated = interruptDescTranslated;
    interruptConfig.InterruptRaw = interruptDescRaw;

    // Our driver must call WdfInterruptCreate once for each interrupt vector that its device requires. 
    // If the device supports message-signaled interrupts (MSI), the driver must create an interrupt object 
    // for each message that the device can support.
    status = WdfInterruptCreate(
        deviceContext->WdfDevice,
        &interruptConfig,
        &interruptAttributes,
        &deviceContext->WdfInterrupt
        );

    if (!NT_SUCCESS(status))
    {
        TraceInterrupt(TRACE_LEVEL_ERROR, "WdfInterruptCreate FAILED: %!STATUS!\n", status);
    }
    else
    {
        PINTERRUPT_CONTEXT interruptContext = InterruptGetContext(deviceContext->WdfInterrupt);
        // do whatever with context info
    }

    FuncExit();
    return status;
} 

Like I said hopefully by now you have this all figured out, but I thought I would post something anyway to contribute.

HKR,Interrupt Management\MessageSignaledInterruptProperties,MessageNumberLimit,0x00010001,8

useful link: https://msdn.microsoft.com/en-us/library/windows/hardware/ff544246(v=vs.85).aspx

注:和Linux有點不同的是,Windows使用註冊表支持MSI中斷,Linux裏面是使用代碼處理的,見:http://blog.csdn.net/juana1/article/details/6746011

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章