Использование структуры 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.