Compartir a través de


Conexión de un controlador KMDF a patillas de E/S gpIO

Un recurso de E/S de GPIO es un conjunto de uno o varios pines GPIO que se configuran como entradas de datos o salidas de datos. El controlador de un dispositivo periférico que se conecta físicamente a estos pines adquiere el recurso de E/S gpIO correspondiente del sistema operativo. El controlador de dispositivo periférico abre una conexión a los patillas GPIO de este recurso y envía solicitudes de E/S al identificador que representa esta conexión.

En el ejemplo de código siguiente se muestra cómo el controlador del marco de controladores en modo kernel (KMDF) de un dispositivo periférico puede obtener una descripción del recurso de E/S gpIO que el administrador de Plug and Play (PnP) ha asignado al controlador.

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;

        ...

}

En el ejemplo de código anterior, la DeviceExtension variable es un puntero al contexto del dispositivo para el dispositivo periférico. La XyzDrvGetDeviceExtension función , que recupera este contexto de dispositivo, se implementa mediante el controlador de dispositivo periférico. Este controlador registró anteriormente su función de devolución de llamada EvtDevicePrepareHardware llamando al método WdfDeviceInitSetPnpPowerEventCallbacks .

En el ejemplo de código siguiente se muestra cómo el controlador de dispositivo periférico puede usar la descripción del recurso GPIO que obtuvo en el ejemplo de código anterior para abrir un identificador WDFIOTARGET en el recurso de E/S GPIO del controlador.

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

En el ejemplo de código anterior, la Device variable es un identificador WDFDEVICE para el objeto de dispositivo de marco para el dispositivo periférico. La función RESOURCE_HUB_CREATE_PATH_FROM_ID crea una cadena que contiene el nombre del recurso de E/S de GPIO. En el ejemplo de código se usa esta cadena para abrir el recurso de E/S de GPIO por nombre.

Una vez que el controlador de dispositivo periférico ha obtenido un identificador para un recurso de E/S de GPIO, este controlador puede enviar solicitudes de control de E/S para leer o escribir datos en los patillas GPIO. Un controlador que abre un recurso de E/S de GPIO para lecturas usa IOCTL_GPIO_READ_PINS solicitudes de control de E/S para leer datos de las patillas del recurso. Un controlador que abre un recurso de E/S de GPIO para escrituras usa IOCTL_GPIO_WRITE_PINS solicitudes de control de E/S para escribir datos en los pines del recurso. En el ejemplo de código siguiente se muestra cómo realizar una operación de lectura o escritura de 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);
    }

    ...

En el ejemplo de código anterior, Data es un puntero a un búfer de datos, Size es el tamaño, en bytes, de este búfer de datos e ReadOperation indica si la operación solicitada es una lectura (TRUE) o una escritura (FALSE).

Para obtener más información

Para obtener más información sobre IOCTL_GPIO_READ_PINS solicitudes, incluida la asignación de patillas de entrada de datos a los bits del búfer de salida de la solicitud, vea IOCTL_GPIO_READ_PINS. Para obtener más información sobre IOCTL_GPIO_WRITE_PINS solicitudes, incluida la asignación de los bits del búfer de entrada de solicitud a los pines de salida de datos, vea IOCTL_GPIO_WRITE_PINS.

Para ver un controlador de ejemplo que muestra cómo escribir un controlador periférico GPIO que se ejecuta en modo kernel, consulte el controlador de ejemplo SimDevice en la colección de controladores de ejemplo gpIO en GitHub.