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

Шрифт
Интервал

>NTSTATUS XDSPdrvDevice::SystemControl(KIrp I) {

> t << "Entering XDSPdrvDevice::SystemControl\n";

> I.ForceReuseOfCurrentStackLocationInCalldown();

> return m_Lower.PnpCall(this, I);

>}

Метод Invalidate вызывается, когда устройство тем или иным образом завершает свою работу: из функций OnStopDevice, OnRemoveDevice а также при всевозможных ошибках. Метод Invalidate объекта устройства также вызывается из деструктора. Его можно вызывать несколько раз — не произойдет ничего страшного; но в методах Invalidate нет никакой защиты от реентерабельности. Т.е. если при работе метода Invalidate возникает какая– либо ошибка и из-за этого Invalidate должен будет вызваться снова, то ни DriverWorks, ни ОС Windows не станут этому мешать. Разработчик должен сам предусмотреть такую возможность и принять меры, чтобы подобная ситуация не привела к нехорошим последствиям.

В методе Invalidate объекта устройства вызываются методы Invalidate всех ресурсов, которые использует драйвер: областей памяти, регистров, контроллеров DMA и т.п. При этом выполняется процедура, обратная процедуре инициализации: освобождаются все ресурсы, используемые объектом, закрываются все его хэндлы, но сам объект не уничтожается и может быть проинициализирован снова. В нашем простом случае нет смысла что-либо корректировать в тексте этого метода — DriverWizard все сделал за нас. Еще бы, ведь наше устройство имеет только один ресурс — диапазон адресов памяти. Но при проектировании более сложных драйверов следует обращать внимание на данный метод. Если разработчик добавляет какие-либо системные ресурсы вручную, то он должен включить соответствующий код в метод Invalidate.

>VOID XDSPdrvDevice::Invalidate() {

> //Вызвать метод Invalidate для диапазона адресов памяти.

> m_MainMem.Invalidate();

>}

Далее следует виртуальная функция OnStartDevice. Она вызывается при приходе IRP– пакета со старшим кодом IRP_MJ_PNP и кодом подфункции IRP_MN_START_DEVICE. Обычно это происходит при старте драйвера после выполнения всех необходимых проверок и инициализаций. В этой функции драйвер инициализирует физическое устройство и приводит его в рабочее состояние. Также здесь драйвер получает список ресурсов, которые имеются в устройстве. На основе этого списка ресурсов выполняется их инициалиция. Хотя мы не вносим изменений в данную функцию, но нельзя не отметить ее огромную важность. Именно в данной функции выполняется инициализация устройства и получение списка его ресурсов. По другому мы их получить никак не можем, т.к. имеем дело с PnP устройством, для которого система распределяет ресурсы самостоятельно.

>NTSTATUS XDSPdrvDevice::OnStartDevice(KIrp I) {

> t << "Entering XDSPdrvDevice::OnStartDevice\n";

> NTSTATUS status = STATUS_SUCCESS; I.Information() = 0;

> //Здесь драйвер получает список ресурсов устройства

> PCM_RESOURCE_LIST pResListRaw = I.AllocatedResources();

> PCM_RESOURCE_LIST pResListTranslated = I.TranslatedResources();

> // Наше устройство является PCI – карточкой и в своем конфигурационном поле содержит

> //базовые адреса диапазонов памяти и портов ввода-вывода. Получаем эти данные

> KPciConfiguration PciConfig(m_Lower.TopOfStack());

> // Инициализируем каждый диапазон отображения адресов. Теперь, после инициализации,

> //базовый адрес отображенного диапазона в виртуальном адресном пространстве

> //процессора может быть получен при помощи вызова метода Base(). Физический адрес на

> //шине адреса ЦП – при помощи CpuPhysicalAddress().

> status = m_MainMem.Initialize(pResListTranslated, pResListRaw, PciConfig.BaseAddressIndexToOrdinal(0));

> if (!NT_SUCCESS(status)) {

>  //Неудача при инициализации области памяти

>  Invalidate();

>  return status;

> }

> //Сюда можно добавить код, выполняющий необходимую инициализацию, специфичную для

> //этого устройства

> return status;

>}

Виртуальная функция OnStopDevice вызывается при остановке устройства. В этом случае система посылает драйверу IRP с старшим кодом IRP_MJ_PNP и кодом подфункции IRP_MN_STOP_DEVICE. Драйвер должен осободить все используемые ресурсы.

>NTSTATUS XDSPdrvDevice::OnStopDevice(KIrp I) {

> NTSTATUS status = STATUS_SUCCESS;

> t << "Entering XDSPdrvDevice::OnStopDevice\n";

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

> 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 подробно описано, почему ЛЮБОЙ драйвер должен поддерживать этот механизм. Это связано, в основном, с проблемами надежности и устойчивости работы системы. Ведь сбой в драйвере — это, практически, сбой в ядре ОС.