Создание запросов IOCTL в драйверах

Драйвер класса или другой драйвер более высокого уровня может выделить IRP для запросов управления вводом-выводом и отправить их следующему драйверу ниже следующим образом:

  1. Выделение или повторное использование пакета запросов ввода-вывода (IRP) с основным кодом функции IRP_MJ_DEVICE_CONTROL или IRP_MJ_INTERNAL_DEVICE_CONTROL. Для выделения IOCTL IRP можно использовать подпрограмму IoBuildDeviceIoControlRequest . Вы также можете использовать процедуры создания и инициализации IRP общего назначения, такие как IoAllocateIrp, IoReuseIrp или IoInitializeIrp. Дополнительные сведения о выделении IRP см. в статье Создание irP для драйверов Lower-Level.

  2. Настройте расположение стека ввода-вывода нижнего драйвера для IRP с помощью кода IOCTL_XXX и соответствующих параметров.

  3. Если запрос IOCTL должен быть выполнен асинхронно, вызовите подпрограмму KeInitializeEvent , чтобы инициализировать объект события в качестве события уведомления. Драйвер использует это событие для ожидания завершения операции ввода-вывода.

  4. Вызовите IoSetCompletionRoutine с IRP, чтобы верхний драйвер при необходимости смог предоставить подпрограмму IoCompletion , чтобы сделать следующее:

    • Определите, как нижний драйвер обработал данный запрос.

    • Повторно используйте IRP для отправки другого запроса или удаления созданного драйвером IRP после того, как нижний драйвер завершит запрошенную операцию. Драйвер не может повторно использовать irP, созданные IoBuildDeviceIoControlRequest . Дополнительные сведения см. в разделе Повторное использованием irP.

  5. Вызовите IoCallDriver , чтобы передать запрос в нижний драйвер.

  6. Если IoCallDriver возвращает STATUS_PENDING, вызовите подпрограмму KeWaitForSingleObject , чтобы поместить текущий поток в состояние ожидания. Драйвер задает в параметре Object подпрограммы адрес объекта события, который был инициализирован в вызове KeInitializeEvent.

    Примечание Если драйвер вызывает KeWaitForSingleObject с параметром Timeout , равным NULL или адресу переменной, содержащей ненулевое значение, драйвер должен выполняться в irQL <= APC_LEVEL в контексте неарбитарного потока. В противном случае драйвер должен работать в irQL <= DISPATCH_LEVEL.

Событие сигнализируется процедурой IoCompletion по завершении запроса IOCTL. После передачи сигнала о событии поток возобновляет выполнение.

Важно Если драйвер выделяет объект события в качестве локальной переменной в стеке, драйвер должен вызвать KeWaitForSingleObject с параметром WaitMode , равным KernelMode. Это значение параметра не позволяет вывести стек на страницу.

Чтобы избежать проблем синхронизации и возможных нарушений доступа, параметры для кодов управления вводом-выводом редко включают внедренные указатели. За исключением некоторых запросов SCSI, буферы в Irp-AssociatedIrp>. SystemBuffer, в Irp-MdlAddress > ив разделе Параметры. DeviceIoControl. Type3InputBuffer в расположении стека ввода-вывода драйвера не содержит указателей на другие буферы данных и не содержит структур, содержащих указатели для системных кодов управления вводом-выводом. Дополнительные сведения об использовании буферов данных с irP, содержащими управляющие коды ввода-вывода, см. в разделе Описания буфера для кодов управления вводом-выводом.

Тем не менее пара драйверов класса/порта, определяющих внутренние коды управления вводом-выводом, может передавать внедренный указатель на память, выделенную драйвером, от драйвера более высокого уровня к драйверу более низкого уровня. Такая пара драйверов класса/порта отвечает за выполнение следующих действий:

  • Доступ к данным может получить только один драйвер за раз.

  • Частные буферы данных доступны драйверу порта в произвольном контексте потока.

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

Любой компонент пользовательского режима пакета драйверов может вызывать DeviceIoControl для отправки запросов на управление вводом-выводом в стек драйверов. Диспетчер ввода-вывода создает запрос IRP_MJ_DEVICE_CONTROL и доставляет его драйверу самого высокого уровня.