1

WDF / KMDF で作成している Windows バス ドライバーに MSI-X 割り込みを実装するのに苦労しています。MSDN のドキュメントを読みましたが、役立つ情報はあまりありません。私の理解では、それは本当に「うまくいく」べきだということです。

ドライバーの INF ファイルを変更して適切なレジストリ キーを追加し、インストール時に適切に機能するように設定されていることを確認しました。PCI 構成スペースを適切に照会し、MSI-X 割り込みがサポートされているかどうかを判断しています。

問題は、この情報を取得した後、割り込みを MSI-X に設定するようにコードを変更する方法がわからないことです。WDF_INTERRUPT_CONFIG_INIT stuct を構成し、WdfInterruptCreate を呼び出す標準的な呼び出しを行いますが、作成される割り込みはメッセージ シグナルではなく、実際にこれを実現するために何をする必要があるかわかりません。

ここに手順の WDF バージョンがありますか、それとも標準の WDFINTERRUPT 作成手順をここで実行する必要がありますか?

誰もこれを行った経験がありますか? 誰でもソースの例を提供できますか?

4

1 に答える 1

2

私は先週、似たようなことに苦労しています。MSI-X 割り込みではなく、単純な MSI 割り込みを動作させようとしているため、私のアプリケーションは少し異なります。しかし、私はほぼ同じ方法で WDF フレームワークを使用しています。

2013 年 4 月頃に最初の質問を投稿したことは承知していますが、更新はありません。元の問題は解決しましたか?もしそうなら、私はあなた自身の解決策を見たいと思います。

私の WDF ドライバーでは、着信ハードウェア リソース リストをマッピングし、WdfCmResourceListGetDescriptor() 関数を使用して解析し、WDFCMRESLIST リスト内の各 PCM_PARTIAL_RESOURCE_DESCRIPTOR 項目を調べています。単一の CmResourceTypeInterrupt 記述子を取得できましたが、それは常に MSI 割り込みではなくレガシー割り込み用でした。私のデバイスは MSI をサポートしています。あなたが説明したように、.inf ファイルに余分なレジストリ エントリを設定した後でも、MSI 記述子がリソース リストにない理由がわかりませんでした。

.inf ファイルにタイプミスがあったことがわかりました。デバイスのインストール セクションに「.HW」サフィックスを追加するのを忘れていました。このサフィックスを追加すると、バス マネージャーはデバイスの pcie 構成アドレスを変更し、ドライバーによってフックされる必要がある適切な MSI 割り込みリソース記述子を作成できます。

[Standard.NT$ARCH$]
%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

MSI 割り込みリソース記述子がリソース リスト (evtMapHWResources コールバックなど) で見つかった場合、その記述子は WdfInterruptCreate() 関数への入力として使用されます。ここにある "tdvr" プレフィックスは、私自身のドライバー命名規則のためのものです。

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;
}

私が言ったように、これですべてが理解できたと思いますが、とにかく投稿して貢献したいと思いました。

于 2013-06-24T21:09:52.590 に答える