Поделиться через


Безопасные цифровые запросы, использующие расширенные функции ввода-вывода

Запросы Secure Digital (SD), которые считывают или записывают больше, чем несколько байт данных, должны использовать расширенную команду ввода-вывода (которая называется CMD53 в спецификации SD). Расширенная команда ввода-вывода предписывает драйверу шины передавать данные по линиям DAT SD-карты. Характеристики передачи данных зависят от возможностей контроллера SD. Например, некоторые контроллеры разрешают программируемый ввод-вывод (PIO); другие разрешают прямой доступ к памяти (DMA). Для обеспечения максимальной совместимости между различными типами контроллеров SD драйверы устройств должны загружать пакет запроса с указателем на MDL, описывающий буфер данных. Драйвер устройства должен создать собственный MDL, если драйвер в более высоком слое не создает MDL и передает его драйверу устройства.

В следующем примере кода показано, как драйвер может выполнять расширенный запрос ввода-вывода с помощью буфера данных, описанного MDL. Этот пример кода схож по форме с примером кода, использующего прямой ввод-вывод, описанным в , запросы безопасного цифрового доступа, использующиепрямой ввод-вывод. Поэтому может быть полезно сначала изучить пример кода прямого ввода-вывода, прежде чем переходить к расширенному примеру кода.

Основное различие между двумя примерами заключается в том, что расширенный пример кода I/O иллюстрирует использование MDL с запросом SD. Существуют также незначительные различия в том, как дескрипторы и пакеты запросов определяются для прямых и расширенных операций ввода-вывода.

    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);

В этом примере кода приведены следующие действия.

  1. инициализируйте дескриптор

    Первым шагом при отправке запроса на команду устройства является определение дескриптора команды SD, SDCMD_DESCRIPTOR. Дескриптор в примере кода определяет расширенную операцию записи ввода-вывода со следующими элементами:

    Элемент Описание

    SD_COMMAND_CODE

    Операция, определяемая дескриптором, выполняет расширенную I/O запись, поэтому значение кода команды – SDCMD_IO_RW_DIRECT.

    SD_COMMAND_CLASS

    Расширенные операции записи ввода-вывода относятся к стандартному набору команд (коды команд 0 до 63), поэтому значение, назначенное этому элементу дескриптора, SDCC_STANDARD.

    НАПРАВЛЕНИЕ_ПЕРЕДАЧИ_SD

    Операции записи требуют передачи с узла на устройство, поэтому значение, назначенное этому элементу дескриптора, SDTD_WRITE.

    SD_TRANSFER_TYPE

    Дескриптор для расширенной операции записи ввода-вывода должен содержать тип передачи. В примере кода указывается одноразовая запись блока, SDTT_SINGLE_BLOCK, который указывает, что хост записывает один блок данных на устройство. Драйвер установил размер блока с помощью предыдущей команды SET_BLOCKLEN (не показан в этом примере кода). Описание команды SET_BLOCKLEN и типа передачи SDTT_SINGLE_BLOCK см. в разделе спецификации MultiMedia Card, опубликованной техническим комитетом Ассоциации карт MultiMedia (MMCA).

    SD_RESPONSE_TYPE

    Дескриптор указывает тип ответа SDRT_1, который задает стандартный ответ R1 на команду и содержит данные о состоянии. Подробнее о ответе R1 см. в спецификации Ассоциации MultiMedia Card .

  2. Установка MDL

    Вызовите IoAllocateMdl, чтобы выделить MDL и передать указатель на буфер, выделенный из нестраничного пула. Затем программа MmBuildMdlForNonPagedPool принимает только что выделенный MDL-файл, указывающий буфер виртуальной памяти в нестраничном пуле и обновляет его, чтобы описать базовые физические страницы. Вызывающие MmBuildMdlForNonPagedPool должны работать в IRQL <= DISPATCH_LEVEL.

  3. инициализировать пакет запроса, выполнив следующие действия:

    • определить функцию запроса:

      После создания дескриптора SD пример кода инициализирует пакет запроса SDBUS_REQUEST_PACKET. Элемент RequestFunction пакета запроса указывает, содержит ли запрос команду устройства (значение SDRF_DEVICE_COMMAND) или операцию свойства (значение SDRF_GET_PROPERTY или SDRF_SET_PROPERTY). Пример кода отправляет команду устройства, поэтому он задает элемент RequestFunction для SDRF_DEVICE_COMMAND.

    • загрузите командный дескриптор. Далее в примере кода недавно инициализированный дескриптор сохраняется в члене пакета запроса, элементе Parameters.DeviceCommand.CmdDesc.

    • инициализация аргумента чтения и записи:

      Пакет запроса содержит структуру SD_RW_DIRECT_ARGUMENT с адресом, куда драйвер шины осуществляет запись. Эта структура также сохраняет номер функции, пространство ввода-вывода которой считывает драйвер шины. В примере кода извлекается номер функции из расширения устройства, что указывает на то, что драйвер ранее извлек эту информацию из карты (вероятно, при запуске устройства с запросом SDRF_GET_PROPERTY и сохранена в расширении устройства).

  4. Отправить запрос

    После инициализации дескриптора и пакета запроса пример использует синхронную процедуру запроса, SdBusSubmitRequest для отправки запроса. Это передает в пакет запроса и сведения о контексте интерфейса, предоставленные системой драйверу при открытии интерфейса SD. Так как это синхронный запрос, драйвер должен выполняться при IRQL меньше DISPATCH_LEVEL.

  5. Результаты команды

    Поскольку в примере кода используется прямая команда ввода-вывода, не предусмотрено использования какого-либо буфера данных, кроме поля ResponseData в пакете запроса SD.

В примере кода выделяется буфер передачи данных из нестраничного пула. Драйвер может использовать PagedPool для буфера передачи данных, при условии, что он блокирует доступ к страницам. Однако драйверы должны всегда выделять буферы передачи данных из нестраничного пула при выполнении запросов SDRF_GET_PROPERTY и SDRF_SET_PROPERTY. Драйверы также должны выделять пакеты запросов SD из нестраничного пула, так как процедура завершения IRP, сопровождающая запрос SD, может выполняться в отложенном вызове процедуры (DPC).

Для всех типов запросов имеется выгода с точки зрения производительности при выделении буферов из пула непрямого доступа, когда буферы небольшие, а драйвер удерживает их ненадолго.