Точка входа DriverEntry
Диспетчер ввода/вывода вызывает точку входа DriverEntry при загрузке драйвера. В NT может существовать только один экземпляр драйвера, вне зависимости от числа физических устройств, контролируемых им. Таким образом, DriverEntry вызывается только один раз, на уровне IRQL равном PASSIVE_LEVEL в системном контексте.
Прототип DriverEntry:
NTSTATUS <strong>DriverEntry</strong> (IN PDRIVER_OBJECT DriverObject, IN PUNICODE STRING RegistryPath);
Где:
DriverObject – указатель на объект-драйвер, соответствующий загружаемому драйверу;
RegistryPath – указатель на строку в формате Unicode с именем ключа реестра, соответствующего загружаемому драйверу.
Возвращаемое значение имеет тип NTSTATUS. Если возвращается успешный статус завершения, диспетчер ввода/вывода немедленно позволяет производить обработку запросов к объектам-устройствам, созданным драйвером. Во всех остальных случаях драйвер не загружается в память, и запросы к нему не передаются.
В функции DriverEntry обычно происходит:
- определение всех других точек входа драйвера (их перечень см. в предыдущем разделе);
- определение конфигурации аппаратного устройства;
- создание одного или нескольких объектов-устройств.
Информация об определении всех других точек входа драйвера будет описана в следующих разделах.
Определение конфигурации аппаратного устройства
Довольно обширную тему, связанную с подготовкой драйвера к использованию аппаратного устройства мы пропустим. Интересующиеся могут обратиться к [Device Driver Development, chapter 13. Driver Entry].
Тем не менее, один часто используемый в драйверах физических устройств момент, а именно – использование реестра – необходимо упомянуть.
В соответствии с принятыми соглашениями драйверы хранят настроечные параметры в ключе реестра \HKLM\CurrentControlSet\Services\ DrvName\Parameters или.. DrvName\DeviceA\Parameters.
Наиболее простой способ запроса содержимого реестра предоставляет функция RtlQueryRegistryValues(). Имя ключа реестра \HKLM\CurrentCont-rolSet\Services\ DrvName содержится во втором параметре функции DriverEntry.
Создание объекта-устройства и символической связи
Как уже говорилось, объект-устройство представляет физическое, логическое или виртуальное устройство, которое должно быть использовано в качестве получателя запросов ввода/вывода. Именованный объект-устройство может быть использован либо из прикладного уровня посредством вызова (Nt) CreateFile(), либо из другого драйвера посредством вызова IoGetDeviceObjectPointer().
Создается объект-устройство с помощью вызова функции IoCreateDevice().
NTSTATUS loCreateDevice(IN PDRIVER_OBJECT DriverObject, IN.ULONG DeviceExtensionSize, IN.PUNICODE_STRING DeviceName, IN.DEVICEJTYPE DeviceType, IN.ULONG DeviceCharacteristics, IN.BOOLEAN Exclusive, OUT. PDEVICE OBJECT *DeviceObject);
Стоит упомянуть, что при необходимости создания нескольких именованных объектов-устройств одного типа (параметр DeviceType) стандартные драйверы NT пользуются определенным соглашением (которое не является обязательным). А именно: к фиксированному имени прибавляется номер устройства, начиная с нуля. Например, СОМ0, СОМ1,… Это позволяет открывать устройства, про которые заранее не известно, существуют они или нет. Для получения следующего номера, для которого еще не создано устройство, драйвер может использовать функцию loGetConfigurationInformation(). Эта функция возвращает указатель на структуру, содержащую число устройств текущего драйвера для каждого обнаруженного типа устройства.
Параметр "тип устройства" (DeviceType) может принимать или одно из предопределенных в ntddk.h значений, начинающихся с FILE_DEVICE_, либо значение в диапазоне 32768…65535, зарезервированное для нестандартных устройств.
Необходимо отметить, что при определении кода запроса ввода/вывода к устройству (Device i/o control code, будет рассмотрен в следующем разделе) следует использовать тот же тип устройства.
Параметр "характеристики устройства" (DeviceCharacteristics) является набором флагов и представляет интерес в основном для разработчиков стандартных типов устройств. Среди возможных значений флагов – FILE_REMO-VABLE_MEDIA, FILE_READ_ONLY_DEVICE, FILE_REMOTE_DEVICE.
Параметр "эксклюзивность устройства" (Exclusive). Когда этот параметр установлен в TRUE, для устройства может быть создан единственный объект-файл. Как видно из рис. 8, взаимосвязь различных объектов может быть довольно сложной. При этом довольно часто в драйвере необходимо представлять, от какого файлового объекта поступил запрос. Для упрощения ситуации можно разрешить использование только одного файлового объекта, то есть в один момент времени устройство будет использоваться только из одного места.
Как уже говорилось, при открытии устройства из подсистемы Win32 для имени устройства в директории \Device в пространстве имен диспетчера объектов должна быть создана символическая связь в директории \?? или \DosDevices. Это можно сделать в драйвере с помощью функции IoCreateSymbolicLink(), либо из прикладной программы с помощью Win32-функции DefmeDosDevice().