case IRP_MJ_READ:
//Чтение
SerialRead(I);
break;
case IRP_MJ_WRITE:
//Запись
SerialWrite(I);
break;
case IRP_MJ_DEVICE_CONTROL:
//IOCTL
switch (I.IoctlCode()) {
default:
//Мы обрабатываем пакет, который не должен быть обработан.
//Поэтому просто выходим.
ASSERT(FALSE);
break;
}
break;
default:
// Драйвер занес в очередь какой-то непонятный пакет,
//он не должен быть обработан.
ASSERT(FALSE);
PnpNextIrp(I);
break;
}
}
Метод Create вызывается, когда пользовательское приложение пытается установить связь с драйвером при помощи вызова API CreateFile(). Обычно этот запрос обрабатывается в нашем объекте устройства и нет смысла пересылать запрос устройству нижнего уровня.
NTSTATUS XDSPdrvDevice::Create(KIrp I) {
NTSTATUS status;
t << "Entering XDSPdrvDevice::Create, " << I << EOL;
//Здесь можно вставить код пользователя, который должен быть вызван при установлении
//приложением связи с устройством.
status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);
t << "XDSPdrvDevice::Create Status " << (ULONG)status << EOL;
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;
//Пользователь закончил работу с устройством, теперь оно свободно.