Безопасные цифровые запросы, использующие расширенные функции ввода-вывода
Запросы 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);
В этом примере кода приведены следующие действия.
инициализируйте дескриптор
Первым шагом при отправке запроса на команду устройства является определение дескриптора команды SD, SDCMD_DESCRIPTOR. Дескриптор в примере кода определяет расширенную операцию записи ввода-вывода со следующими элементами:
Элемент Описание Операция, определяемая дескриптором, выполняет расширенную I/O запись, поэтому значение кода команды – SDCMD_IO_RW_DIRECT.
Расширенные операции записи ввода-вывода относятся к стандартному набору команд (коды команд 0 до 63), поэтому значение, назначенное этому элементу дескриптора, SDCC_STANDARD.
Операции записи требуют передачи с узла на устройство, поэтому значение, назначенное этому элементу дескриптора, SDTD_WRITE.
Дескриптор для расширенной операции записи ввода-вывода должен содержать тип передачи. В примере кода указывается одноразовая запись блока, SDTT_SINGLE_BLOCK, который указывает, что хост записывает один блок данных на устройство. Драйвер установил размер блока с помощью предыдущей команды SET_BLOCKLEN (не показан в этом примере кода). Описание команды SET_BLOCKLEN и типа передачи SDTT_SINGLE_BLOCK см. в разделе спецификации MultiMedia Card, опубликованной техническим комитетом Ассоциации карт MultiMedia (MMCA).
Дескриптор указывает тип ответа SDRT_1, который задает стандартный ответ R1 на команду и содержит данные о состоянии. Подробнее о ответе R1 см. в спецификации Ассоциации MultiMedia Card .
Установка MDL
Вызовите IoAllocateMdl, чтобы выделить MDL и передать указатель на буфер, выделенный из нестраничного пула. Затем программа MmBuildMdlForNonPagedPool принимает только что выделенный MDL-файл, указывающий буфер виртуальной памяти в нестраничном пуле и обновляет его, чтобы описать базовые физические страницы. Вызывающие MmBuildMdlForNonPagedPool должны работать в IRQL <= DISPATCH_LEVEL.
инициализировать пакет запроса, выполнив следующие действия:
определить функцию запроса:
После создания дескриптора 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 и сохранена в расширении устройства).
Отправить запрос
После инициализации дескриптора и пакета запроса пример использует синхронную процедуру запроса, SdBusSubmitRequest для отправки запроса. Это передает в пакет запроса и сведения о контексте интерфейса, предоставленные системой драйверу при открытии интерфейса SD. Так как это синхронный запрос, драйвер должен выполняться при IRQL меньше DISPATCH_LEVEL.
Результаты команды
Поскольку в примере кода используется прямая команда ввода-вывода, не предусмотрено использования какого-либо буфера данных, кроме поля ResponseData в пакете запроса SD.
В примере кода выделяется буфер передачи данных из нестраничного пула. Драйвер может использовать PagedPool для буфера передачи данных, при условии, что он блокирует доступ к страницам. Однако драйверы должны всегда выделять буферы передачи данных из нестраничного пула при выполнении запросов SDRF_GET_PROPERTY и SDRF_SET_PROPERTY. Драйверы также должны выделять пакеты запросов SD из нестраничного пула, так как процедура завершения IRP, сопровождающая запрос SD, может выполняться в отложенном вызове процедуры (DPC).
Для всех типов запросов имеется выгода с точки зрения производительности при выделении буферов из пула непрямого доступа, когда буферы небольшие, а драйвер удерживает их ненадолго.