Интернет-магазин

Просмотр корзины
В корзине:

товаров - 0 шт.



§ 25. Драйвер с обработкой прерывания от LPT порта (Часть 2)

Дмитрий Иванов, Январь 2007
Статья впервые опубликованна 16 Мая 2014

Файлы к статье скачать

Продолжаем двигаться дальше. Напомню, в предыдущей статье мы скомпилировали драйвер, который может обрабатывать прерывания от LPT порта. Теперь нам надо создать приложение, которое будет запускать этот драйвер и реагировать на прерывание, которое обрабатывает драйвер.


Создадим Windows приложение на основе MFC в Microsoft Visual C++ 6.0. Для этого создайте проект MFC приложения на основе диалогового окна (о том как это делается я уже подробно рассказывал в какой-то из бесплатных статей). Назовите приложение, например, WinTest. Добавьте на окно диалога две кнопки. Назовите их, например, Start и Stop чтобы вся конструкция выглядела примерно так:

Далее, добавьте к проекту файлы CSManager.cpp и h.h (см. файлы к стаье), в которых реализована динамическая загрузка драйвера в память (в качестве символического имени драйвера используется имя drvNAME). В принципе, проект можно самим и не строить, он уже полностью готовый находтся в файлах к статье.

Рассмотрим код, выполняемый при нажатии конопки Start (функция OnButton1()). Сначала, спомощью вызова функции InstallDriverWithSCManager() реализованной в файле CSManager.cpp, проводится динамическая загрузка драйвера в память. Если загрузка прошла успешно, выводится сообщение об этом. Затем мы с помощью OpenEvent() подключаемся к глобальному системному событию с именем SignalEvent (помните, такое имя мы задали в коде драйвера для этого события). Потом стартуем параллельный поток, в котором будет отслеживаться возникновение события.

void CWinTestDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	bool status=InstallDriverWithSCManager();

	if (status)
	{
		MessageBox("Ok", "", MB_OK);
		hEvent=OpenEvent(SYNCHRONIZE, FALSE, "SignalEvent");
		AfxBeginThread(proc1,this);
	}
	else
	{
		MessageBox("Kall", "", MB_OK);
	}	
}

Рассмотрим функцию proc1() в контексте которой выполняется параллельный поток. В ней стартует бесконечный цикл, внутри которого сразу же идет вызов функции WaitForSingleObject(), которая полностью останавливает выполнение этого потока без затрат процессорного времени до тех пок, пока, событие SignalEvent не перейдет в активное состояние. А это произойдет только тогла, когда случится прерывание порта LPT и в функции драйвера по обработке прерывания это событие не будет взведено. Если такое случилось, то поток "размораживается", событие сбрасывается и выдается информационное собщение о том, что произошло прерыание. Начинается новый этап цикла while, но событие уже сброшено (как минимум, в драйвере) и WaitForSingleObject опять начинает ждать, пока не произойдет прерывание.

UINT proc1(LPVOID pParam)
{
	while(true)
	{
		WaitForSingleObject(hEvent, INFINITE);
		ResetEvent(hEvent);
		MessageBox(NULL,"Произошло событие","Info",MB_OK);
	}
	return 0;
}

Напомню, что если бы мы не запускали параллельный поток, а сделали бы вызов WaitForSingleObject(), например внутри обработчика конопки, то программа полностью зависла бы и не реагировала ни на какие действия с нашей стороны, т.к. она будет "заморожена" и "очнется" только на то время когда выскочит сообщение о прошедшем событии, после чего снова "впадет в спячку".

Обработчик кнопки Stop весьма прост и содержит только вызов функции StopDriver(), реализованной в файле CSManager.cpp, которая проводит корректную выгрузку драйвера из памяти.

void CWinTestDlg::OnButton2() {
	
	StopDriver();
	MessageBox("Stop Ok", "", MB_OK);	
}

Прежде чем тестировать это приложение, необходимо убедиться в одной вещи. Зайдете Пуск -> Настройка -> Панель управления -> Система -> Оборудование -> Диспетчер устройств -> Порты (COM и LPT) -> Порт принтера (LPT1) -> Свойства. На вкладке "Параметры порта" обязательно должна быть установле кнопка "Использовать любое прерывание, назначенное порту".

Итак, настало время проверить, работает ли вся эта система из приложения и драйвера, ловится ли прерывание от LPT1. Запускайте приложение, стартуйте драйвер. Если выскочило сообщение "Kall" (уж простите за реалистичность), убедитесь, что драйвер xDRV.sys (который мы скомпилировали в прошлой статье) расположен в одной директории с программой. Теперь нам надо вызвать это самое прерывание. Для этого достаточно соединить проводником любой из выводов с 18 по 25 (земля) с выводом 10 (ACK, запрос на прерывание). Я для этого использую мое LPT устройство, не раз появлявшееся на страницах этого сайта:

Yes! Вот и оно! Выскакивает сообщение о прерывании. Лично у меня в этот момент, когда я в первый раз это сделал эмоции пошли через край. Заодно, в регистре DATA должно появится число 60. Теперь, нажмите Ok на окне сообщения, отсоедините 10-тый вывод от земли и подсоедините снова. Вот тут может возникнуть разочарование: сообщения о прерывании нет, только почему-то остальные светодиоды переодически помаргивают. Это происходит из-за вмешательства в нашу работу родного драйвера порта, входящего в состав Windows. Это именно он поймал прерывание, и стал "общаться" с принтером, который как он считает там сейчас установлен (поэтому светодиоды помигивают). Тут уж сходу ничего не поделаешь, придется подождать. Если его так и оставить с замкнутым 10-ым выводом примерно на минуту в покое, то он убедившись что принтер "сдох" и на его призывы не отвечает понимает, что ловить ему здесь не чего и больше в работу нашего драйвера не вмешивается. Теперь остановите наш драйвер кнопкой Stop, перезапустите приложение, загрузите драйвер. Вот теперь на каждое возникновение прерывания программа реагирует адекватно с выводом сообщения. С этим конечно можно как-то бороться програмным способом, но мне это пока не известно, надо исходник Microsoft-овского драйвера паралельного порта изучать (он в примерах DDK есть).


Итак, поздравляю! Вы только что освоили на практике, как обрабатывать прерывания от порта LPT в Windows 2000, XP, что не так уж и слабо.




© Дмитрий Иванов
Январь 2007
http://www.kernelchip.ru



© KERNELCHIP 2006 - 2017