Compartilhar via


Manipulando solicitações de IOCTL_SPB_FULL_DUPLEX

Alguns ônibus, como SPI, permitem que transferências de leitura e gravação ocorram simultaneamente entre o controlador de barramento e um dispositivo no ônibus. Para dar suporte a essas transferências full-duplex, a definição da interface de solicitação de E/S simples de barramento periférico (SPB) inclui, como opção, o IOCTL_SPB_FULL_DUPLEX ioctl (código de controle de E/S). Somente os drivers de controlador SPB para controladores de barramento que implementam transferências full-duplex em hardware devem dar suporte ao IOCTL_SPB_FULL_DUPLEX IOCTL.

Se um driver de controlador SPB der suporte a solicitações de E/S para transferências full-duplex, o driver deverá usar o IOCTL_SPB_FULL_DUPLEX IOCTL para essas solicitações e deve seguir as diretrizes de implementação apresentadas neste tópico. A finalidade dessas diretrizes é incentivar o comportamento uniforme em todas as plataformas de hardware que dão suporte a solicitações de IOCTL_SPB_FULL_DUPLEX . Os drivers para dispositivos periféricos conectados ao SPB podem contar com essas solicitações para produzir resultados semelhantes, independentemente da plataforma em que eles são executados.

Requisitos de buffer

Uma solicitação IOCTL_SPB_FULL_DUPLEX é formatada da mesma forma que uma solicitação de IOCTL_SPB_EXECUTE_SEQUENCE , mas com estas restrições:

  • A estrutura SPB_TRANSFER_LIST na solicitação deve conter exatamente duas entradas. A primeira entrada descreve um buffer que contém dados a serem gravados no dispositivo. A segunda entrada descreve um buffer usado para armazenar dados lidos do dispositivo.
  • Cada estrutura SPB_TRANSFER_LIST_ENTRY na lista de transferência deve especificar um valor DelayInUs igual a zero.

Durante uma transferência de duplex completa, as transferências de leitura e gravação começam em uníssono. O primeiro byte de dados de gravação é transmitido pelo barramento ao mesmo tempo que o primeiro byte de dados de leitura.

Os buffers de gravação e leitura na solicitação de IOCTL_SPB_FULL_DUPLEX não precisam ter o mesmo comprimento.

Se o buffer de leitura for menor que o buffer de gravação, a transferência de barramento full-duplex continuará até que todo o conteúdo do buffer de gravação seja gravado no dispositivo. Depois que o buffer de leitura estiver cheio, o controlador de barramento descartará todos os dados adicionais recebidos do dispositivo até que a transferência completa do barramento duplex seja concluída.

Se o buffer de gravação for menor que o buffer de leitura, a transferência de barramento full-duplex continuará até que o buffer de leitura esteja cheio. Depois que todo o conteúdo do buffer de gravação for gravado no dispositivo, o controlador de barramento gravará zeros no dispositivo até que a transferência completa do barramento duplex seja concluída.

Se a solicitação de IOCTL_SPB_FULL_DUPLEX for concluída com êxito, o driver do controlador SPB definirá o membro Status do bloco de status de E/S como STATUS_SUCCESS e definirá o membro Information como o número total de bytes transferidos (bytes lidos mais bytes gravados) durante a transferência completa duplex. O valor de contagem no membro Informações nunca deve exceder a soma do tamanho do buffer de leitura e do tamanho do buffer de gravação.

Se o buffer de leitura for menor que o buffer de gravação, o valor de contagem no membro Informações não deverá incluir os bytes de dados que o controlador de barramento lê do dispositivo (e descarta) depois que o buffer de leitura estiver cheio. Por exemplo, se uma transferência full-duplex com um buffer de gravação de 1 byte e um buffer de leitura de 4 bytes for concluído com êxito, o valor de contagem deverá ser 5, não 8. Da mesma forma, se o buffer de gravação for menor que o buffer de leitura, o valor de contagem não deverá incluir os zeros gravados no dispositivo depois que o buffer de gravação for esvaziado.

Verificação de parâmetros

Embora as solicitações IOCTL_SPB_EXECUTE_SEQUENCE e IOCTL_SPB_FULL_DUPLEX tenham formatos semelhantes, elas são tratadas de forma diferente pela extensão de estrutura do SPB (SpbCx). Para a solicitação IOCTL_SPB_EXECUTE_SEQUENCE , o SpbCx valida os valores de parâmetro na solicitação e captura os buffers da solicitação no contexto de processo do originador da solicitação. O SpbCx passa IOCTL_SPB_EXECUTE_SEQUENCE solicitações para o driver do controlador SPB por meio da função de retorno de chamada EvtSpbControllerIoSequence do driver, que é dedicada a essas solicitações.

Por outro lado, o SpbCx trata a solicitação IOCTL_SPB_FULL_DUPLEX como uma solicitação IOCTL personalizada e definida pelo driver. O SpbCx passa IOCTL_SPB_FULL_DUPLEX solicitações para o driver do controlador SPB por meio da função de retorno de chamada EvtSpbControllerIoOther do driver, que também manipula quaisquer solicitações IOCTL personalizadas compatíveis com o driver. O SpbCx não faz nenhuma verificação de parâmetro ou captura de buffer para essas solicitações. O driver é responsável por qualquer verificação de parâmetro ou captura de buffer que possa ser necessária para as solicitações IOCTL que o driver recebe por meio de sua função EvtSpbControllerIoOther . Para habilitar a captura de buffer, o driver deve fornecer uma função de retorno de chamada EvtIoInCallerContext quando o driver registra sua função EvtSpbControllerIoOther . Para obter mais informações, consulte Usando a estrutura de SPB_TRANSFER_LIST para IOCTLs personalizadas.

Normalmente, o driver do controlador SPB valida os valores de parâmetro em uma solicitação IOCTL_SPB_FULL_DUPLEX na função EvtSpbControllerIoOther em vez de na função EvtIoInCallerContext . O exemplo de código a seguir mostra como o driver pode implementar a verificação de parâmetros. Neste exemplo, o driver verifica se os seguintes requisitos de parâmetro são atendidos:

  • A lista de transferência na solicitação contém exatamente duas entradas.
  • A primeira entrada na lista de transferência é para um buffer de gravação e a segunda é para um buffer de leitura.
  • O valor DelayInUs para ambas as entradas é zero.
//
// 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);

Depois de verificar os valores de parâmetro, o exemplo de código anterior chama uma rotina interna do driver, chamada MyDriverPerformFullDuplexTransfer, para iniciar a transferência de E/S full-duplex.