KMDF ドライバーの GPIO I/O ピンへの接続

GPIO I/O リソースは、データ入力またはデータ出力として構成されている 1 つ以上の GPIO ピンのセットです。 これらのピンに物理的に接続する周辺機器のドライバーは、オペレーティング システムから対応する GPIO I/O リソースを取得します。 周辺機器ドライバーは、このリソースの GPIO ピンへの接続を開き、この接続を表すハンドルに I/O 要求を送信します。

次のコード例は、周辺機器のカーネル モード ドライバー フレームワーク (KMDF) ドライバーが、プラグ アンド プレイ (PnP) マネージャーがドライバーに割り当てた GPIO I/O リソースの記述を取得する方法を示しています。

NTSTATUS
  EvtDevicePrepareHardware(
    _In_ WDFDEVICE Device,
    _In_ WDFCMRESLIST ResourcesRaw,
    _In_ WDFCMRESLIST ResourcesTranslated
    )
{
    int ResourceCount, Index;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
    XYZ_DEVICE_CONTEXT *DeviceExtension;

    ...

    DeviceExtension = XyzDrvGetDeviceExtension(Device);
    ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
    for (Index = 0; Index < ResourceCount; Index += 1) {
        Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
        switch (Descriptor->Type) {

        //
        // GPIO I/O descriptors
        //

        case CmResourceTypeConnection:

            //
            // Check against expected connection type.
            //

            if ((Descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
                (Descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {

                DeviceExtension->ConnectionId.LowPart = Descriptor->u.Connection.IdLowPart;
                DeviceExtension->ConnectionId.HighPart = Descriptor->u.Connection.IdHighPart;

        ...

}

前のコード例では、DeviceExtension 変数は周辺機器のデバイス コンテキストへのポインターです。 このデバイス コンテキストを取得する XyzDrvGetDeviceExtension 関数は、周辺機器ドライバーによって実装されます。 このドライバーは以前に、WdfDeviceInitSetPnpPowerEventCallbacks メソッドを呼び出すことによって、EvtDevicePrepareHardware コールバック関数を登録しました。

次のコード例は、周辺機器ドライバーが前のコード例で取得した GPIO リソースの記述を使用して、ドライバーの GPIO I/O リソースへの WDFIOTARGET ハンドルを開く方法を示しています。

NTSTATUS IoRoutine(WDFDEVICE Device, BOOLEAN ReadOperation) 
{
    WDFIOTARGET IoTarget;
    XYZ_DEVICE_CONTEXT *DeviceExtension;
    UNICODE_STRING ReadString;
    WCHAR ReadStringBuffer[100];;
    BOOL DesiredAccess;
    NTSTATUS Status;
    WDF_OBJECT_ATTRIBUTES ObjectAttributes;
    WDF_IO_TARGET_OPEN_PARAMS OpenParams

    DeviceExtension = XyzDrvGetDeviceExtension(Device);
    RtlInitEmptyUnicodeString(&ReadString,
                              ReadStringBuffer,
                              sizeof(ReadStringBuffer));

    Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&ReadString,
                                              DeviceExtension->ConnectionId.LowPart,
                                              DeviceExtension->ConnectionId.HighPart);

    NT_ASSERT(NT_SUCCESS(Status));

    WDF_OBJECT_ATTRIBUTES_INIT(&ObjectAttributes);
    ObjectAttributes.ParentObject = Device;

    Status = WdfIoTargetCreate(Device, &ObjectAttributes, &IoTarget);
    if (!NT_SUCCESS(Status)) {
        goto IoErrorEnd;
    }   

    if (ReadOperation != FALSE) {
        DesiredAccess = GENERIC_READ;
    } else {
        DesiredAccess = GENERIC_WRITE;
    }

    WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&OpenParams, ReadString, DesiredAccess);

    Status = WdfIoTargetOpen(IoTarget, &OpenParams);
    if (!NT_SUCCESS(Status)) {
        goto IoErrorEnd;
    }
    ...

前のコード例では、Device 変数は周辺機器のフレームワーク デバイス オブジェクトに対する WDFDEVICE ハンドルです。 RESOURCE_HUB_CREATE_PATH_FROM_ID 関数は、GPIO I/O リソースの名前を含む文字列を作成します。 このコード例では、この文字列を使用して、GPIO I/O リソースを名前で開きます。

周辺機器ドライバーが GPIO I/O リソースへのハンドルを取得した後、このドライバーは GPIO ピンに対するデータの読み取りまたはデータの書き込みのために I/O コントロール要求を送信できます。 読み取り用に GPIO I/O リソースを開くドライバーは、IOCTL_GPIO_READ_PINS I/O コントロール要求を使用して、リソース内のピンからデータを読み取ります。 書き込み用に GPIO I/O リソースを開くドライバーは、IOCTL_GPIO_WRITE_PINS I/O コントロール要求を使用して、リソース内のピンにデータを書き込みます。 次のコード例は、GPIO の読み取りまたは書き込み操作を実行する方法を示しています。

    WDF_OBJECT_ATTRIBUTES RequestAttributes;
    WDF_OBJECT_ATTRIBUTES Attributes;
    WDF_REQUEST_SEND_OPTIONS SendOptions;
    WDFREQUEST IoctlRequest;
    WDFIOTARGET IoTarget;
    WDFMEMORY WdfMemory;
    NTSTATUS Status;

    WDF_OBJECT_ATTRIBUTES_INIT(&RequestAttributes);
    Status = WdfRequestCreate(&RequestAttributes, IoTarget, &IoctlRequest);
    if (!NT_SUCCESS(Status)) {
        goto RwErrorExit;
    }

    //
    // Set up a WDF memory object for the IOCTL request.
    //

    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
    Attributes.ParentObject = IoctlRequest;
    Status = WdfMemoryCreatePreallocated(&Attributes, Data, Size, &WdfMemory);
    if (!NT_SUCCESS(Status)) {
        goto RwErrorExit;
    }

    //
    // Format the request.
    //

    if (ReadOperation != FALSE) {
        Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
                                                  IoctlRequest,
                                                  IOCTL_GPIO_READ_PINS,
                                                  NULL,
                                                  0,
                                                  WdfMemory,
                                                  0);

    } else {
        Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
                                                  IoctlRequest,
                                                  IOCTL_GPIO_WRITE_PINS,
                                                  WdfMemory,
                                                  0,
                                                  WdfMemory,
                                                  0);
    }

    if (!NT_SUCCESS(Status)) {
        goto RwErrorExit;
    }

    //
    // Send the request synchronously (with a 60-second time-out).
    //

    WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions,
                                  WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions,
                                         WDF_REL_TIMEOUT_IN_SEC(60));

    Status = WdfRequestAllocateTimer(IoctlRequest);
    if (!NT_SUCCESS(Status)) {
        goto RwErrorExit;
    }

    if (!WdfRequestSend(IoctlRequest, IoTarget, &SendOptions)) {
        Status = WdfRequestGetStatus(IoctlRequest);
    }

    ...

前のコード例では、Data はデータ バッファーへのポインターで、Size はこのデータ バッファーのサイズ (バイト単位) です。また、ReadOperation は要求された操作が読み取り (TRUE) か書き込み (FALSE) かを示します。

詳細情報

要求出力バッファー内のビットに対するデータ入力ピンのマッピングなど、IOCTL_GPIO_READ_PINS 要求の詳細については、「IOCTL_GPIO_READ_PINS」を参照してください。 データ出力ピンに対する要求入力バッファー内のビットのマッピングなど、IOCTL_GPIO_WRITE_PINS 要求の詳細については、「IOCTL_GPIO_WRITE_PINS」を参照してください。

カーネル モードで実行される GPIO 周辺機器ドライバーを記述する方法を示すサンプル ドライバーについては、GitHub の GPIO サンプル ドライバー コレクションの SimDevice サンプル ドライバーを参照してください。