Пояснения по использованию

IRP_MJ_DEVICE_CONTROL и IRP_MJ_INTERNAL_DEVICE_CONTROL

Пример обработки запросов чтения/записи

Завершение запроса в/в

Получение буфера

Расположение буфера в зависимости от метода его передачи для запросов чтения и записи полностью определяется таблицей 1.

Для завершения запроса IRP на чтение/запись, необходимо установить поле Irp->IoStatus.Information равным числу прочитанных/записанных в буфер байт. В случае буферизованного в/в это поле укажет Диспетчеру в/в, сколько байт нужно скопировать из промежуточного буфера в невыгружаемой области системного адресного пространства в пользовательский буфер.

Пример обработки запросов чтения/записи. Получение адреса буфера для чтения/записи и его длины. Такой код вставляется в обработчик диспетчерских функций MajorFunction[IRP_MJ_READ], MajorFunction[IRP_MJ_WRITE].

//получение адреса буфера для чтения/записи

//в случае буферизованного в/в

BufferAddress = Irp->AssociatedIrp.SystemBuffer;

//в случае прямого в/в

BufferAddress = MmGetSystemAddressForMdl(Irp->MdlAddress);

//в случае Neither i/o

BufferAddress = Irp->AssociatedIrp.UserBuffer;

//получение длины буфера для чтения/записи

stack = = IoGetCurrentIrpStackLocation(Irp);

BufferLength = stack->Parameters.Read.Length;

Как говорилось выше, точка входа драйвера IRP_MJ_DEVICE_CONTROL вызывается при вызове пользовательской программой функции DeviceIoControl(). Прототип этой функции показан на рис.:

BOOL DeviceIoControl(

HANDLE hDevice, // описатель открытого устройства

DWORD dwIoControlCode, // контрольный код запрашиваемой операции

LPVOID lpInBuffer, // адрес буфера со входными данными

DWORD nInBufferSize, // размер входного буфера

LPVOID IpOutBuffer, // адрес буфера для приема выходных данных

DWORD nOutBufferSize, // размер выходного буфера

LPDWORD IpBytesReturnedy // адрес переменной для получения числа реально

// переданных байтов данных

LPOVERLAPPED IpOverlapped // адрес структуры для обеспечения асинхронности в/в

);

Рис.. Прототип функции DeviceIoControl().

Зачем нужен irp_mj_device_control? Когда драйвер поддерживает определенный тип устройства, такое устройство обычно имеет набор специализированных возможностей, которые могут управляться через драйвер. Эти возможности не могут быть задействованы использованием стандартных кодов функций irp_mj_create, irp_mj_close, irp_mj_read и irp_mj_write. Например, драйвер устройства для лентопротяжного устройства SCSI должен обеспечить механизм, который дает возможность пользователям послать запрос на стирание ленты. Такие зависящие от устройства запросы описываются, используя главный функциональный код irp_mj_device_control. Устройство обычно может принимать несколько разнотипных команд. Для драйвера тип такой команды указывается Кодом Управления ввода-вывода (IOCTL), который передается как часть запроса в/в.

Возвращаясь к функции DeviceIoControl(), код управления в/в (IOCTL) указывается во втором параметре этой функции. Код управления в/в имеет специальный формат, указывающий метод передачи буфера и другую информацию. Этот формат будет рассмотрен в следующем разделе.

Путаница может возникнуть при задании буфера для в/в. Как видно из прототипа функции DeviceIoControl(), она может передавать 2 буфера (3 и 5 параметры). Несмотря на названия буферов – входной и выходной буфер – выходной буфер может быть использован как для передачи данных в драйвер, так и для приема данных из драйвера. Разница будет в используемом методе передачи буфера. Использование буферов будет подробно рассмотрено в разделе “Получение буфера”.

[8.1.2.2] Задание кода управления вводом/выводом (IOCTL)

Формат кода управления в/в показан на рис..

Для задания кода в таком формате в заголовочных файлах ntddk.h и windows.h определен специальный макрос CTL_CODE:

CTL_CODE(DeviceType, Function, Method, Access)

Рис. 2. Формат кода управления в/в

Рассмотрим составляющие кода управления в/в:

· Поле DeviceType определяет тип объекта-устройство, которому предназначен запрос. Это тот самый тип устройства, который передается функции IoCreateDevice() при создании устройства. Как уже говорилось, существует два диапазона значений типов устройств: 0-32767 – зарезервированные значения для стандартных типов устройств, 32768-65535 – диапазон значений типов устройств для выбора разработчиком. Следует отметить, что несколько разных устройств могут иметь одинаковое значение типа устройства. Поскольку каждый запрос в/в предназначен конкретному устройству, совпадение типов устройств не приводит к неприятностям. Также необходимо отметить, что тип устройства в коде управления в/в может не совпадать с типом устройства объекта-устройство и это не будет являться ошибкой.

· Поле Function идентифицирует конкретные действия, которые должно предпринять устройство при получении запроса. Значения поля Function должны быть уникальны внутри устройства. Как и для типов устройств, существует два диапазона значений поля Function: 0-2047 – зарезервированный диапазон значений, и 2048-4095 – диапазон значений, доступный разработчикам устройств.

· Поле Method указывает метод передачи буферов данных. Для понимания этого поля вернемся к функции DeviceIoControl(). Функция передает два буфера – InBuffer и OutBuffer. Буфер InBuffer передает данные драйверу, буфер OutBuffer может передавать данные в обоих направлениях (к драйверу и от драйвера). В следующей таблице приведены возможные значения поля Method и методы передачи буферов InBuffer и OutBuffer.

  Значение поля Method Использование OutBuffer Используемый метод передачи буфера
InBuffer OutBuffer
METHOD_BUFFERED   Буферизованный в/в (Buffered I/O)
METHOD_IN_DIRECT Передача данных к драйверу Буферизованный в/в Прямой в/в. Осуществляется проверка буфера на доступ по чтению
METHOD_OUT_DIRECT Приема данных от драйвера Буферизованный в/в Прямой в/в. Осуществляется проверка буфера на доступ по записи
METHOD_NEITHER   Neither I/O

Местоположение буферов данных в пакете IRP будет рассмотрено в следующем разделе (“Получение буфера”).

· Поле Access указывает тип доступа, который должен был быть запрошен (и предоставлен) при открытии объекта-файл, для которого передается данный код Управления вводом-выводом. Возможные значения для этого параметра следующие:

· file_any_access. Это значение указывает, что при вызове CreateFile() мог быть запрошен любой доступ.

· file_read_access. Это значение указывает, что должен был быть запрошен доступ для чтения.

· file_write_access. Это значение указывает, что должен был быть запрошен доступ для записи.

Заметим, что file_read_access и file_write_access могут быть указаны одновременно, чтобы указать, при открытии устройства должен быть предоставлен и доступ на чтение, и доступ на запись.

Параметр Access требуется потому, что операции управления в/в, по своей сути не есть операция чтения или записи., Прежде, чем будет разрешена запрашиваемая операция в/в, Диспетчер Ввода - вывода должен знать, какой режим доступа нужно проверить в таблице описателей.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: