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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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