xDRV.sys - драйвер с обработкой прерывания LPT порта.
Драйвер xDRV.sys может свободно "общаться" с любым портом Вашего ПК (запись/чтение данных) под управлением ОС Windows NT, 2000, XP + самое главное, что отличает его от подобных аналогов, имеет возможность перехватывать и обрабатывать прерывание LPT порта! (имеется введу LPT1 c адресом 0x378 и запросом на прерывание IRQ 07). Пришлось хорошенько помучится с этм драйвером, пока он стал корректно и стабильно работать. Результатами успешной работы хотел бы поделиться с общественностью.
Изменения:
18.03.2007 - исправлена библиотека xDRV.dll. Теперь проблем с подключением библиотеки в других компиляторах быть не должно. Добавлен пример работы с драйвером на языке Delphi.
Программная часть
Теперь рассмотрим, как можно этот драйвер применить на практике. Для начала скачайте архив с драйвером и библиотекой функций для работы с ним.
Там Вы найдете собственно сам драйвер xDRV.sys, динамическую библиотеку xDRV.dll, статическую библиотеку xDRV.lib, которая может потребоваться при компиляции приложения со статическим подключением dll и заголовочный файл с описаниями функций, используя которые можно управлять драйвером. Рассмотрим эти самые функции:
С++: bool xDRV_OpenDriver();
Delphi: function xDRV_OpenDriver(): Boolean;
Драйвер xDRV.sys является динамически загружаемым. Для его загрузки и инициализации и служит эта функция. Если драйвер загружен успешно она вернет true, иначе false. Вызываться она должна один раз в начале работы приложения. Если она вернула false, попробуйте перезагрузить компьютер. Может быть xDRV.sys уже был загружен в память и функция xDRV_StopDriver() для его корректной остановки не использовалась. Драйвер и библиотека должны находится в одной директории с исполняемой программой.
С++: void xDRV_StopDriver();
Delphi: procedure xDRV_StopDriver();
Как ни покажется странным эта функция довольно важна. Должна быть обязательно вызвана в конце работы приложения. Если так не сделать драйвер останется в памяти и будет перехватывать прерывания. Хуже того, при повторной попытке его загрузки может возникнуть ошибка.
С++: void xDRV_Write(unsigned short PortAdr, unsigned char PortValue);
Эта функция позволяет записать байт данных (PortValue) в порт (PortAdr). Например, чтобы на всех линиях регистра DATA LPT порта установить еденицу нужно вызвать ее с параметрами: xDRV_Write(0x378, 255)
С++: unsigned char xDRV_Read(unsigned short PortAdr);
Delphi: function xDRV_Read(PortAdr: LongInt): Byte;
Назначение этой функции я думаю, в полне понятно. Она прочтет и вернет значение в порту (PortAdr).
А теперь самое интересное, ради чего весь этот драйвер и делался. Для того чтобы драйвер мог сообщить запустившему его приложению что произошло прерывание, необходимо передать ему адрес специальной функции с жестко заданной сигнатурой. Как только произойдет прерывание будет вызвана эта специальная функция. Она имеет вид:
void Имя_функции(void* имя_перемнной);
В качестве второго параметра xDRV_InitInterput() можно передать какое-либо значение (благо оно void), которое будет передано в спец. функцию при ее вызове драйвером. Особенно такая возможность будет смысл при работе в MFC, где можно будет передать адрес на класс приложения.
Чтобы окончательно разъяснить принципы работы с xDRV.sys предлагаю Вашему вниманию три готовых проекта тестовых приложений с исходным кодом, использующих все функции этого драйвера. Два из них написаны на языке Cи\C++ в среде Microsoft Visual C++ 6.0. Первое в WinAPI варианте, второе - MFC. И наконец, добавлен тестовый проект на языке Delphi (среда разработки: Borland Delphi 7). Желательно, приложения не запускать до тех пор, пока Вы не ознакомитесь с этой статьей до конца.
Теперь займемся "железом". Тут есть некоторые спецефические особенности, без учета которых регестрировать прерывания не удасться.Зайдете Пуск -> Настройка -> Панель управления -> Система -> Оборудование -> Диспетчер устройств -> Порты (COM и LPT) -> Порт принтера (LPT1) -> Свойства. На вкладке "Параметры порта" обязательно должна быть установле кнопка "Использовать любое прерывание, назначенное порту".
Далее, берем разъем испытуемого LPT порта и обязательно! устанавливаем 15-тый контакт (бит 3 регистра STATUS - ERROR) в ноль, соеденив его напрмер, с любым из земляных выводов порта (18-25). Причина такого хода будет пояснена ниже.
Вот теперь запускайте приложение использующие xDRV.sys. Те программы, которые выложены в качестве примера проверенные и лично у меня прекрасно работали. Надеюсь, что у Вас также и Вы увидели сообщение об успешном открытии драйвера. Можно попробовать читать/писать в порт - должно работать, но перейдем к самому интересному - перехвату прерывания (15-тый контакт должен быть посажен на знмлю). Как известно, чтобы вызвать прерывание надо использовать 10-тый контакт LPT порта (ACK). Так и сделаем. Драйвер xDRV.sys регеструет прерывание по спаду сигнала на 10-ом контакте. Т.е. как только Вы соедините его (контакт) с землей, Вы должны тут же увидеть сообщение из программы о регестрации прерывания. Вот оно чудо!!! Отсоедините линию ACK от земли, закройте информационное окошко и подключите контакт еще раз к земле - и опять программа должна тут же выдать сообщение о прерывании.
Теперь обещанное объяснение по поводу линии ERROR. Если бы мы эту линию на ноль не посадили бы, то программа смогла бы обработать только одно прерывание. Повторные попытки подергать линию ACK ни к чему не приведут. При этом в регистре DATA и CONTROL начнуться хаотические помигивания, которые будут длиться примерно минуту. Причиной этому всему эвляется родной драйвер порта, входящий в состав ОС. Он также как и xDRV.sys получает сигнал о прерывании и не обращая никако-го внимания нагло душит своего собрата - xDRV.sys (в области обработки прерываний). Помигивания в порту - это драйвер ОС пытается достучаться до "принтера", который как он считает подключен к порту и послал сигнал о прерывании. Т.к. там никакого принтера нет, то все бесполезно и примерно через минуту родной драйвер принимает решение что принтер "сдох" и больше на его никакого внимания не обращает. Так что теперь если закрыть приложение (обязательно применив функцию xDRV_StopDriver()) и запустить снова, то никаких проблем не будет можно перехватывать все прерывания - Microsoft`овский драйвер мешать не будет.
А вот для того чтобы не ждать минуту и не перезагружать приложения, надо сразу установить линию ERROR в ноль - это будет означать что наш "псевдо принтер" неисправен и обращать внимание на его прерывания не надо. Родной драйвер так и поступает (в отличие от xDRV.sys) и больше в работу xDRV.sys не лезет.
Конечно мы теряем одну из линий для нашего управления и передачи данных, но я думаю такая потеря компенсируется возможностью обработки прерываний.