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


Обработка запросов IOCTL_SPB_FULL_DUPLEX

Некоторые автобусы, например SPI, обеспечивают одновременную передачу данных чтения и записи между контроллером шины и устройством в шине. Для поддержки этих полнодуплексных передач определение простого интерфейса запроса ввода-вывода для периферийной шины (SPB) включает, как вариант, код управления IOCTL_SPB_FULL_DUPLEX ввода-вывода (IOCTL). Только драйверы контроллера SPB для контроллеров шины, которые реализуют полнодуплексную передачу на оборудовании, должны поддерживать IOCTL_SPB_FULL_DUPLEX IOCTL.

Если драйвер контроллера SPB поддерживает запросы ввода-вывода для полнодуплексной передачи данных, драйвер должен использовать для этих запросов IOCTL_SPB_FULL_DUPLEX IOCTL и следовать рекомендациям по реализации, представленным в этом разделе. Цель этих рекомендаций — поощрять единообразное поведение на всех аппаратных платформах, поддерживающих запросы IOCTL_SPB_FULL_DUPLEX . Драйверы периферийных устройств, подключенных к SPB, могут использовать эти запросы для получения аналогичных результатов независимо от того, на какой платформе они работают.

Требования к буферу

Запрос IOCTL_SPB_FULL_DUPLEX форматируется так же, как запрос IOCTL_SPB_EXECUTE_SEQUENCE , но со следующими ограничениями:

  • Структура SPB_TRANSFER_LIST в запросе должна содержать ровно две записи. Первая запись описывает буфер, содержащий данные для записи на устройство. Вторая запись описывает буфер, используемый для хранения данных, считыванных с устройства.
  • Каждая структура SPB_TRANSFER_LIST_ENTRY в списке передачи должна указывать значение DelayInUs , равное нулю.

Во время полнодуплексной передачи операции чтения и записи начинаются в унисон. Первый байт данных записи передается по шине одновременно с первым байтом данных для чтения.

Буферы записи и чтения в запросе IOCTL_SPB_FULL_DUPLEX не обязательно должны иметь одинаковую длину.

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

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

Если запрос IOCTL_SPB_FULL_DUPLEX завершается успешно, драйвер контроллера SPB устанавливает для элемента Status блока состояния ввода-вывода значение STATUS_SUCCESS, а для элемента Information — общее количество переданных байтов (байтов чтения и байтов, записанных) во время полнодуплексной передачи. Значение count в элементе Information никогда не должно превышать сумму размера буфера чтения и размера буфера записи.

Если буфер чтения короче буфера записи, значение count в элементе Information не должно включать байты данных, которые контроллер шины считывает с устройства (и удаляет) после заполнения буфера чтения. Например, если полнодуплексная передача с 1-байтным буфером записи и 4-байтовый буфер чтения завершается успешно, значение count должно быть равно 5, а не 8. Аналогичным образом, если буфер записи короче буфера чтения, значение count не должно включать нули, записанные на устройство после очистки буфера записи.

Проверка параметров

Хотя запросы IOCTL_SPB_EXECUTE_SEQUENCE и IOCTL_SPB_FULL_DUPLEX имеют одинаковые форматы, они обрабатываются по-разному расширением платформы SPB (SpbCx). Для запроса IOCTL_SPB_EXECUTE_SEQUENCE SpbCx проверяет значения параметров в запросе и фиксирует буферы запроса в контексте процесса инициатора запроса. SpbCx передает IOCTL_SPB_EXECUTE_SEQUENCE запросы драйверу контроллера SPB через функцию обратного вызова EvtSpbControllerIoSequence драйвера, предназначенную для этих запросов.

В отличие от этого, SpbCx обрабатывает запрос IOCTL_SPB_FULL_DUPLEX как настраиваемый, определяемый драйвером запрос IOCTL. SpbCx передает IOCTL_SPB_FULL_DUPLEX запросы драйверу контроллера SPB через функцию обратного вызова EvtSpbControllerIoOther драйвера, которая также обрабатывает любые пользовательские запросы IOCTL, поддерживаемые драйвером. SpbCx не выполняет проверку параметров или запись буфера для этих запросов. Драйвер отвечает за проверку параметров или запись буфера, которые могут потребоваться для запросов IOCTL, получаемых драйвером через функцию EvtSpbControllerIoOther . Чтобы включить запись буфера, драйвер должен предоставить функцию обратного вызова EvtIoInCallerContext , когда драйвер регистрирует свою функцию EvtSpbControllerIoOther . Дополнительные сведения см. в статье Использование структуры SPB_TRANSFER_LIST для пользовательских списков IOCTL.

Как правило, драйвер контроллера SPB проверяет значения параметров в запросе IOCTL_SPB_FULL_DUPLEX в функции EvtSpbControllerIoOther , а не в функции EvtIoInCallerContext . В следующем примере кода показано, как драйвер может реализовать проверку параметров. В этом примере драйвер проверяет, выполнены ли следующие требования к параметрам:

  • Список передачи в запросе содержит ровно две записи.
  • Первая запись в списке передачи — для буфера записи, а вторая — для буфера чтения.
  • Значение DelayInUs для обеих записей равно нулю.
//
// 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);

После проверки значений параметров предыдущий пример кода вызывает внутреннюю подпрограмму драйвера с именем MyDriverPerformFullDuplexTransfer, чтобы инициировать полнодуплексную передачу ввода-вывода.