Курсовая работа: Протоколирование обмена информацией между компьютером и внешним запоминающим USB-устройством
5. На эти PDO посылают запрос IRP_MN_QUERY_ID, в ответ на который драйвер системной шины сообщает идентификаторы этих устройств;
6. Получив идентификаторы, система пытается найти и загрузить драйверы устройств;
7. Найдя драйвер для устройств, система загружает его в память, вызывая его DriverEntry . Потом вызывается AddDevice , где создается FDO для устройства. Если устройств, управляемых этим драйвером, несколько, то AddDevice будет вызвана для каждого устройства. Если в реестре зарегистрированы дополнительные фильтры, то они также загружаются в память. Затем система посылает на FDO запрос IRP_MN_START_DEVICE;
8. Происходит посылка на FDO запроса IRP_MN_QUERY_DEVICE_RELATIONS. Если устройство само является шиной или держит на себе другие устройства, которыми само не управляет, то для устройства на нем повторяется вся последовательность действий, начиная с пункта 5.
Функция AddDevice , вызываемая для каждого FDO, вызывает IoCreateDevice и IoAttachDeviceToStack , обеспечивая построение стека устройств. Стек устройств обеспечивает прохождение запросов от пользовательских программ до аппаратного (нижнего) уровня драйверов (Рис. 1.4.1.1).
Рис. 1.4.1.1 Стек устройств
Из вышесказанного становится понятным, что разрабатываемый драйвер должен являться драйвером-фильтром нижнего уровня, связанным с клиентским драйвером USB‑накопителя. Необходимость работы с клиентским USB‑драйвером объясняется тем, что именно на этом уровне перехватываемая информация обладает требуемой структурированностью – передаются именно файлы, а не блоки информации (кадры или составленные из них транзакции), определяемые протоколом обмена по USB.
1.4.2 Точки входа WDM-драйвера
WDM‑драйверы отличаются от унаследованных драйверов тем, что должны содержать дополнительные точки входа для поддержки PnP, и, в целом, они более логичны по структуре. Приведем список точек входа и кратко охарактеризуем их назначение:
NTSTATUSDriverEntry (
INPDRIVER_OBJECTDriverObject, // указатель на объект драйвера
INPUNICODE_STRINGRegistryPath) // путь к подразделу регистра,
// относящегося к драйверу
Эта функция выполняется при загрузке драйвера операционной системой. В WDM‑драйверах на DriverEntry возложены обязанности по регистрации всех остальных точек входа драйвера.
NTSTATUS AddDevice (
IN PDRIVER_OBJECT DriverObject, // указательнаобъектдрайвера
INPDEVICE_OBJECTPhysicalDeviceObject) // указатель на родительский PDO
В драйверах, поддерживающих PnP, через эту точку входа менеджер PnP посылает драйверу уведомление об обнаружении устройства, за которое должен отвечать драйвер. ФункцияAddDevice должна создать объект устройства с помощью вызова IoCreateDevice и при необходимости присоединить его к стеку устройств с помощью IoAttachDeviceToDeviceStack .
NTSTATUS DriverUnload (
IN PDRIVER_OBJECT DriverObject) // указательнаобъектдрайвера
Вызывается при выгрузке драйвера. В этой функции должны осво
бождаться все затребованные драйвером ресурсы. Драйверы WDM‑модели
выполняют эти действия в обработчике запросов IRP_MJ_PNP с субкодом IRP_MN_REMOVE_DEVICE, то есть при удалении устройства из системы.
Следует выделить отдельный класс точек входа драйвера, которые предназначены для обработки IRP‑пакетов с различными кодами операций. Эти точки входа регистрируются при загрузке драйвера в функции DriverEntry . Регистрация производится путем заполнения элементов массива MajorFunction адресами диспетчеризуемых функций. Индексом в этом массиве являются коды IRP_MJ_XXX, то есть описанные числами типы пакетов IRP. Диспетчер ввода / вывода, ориентируясь на заполнение этого массива, вызывает нужные функции драйвера.
Поскольку для драйвера важны только адреса рабочих процедур, то все рабочие процедуры могут иметь совершенно произвольные имена.
1.5 Пакет запроса ввода / вывода ( IRP)
Пакеты ввода / вывода (IRP‑пакеты) используются для передачи запросов к драйверу от его клиентов. Они являются структурами данных переменной длины, и состоят из стандартного заголовка, содержащего общую учетную информацию, и одного или нескольких блоков параметров, называемых ячейками стека ввода / вывода (I/OStackLocation).
Приведем структуру заголовка IRP‑пакета:
Таблица 1.5.1. Структура заголовка IRP‑пакета.
Поля | Описание |
IO_STATUS_BLOCK IoStatus | Статус запроса |
PVOID AssociatedIrp. SystemBuffer | Указатель на системный буфер для случая, если устройство поддерживает буферизованный ввод / вывод |
PMDL MdlAddress | Указатель на MDL‑список в случае, если устройство поддерживает прямой ввод / вывод |
PVOID UserBuffer | Адрес пользовательского буфера для ввода / вывода |
BOOLEAN Cancel | Индикатор того, что IRP‑пакет должен быть аннулирован |
Основное назначение ячеек стека ввода / вывода состоит в том, чтобы хранить функциональный код и параметры запроса на ввод / вывод. Ниже, в таблице 1.5.2 приводятся поля ячеек стека ввода / вывода, к которым драйвер может обращаться непосредственно по указателю (чего не рекомендуется делать для остальных полей):