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

ЖАНРЫ

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

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

Шрифт:

 Invalidate;

 // Здесь добавляется код, специфичный для данного устройства.

 return status;

}

Виртуальная функция OnRemoveDevice вызывается при извлечении устройства из системы. При этом системная политика PnP сама позаботится об удалении PDO.

NTSTATUS XDSPdrvDevice::OnRemoveDevice(KIrp I) {

 t << "Entering XDSPdrvDevice::OnRemoveDevice\n";

 // Освободить ресурсы устройства

 Invalidate;

 // Здесь добавляется код, специфичный для данного устройства.

 return STATUS_SUCCESS;

}

Иногда бывает необходимо отменить обработку IRP, уже поставленного в очередь (такие запросы иногда посылает диспетчер В/В). Когда такая ситуация может возникнуть?

Представим такую ситуацию: в приложении пользователя поток послал нашему драйверу запрос на ввод-вывод и завершил свою работу. А IRP-пакет попал в очередь запросов и терпеливо ждет своей очереди на обработку. Конечно же, обработка такого "бесхозного" IRP-пакета должна быть отменена. Для этого драйвером поддерживается целый механизм отмены обработки запросов. В Win2000 DDK подробно описано, почему ЛЮБОЙ драйвер должен поддерживать этот механизм. Это связано, в основном, с проблемами надежности и устойчивости работы системы. Ведь сбой в драйвере — это, практически, сбой в ядре ОС.

В классе KPnPDevice механизм отмены запроса реализован при помощи метода CancelQueuedIrp.

VOID XDSPdrvDevice::CancelQueuedIrp(KIrp I) {

 //Получаем очередь IRP-пакетов этого устройства.

 KDeviceQueue dq(DeviceQueue);

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

 //быть обработан.

 if ( (PIRP)I == CurrentIrp ) {

//Уничтожить пакет.

CurrentIrp = NULL;

//При вызове метода CancelQueuedIrp устанавливается глобальная системная

//защелка (SpinLock). Теперь следует ее сбросить.

CancelSpinLock::Release(I.CancelIrql);

t << "IRP canceled " << I << EOL;

I.Information = 0;

I.Status = STATUS_CANCELLED;

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

PnpNextIrp(I);

 }

 //Удалить из очереди пакет. Если это удалось, то функция вернет true.

 else if (dq.RemoveSpecificEntry(I)) {

// Это удалось. Теперь сбрасываем защелку.

CancelSpinLock::Release(I.CancelIrql);

t << "IRP canceled " << I << EOL;

I.Information = 0;

I.PnpComplete(this, STATUS_CANCELLED);

 } else {

//Неудача. Сбрасываем защелку.

CancelSpinLock::Release(I.CancelIrql);

 }

}

Меотод StartIo является виртуальной функцией. Она вызывается системой, когда драйвер готов обрабатывать следующий запрос в очереди. Это чрезвычайно важная функция: она является диспетчером всех запросов на ввод-вывод, поступаемых к нашему драйверу. В функции вызываются обработчики запросов на чтение, запись а также обработчики вызовов IOCTL. К счастью, умный DriverWizard генерирует скелет функции автоматически и вносить изменения в нее в нашем простом случае не требуется. В принципе, в эту функцию можно ввести какие-то дополнительные проверки IRP-пакетов.

VOID XDSPdrvDevice::StartIo(KIrp I) {

 t << "Entering StartIo, " << I << EOL;

 // Здесь надо проверить, отменен этот запрос или нет. Это производится при помощи вызова

 //метода TestAndSetCancelRoutine. Также этот метод устанавливает новую функцию отмены

 //пакетов, если это необходимо. Адрес новой функции передается вторым параметром. Если

 //он равен NULL,то вызывается старая функция. Если пакет должен быть отменен, функция

 //вернет FALSE.

 if (!I.TestAndSetCancelRoutine(LinkTo(CancelQueuedIrp), NULL, CurrentIrp)) {

//Пакет отменен.

return;

 }

 // Начать обработку запроса.

 // Выбрать необходимую функцию

 switch (I.MajorFunction) {

 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;

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