Чтение онлайн

ЖАНРЫ

Использование NuMega DriverStudio для написания WDM-драйверов

Тарво Александр

Шрифт:

И драйвер, и приложение пользователя различают, какую функцию управления устройством вызвать, при помощи IOCTL-кодов. Такой код представляет собой обыкновенное 32-разрядное число. Для удобства ему директивой #define задают какое-то понятное имя. Например, в нашем случае зададим IOCTL-код, при получении которого драйвер будет возвращать количество памяти "на борту" PCI-устройства.

#define XDSPDRV_IOCTL_GETMEMSIZE 0x800

Если при чтении драйверу посылается IRP-пакет со старшим кодом функции IRP_MJ_READ, при записи — IRP_MJ_WRITE, то при вызове функции DeviceIOControl для нашего устройства драйвер получает пакет со старшим кодом IRP_MJ_IOCONTROL и младшим — код самой IOCTL-функции. Метод DeviceControl вызывается при получении драйвером IRP со старшим кодом IRP_MJ_DEVICE_CONTROL. Она действует подобно методу StartIo. В зависимости от кода IOCTL производится вызов соответствующей функции.

NTSTATUS XDSPdrvDevice::DeviceControl(KIrp I) {

 NTSTATUS status;

 t << "Entering XDSPdrvDevice::Device Control, " << I << EOL;

 switch (I.IoctlCode) {

 case XDSPDRV_IOCTL_GETMEMSIZE:

//Получен определенный нами IOCTL-код XDSPDRV_IOCTL_GETMEMSIZE.

//Вызвать соответствующий обработчик.

status = XDSPDRV_IOCTL_GETMEMSIZE_Handler(I);

break;

 default:

//Этот код не определен.

status = STATUS_INVALID_PARAMETER;

break;

 }

 if (status == STATUS_PENDING)

 // Если драйвер по каким-то причинам отложил обработку запроса, переменной status

 //присваивается значение STATUS_PENDING. Этот код будет возвращен методом

 //DeviceControl.

 {

return status;

 } else

 //В противном случае завершаем обработку пакета.

 {

return I.PnpComplete(this, status);

 }

}

Метод XDSPDRV_IOCTL_GETMEMSIZE_Handler является обработчиком IOCTL–кода XDSPDRV_IOCTL_GETMEMSIZE. Получив этот код, драйвер возвращает общий объем памяти устройтсва. Шаблон метода сгенерирован DriverWizard, но программист должен написать практически весь его код.

NTSTATUS XDSPdrvDevice::XDSPDRV_IOCTL_GETMEMSIZE_Handler(KIrp I) {

 NTSTATUS status = STATUS_SUCCESS;

 t << "Entering XDSPdrvDevice::XDSPDRV_IOCTL_GETMEMSIZE_Handler, " << I << EOL;

 //Количество памяти будет возвращено как число unsigned long. Поэтому определяем

 //указатель на unsigned long.

 unsigned long *buf;

 //Получаем указатель на буфер пользователя

 buf=(unsigned long*) I.UserBuffer;

 //Записываем туда количество памяти нашего устройства. Получаем его при помощи

 //метода Count объекта m_MainMem.

 *buf=m_MainMem.Count;

 //Длина возвращаемых нами данных равна длине числа unsigned long.

 I.Information = sizeof(unsigned long);

 //Возвращаем STATUS_SUCCESS

 return status;

}

Написание драйвера завершено. Возможно, у Вас сложилось впечатление, что DriverWizard может практически все и написание драйвера — очень простая задача. Но не следует забывать, что наш драйвер — всего-то простейшая демонстрационная программа, которая практически не выполняет никаких полезных действий. Написание реальных драйверов является гораздо более сложной задачей.

Если бы драйвер был написан с использованием пакета DDK, то он бы имел практически ту же структуру и почти тот же код (правда, не объектно-ориентированный). Но в таком случае весь драйвер пришлось бы писать вручную, а DriverWizard генерирует скелет драйвера автоматически. Это сильно облегчает процесс разработки драйвера, позволяя программисту не заботиться о написании скелета драйвера и предохраняя его от возможных ошибок.

2.4 Разработка dll-библиотеки для взаимодействия с драйвером

dll-библиотека (Dynamic Link Library) — программный модуль, который может быть динамически подключен к выполняющемуся процессу. Dll–библиотека может содержать функции и данные. При подключении dll к процессу она отображается на адресное пространство этого процесса.

Если говорить по русски, то это означает: в любой момент времени программа может загрузить dll-библиотеку, получить указатели на функции и данные этой библиотеки. Потом приложение как-то использует функции и данные библиотеки, и когда они больше не нужны — выгружает библиотеку.

Dll-библиотека содержит два вида функций: внешние (External) и внутренние (Internal). Внутренние функции могут вызываться только самой dll, а внешние может также вызывать приложение, подключившее библиотеку. В этом случае говорят, что dll-библиотека экспортирует функции и данные.

Как было упомянуть выше, в настоящее время для связи с драйвером используется схема Приложение→Библиотека dll→Драйвер. При использовании такой архитектуры запрос приложения на операцию ввода-вывода поступает в dll-библиотеку, проходит там предварительную обработку и передается драйверу. Результат, возвращенный драйвером библиотеке dll, также обрабатывается и передается приложению. Преимущества такого подхода очевидны:

• Выпускается огромное количество различных периферийных устройств, и, соответственно, для каждого устройства разрабатывается свой драйвер. Программисту будет тяжело разбираться во всех тонкостях работы драйвера устройства: формат данных для чтения/записи, запоминать непонятные IOCTL-коды. Гораздо лучше — предоставить для него понятный интерфейс API-функций для работы с устройством. Еще лучше, если такой интерфейс будет унифицированным для всех устройств данного типа. Задача dll-библиотеки, поставляемой с драйвером – связать стандартные интерфейсы, предоставляемые прикладной программе, со специфическими алгоритмами работы драйвера.

• если в будущем измениться алгоритм взаимодействия приложения с драйвером, то пользователю для работы с новым драйвером будет необходимо обновить только библиотеку dll. Все ранее разработанные программы остануться прежними.

Естественно, такой подход имеет свои минусы. В данном случае за счет большего числа вызовов, через которые проходит запрос на ввод-вывод, снижается быстродействие работы системы.

В нашем случае нам необходимо разработать dll-библиотеку, которая будет предоставлять приложению три функции: чтение памяти, запись в память и получение общего количества памяти устройства. Естественно, dll – библиотеку мы также будем проектировать в среде Visual C++.

Поделиться с друзьями: