Compartir a través de


Uso de la estructura de SPB_TRANSFER_LIST para ICTLs personalizados

Si el controlador de controlador de bus periférico simple (SPB) admite una o varias solicitudes de control de E/S (IOCTL) personalizadas, use la estructura SPB_TRANSFER_LIST para describir los búferes de lectura y escritura en estas solicitudes. Esta estructura proporciona una manera uniforme de describir los búferes en una solicitud y evita la sobrecarga de copia de búfer asociada a METHOD_BUFFERED operaciones de E/S.

Si las solicitudes IOCTL personalizadas usan la estructura SPB_TRANSFER_LIST , el controlador del controlador SPB debe llamar al método SpbRequestCaptureIoOtherTransferList para capturar estos búferes en el contexto de proceso del originador de la solicitud. El controlador puede llamar al método SpbRequestGetTransferParameters para acceder a estos búferes.

Las solicitudes IOCTL_SPB_FULL_DUPLEX y IOCTL_SPB_EXECUTE_SEQUENCE , que se definen como parte de la interfaz de solicitud de E/S de SPB, usan la estructura SPB_TRANSFER_LIST para describir sus búferes de lectura y escritura. La estructura SPB_TRANSFER_LIST de una solicitud de IOCTL_SPB_FULL_DUPLEX describe tanto el búfer de escritura como el búfer de lectura (en ese orden) en la solicitud. La estructura SPB_TRANSFER_LIST de una solicitud de IOCTL_SPB_EXECUTE_SEQUENCE puede describir una secuencia arbitraria de búferes de lectura y escritura.

De forma similar, puede definir las E/STL personalizadas para requerir que sus estructuras de SPB_TRANSFER_LIST usen alguna combinación de búferes de lectura y escritura y especifiquen cualquier ordenación de los búferes de la lista que pueda ser necesaria.

El controlador de Kernel-Mode Driver Foundation (KMDF) para un dispositivo periférico SPB llama a un método como WdfIoTargetSendIoctlSynchronously para enviar una solicitud IOCTL a un controlador SPB. Este método tiene parámetros InputBuffer y OutputBuffer . Los controladores de algunos tipos de dispositivos pueden usar estos dos parámetros para apuntar al búfer de escritura y al búfer de lectura, respectivamente, para una solicitud IOCTL. Sin embargo, para enviar una solicitud IOCTL a un controlador SPB, el controlador de dispositivo periférico SPB establece el parámetro InputBuffer para que apunte a un descriptor de memoria que apunte a una estructura de SPB_TRANSFER_LIST . Esta estructura describe los búferes de lectura o escritura necesarios para la operación de control de E/S. El controlador establece el parámetro OutputBuffer en NULL.

Del mismo modo, el controlador User-Mode Driver Foundation (UMDF) de un dispositivo periférico SPB llama a un método como IWDFIoTarget::FormatRequestForIoctl para dar formato a una solicitud de E/S para una operación de control de E/S. Este método tiene parámetros pInputMemory y pOutputMemory . Los controladores de algunos tipos de dispositivos pueden usar estos dos parámetros para apuntar al búfer de escritura y al búfer de lectura para una solicitud IOCTL. Sin embargo, para enviar una solicitud IOCTL a un controlador SPB, el controlador de dispositivo periférico SPB establece el parámetro pInputMemory para que apunte a un objeto de memoria que contiene una estructura de SPB_TRANSFER_LIST . Esta estructura describe los búferes de lectura o escritura necesarios para la operación de control de E/S. El controlador establece el parámetro pOutputMemory en NULL.

Comprobación de parámetros y captura de búfer

Cuando la extensión del marco de SPB (SpbCx) recibe una solicitud de IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx pasa esta solicitud al controlador del controlador SPB llamando a la función EvtSpbControllerIoSequence del controlador. Antes de esta llamada, SpbCx inspecciona la estructura SPB_TRANSFER_LIST que describe los búferes de la solicitud. SpbCx captura estos búferes en el contexto de proceso del originador de la solicitud. (Solo se puede acceder a los búferes en memoria en modo de usuario en el proceso en el que se asigna la memoria). Además, SpbCx comprueba si los valores de parámetro de la solicitud son válidos.

Cuando SpbCx recibe una solicitud IOCTL_SPB_FULL_DUPLEX o una solicitud IOCTL personalizada, SpbCx pasa esta solicitud al controlador del controlador SPB llamando a la función de devolución de llamada EvtSpbControllerIoOther del controlador. Antes de realizar esta llamada, SpbCx no realiza ninguna comprobación de validación de los valores de parámetro de la solicitud y no captura los búferes de la solicitud en el contexto del originador. La comprobación de parámetros y la captura del búfer para estas solicitudes es responsabilidad del controlador del controlador SPB.

Si un controlador de controlador SPB admite la solicitud de IOCTL_SPB_FULL_DUPLEX o admite cualquier solicitud IOCTL personalizada que use la estructura de SPB_TRANSFER_LIST para sus búferes, el controlador debe implementar una función de devolución de llamada EvtIoInCallerContext . El controlador proporciona un puntero a esta función como parámetro de entrada en la llamada al método SpbControllerSetIoOtherCallback que registra la función de devolución de llamada EvtSpbControllerIoOther del controlador. Cuando SpbCx recibe una solicitud de IOCTL_SPB_FULL_DUPLEX o una solicitud IOCTL personalizada, SpbCx llama a la función EvtIoInCallerContext del controlador en el contexto del autor. Si la solicitud IOCTL usa la estructura SPB_TRANSFER_LIST , la función EvtIoInCallerContext llama al método SpbRequestCaptureIoOtherTransferList para capturar los búferes de la solicitud. La función EvtIoInCallerContext también puede realizar algún procesamiento preliminar de la solicitud.

En el ejemplo de código siguiente se muestra una función EvtIoInCallerContext implementada por un controlador de controlador SPB.

VOID
EvtIoInCallerContext(
    _In_  WDFDEVICE   SpbController,
    _In_  WDFREQUEST  FxRequest
    ) 
{
    NTSTATUS status = STATUS_SUCCESS;
    WDF_REQUEST_PARAMETERS fxParams;
  
    WDF_REQUEST_PARAMETERS_INIT(&fxParams);
    WdfRequestGetParameters(FxRequest, &fxParams);

    if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
        (fxParams.Type != WdfRequestTypeDeviceControlInternal))
    {
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The driver should check for custom IOCTLs that it handles.
    // If the IOCTL is not recognized, complete the request with a
    // status of STATUS_NOT_SUPPORTED.
    //

    switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
    {
        ...

    default:
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The IOCTL is recognized. Capture the buffers in the request.
    //

    status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);

    //
    // If the capture fails, the driver must complete the request instead
    // of placing it in the SPB controller's request queue.
    //

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = WdfDeviceEnqueueRequest(SpbController, FxRequest);

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

exit:

    if (!NT_SUCCESS(status))
    {
        WdfRequestComplete(FxRequest, status);
    }
}

En el ejemplo de código anterior, la switch instrucción comprueba que la solicitud contiene un IOCTL que reconoce el controlador del controlador SPB. (Por motivos de brevedad, no se muestra el cuerpo de la switch instrucción). A continuación, la llamada al método SpbRequestCaptureIoOtherTransferList captura los búferes de la solicitud. Si esta llamada se realiza correctamente, la solicitud se agrega a la cola de E/S del controlador SPB. De lo contrario, la solicitud se completa con un código de estado de error.

Para obtener un ejemplo de código que muestra la comprobación de parámetros mediante una función EvtSpbControllerIoOther , vea Control de solicitudes IOCTL_SPB_FULL_DUPLEX.