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(¶ms);
SpbRequestGetParameters(SpbRequest, ¶ms);
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.