Partilhar via


Solicitações seguras de E/S digital que usam Entradas/Saídas estendidas

As solicitações Secure Digital (SD) que leem ou gravam mais do que apenas alguns bytes de dados devem usar um comando de E/S estendido (referido como CMD53 na especificação SD). O comando de E/S estendida instrui o controlador de barramento a transmitir dados pelas linhas DAT do cartão SD. As características de uma transferência de dados dependem das capacidades do controlador SD. Por exemplo, alguns controladores só permitem E/S PROGRAMÁVEIS (PIO); outros permitem acesso direto à memória (DMA). Para máxima compatibilidade entre diferentes tipos de controladores SD, os drivers de dispositivo devem carregar o pacote de solicitação com um ponteiro para um MDL que descreva o buffer de dados. O driver de dispositivo deve construir seu próprio MDL, a menos que um driver em uma camada superior construa o MDL e o passe para o driver de dispositivo.

O exemplo de código a seguir mostra como um driver pode executar uma solicitação de E/S estendida usando um buffer de dados descrito por um MDL. Este exemplo de código é semelhante em formato ao exemplo de código de E/S direta descrito em Secure Digital Requests That Use Direct I/O, portanto, pode ser útil estudar o exemplo de código de E/S direta antes de estudar o exemplo de código de E/S estendida.

A principal diferença entre os dois exemplos é que o exemplo de código de I/O expandido ilustra como usar MDLs com uma solicitação SD. Há também pequenas diferenças na forma como os descritores e pacotes de solicitação são definidos para E/S direta e estendida.

    const SDCMD_DESCRIPTOR WriteIoExtendedDesc =
    {SDCMD_IO_RW_EXTENDED, SDCC_STANDARD,
    SDTD_WRITE, SDTT_SINGLE_BLOCK, SDRT_1};
    
    // first, get an MDL to map the data. Call IoAllocateMdl to
    // allocate an MDL and pass in a pointer to a buffer  
    // allocated from the non-paged pool.
    
    mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, NULL);
    
    if (mdl == NULL) {
      return STATUS_INSUFFICIENT_RESOURCES;
    }
    
    MmBuildMdlForNonPagedPool (mdl);
    
    // next, allocate a request packet for the arguments of the command
     
    sdrp = ExAllocatePool(NonPagedPool, sizeof(SDBUS_REQUEST_PACKET));
    
    if (!sdrp) {
      IoFreeMdl(mdl);
      return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(sdrp, sizeof(SDBUS_REQUEST_PACKET));
    sdrp->RequestFunction = SDRF_DEVICE_COMMAND;
    sdrp->Parameters.DeviceCommand.CmdDesc = 
    WriteIoExtendedDesc;
    
    // then, set up the argument and command descriptor
    sdIoArgument.u.AsULONG = 0;
    sdIoArgument.u.bits.Address = Offset;
    
    // retrieve function number, the driver previously initialized 
    // this value with the SdBus GetProperty call
    sdIoArgument.u.bits.Function = pDevExt->FunctionNumber;
    sdIoArgument.u.bits.WriteToDevice = 1;
    
    sdrp->Parameters.DeviceCommand.Argument = 
        sdIoArgument.u.AsULONG;
    
    sdrp->Parameters.DeviceCommand.Mdl = mdl;
    sdrp->Parameters.DeviceCommand.Length = Length;
    // finally, submit the request
    status = SdBusSubmitRequest(pDevExt->BusInterface.Context,sdrp);
    
    IoFreeMdl(mdl);
    ExFreePool(sdrp);

Este exemplo de código inclui as seguintes etapas:

  1. inicializar o descritor

    A primeira etapa no envio de uma solicitação de comando de dispositivo é definir um descritor de comando SD, SDCMD_DESCRIPTOR. O descritor no exemplo de código define uma operação de gravação de E/S estendida com os seguintes elementos:

    Elemento Descrição

    SD_COMMAND_CODE

    A operação definida pelo descritor executa uma gravação de E/S estendida, de modo que o valor do código de comando é SDCMD_IO_RW_DIRECT.

    SD_COMMAND_CLASS

    As operações de gravação de E/S estendidas pertencem ao conjunto de comandos padrão (códigos de comando de 0 a 63), portanto, o valor atribuído a esse membro do descritor é SDCC_STANDARD.

    SD_TRANSFER_DIRECTION

    As operações de gravação exigem uma transferência do host para o dispositivo, portanto, o valor atribuído a esse membro do descritor é SDTD_WRITE.

    SD_TRANSFER_TYPE

    O descritor para uma operação de gravação de E/S estendida deve incluir um tipo de transferência. O exemplo de código especifica uma gravação de bloco único, SDTT_SINGLE_BLOCK, que indica que o host grava um bloco de dados no dispositivo. O driver estabeleceu o tamanho de um bloco por um comando SET_BLOCKLEN anterior (não ilustrado neste exemplo de código). Para obter uma explicação do comando SET_BLOCKLEN e do tipo de transferência SDTT_SINGLE_BLOCK, consulte A especificação do cartão MultiMedia, publicada pelo comitê técnico da MultiMedia Card Association (MMCA).

    SD_RESPONSE_TYPE

    O descritor especifica um tipo de resposta de SDRT_1, que especifica uma resposta R1 padrão ao comando e contém dados de status. Para obter uma explicação da resposta R1, consulte a especificação MultiMedia Card Association.

  2. configurar o MDL

    Chame IoAllocateMdl para alocar um MDL e passar um ponteiro para um buffer alocado a partir do pool não paginado. Em seguida, a rotina MmBuildMdlForNonPagedPool usa o MDL recém-alocado que especifica um buffer de memória virtual no pool não paginado e o atualiza para descrever as páginas físicas subjacentes. Os chamadores de MmBuildMdlForNonPagedPool devem estar sendo executados em IRQL <= DISPATCH_LEVEL.

  3. Inicialize o Pacote de Solicitação concluindo as seguintes etapas:

    • Definir a função de solicitação:

      Depois de criar um descritor SD, o exemplo de código inicializa o pacote de solicitação, SDBUS_REQUEST_PACKET. O membro RequestFunction do pacote de solicitação especifica se a solicitação contém um comando de dispositivo (valor SDRF_DEVICE_COMMAND) ou uma operação de propriedade (valores SDRF_GET_PROPERTY ou SDRF_SET_PROPERTY). O exemplo de código está a enviar um comando de dispositivo, portanto, define o membro RequestFunction como SDRF_DEVICE_COMMAND.

    • Carregue o descritor de comando. Em seguida, o exemplo de código armazena o descritor recém-inicializado no membro Parameters.DeviceCommand.CmdDesc do pacote de solicitação.

    • inicializar o argumento de leitura/gravação:

      O pacote de solicitação contém uma estrutura SD_RW_DIRECT_ARGUMENT com o local no qual o controlador de barramento grava. Esta estrutura também armazena o número da função cujo espaço de E/S o motorista do ônibus lê. O exemplo de código recupera o número da função da extensão do dispositivo, o que implica que o driver recuperou anteriormente essas informações da placa (provavelmente quando iniciou o dispositivo com uma solicitação de SDRF_GET_PROPERTY e a armazenou na extensão do dispositivo.

  4. Submeter o pedido

    Depois de inicializar o descritor e o pacote de solicitação, o exemplo usa a rotina de solicitação síncrona SdBusSubmitRequest enviar a solicitação. Ele passa o pacote de solicitação e as informações de contexto da interface que o sistema forneceu ao driver quando abriu a interface SD. Como esta é uma solicitação síncrona, o driver deve estar a ser executado em um IRQL inferior ao DISPATCH_LEVEL.

  5. Resultados do Comando

    Como o exemplo de código usa um comando de E/S direta, nenhum buffer de dados além do campo ResponseData no pacote de solicitação SD.

O exemplo de código aloca um buffer de transferência de dados do pool não paginado. Um driver pode usar PagedPool para um buffer de transferência de dados, desde que bloqueie as páginas em questão. No entanto, os drivers devem sempre alocar buffers de transferência de dados do pool não paginado ao fazer solicitações de SDRF_GET_PROPERTY e SDRF_SET_PROPERTY. Os drivers também devem alocar pacotes de solicitação SD do pool não paginado porque a rotina de conclusão do IRP que acompanha a solicitação SD pode ser executada numa chamada de procedimento diferido (DPC).

Quando os buffers são pequenos e o driver os mantém brevemente, há vantagens de desempenho na alocação de buffers do pool não paginado para todos os tipos de solicitações.