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


Использование структуры SPB_TRANSFER_LIST для пользовательских списков IOCTL

Если драйвер контроллера простой периферийной шины (SPB) поддерживает один или несколько запросов пользовательского управления вводом-выводом (IOCTL), используйте структуру SPB_TRANSFER_LIST для описания буферов чтения и записи в этих запросах. Эта структура обеспечивает единый способ описания буферов в запросе и позволяет избежать дополнительных затрат на копирование буфера, связанных с METHOD_BUFFERED операциями ввода-вывода.

Если пользовательские запросы IOCTL используют структуру SPB_TRANSFER_LIST , драйвер контроллера SPB должен вызвать метод SpbRequestCaptureIoOtherTransferList , чтобы записать эти буферы в контексте процесса инициатора запроса. Драйвер может вызывать метод SpbRequestGetTransferParameters для доступа к этим буферам.

Запросы IOCTL_SPB_FULL_DUPLEX и IOCTL_SPB_EXECUTE_SEQUENCE , определенные как часть интерфейса запросов ввода-вывода SPB, используют структуру SPB_TRANSFER_LIST для описания буферов чтения и записи. Структура SPB_TRANSFER_LIST для запроса IOCTL_SPB_FULL_DUPLEX описывает буфер записи и буфер чтения (в этом порядке) в запросе. Структура SPB_TRANSFER_LIST для запроса IOCTL_SPB_EXECUTE_SEQUENCE может описывать произвольную последовательность буферов чтения и записи.

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

Драйвер Kernel-Mode Driver Foundation (KMDF) для периферийного устройства SPB вызывает метод , например WdfIoTargetSendIoctlSynchronously , чтобы отправить запрос IOCTL контроллеру SPB. Этот метод имеет параметры InputBuffer и OutputBuffer . Драйверы для некоторых типов устройств могут использовать эти два параметра для указания буфера записи и буфера чтения соответственно для запроса IOCTL. Однако для отправки запроса IOCTL контроллеру SPB драйвер периферийного устройства SPB задает параметр InputBuffer , указывающий на дескриптор памяти, указывающий на структуру SPB_TRANSFER_LIST . Эта структура описывает все буферы чтения или записи, необходимые для операции управления вводом-выводом. Драйвер задает для параметра OutputBuffer значение NULL.

Аналогичным образом драйвер User-Mode Driver Foundation (UMDF) для периферийного устройства SPB вызывает метод , например IWDFIoTarget::FormatRequestForIoctl , для форматирования запроса ввода-вывода для операции управления вводом-выводом. Этот метод имеет параметры pInputMemory и pOutputMemory . Драйверы для некоторых типов устройств могут использовать эти два параметра для указания буфера записи и буфера чтения для запроса IOCTL. Однако для отправки запроса IOCTL контроллеру SPB драйвер периферийного устройства SPB задает параметр pInputMemory, указывающий на объект памяти, содержащий структуру SPB_TRANSFER_LIST . Эта структура описывает все буферы чтения или записи, необходимые для операции управления вводом-выводом. Драйвер задает для параметра pOutputMemory значение NULL.

Проверка параметров и запись буфера

Когда расширение платформы SPB (SpbCx) получает запрос IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx передает этот запрос драйверу контроллера SPB, вызвав функцию EvtSpbControllerIoSequence драйвера. Перед этим вызовом SpbCx проверяет структуру SPB_TRANSFER_LIST , описывающую буферы в запросе. SpbCx фиксирует эти буферы в контексте процесса инициатора запроса. (Доступ к буферам в памяти в пользовательском режиме можно получить только в процессе выделения памяти.) Кроме того, SpbCx проверяет, допустимы ли значения параметров в запросе.

Когда SpbCx получает запрос IOCTL_SPB_FULL_DUPLEX или пользовательский запрос IOCTL, SpbCx передает этот запрос драйверу контроллера SPB, вызывая функцию обратного вызова EvtSpbControllerIoOther драйвера. Перед выполнением этого вызова SpbCx не проверяет значения параметров в запросе и не фиксирует буферы запроса в контексте инициатора. За проверку параметров и запись буфера для этих запросов отвечает драйвер контроллера SPB.

Если драйвер контроллера SPB поддерживает запрос IOCTL_SPB_FULL_DUPLEX или любой пользовательский запрос IOCTL, использующий для буферов структуру SPB_TRANSFER_LIST , драйвер должен реализовать функцию обратного вызова EvtIoInCallerContext . Драйвер предоставляет указатель на эту функцию в качестве входного параметра в вызове метода SpbControllerSetIoOtherCallback , который регистрирует функцию обратного вызова EvtSpbControllerIoOther драйвера. Когда SpbCx получает запрос IOCTL_SPB_FULL_DUPLEX или пользовательский запрос IOCTL, spbCx вызывает функцию EvtIoInCallerContext драйвера в контексте инициатора. Если запрос IOCTL использует структуру SPB_TRANSFER_LIST , функция EvtIoInCallerContext вызывает метод SpbRequestCaptureIoOtherTransferList для записи буферов в запросе. Функция EvtIoInCallerContext также может выполнять предварительную обработку запроса.

В следующем примере кода показана функция EvtIoInCallerContext , реализованная драйвером контроллера SPB.

VOID
EvtIoInCallerContext(
    _In_  WDFDEVICE   SpbController,
    _In_  WDFREQUEST  FxRequest
    ) 
{
    NTSTATUS status = STATUS_SUCCESS;
    WDF_REQUEST_PARAMETERS fxParams;
  
    WDF_REQUEST_PARAMETERS_INIT(&fxParams);
    WdfRequestGetParameters(FxRequest, &fxParams);

    if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
        (fxParams.Type != WdfRequestTypeDeviceControlInternal))
    {
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The driver should check for custom IOCTLs that it handles.
    // If the IOCTL is not recognized, complete the request with a
    // status of STATUS_NOT_SUPPORTED.
    //

    switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
    {
        ...

    default:
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The IOCTL is recognized. Capture the buffers in the request.
    //

    status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);

    //
    // If the capture fails, the driver must complete the request instead
    // of placing it in the SPB controller's request queue.
    //

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = WdfDeviceEnqueueRequest(SpbController, FxRequest);

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

exit:

    if (!NT_SUCCESS(status))
    {
        WdfRequestComplete(FxRequest, status);
    }
}

В предыдущем примере кода инструкция проверяет, switch содержит ли запрос IOCTL, который распознает драйвер контроллера SPB. (Для краткости текст switch оператора не отображается.) Затем вызов метода SpbRequestCaptureIoOtherTransferList захватывает буферы в запросе. Если этот вызов завершается успешно, запрос добавляется в очередь ввода-вывода контроллера SPB. В противном случае запрос завершается с кодом состояния ошибки.

Пример кода, демонстрирующий проверку параметров функцией EvtSpbControllerIoOther , см. в разделе Обработка запросов IOCTL_SPB_FULL_DUPLEX.