共用方式為


將 KMDF 驅動程式連線到 GPIO I/O 針腳

GPIO I/O 資源是一組一或多個 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 資源的控制碼之後,此驅動程式可以傳送 I/O 控制要求,以讀取或將資料寫入 GPIO 針腳。 開啟 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 範例驅動程式。