Шрифт:
Интервал:
Закладка:
XDSPdrvDevice::~XDSPdrvDevice() {
t << "Entering XDSPdrvDevice::~XDSPdrvDevice() (destructor)n";
}
Метод DefaultPnp — виртуальная функция, которая должна быть переопределена любым объектом устройства. Эта обработчик по умолчанию для IRP-пакета, у которого старший код функции (major function code) равен IRP_MJ_PNP. Драйвер обрабатывает некоторые из таких пакетов, у которых младший код функции равен IRP_MN_STOP_DEVICE, IRP_MN_START_DEVICE и т.п. (см. ниже) также при помощи виртуальных функций. Но те пакеты, которые не обрабатываются объектом устройства, передаются этой функции. Она ничего с ними не делает, а просто передает их устройству нижнего уровня (если такое есть, конечно). Не стоит изменять текст этой функции.
NTSTATUS XDSPdrvDevice::DefaultPnp(KIrp I) {
t << "Entering XDSPdrvDevice::DefaultPnp with IRP minor function=" << PNPMinorFunctionName(I.MinorFunction()) << EOL;
I.ForceReuseOfCurrentStackLocationInCalldown();
return m_Lower.PnpCall(this, I);
}
Метод SystemControl выполняет похожую функцию для IRP-пакетов, у которых старший код функции IRP_MJ_SYSTEM_CONTROL. Он также является виртуальной функцией и не выполняет никаких полезных действий, а просто передает IRP-пакет устройству нижнего уровня. Что-то менять в тексте этого метода надо только в том случае, если наше устройство является WMI-провайдером.
NTSTATUS XDSPdrvDevice::SystemControl(KIrp I) {
t << "Entering XDSPdrvDevice::SystemControln";
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::OnStartDevicen";
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::OnStopDevicen";
//Освободить ресурсы устройства
Invalidate();
// Здесь добавляется код, специфичный для данного устройства.
return status;
}
Виртуальная функция OnRemoveDevice вызывается при извлечении устройства из системы. При этом системная политика PnP сама позаботится об удалении PDO.
NTSTATUS XDSPdrvDevice::OnRemoveDevice(KIrp I) {
t << "Entering XDSPdrvDevice::OnRemoveDevicen";
// Освободить ресурсы устройства
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. Также этот метод устанавливает новую функцию отмены
- Тонкости реестра Windows Vista. Трюки и эффекты - Роман Клименко - Программы
- Защита вашего компьютера - Сергей Яремчук - Программы
- 200 лучших программ для Linux - Сергей Яремчук - Программы
- Технология Windows Installer. Часть I. Обзор возможностей - Алифанов Андрей - Программы
- Прикладные свободные программы и системы в школе - Максим Отставнов - Программы