Создание запросов IOCTL в драйверах
Драйвер класса или другой драйвер более высокого уровня может выделить IRP для запросов управления вводом-выводом и отправить их следующему драйверу ниже следующим образом:
Выделение или повторное использование пакета запросов ввода-вывода (IRP) с основным кодом функции IRP_MJ_DEVICE_CONTROL или IRP_MJ_INTERNAL_DEVICE_CONTROL. Для выделения IOCTL IRP можно использовать подпрограмму IoBuildDeviceIoControlRequest . Вы также можете использовать процедуры создания и инициализации IRP общего назначения, такие как IoAllocateIrp, IoReuseIrp или IoInitializeIrp. Дополнительные сведения о выделении IRP см. в статье Создание irP для драйверов Lower-Level.
Настройте расположение стека ввода-вывода нижнего драйвера для IRP с помощью кода IOCTL_XXX и соответствующих параметров.
Если запрос IOCTL должен быть выполнен асинхронно, вызовите подпрограмму KeInitializeEvent , чтобы инициализировать объект события в качестве события уведомления. Драйвер использует это событие для ожидания завершения операции ввода-вывода.
Вызовите IoSetCompletionRoutine с IRP, чтобы верхний драйвер при необходимости смог предоставить подпрограмму IoCompletion , чтобы сделать следующее:
Определите, как нижний драйвер обработал данный запрос.
Повторно используйте IRP для отправки другого запроса или удаления созданного драйвером IRP после того, как нижний драйвер завершит запрошенную операцию. Драйвер не может повторно использовать irP, созданные IoBuildDeviceIoControlRequest . Дополнительные сведения см. в разделе Повторное использованием irP.
Вызовите IoCallDriver , чтобы передать запрос в нижний драйвер.
Если 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 и доставляет его драйверу самого высокого уровня.