Compartir a través de


Control de solicitudes de IOCTL_SPB_FULL_DUPLEX

Algunos autobuses, como SPI, permiten transferencias de lectura y escritura para que se produzcan simultáneamente entre el controlador de bus y un dispositivo en el bus. Para admitir estas transferencias dúplex completas, la definición de la interfaz de solicitud de E/S de bus periférico simple (SPB) incluye, como opción, el código de control de E/S de IOCTL_SPB_FULL_DUPLEX (IOCTL). Solo los controladores de controlador SPB para los controladores de bus que implementan transferencias dúplex completas en hardware deben admitir el IOCTL_SPB_FULL_DUPLEX IOCTL.

Si un controlador de controlador SPB admite solicitudes de E/S para transferencias dúplex completas, el controlador debe usar el IOCTL_SPB_FULL_DUPLEX IOCTL para estas solicitudes y debe seguir las directrices de implementación que se presentan en este tema. El propósito de estas directrices es fomentar un comportamiento uniforme en todas las plataformas de hardware que admitan solicitudes de IOCTL_SPB_FULL_DUPLEX . Los controladores para dispositivos periféricos conectados a SPB pueden confiar en estas solicitudes para generar resultados similares, independientemente de la plataforma en la que se ejecuten.

Requisitos del búfer

Una solicitud IOCTL_SPB_FULL_DUPLEX tiene el mismo formato que una solicitud de IOCTL_SPB_EXECUTE_SEQUENCE , pero con estas restricciones:

  • La estructura SPB_TRANSFER_LIST de la solicitud debe contener exactamente dos entradas. La primera entrada describe un búfer que contiene datos que se van a escribir en el dispositivo. En la segunda entrada se describe un búfer que se usa para contener los datos leídos del dispositivo.
  • Cada estructura SPB_TRANSFER_LIST_ENTRY de la lista de transferencia debe especificar un valor DelayInUs de cero.

Durante una transferencia dúplex completa, las transferencias de lectura y escritura comienzan por unísono. El primer byte de datos de escritura se transmite a través del bus al mismo tiempo que el primer byte de datos de lectura.

No es necesario que los búferes de escritura y lectura de la solicitud de IOCTL_SPB_FULL_DUPLEX sean de la misma longitud.

Si el búfer de lectura es más corto que el búfer de escritura, la transferencia de bus dúplex completa continúa hasta que todo el contenido del búfer de escritura se escribe en el dispositivo. Una vez que el búfer de lectura esté lleno, el controlador de bus descarta todos los datos adicionales recibidos del dispositivo hasta que se complete la transferencia completa del bus dúplex.

Si el búfer de escritura es más corto que el búfer de lectura, la transferencia de bus dúplex completa continúa hasta que el búfer de lectura está lleno. Después de escribir todo el contenido del búfer de escritura en el dispositivo, el controlador de bus escribe ceros en el dispositivo hasta que se completa la transferencia de bus dúplex completa.

Si la solicitud de IOCTL_SPB_FULL_DUPLEX se completa correctamente, el controlador del controlador SPB establece el miembro Status del bloque de estado de E/S en STATUS_SUCCESS y establece el miembro Information en el número total de bytes transferidos (bytes leídos más bytes escritos) durante la transferencia dúplex completa. El valor count del miembro Information nunca debe superar la suma del tamaño del búfer de lectura y el tamaño del búfer de escritura.

Si el búfer de lectura es más corto que el búfer de escritura, el valor de recuento del miembro Information no debe incluir los bytes de datos que el controlador de bus lee del dispositivo (y descarta) después de que el búfer de lectura esté lleno. Por ejemplo, si una transferencia dúplex completa con un búfer de escritura de 1 byte y un búfer de lectura de 4 bytes se completa correctamente, el valor de recuento debe ser 5, no 8. Del mismo modo, si el búfer de escritura es más corto que el búfer de lectura, el valor de recuento no debe incluir los ceros escritos en el dispositivo después de vaciar el búfer de escritura.

Comprobación de parámetros

Aunque las solicitudes de IOCTL_SPB_EXECUTE_SEQUENCE y IOCTL_SPB_FULL_DUPLEX tienen formatos similares, la extensión del marco de SPB (SpbCx) las controla de forma diferente. Para la solicitud IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx valida los valores de parámetro de la solicitud y captura los búferes de la solicitud en el contexto de proceso del originador de la solicitud. SpbCx pasa IOCTL_SPB_EXECUTE_SEQUENCE solicitudes al controlador del controlador SPB a través de la función de devolución de llamada EvtSpbControllerIoSequence del controlador, que está dedicada a estas solicitudes.

En cambio, SpbCx trata la solicitud IOCTL_SPB_FULL_DUPLEX como una solicitud IOCTL personalizada definida por el controlador. SpbCx pasa IOCTL_SPB_FULL_DUPLEX solicitudes al controlador del controlador SPB a través de la función de devolución de llamada EvtSpbControllerIoOther del controlador, que también controla las solicitudes IOCTL personalizadas que admite el controlador. SpbCx no realiza ninguna comprobación de parámetros ni captura de búfer para estas solicitudes. El controlador es responsable de cualquier comprobación de parámetros o captura de búfer que pueda ser necesaria para las solicitudes IOCTL que recibe el controlador a través de su función EvtSpbControllerIoOther . Para habilitar la captura de búfer, el controlador debe proporcionar una función de devolución de llamada EvtIoInCallerContext cuando el controlador registra su función EvtSpbControllerIoOther . Para obtener más información, consulte Uso de la estructura de SPB_TRANSFER_LIST para ICTLs personalizados.

Normalmente, el controlador del controlador SPB valida los valores de parámetro en una solicitud de IOCTL_SPB_FULL_DUPLEX en la función EvtSpbControllerIoOther en lugar de en la función EvtIoInCallerContext . En el ejemplo de código siguiente se muestra cómo el controlador podría implementar la comprobación de parámetros. En este ejemplo, el controlador comprueba que se cumplen los siguientes requisitos de parámetro:

  • La lista de transferencias de la solicitud contiene exactamente dos entradas.
  • La primera entrada de la lista de transferencia es para un búfer de escritura y la segunda es para un búfer de lectura.
  • El valor DelayInUs de ambas entradas es cero.
//
// Validate the transfer count.
//

SPB_REQUEST_PARAMETERS params;
SPB_REQUEST_PARAMETERS_INIT(&params);
SpbRequestGetParameters(SpbRequest, &params);

if (params.SequenceTransferCount != 2)
{
    //
    // The full-duplex request must have 
    // exactly two transfer descriptors.
    //
    
    status = STATUS_INVALID_PARAMETER;        
    goto exit;
}

//
// Retrieve the write and read transfer descriptors.
//

const ULONG fullDuplexWriteIndex = 0;
const ULONG fullDuplexReadIndex = 1;

SPB_TRANSFER_DESCRIPTOR writeDescriptor;
SPB_TRANSFER_DESCRIPTOR readDescriptor;
PMDL pWriteMdl;
PMDL pReadMdl;

SPB_TRANSFER_DESCRIPTOR_INIT(&writeDescriptor);
SPB_TRANSFER_DESCRIPTOR_INIT(&readDescriptor);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexWriteIndex, 
    &writeDescriptor,
    &pWriteMdl);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexReadIndex, 
    &readDescriptor,
    &pReadMdl);
    
//
// Validate the transfer direction of each descriptor.
//

if ((writeDescriptor.Direction != SpbTransferDirectionToDevice) ||
    (readDescriptor.Direction != SpbTransferDirectionFromDevice))
{
    //
    // For full-duplex I/O, the direction of the first transfer
    // must be SpbTransferDirectionToDevice, and the direction
    // of the second must be SpbTransferDirectionFromDevice.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

//
// Validate the delay for each transfer descriptor.
//

if ((writeDescriptor.DelayInUs != 0) || (readDescriptor.DelayInUs != 0))
{
    //
    // The write and read buffers for full-duplex I/O are transferred
    // simultaneously over the bus. The delay parameter in each transfer
    // descriptor must be set to 0.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

MyDriverPerformFullDuplexTransfer(
    pDevice, 
    pRequest,
    writeDescriptor,
    pWriteMdl,
    readDescriptor,
    pReadMdl);

Después de comprobar los valores de parámetro, el ejemplo de código anterior llama a una rutina interna del controlador, denominada MyDriverPerformFullDuplexTransfer, para iniciar la transferencia de E/S dúplex completa.