MiniFAQ

К проекту LPTWDMIO.

Содержание

- О проекте
- Условия использования
- Драйвер для прямого доступа к портам

1. Функциональное назначение
2. Исходники
3. Перекомпиляция драйвера
4. Платформы Windows, на которых работает драйвер
5. Варианты установки

- Работа с драйвером из программ на Delphi

1. Модуль LPTIO.pas
2. Нумерация портов и регистров
3. Нумерация отдельных бит регистров
4. Функции для вывода данных
5. Функции для ввода данных
6. Автозагрузка драйвера

- Заключение

1. О проекте

Проект LptWdmIo -- это некоммерческий проект программного обеспечения (ПО), ставящий целью создание простого и надёжного компонента для работы с параллельными портами IBM-совместимых персональных компьютеров, работающих под управлением ОС Windows.

2. Условия использования

ПО, созданное в рамках проекта распространяется свободно (и бесплатно).

Вы можете копировать, распространять и модифицировать ПО по своему усмотрению.

Разрешается использование исходников для своих разработок, в т.ч. коммерческих.

3. Драйвер для прямого доступа к портам

3.1. Функциональное назначение

Драйвер LPTWDMIO.sys предоставляет пользовательским приложениям возможность управлять параллельными портами ПК.

Обращение к драйверу из пользовательских приложений осуществляется через ф-ю DeviceIoControl( ).

Он поддерживает два вида операций -- чтение из порта и записи в порт.

За одно обращение к драйверу возможны несколько (от одной и более) акций вывода (ввода) данных в (из) регистров порта. Это позволяет легко реализовывать сложные протоколы управления внешними устройствами.

3.2. Исходники

Драйвер написан полностью на Ассемблере.

В прилагаемом архиве LPTWDMIO_3.zip находятся следующие файлы:

Main.asm | Головной модуль драйвера
UseWdm.inc | Определения для использования драйверного API
IoctlCodes.inc | Определения управляющих кодов для обращения к драйверу через DeviceIoControl( )
Resource.rc | Информация о версии и т.п.

Эти четыре файла содержат полный набор исходных текстов, достаточный для воспроизведения драйвера.

3.3. Перекомпиляция драйвера

Чтобы перекомпилировать драйвер, потребуется Ассемблер MASM 6.0, Компоновщик LINK и компилятор ресурсов от фирмы Microsoft.

Их можно взять из комплекта Windows DDK или воспользоваться пакетом Masm32, (более-менее) распространённым в сети.

Больше никаких дополнительных средств (MS Visual Studio, и т.п.) не потребуется.

Для перекомпиляции драйвера служат следующие файлы:

Wdm.lib | Библиотека (взята из Windows 2000 DDK), позволяющая выполнить сборку драйвера.
Assemble.cmd | Командный файл компиляции модуля main.asm в объектный вид
Link.cmd | Командный файл для сборки бинарника драйвера из объектного файла, файла двоичных ресурсов с использованием библиотеки wdm.lib.
Linkcmd.rsp | Параметры Компоновщика для команды Link.cmd
Resource.cmd | Командный файл для компиляции файла ресурсов resource.rc в бинарный вид.
Buildall.cmd | Командный файл для полной перекомпиляции драйвера

Если вы работаете на платформе Windows 9x, просто переименуйте файлы *.cmd в *.bat.

Если вы используете Windows DDK, просто распакуйте исходный архив LPTWDMIO_3.zip в подкаталог \NTDDK\SRC\LPTWDMIO.

Затем откройте консоль и перейдите в этот каталог.

После запуска buildall.cmd исходники будут откомпилированы, собраны и новый бинарник будет помещён в подкаталог Disk1.

Если вы не используете DDK, потребуется небольшая правка командных файлов -- так, чтобы были верно прописаны пути к Ассемблеру, Компоновщику и компилятору ресурсов. А именно:

Если вы используете Windows DDK:

--Для Windows 2000 DDK -- распакуйте архив в подкаталог \NTDDK\src\LPTWDMIO,

откройте консоль и перейдите в этот каталог. Для полной перекомпиляции запустите buildall.cmd.

--Для Windows 98 DDK -- распакуйте архив в подкаталог \98DDK\src\LPTWDMIO.

Ассемблер и линкер находятся в подкаталоге \98DDK\bin\win98, поэтому придётся подредактировать

файлы assemble.cmd, link.cmd, resource.cmd, добавив в относительный путь к соотв. утилите

подстроку Win98.

Пример: link.cmd

было ..\..\bin\link.exe @linkcmd.rsp,

стало ..\..\bin\win98\link.exe @linkcmd.rsp

и т.д.

Дальше действуйте как в случае с Windows 2000 DDK.

Если вы используете Masm32

:

-- Pаспакуйте архив в подкаталог \Masm32\src\LPTWDMIO, далее действуйте как

в случае с Windows 2000 DDK.

3.4. Платформы Windows, на которых работает драйвер

Windows 98 | Проверено
Windows Me | Проверено
Windows NT4 | НЕ проверено, но противопоказаний нет
Windows 2000 Prof. | Проверено
Windows XP Home Edition | Проверено

На ОС Windows 2000 Server и Windows XP Prof. драйвер не проверялся. Но противопоказаний к использованию нет.

3.5. Варианты установки

Их два:

1. Установка драйвера вручную.
2. Автоматическая установка.

Установка драйвера вручную.

Установка вручную практикуется при использовании LPTWDMIO на ОС Windows 98/Me.

В этом случае надо запустить Мастер установки оборудования и указать ему путь к .inf файлу в подкаталоге Disk1.

Там же должен находиться файл lptwdmio.sys.

После установки потребуется перезагрузка.

Удалить драйвер можно через Диспетчер устройств (значок Система в панели управления).

После удаления также может потребоваться перезагрузка.

При работе на ОС Windows 2000/XP также возможна установка вручную аналогичным способом.

Но в отличие от Windows 98/Me при установке перезагрузка точно не потребуется, драйвер стартует сразу.

Кроме того у ручной инсталляции есть одно преимущество: если клиентская программа была запущена от имени пользователя, не обладающего правами администратора, она всё равно сможет работать с портами через драйвер.

Автоматическая установка.

Автоматическая установка выполняется при создании объекта для работы с драйвером (см. след. пункт) в программе пользователя в том случае, если программа работает на платформе семейства NT -- т.е. Windows NT4/2000/XP и драйвер не был ранее установлен вручную.

При этом со стороны пользователя не требуется каких-либо дополнительных действий.

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

4. Работа с драйвером из программ на Delphi

В архиве LPTWDMIO_3.zip находятся исходные тексты тестовой программы на Delphi.

4.1. Модуль LPTIO.pas

Чтобы облегчить программистам использование драйвера, был написан модуль LPTIO.pas.

В этом модуле определён класс TLptPortConnection.

Для того, чтобы работать с портами, пользовательская программа должна создать объект данного класса. Объект сам связывается с драйвером и пользователю остаётся только проверить результат -- готов объект или нет:

// <...>

type

TForm1 = class(TForm) // Класс для пользовательской формы

// <...>

procedure FormCreate(Sender: TObject); // Обработчик создания формы

procedure FormDestroy(Sender: TObject); // Обработчик разрушения

Lpt : TLptPortConnection; // Указатель на объект для работы с портами

end; // class

// <...>

// Обработчик создания формы

procedure TForm1.FormCreate(Sender: TObject);

var msg : AnsiString;

begin

Lpt := TLptPortConnection.Create;

if not Lpt.Ready then

begin { объект не готов -- покажем код ошибки }

msg := 'Ошибка при создании объекта Lpt, код = ' + IntToStr(GetLastError());

Application.MessageBox(PChar(msg),'ERROR',MB_OK);

Application.Terminate;

end;

end;

// Обработчик разрушения формы

procedure TForm1.FormDestroy(Sender: TObject);

begin

Lpt.Destroy;

end;

// <...>

Объект класса TLptPortConnection предоставляет в распоряжение пользователя ряд функций, большая часть которых описана в следующих пунктах.

Здесь же упомянем следующие:

function Ready : boolean; | Возвращает признак готовности (true) или неготовности (false)
function IsNtPlatform : boolean; | Функцияя возвращает true, если работаем на платформе NT. Иначе -- false.
function IsPortPresent(LptNumber : byte) : boolean; | Ф-я тестирования наличия порта. Возвратит true, если порт присутствует
function IsPortBidirectional(LptNumber : byte) : boolean; | Ф-я тестирования порта на двунаправленность. Если порт двунаправленный, возвратит true.

Если ф-я Ready( ) сразу после создания объекта возвращает false, это значит, что объект не смог связаться с драйвером.

При работе под ОС Windows 98/Me такой ситуации не возникает, т.к. если драйвер не установлен, объект класса TLptConnection будет использовать прямые обращения к регистрам портов.

При работе под ОС семейства NT это как правило означает неудачу при попытке старта сервиса -- не найден драйвер (должен быть размещён в каталоге программы) или нет административных полномочий.

И ещё одно замечание -- не создавайте несколько экземпляров объекта типа TLptPortConnection в одном приложении. Это совершенно не нужно.

4.2. Нумерация портов и регистров

Обращения к регистрам портов производятся по их логическим номерам. Номер составляется из маски порта и маски регистра.

Логический номер имеет размер 1 байт.

В модуле LPTIO.pas определены следующие константы:

{ Номера портов LPT }

LPT1 : byte = $10; // база $3BC

LPT2 : byte = $20; // $378

LPT3 : byte = $30; // $278

{ Смещения регистров порта }

LPT_DATA_REG : byte = 0; // Регистр данных

LPT_STATE_REG : byte = 1; // Регистр состояния

LPT_CONTROL_REG : byte = 2; // Регистр управления

LPT_EPP_ADDRESS : byte = 3; // Регистр адреса EPP

LPT_EPP_DATA : byte = 4; // Регистр данных EPP

Например, логический номер регистра управления порта LPT2:

(LPT2 or LPT_CONTOL_REG)

при этом обращение будет выполняться по адресу $378+2 = $37A.

4.3. Нумерация отдельных бит регистров

Побитная раскладка регистров порта LPT определена в виде двух наборов констант -- для регистров управления и для регистров состояния:

{ Битовые расклады регистров / разъём 25 pin / разъём Centronic }

{ Битовый расклад регистра УПРАВЛЕНИЯ }

STROBE : byte = $01; { Строб, 1 /1 }

AUTOFEED : byte = $02; { Автопротяжка, 14/14 }

INIT : byte = $04; { Инициализация, 16/31 }

SELECTIN : byte = $08; { Выбор принтера, 17/36 }

IRQE : byte = $10; { Прерывание, ------ }

DIRECTION : byte = $20; { Направление ШД, ------ }

{ Битовый расклад регистра СОСТОЯНИЯ }

IRQS : byte = $04; { Флаг прерывания,------ }

ERROR : byte = $08; { Признак ошибки, 15/32 }

SELECT : byte = $10; { Признак выбора, 13/13 }

PAPEREND : byte = $20; { Конец бумаги, 12/12 }

ACK : byte = $40; { Готовность к приёму данных, 10/10}

BUSY : byte = $80; { Занятость, 11/11 }

Эти значения могут быть использованы, например для управления состоянием отдельных линий.

Например, вот так можно установить бит INIT в регистре управления порта LPT1:

Lpt.WritePort(LPT1,LPT_CONTROL_REG, (INIT or Lpt.ReadPort(LPT1,LPT_CONTROL_REG)) )

4.4. Функции для вывода данных

Этих ф-й две: WritePorts( ) и WritePort( ).

WritePorts( )

предназначена для вывода пакета данных (множество значений). Определена следующим образом:

function WritePorts(PairArray : PADRDATASTRUCT; PairCount : cardinal) : boolean;

PairArray должен указывать на массив структур типа ADRDATASTRUCT:

{ Структура Адрес-Данные }

ADRDATASTRUCT = record

Adr : byte; { адрес == <Номер порта> or <Смещение регистра> }

Data : byte; { данные для вывода или место для прочитанного байта }

end;

Массив передаётся в драйвер полностью, цикл по структурам происходит внутри самого драйвера.

Для каждой структуры выполняется вывод данных в регистр порта.

Это позволяет выдавать данные в порты с максимальной скоростью, причём акт выдачи такого блока данных не может быть прерван до его завершения другими пользовательскими приложениями, что весьма удобно для реализации протоколов передачи, критичных ко времени.

Параметр PairCount -- должен содержать количество структур в массиве PairArray.

WritePort( )

предназначена для вывода одиночного байта в указанный порт.

procedure WritePort (LptNumber : byte; RegOffset : byte; Value : byte);

Здесь LptNumber -- одна из констант LPT1..LPT3, определяет номер порта,

RegOffset

-- одна из констант LPT_DATA_REG, LPT_STATE_REG, LPT_CONROL_REG, определяет номер регистра порта.

Value

-- значение, которое будет выведено в указанный регистр.

4.5. Функции для ввода данных

Для ввода данных предназначены функции ReadPorts( ) и ReadPort( ).

function ReadPorts (PairArray : PADRDATASTRUCT; PairCount : cardinal) : boolean;

Параметры задаются аналогично WritePorts( ), отличие в том, что при выполнении этой процедуры в поля Data каждой структуры ADRDATASTRUCT будут записаны значения, прочитанные из регистров портов, номера которых (<порт> or <регистр>) были указаны в полях Adr.

Функция возвращает false, если объект TLptConnection не готов к работе или если произошла ошибка в драйвере.

function ReadPort (LptNumber : byte; RegOffset : byte) : byte;

Параметры задаются аналогично WritePort( ). Возвращаемое значение -- результат чтения регистра порта.

4.6 Автозагрузка драйвера

Автозагрузка драйвера выполняется объектом типа TLptConnection при работе на NT-платформах Windows в том случае, если драйвер не был установлен вручную.

Однако, для успешного старта драйвера необходимо, чтобы программа запускалась от имени пользователя, обладающего административными полномочиями.

5. Заключение

Если вы хотите высказать предложения или замечания, пишите автору.

Сайт проекта -- http://progrex.narod.ru

(C) 2002 год.