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

ЖАНРЫ

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

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

Шрифт:

 return status;

}

Аналогично метод Close вызывается при разрыве связи приложения с драйвером.

NTSTATUS XDSPdrvDevice::Close(KIrp I) {

 NTSTATUS status;

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

 //Здесь можно вставить код пользователя, который должен быть вызван при разрыве

 //приложением связи с устройством.

 status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);

 t << "XDSPdrvDevice::Close Status " << (ULONG)status << EOL;

 return status;

}

В этих методах можно ввести проверки каких-либо условий. Отвлечемся на секунду от нашей PCI-карточки и обратим внимание на другой хороший пример — тот же программатор микроконтроллеров. Предположим, пользователь подключил программатор к компьютеру и начинает записывать в память микроконтроллера разработанную им программу. В принципе, ничто не помешает ему открыть еще одну копию программы и писать в ту же микросхему что-то совсем другое. В результате, в эту несчастную микросхему запишется невообразимая каша. Для того, чтобы избежать такой ситуации, в объекте драйвера надо установить флаг, который будет показывать, свободно ли это устройство, или оно уже кем-то используется. Это может выглядеть так:

NTSTATUS MyPrettyDevice::OnStartDevice(KIrp I) {

 NTSTATUS status = STATUS_SUCCESS;

 I.Information = 0;

 . . . //Какая-то инициализация – может, PCI,

 //может – какое-то другое оборудование…

 //Устройство только что заработало – конечно, оно свободно…

 m_AlreadyUsed = false;

 return status;

}

NTSTATUS MyPrettyDevice::Create(KIrp I) {

 NTSTATUS status;

 if (m_AlreadyUsed)

//Это устройство уже используется кем-то. Нельзя допустить его использование

//несколькими приложениями одновременно.

//Возвращаем ошибку.

status = I.PnpComplete(this, STATUS_INVALID_PARAMETER, IO_NO_INCREMENT);

 else {

//Это устройство свободно. Устанавливаем флаг и возвращаем успех.

m_AlreadyUsed = false;

status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);

 }

 return status;

}

NTSTATUS MyPrettyDevice::Close(KIrp I) {

 NTSTATUS status;

 //Пользователь закончил работу с устройством, теперь оно свободно.

 //Сбрасываем флаг.

 m_AlreadyUsed = false;

 status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);

 return status;

}

Функция SerialRead вызывается, когда драйвер получает запрос на чтение. Это важная функция. Т.к. мы хотим, чтобы приложение пользователя могло читать и писать в память микросхемы, то именно сюда необходимо добавлять наш код. Все фрагменты кода, добавленные программистом, будут выделены жирным шрифтом:

//This code was added by the programmer

Фактически в данном методе мы должны прочитать содержимое памяти и передать его приложению пользователя. Но тут самое время вспомнить, что плата обменивается с памятью 4– байтными словами. Поэтому для операций с памятью следует применять метод ind/outd.

void XDSPdrvDevice::SerialRead(KIrp I) {

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

 NTSTATUS status = STATUS_SUCCESS;

 //Здесь мы получаем буфер пользователя. Он передается через Irp.

 KMemory Mem(I.Mdl);

 PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace;

 //Теперь pBuffer – указатель на буфер пользователя.

 //Здесь мы получаем число 4-байтных слов, которое должно быть прочитано. Оно также

 //передается через Irp, как запрашиваемое количество байт для чтения.

 ULONG dwTotalSize = I.ReadSize(CURRENT);

 ULONG dwBytesRead = dwTotalSize;

 //Здесь мы читаем заданное число байт из памяти устройства. Плата XDSP680 обменивается

 //с памятью 4-байтными словами.Начальный адрес – 0, dwTotalSize 4-байтных слов будут

 //прочитаны в буфер pBuffer.

 m_MainMem.ind(0,(ULONG*)pBuffer,dwTotalSize);

 //Возвращаем количество прочитанных слов

 I.Information = dwBytesRead;

 I.Status = status;

 //Обработать следующий IRP-пакет.

 PnpNextIrp(I);

}

Метод SerialWrite работает практически так же, только он записывает данные в память устройства, а не считывает их.

void XDSPdrvDevice::SerialWrite(KIrp I) {

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

 NTSTATUS status = STATUS_SUCCESS;

 KMemory Mem(I.Mdl);

 PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace;

 ULONG dwTotalSize = I.WriteSize(CURRENT);

 ULONG dwBytesSent = dwTotalSize;

 m_MainMem.outd(0,(ULONG*)pBuffer,dwTotalSize);

 I.Information = dwBytesSent;

 I.Status = status;

 PnpNextIrp(I);

}

Как мы упоминали ранее, для большинства драйверов устройств недостаточно функций чтения и записи. Мало-мальски сложное устройство требует еще и множества других операций: получить состояние, получить информацию об устройстве, как-то отконфигурировать его. Для выполнения этих задач служат функции управления вводом-выводом, IO Control; сокращенно — IOCTL. IOCTL предоставляет программисту возможность разработать практически неограниченное количество различных функций управления устройством.

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