Parallel port driver что это

Обновлено: 05.07.2024

Принтер доступен через /dev/lp0, а параллельный порт доступен через /dev/parport0. Разница заключается в уровне управления, который можно осуществлять по проводам в кабеле параллельного порта.

  • проверять линии статуса,
  • задавать линии управления,
  • задавать/проверять линии данных (и управлять направлением линий данных),
  • ожидать прерывания (срабатывает при изменении одной из линий статуса),
  • узнавать, сколько произошло новых прерываний,
  • задавать ответ на прерывание,
  • использовать согласование IEEE 1284 (чтобы сообщить периферийному устройству, какой режим передачи использовать),
  • передавать данные с использованием указанного режима IEEE 1284.

Драйвер в пространстве ядра или в пространстве пользователя?

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

Другой критерий - это лёгкость разработки. В большинстве случаев проще написать драйвер, который будет работать в пространстве пользователя, потому что (а) одно неверное движение не приведёт к аварии всего компьютера, (б) имеется доступ к пользовательским библиотекам (таким как библиотека C), и (в) его проще отлаживать.

Интерфейс программирования

Интерфейс ppdev во многом совпадает с интерфейсом символьных специальных устройств, т.к. он тоже поддерживает функции open, close, read, write и ioctl. Константы для команд ioctl имеются в файле include/linux/ppdev.h.
Начало и завершение: open и close
Файл устройства /dev/parport0 представляет любое устройство, подключенное к parport0 - первому параллельному порту в системе. Каждый раз при открытии файла устройства, он представляет (для процесса, выполняющего открытие) другое устройство. Он также может быть открыт более одного раза, но в любой момент только один экземпляр действительно будет управлять параллельным портом. Процесс, который открыл /dev/parport0, работает с параллельным портом через механизм совместного доступа таким же образом, как и любой другой драйвер устройства. Драйвер в пространстве пользователя может работать с параллельным портом совместно как с драйверами устройств пространства ядра, так и с драйверами пространства пользователя.
Управление: ioctl

Большая часть управления выполняется через вызовы ioctl. При помощи ioctl драйвер пространства пользователя может управлять как драйвером ppdev в ядре, так и самим физическим параллельным портом. Вызов ioctl принимает в качестве параметров дескриптор файла (который был получен при открытии файла устройства), команду, и (не обязательный) указатель на некоторые данные.
PPCLAIM


Затребовать доступ к порту. Необходимо сделать это перед тем, как приступить к работе с параллельным портом. Отметим, что некоторые операции действуют только на драйвер ppdev, но не на порт - например, PPSETMODE. Они могут осуществляться только в тот момент, когда доступ к порту не затребован.
PPEXCL


Указывает драйверу ядра запретить любое совместное использование с другими драйверами, то есть запрашивается исключительный доступ. Команда PPEXCL действует только пока доступ к порту ещё никем не затребован. Последующий запрос ioctl PPCLAIM может завершится неудачно, т.к. к этому моменту доступ к порту может быть предоставлен какому-то другому драйверу.

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

Отметим, что ioctl PPEXCL на самом деле не запрашивает доступ к порту - действие откладывается до тех пор, пока не будет выполнена команда ioctl PPCLAIM.
PPRELEASE


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


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

Важно не требовать параллельный порт надолго, потому что драйверам других устройств не останется времени на обслуживание их устройств. Если ваше устройство не позволяет использовать совместный доступ к порту, лучше затребовать параллельный порт в исключительный доступ (см. PPEXCL).
PPNEGOT


Производит согласование одного из режимов IEEE 1284. Согласование - это метод, по которому компьютер и периферийное устройство принимают решение об используемом протоколе передачи данных.

Устройство, совместимое с IEEE 1284, начинает работу в совместимом режиме, а затем компьютер может согласовать другой режим (например, ECP).

  • IEEE1284_MODE_COMPAT
  • IEEE1284_MODE_NIBBLE
  • IEEE1284_MODE_BYTE
  • IEEE1284_MODE_EPP
  • IEEE1284_MODE_ECP


Задаёт режим передачи IEEE 1284, который будет использоваться вызовами read и write.

Параметр ioctl должен быть указателем на int.
PPGETMODE


Возвращает текущий режим IEEE 1284, используемый read и write.
PPGETTIME


Возвращает значение таймаута. Вызовы read и write завершаются, если периферийное устройство не ответит достаточно быстро. ioctl PPGETTIME возвращает время, в течение которого периферийное устройство считается доступным, даже если оно не отвечает.

Параметр ioctl должен быть указателем на структуру timeval.
PPSETTIME


Задаёт таймаут. Параметр ioctl должен быть указателем на структуру timeval.
PPGETMODES


Запрашивает возможности оборудования (то есть поле modes из структуры parport).
PPSETFLAGS

  • PP_FASTWRITE
  • PP_FASTREAD
  • PP_W91284PIC
  • PPWCONTROL


Возвращает последнее значение, записанное в регистр управления, в виде unsigned char: каждый бит соответствует управляющий линии (некоторые из них не используются). Параметр ioctl должен быть указателем на unsigned char.

При этом оборудование фактически не затрагивается, т.к. последнее записанное значение запоминается программно. Так сделано, поскольку некоторое аппаратное обеспечение параллельных портов не предоставляет доступ к регистру управления.

  • PARPORT_CONTROL_STROBE
  • PARPORT_CONTROL_AUTOFD
  • PARPORT_CONTROL_SELECT
  • PARPORT_CONTROL_INIT


Переключить управляющие линии. Поскольку часто бывает нужно изменить один из управляющих сигналов, не трогая остальные, было бы не очень эффективно для драйвера в пространстве пользователя сначала воспользоваться PPRCONTROL, внести изменения и затем воспользоваться PPWCONTROL. Конечно, каждому драйверу придётся запоминать состояние управляющих линий (они не могут быть изменены из другого места), но для предоставления PPRCONTROL самому ppdev тоже приходится запоминать состояние управляющих линий.

ioctl PPFCONTROL для переключения управляющих линий аналогичен PPWCONTROL, но воздействует лишь на ограниченный набор управляющих линий. Параметр ioctl - это указатель на структуру ppdev_frob_struct:
Поля mask и val - это битовое ИЛИ над именами управляющих линий (таких же, как в PPWCONTROL). PPFCONTROL выполняет следующую операцию:
Другими словами, сигналы, указанные в mask, примут значения, указанные в val.
PPRSTATUS


Возвращает unsigned char, содержащий биты для каждой из активных линий состояния (например, PARPORT_STATUS_BUSY). Параметр ioctl должен быть указателем на unsigned char.
PPDATADIR


Управление направлением линий данных. Обычно параллельный порт компьютера управляет линиями данных, но в байтовом режиме передачи от периферийного устройства на компьютер нужно отключить это управление и позволить периферийному устройству управлять этими сигналами. (Если управление параллельным портом со стороны компьютера останется активным, то порт может повредиться.)

Этот вызов бывает нужен только в сочетании с PPWDATA или PPRDATA.

Параметр ioctl - это указатель на int. Если int - ноль, управление линиями данных включается (прямое направление). Если же int - не ноль, то управление линиями данных отключается (обратное направление).
PPWDATA


Задаёт линии данных (если они находится в режиме прямого направления). Параметр ioctl - указатель на unsigned char.
PPRDATA


Читает линии данных (если они находится в режиме обратного направления). Параметр ioctl - указатель на unsigned char.
PPCLRIRQ


Очищает счётчик прерываний. Драйвер ppdev хранит счётчик произошедших прерываний. PPCLRIRQ сохранит этот счётчик в int, указатель на который передан в качестве параметра ioctl.

После этого счётчик прерываний сбрасывается в ноль.
PPWCTLONIRQ


Задаёт признак ответа. После того, как произойдёт прерывание, обработчик должен выставить линии управления в соответствии с запросом. Параметр ioctl - указатель на unsigned char, который интерпретируется так же, как в PPWCONTROL.

Этот ioctl введён по соображениям скорости. Без этого ioctl соответствующее прерывание начнёт обрабатываться в обработчике прерываний, переключится через poll или select на драйвер в пользовательском пространстве, а затем переключится обратно в ядро, чтобы обработать PPWCONTROL. Выполнение всех процедур в обработчике прерывания значительно быстрее.

Передача данных: read и write
Передача данных при помощи read и write осуществляется очевидным образом. Данные передаются с использованием текущего режима IEEE 1284 (см. ioctl PPSETMODE). В режимах, которые позволяют передавать данные только в одном направлении, будет работать только соответствующая функция.
Ожидание событий: poll и select

Драйвер ppdev позволяет драйверам устройств, работающим в пространстве пользователя, ожидать прерываний при помощи poll (и select, который реализуется средствами poll).

Примеры

Имеющиеся здесь два примера описывают процесс написания простого драйвера принтера для ppdev. В первом примере используется функция write, а во втором примере - непосредственная манипуляция линиями данных и управления.

Сначала нужно открыть устройство.
Параметр name из вышеприведённого фрагмента должен быть строкой, содержащей имя файла устройства параллельного порта, например "/dev/parport0". (Если файлов /dev/parport нет, то их можно создать при помощи mknod. Это файлы специальных символьных устройств со старшим номером 99.)

Прежде чем работать с портом, нужно получить к нему доступ.
Наш драйвер принтера будет просто копировать свой ввод (со стандартного потока ввода) на принтер. Сделать это можно одним из двух способов. Первый способ - передать всё драйверу, работающему в ядре, зная что принтер работает по протоколу, который в IEEE 1284 называется режимом совместимости.
Определение функция write_printer в фрагменте выше не показано. Это сделано специально, поскольку приведённый в фрагменте главный цикл может использоваться с обоими рассматриваемыми методами управления принтером. Вот первая реализация write_printer:
При помощи функции write данные передаются драйверу, работающему в пространстве ядра. Дальше он обрабатывает их по протоколу принтера.

Теперь давайте попробуем пойти более сложным путём! В рассматриваемом примере нет никаких причин, чтобы делать что-либо кроме вызова write, потому что принтер работает по протоколу IEEE 1284. С другой стороны, этот пример не требует наличия драйвера в пространстве пользователя, потому что уже есть один, который работает в пространстве ядра. В целях иллюстрации, попробуем представить, что принтер работает по протоколу, который в Linux ещё не реализован.

Получим альтернативную реализацию write_printer (для краткости обработка ошибок не выполняется):
Чтобы продемонстрировать интерфейс ppdev слегка подробнее, приведём небольшой фрагмент кода, который предназначен для имитации протокола принтера со стороны принтера.
А вот пример (тоже без обработки ошибок), который демонстрирует, как читать данные из порта в режиме ECP, с необязательным начальным согласованием режима ECP.

В практике любителей радио , измерительной и робототехники наибольшей популярно стью пользуется параллельный порт персонального компьютера. Многие устройства как со зданные, так и разрабатываемые, управляются от параллельного порта. Изучив основы раз работки драйверов, мы может без особого труда создать несложный драйвер для устройства, присоединенного к параллельному порту ПК. Сам по себе, без дополнительной электроники, параллельный порт может служить неплохим генератором звуковых колебаний, в качестве анализатора входных цифровых сигналов или использоваться для функционирования более сложных схем, например, аналого цифровых преобразователей. Рассмотрим два аппаратно программных проекта, работающих с параллельным портом принтера, для которых создадим простейшие драйверы.

Первое приложение представляет собой генератор прямоугольных импульсов частотой

Для реализации программной части нам потребуется создать драйвер параллельного

порта и приложение пользователя, работающее с этим драйвером. Начнем с драйвера. Са мый простой метод генерации импульсов на каком либо выводе порта – прочитать значение защелки порта, инвертировать его и переслать обратно в параллельный порт. Таким обра зом, можно получить один прямоугольный импульс. Для генерации непрерывной последова тельности импульсов с определенной частотой необходимо периодически повторять опера цию «считывание инверсия запись» в регистре 0x378. Период повторения импульсов можно задавать либо в самом драйвере устройства либо в приложении пользователя. Мы будем

использовать второй способ, задавая интервал времени в приложении пользователя – этот метод несравненно проще, чем тот, который можно было бы реализовать в самом драйвере.

Вначале разработаем драйвер (назовем его lptgen.sys), который будет работать с «вирту альным» устройством lptgen, в качестве которого фактически будет выступать порт вывода параллельного порта ПК. Наш драйвер будет обрабатывать IOCTL команду IOCTL_WRITE в пакете запроса IRP_MJ_DEVICE_CONTROL. Вот исходный текст драйвера:

0x801,\ METHOD_BUFFERED,\ FILE_ANY_ACCESS)

lptgen_Unload (IN PDRIVER_OBJECT DriverObject)

RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME); IoDeleteSymbolicLink(&DosDeviceName); IoDeleteDevice(DriverObject->DeviceObject);

lptgen_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

lptgen_Close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

lptgen_Ioctl(IN PDEVICE_OBJECT DeviceObject,

PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(Irp); ULONG ctlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;

if (ctlCode == IOCTL_WRITE)

mov DX, DATA in AL, DX not AL

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

PDEVICE_OBJECT DeviceObject; UNICODE_STRING NtDeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status;

status = IoCreateDevice(DriverObject, sizeof(MY_DEVICE_EXTENSION),

status = IoCreateSymbolicLink(&DosDeviceName, &NtDeviceName);

DO_DEVICE_INITIALIZING; DeviceObject->Flags |= DO_BUFFERED_IO;

DriverObject->MajorFunction[IRP_MJ_CREATE] = lptgen_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = lptgen_Close; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = lptgen_Ioctl; DriverObject->DriverUnload = lptgen_Unload;

Во многом исходный текст драйвера нам знаком, поэтому я остановлюсь на реализации функции lptgen_Ioctl. Здесь мы используем блок ассемблерных команд. Вначале содержимое регистра 0x378 помещается в регистр AL командой in, где оно инвертируется, после чего выво дится обратно в регистр по команде out. Здесь мы предполагаем, что в качестве базового реги стра параллельного порта используется регистр с адресом 0x378. Если на вашем компьютере базовый адрес другой, например, 0x278, то необходимо переопределить константу DATA.

Таким образом, каждый раз при вызове функции DeviceIoControl() из приложения

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

дов регистра 0x378.

Перейдем теперь к разработке приложения пользователя. Здесь, как и в предыдущих приложениях, мы будем использовать динамическую загрузку выгрузку драйвера, а для опе раций с устройством использовать функцию WINAPI DeviceIoControl(), которой будем переда вать код команды IOCTL_WRITE. Вот исходный текст пользовательской программы:

0x801,\ METHOD_BUFFERED,\ FILE_ANY_ACCESS)

SC_HANDLE scm, svc; SERVICE_STATUS ServiceStatus;

HANDLE fh; DWORD bytes;

scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

printf("Cannot open SCM!\n");

svc = CreateService(scm, "lptgen", "lptgen",

SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "i:\\lptgen.sys",

NULL, NULL, NULL, NULL, NULL);

printf("Cannot create service!\n"); CloseHandle(scm);

StartService(svc, 0, NULL); CloseServiceHandle(svc); CloseServiceHandle(scm);

0, NULL, OPEN_EXISTING,

if (fh != INVALID_HANDLE_VALUE)

printf("Type any key to exit\n");

DeviceIoControl(fh, IOCTL_WRITE, NULL,

scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

printf("Cannot open SCM!\n");

svc = OpenService(scm, "lptgen", SERVICE_ALL_ACCESS); ControlService(svc, SERVICE_CONTROL_STOP, &ServiceStatus); DeleteService(svc);

Здесь основная работа выполняется в цикле while (! _kbhit()). Этот цикл выполняется до тех пор (как и генерация сигнала на выходе параллельного порта), пока пользователь не на жмет любую клавишу. Функция Sleep(1) выполняет задержку на 1 миллисекунду, а поскольку для генерации полного периода колебаний требуется два цикла, то в результате получим пе риод колебаний 2 мс, что соответствует частоте 500Гц. Для получения частоты, например, в 100Гц аргумент функции Sleep() должен иметь значение 5 и т. д.

Наш второй проект намного сложнее. Мы разработаем программную часть аналого циф рового преобразователя на микросхеме LTC1286, который управляется с параллельного порта ПК. Этот проект, но с использованием драйвера PortTalk, мы анализировали в главе 3. Напомню, как выглядит аппаратная часть проекта (рис. 7.13):

Схема аппаратной части АЦП

Сначала разработаем драйвер параллельного порта (назовем его adc1286.sys), который будет собирать данные с АЦП по запросу IRP_MJ_DEVICE_CONTROL и передавать их приложе нию пользователя. Исходный текст драйвера приведен далее:

0x801,\ METHOD_BUFFERED,\ FILE_ANY_ACCESS)

typedef struct _MY_DEVICE_EXTENSION

adc_Unload (IN PDRIVER_OBJECT DriverObject)

RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME); IoDeleteSymbolicLink(&DosDeviceName); IoDeleteDevice(DriverObject->DeviceObject);

adc_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

adc_Close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

ОСНОВЫ РАЗРАБОТКИ ДРАЙВЕРОВ УСТРОЙСТВ В WINDOWS

adc_IoctlR(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

PMY_DEVICE_EXTENSION dx = (PMY_DEVICE_EXTENSION)DeviceObject-

PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(Irp);

ULONG ctlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode; ULONG OutputLength = pIoStack-

PUCHAR buf = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; PULONG Lbuf = &dx->L1;

if (ctlCode == IOCTL_READ)

mov DX, DATA xor AX, AX bts AX, 7

btr AX, 7 out DX, AL

btr AX, 6 out DX, AL

in AL, DX bt AX, 3 rcl CX, 1

bts AX, 6 out DX, AL

bts AX, 7 out DX, AL

mov EDX, DWORD PTR Lbuf mov WORD PTR [EDX], CX

Irp->IoStatus.Information = OutputLength; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

PDEVICE_OBJECT DeviceObject; UNICODE_STRING NtDeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status;

status = IoCreateDevice(DriverObject, sizeof(MY_DEVICE_EXTENSION),

status = IoCreateSymbolicLink(&DosDeviceName, &NtDeviceName);

ОСНОВЫ РАЗРАБОТКИ ДРАЙВЕРОВ УСТРОЙСТВ В WINDOWS

DO_DEVICE_INITIALIZING; DeviceObject->Flags |= DO_BUFFERED_IO;

DriverObject->MajorFunction[IRP_MJ_CREATE] = adc_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = adc_Close; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = adc_IoctlR; DriverObject->DriverUnload = adc_Unload;

В этом драйвере основная работа выполняется функцией adc_IoctlR, которая обрабаты вает пакет запроса IRP_MJ_DEVICE_CONTROL с кодом IOCTL команды IOCTL_READ. Поскольку драйвер должен возвращать данные приложению, то мы определили беззнаковую целочис ленную 32 битовую переменную L1 в области расширения. Здесь нужно сделать одно очень важное замечание: драйвер ядра, как правило, обрабатывает целочисленные данные, хотя может работать и с функциями математического сопроцессора. В данном случае мы будем передавать в программу пользователя 32 битовый результат аналого цифрового преобразо вания, а окончательную обработку результата будет выполнять приложение пользователя. В конечном итоге на экран дисплея будет выведено значение результата преобразования в формате вещественного числа с плавающей точкой.

Второй важный момент. При работе с АЦП LTC1286 мы используем ассемблерный код. Для такого класса приложений реального времени размер и эффективность программного кода имеют первостепенное значение, хотя в других случаях вполне возможно использова ние функций _inp() и _outp языка C++.

Обратите внимание, как из ассемблерного кода мы получаем доступ к переменной L1 –

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

Теперь перейдем к приложению пользователя, которое получает данные от нашего

устройства adc1286. Исходный текст приложения показан далее:

0x801,\ METHOD_BUFFERED,\ FILE_ANY_ACCESS)

SC_HANDLE scm, svc; SERVICE_STATUS ServiceStatus;

HANDLE fh; int binRes; float total;

scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

printf("Cannot open SCM!\n");

svc = CreateService(scm, "adc1286", "adc1286", SERVICE_ALL_ACCESS,

SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "i:\\adc1286.sys", NULL,

printf("Cannot create service!\n"); CloseHandle(scm);

StartService(svc, 0, NULL); CloseServiceHandle(svc); CloseServiceHandle(scm);

fh = CreateFile("\\\\.\\adc1286", GENERIC_READ | GENERIC_WRITE,

if (fh != INVALID_HANDLE_VALUE)

DeviceIoControl(fh, IOCTL_READ, NULL,

total = 5.0 / 4096.0 * binRes;

printf("ADC LTC1286 result: %5.3f V\n", total);

scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

printf("Cannot open SCM!\n");

svc = OpenService(scm, "adc1286", SERVICE_ALL_ACCESS); ControlService(svc, SERVICE_CONTROL_STOP, &ServiceStatus); DeleteService(svc);

В этом приложении, как и в предыдущих, используется WINAPI функция DeviceIoControl(), которая посылает устройству команду IOCTL_READ. Драйвер устройства adc1286 возвращает

32 битовый двоичный результат, который нужно преобразовать в вещественное число с пла

вающей точкой. По этой причине в приложении объявлены две переменные:

Переменная binRes будет содержать двоичный результат преобразования, а переменная total – окончательное вещественное значение аналого цифрового преобразования. Для

12 битового АЦП с напряжением смещения, равным 5В, значение результата в формате пла

вающей точки будет вычисляться следующим образом:

total = 5.0 / 4096.0 * binRes;

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

Источник: Магда Ю. С. Компьютер в домашней лаборатории. – М.: ДМК Пресс, 2008. – 200 с.: ил.

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

тронными исполнительными устройствами и устройств обработки данных как в промышлен

ности, так и лабораторных исследованиях.

Известно, что современные операционные системы Windows 2000/XP/2003 не позволя ют пользовательским программам напрямую работать с регистрами параллельного порта (как, впрочем, и с другими портами в адресном пространстве ввода вывода), поскольку дос туп к портам ввода вывода могут получить только процессы, выполняющиеся в режиме ядра, например, драйверы устройств и некоторые системные сервисы.

В более ранних операционных системах линейки Windows 95/98/Millenium такой проблемы

не было, поскольку все ресурсы системы были доступны пользовательскому процессу, и управ лять вводом выводом через порт можно было непосредственно инструкциями ассемблера in и out. Реализовать ввод вывод данных в параллельный порт в Windows можно, используя функ ции Win API CreateFile, ReadFile и WriteFile, хотя это будет несколько сложнее и потре бует разработки более сложного аппаратного интерфейса управляемого устройства.

Для управления параллельным портом посредством функций WINAPI необходимо внача ле открыть устройство функцией CreateFile, задав в качестве первого параметра «LPTn», где n — номер одного из параллельных портов, присутствующих в системе. Обычно n равно 1,

т. е. используется «LPT1». После получения дескриптора устройства с помощью функции

CreateFile можно выполнять операции чтения записи в устройство. Пример доступа к па

раллельному порту посредством функций WINAPI показан далее:

char *buf = "Any string"; DWORD bytes;

0, NULL, OPEN_EXISTING,

if (hLPT == INVALID_HANDLE_VALUE)

printf("Could not open file (error %d)\n", GetLastError());

bool fSuccess = WriteFile(hLPT, buf, strlen(buf),

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

Для ввода вывода данных в параллельный порт в операционных системах Windows

2000/XP/2003/Vista мы будем использовать драйвер PortTalk, позволяющий осуществлять доступ к физическим портам ввода вывода напрямую. Принцип работы драйвера мы не бу дем рассматривать подробно, скажу лишь, что его основная функция – очистить бит защиты, который устанавливается для всех приложений Windows, работающих в пользовательском режиме. Данный бит запрещает приложению, работающему в пользовательском режиме, обращаться напрямую к защищенным ресурсам системы, к которым относятся регистры вво да вывода физических устройств и системные области памяти. Если бит сбросить, то ваше приложение сможет получить доступ к этим ресурсам, причем программировать порты ввода вывода можно будет с помощью языка ассемблера точно так же, как это имеет место в Win dows 98/Me. Перейдем к практическим аспектам работы с параллельным портом.

Источник: Магда Ю. С. Компьютер в домашней лаборатории. – М.: ДМК Пресс, 2008. – 200 с.: ил.

Прочитал я недавно где-то в интернете, что драйвер параллельного порта в Windows 2000 и Windows XP непосредственно поддерживает работу с устройствами в режимах EPP и ECP, и решил проверить, в чем это выражается и как это использовать. Меня больше интересовал режим EPP, который более практичен, так как представляет собой "вынос" шины ISA за пределы компьютера. Попытки найти что-то путное в интернете привели к статье Тарасенко, где неплохо изложены общие принципы работы с драйвером параллельного порта. Но этого было недостаточно, поэтому пришлось лезть на MSDN и посмотреть, что по этому поводу говорит Майкрософт. Далекий от совершенства online-справочник сориентирован в основном на разработчиков драйверов, поскольку предполагает специальные знания на каждом шагу. Поэтому одновременно с библиотечным разделом Operating a Parallel Device Attached to a Parallel Port мне пришлось держать открытыми некоторые файлы из DDK. Возможно потому, что я сам скорее железячник, чем программист, я избегаю написания собственных драйверов. Ведь для того, чтобы мое устройство заработало на чужом компьютере, туда придется поставить собственный драйвер кустарного производства, а это, во-первых, неудобно, во-вторых, может привести к "непредсказуемому поведению системы": начиная от дырок для вирусов (что всегда очень трудно просчитать) и заканчивая тривиальным крахом системы. Как мне кажется, большая часть пользователей склоняется к применению того, что нам досталось от Microsoft в том убогом виде как это есть. Именно для этих людей я и решил написать статью, чтобы помочь им избежать трудностей, с которыми я столкнулся.

Начну с того, что объясню общие правила работы клиента с каким-либо драйвером Windows. Вообще говоря, под клиентом понимается или другой драйвер, работающий в режиме ядра, или приложение, работающее в пользовательском режиме. В MSDN, к сожалению, не часто проводят эту грань различия в том или ином документе, а разница есть: не все, что может использовать клиент-драйвер, может применить клиент-приложение. Проходит время пока следуя тексту, наконец поймешь, что вот именно ЭТО пригодно только для драйвера. Windows следует идеологии многоуровневых драйверов. В качестве примера можно привести драйвер от производителя принтера, использующий для своей работы драйвер параллельного порта Microsoft, тот же самый которым мы хотели бы воспользоваться непосредственно из приложения. Забегая вперед скажу, что поскольку мое тестовое устройство все-таки не захотело сразу работать из под Windows, несмотря на нормальную работу в EPP режиме из под DOS, мне пришлось, вооружившись цифровым осциллографом с памятью и логическим анализатором, более внимательно изучить, что же все-таки предлагает Майкрософт за рамками собственной документации. Результаты и побудили меня к написанию этой статьи.

Работа с драйвером устройства (bus driver) из приложения сводится к четырем шагам:

  1. открыть устройство;
  2. настроить нужный режим;
  3. читать из и писать в устройство;
  4. закрыть устройство.

Все эти операции проделываются с помощью механизма запросов ввода-вывода драйвера (IRPs). Пользователю доступны функции, формирующие такие запросы. В Delphi для их использования нужно подключить модуль Windows.pas:

1 ШАГ

Функция CreateFile формирует запрос, открывающий устройство. Например, такой вызов открывает порт LPT1 для операций асинхронного чтения и записи:

Если все запросы должны выполняться синхронно, то вызов будет выглядеть так:

Здесь hLPT - дескриптор устройства, который затем используется при обращении к его драйверу:

2 ШАГ

Управление работой устройства, определение его состояния, поддержка режимов и т.д. осуществляется с помощью запросов IRP_MJ_DEVICE_CONTROL и IRP_MJ_INTERNAL_DEVICE_CONTROL. В режиме пользователя поддерживается только запрос первого типа - он формируется с помощью функции DeviceIoControl. В качестве одного из параметров этой функции фигурирует код операции (IOCTL), который определяет действие, выполняемое драйвером. Для некоторых устройств (например, COM-порта) в API Win32 определены функции управления, которые служат оболочкой для DeviceIoControl при определенном значении IOCTL. Это делает программу более наглядной и читаемой. Для параллельного порта я такой возможности не обнаружил, хотя это не вызывает трудностей, поскольку никто не мешает описать такие функции самому.

Тело такой функции будет сводится к вызову DeviceIoControl с определенным набором параметров. Гораздо более неприятный момент заключается в том, что для LPTx невозможно определить коммуникационное событие, чтобы затем обработать его в отдельном потоке как это можно сделать, например, для последовательного порта с помощью вызова SetCommEvents. Поэтому о готовности Вашего устройства к каким-либо операциям, оно может сообщить, только выставив флаг в некотором своем регистре, который Вы будете регулярно опрашивать (например, по таймеру), что конечно не очень удобно и эффективно. Вообще говоря, в режиме EPP параллельного порта определено внешнее прерывание по положительному переходу на линии 10 (nACK), и драйвер содержит его обработчик. Доступ к обработчику можно получить с помощью IRP_MJ_INTERNAL_DEVICE_CONTROL, но только в режиме ядра. Еще раз хочу подчеркнуть, что все изложенное - результат моих собственных поисков, поэтому не исключено, что какое-то решение от Microsoft для обработки событий параллельного порта в режиме пользователя существует. Если кто-нибудь знает, поделитесь. В конце статьи я укажу E-mail для связи.

Рассмотрим по порядку все коды операций доступные в качестве аргумента в вызове DeviceIoControl при работе с LPTx. Код представляет собой 32-разрядное слово и строится по определенному правилу, которое учитывает тип устройства, вид и метод доступа. Не вдаваясь в подробности, перечислим значения кодов для управления параллельным портом и их идентификаторы, принятые в Microsoft.

Идентификатор кода IOCTL Значение кода
IOCTL_IEEE1284_GET_MODE $160014
IOCTL_IEEE1284_NEGOTIATE $160018
IOCTL_PAR_GET_DEFAULT_MODES $160028
IOCTL_PAR_GET_DEVICE_CAPS $160024
IOCTL_PAR_IS_PORT_FREE $160054
IOCTL_PAR_QUERY_DEVICE_ID $16000C
IOCTL_PAR_QUERY_DEVICE_ID_SIZE $160010
IOCTL_PAR_QUERY_INFORMATION $160004
IOCTL_PAR_QUERY_LOCATION $160058
IOCTL_PAR_QUERY_RAW_DEVICE_ID $160030
IOCTL_PAR_SET_INFORMATION $160008
IOCTL_PAR_SET_READ_ADDRESS $160020
IOCTL_PAR_SET_WRITE_ADDRESS $16001C
IOCTL_SERIAL_GET_TIMEOUTS $1B001C
IOCTL_SERIAL_SET_TIMEOUTS $1B0020

Обращаю внимание читателя, что статья приготовлена для сайта Delphi, поэтому все примеры кода и т.п. приводятся на Паскале. Коды в таблице указаны в шестнадцатеричном формате (т.е. 0х160014 и т.д.).

Код IOCTL_IEEE1284_GET_MODE предназначен для формирования запроса текущего режима порта:

Если запрос синхронный, то он выглядит так:

@Mode - указатель на буфер, в котором драйвер возвращает текущий режим. Следующий параметр сообщает драйверу размер буфера, а параметр ret возвращает размер структуры, через которую передаются данные. Структура PARCLASS_NEGOTIATION_MASK имеет два поля: usReadMask - определяет режим работы порта при чтении, а usWriteMask - при записи. Вот возможные значения этих переменных:

Сразу после того, как порт открыт, он устанавливается в режим CENTRONICS по записи и NIBBLE по чтению.

Код операции IOCTL_IEEE1284_NEGOTIATE предназначен для согласования режима работы порта и устройства:

@ReqMode указывает на структуру PARCLASS_NEGOTIATION_MASK, которая содержит маску тестирования режимов для работы с устройством. Маска представляет собой произвольную сумму, указанных выше констант.

Драйвер выполняет последовательность согласования с устройством для каждого указанного в маске режима в соответствии со спецификацией IEEE 1284. Если соответствующий бит в маске выставлен в 1, то данный режим проверяется на возможность его применения при работе с подключенным устройством, а затем выбирается режим с максимальной пропускной способностью. Этот режим устанавливается в качестве текущего, а соответствующие ему значения драйвер возвращает в структуре LptMode. Кроме указанных выше констант, однозначно обозначающих режимы, Windows определяет еще две маски для запроса:

Чтобы запросить проверку всех режимов, нужно указать $7FF.

После согласования режима драйвер не переводит выходные линии порта в состояние, соответствующее выбранному режиму! Он оставляет их в состоянии инициализации:

Сигнал Конт. Состояние
nSelectIn(1284 Active) 17 низкий
nAutoFeed 4 высокий
nStrobe 1 высокий
Initialize 16 высокий

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

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

В структуре Mode возвращается режим по умолчанию в той же манере, что и для запроса текущего режима IOCTL_IEEE1284_GET_MODE.

  • совместимости (Centronics);
  • полубайтный (Nibble);
  • байтный (Byte_Bidir);
  • EPP;
  • ECP.

Майкрософт добавляет несколько подрежимов:

  • адресуемый полубайтный (CHANNEL_NIBBLE);
  • программный EPP (EPP_SW);
  • программный ECP (ECP_SW);
  • упрощенный ECP (BOUNDED_ECP).

Запрос с кодом IOCTL_PAR_GET_DEVICE_CAPS похож на IOCTL_IEEE1284_NEGOTIATE с той разницей, что он не меняет режим драйвера, а только проводит циклы согласования с устройством для всех(. ) режимов, чтобы выяснить какие из них поддерживаются. Затем результат проверки возвращается в уже известной структуре PARCLASS_NEGOTIATION_MASK.

Если выдать этот запрос на пустой порт (без устройства), то будет отмечена поддержка только CENTRONICS и IEEE_COMPATIBILITY. Соответственно и включить никакие другие режимы будет невозможно. Исключение составляет только NIBBLE, который согласно спецификации должен поддерживаться всеми IEEE1284-устройствами. Чтобы использовать другой режим, например EPP, необходимо подключить устройство, поддерживающее последовательность согласования для этого режима. В ходе цикла согласования хост выставляет на шину данных байт совместимости, который уникален для каждого режима:

Затем по отрицательному переходу сигнала Paper End (конт. 12) хост проверяет уровень на линии Select (конт. 13). Если устройство подтверждает режим, то на эту линию оно должно выставить 1, в противном случае - 0. Байт совместимости имеет очень удобную структуру для его аппаратной обработки: за каждым режимом закреплен определенный бит, который выставляется в единицу только для этого режима. Поэтому, скажем для EPP, достаточно защелкнуть 6 бит (считая от 0) по сигналу nStrobe (1 конт.) и вернуть его по линии Select. Если сигнал Select просто навсегда установить в 1 (подтянуть к +5В), то устройство будет подтверждать все режимы.

Что касается других сигналов, то для согласования работы с драйвером параллельного порта достаточно на линях nError (конт. 15) и Paper End выставить лог. 1, а для формирования сигнала завершения цикла согласования можно по линии nACK (конт. 10) вернуть в хост уровень nAutoFeed (конт. 14). Так как оборванный вход LPT-порта воспринимается как 1, то для реализации этой последовательности достаточно просто воткнуть в разъем перемычку на контакты 10 и 14. Такое "устройство" драйвер распознает как поддерживающее следующие режимы: CENTRONICS, IEEE_COMPATIBILITY, NIBBLE, CHANNEL_NIBBLE, BYTE_BIDIR, EPP_SW, - т.е. все режимы, кроме аппаратного EPP и всех разновидностей ECP. Дело в том, что согласование ECP (который, кстати, придуман Microsoft в сотрудничестве с HP) требует более сложной последовательности согласования, и простой аппаратурой здесь не обойтись. В интернете свободно распространяется файл ecp_reg.pdf от Microsoft с подробным описанием режима.

Ситуация с аппаратным EPP еще более оригинальная: при запросе этого режима на разъеме порта……..ничего не происходит. А драйвер сообщает, что режим не поддерживается. Отсутствие даже намека на попытку согласования EPP_HW позволяет сделать вывод о том, что именно сам драйвер не поддерживает этот режим,- возможно из-за каких-то трений между Microsoft и Intel - автором EPP, может из-за технических нестыковок. Ниже сопоставляются сигналы в режимах аппаратного и программного EPP, а также применение соответствующих линий в цикле согласования.

№ конт. Centronics Аппарат. EPP Прогр. EPP Согласование
1 nStrobe nWrite nWrite nStrobe
10 nAck Interrupt ? nAck
11 Busy nWait nWait -
12 Paper End - - PE
13 Select - - Select
14 nAutoFeed Data Strobe Data Strobe nAutoFeed
15 nError - - nError
16 nInitialize nReset Address Strobe -
17 nSelectPrinter Address Strobe 1284 Active 1284 Active

Здесь надо обратить внимание на две вещи. Во-первых, в программной реализации EPP Майкрософт случайно или намеренно перепутал сигналы местами: строб адреса теперь на контакте 16 разъема, т.е. он соответствует сигналу nInitialize. На контакте 17 остается признак интерфейса 1284, как и во всех остальных режимах, включая последовательность согласования. Этот сигнал можно использовать как ChipSelect (активный высокий). Сигнала сброса nReset как такового нет, но есть последовательность сброса, которую выполняет драйвер по соответствующему запросу (см. далее). Во-вторых, из-за ограниченности набора сигналов одни и те же линии используются как в циклах квитирования режимов, так и в цикле согласования (например, Data Strobe - AutoFeed, Write - Strobe). Поэтому если не принять определенных мер, то во время последовательности согласования будет сымитирован цикл записи, и в регистр устройства будет записан байт совместимости, что не всегда допустимо. Мало того, непосредственно перед этим имитируется чтение данных из устройства, несмотря на наличие байта на выходе LPT. Работа двух устройств на выход одновременно не сулит ничего хорошего. В моем случае внешнее устройство "перетягивало" порт, изменяя байт совместимости. В худшем случае что-нибудь может выгореть.

Последовательность согласования предусматривает возможность запроса идентификатора устройства, который представляет собой нуль-терминальную строку. Эту строку Windows выдает на экран при обнаружении нового устройства. Чтобы сделать запрос ID, придется воспользоваться кодами IOCTL_PAR_QUERY_DEVICE_ID, IOCTL_PAR_QUERY_DEVICE_ID_SIZE, IOCTL_PAR_QUERY_RAW_DEVICE_ID.

С помощью кода IOCTL_PAR_QUERY_INFORMATION у драйвера можно запросить информацию об его состоянии.

В поле ParInfo.Status драйвер возвращает байт, который может представлять собой комбинацию следующих чисел

Прямого соответствия между битами ParInfo.Status и физическими регистрами параллельного порта нет, но какая-то нетривиальная взаимосвязь существует: определенные комбинации входных сигналов на разъеме порождают различное состояние поля статуса драйвера.

Код IOCTL_PAR_SET_INFORMATION применяется для сброса драйвера.

Обратите внимание на значение, которое присваивается переменной ParControl.Init. Других вариантов не существует. При таком запросе драйвер сбрасывает nSelectIn (1284 Active) в ноль, а на линию nInitialize (Address Strobe) выдает отрицательный строб. При этом сигнал nStrobe (Write) сохраняет высокий уровень. Такая последовательность чем-то похожа на цикл чтения адреса EPP, которая на практике редко используется. Поэтому по условию

  • nStrobe (конт. 1) - высокий;
  • nInitialize (конт. 16) - низкий;
  • nSelectIn (конт. 17) - низкий;

можно сформировать сигнал сброса устройства.

Запрос IOCTL_SERIAL_SET_TIMEOUTS устанавливает значение таймаута, которое драйвер использует в операциях записи в режимах SPP и ECP_SW. Прочитать установленное значение можно с помощью IOCTL_SERIAL_GET_TIMEOUTS.

3 ШАГ

Чтобы сформировать цикл записи адреса EPP, нужно воспользоваться кодом IOCTL_PAR_SET_WRITE_ADDRESS.

Новый цикл будет сформирован лишь при условии, что в очередном запросе драйверу будет передан новый адрес. Драйвер пытается устранять избыточные операции - благая цель, которая усложняет систему и как следствие влечет ошибки. Я полагаю, что программист Майкрософт не правильно понял смысл чтения адреса EPP, поэтому такая операция отсутствует, зато есть команда IOCTL_PAR_SET_READ_ADDRESS, которая не формирует физических циклов, но настраивает драйвер таким образом, что он создает цикл записи адреса непосредственно перед циклом чтения данных. При этом драйвер, оптимизируя циклы адреса, не всегда работает разумно. Поэтому, не вдаваясь в подробности, я не рекомендую вообще использовать IOCTL_PAR_SET_READ_ADDRESS, тем более что он не дает ничего дополнительно по сравнению с IOCTL_PAR_SET_WRITE_ADDRESS.

Для записи данных в устройство используется функция WriteFile, а для чтения ReadFile. Обе функции обрабатывают поток данных, а не отдельный байт. Это означает, что для режима EPP будет последовательно сформировано столько циклов записи (чтения) данных, сколько необходимо, чтобы передать весь массив байт за байтом. Естественно, что все данные при этом уйдут по одному адресу. Ниже приводится пример кода, в котором производится запись $55 по адресу $AA, а затем чтение по адресам $AA и $BB.

4 ШАГ

Закрывается устройство обычным образом: с помощью функции CloseHandle.

Параметр - Parallel Port Mode

Параллельный порт относится к числу давно используемых и хорошо зарекомендовавших себя элементов компьютера. И одной из важнейших опций BIOS, отвечающих за его настройку, является опция Parallel port mode (Режим работы параллельного порта). Данная опция позволяет установить необходимый пользователю режим работы параллельного порта. Как правило, опция содержит следующие варианты выбора: Normal (SPP), ECP, EPP, ECP+EPP. Обычно эта функция входит в раздел BIOS Onboard Parallel Port.

Принцип работы

Параллельный порт (LPT) персонального компьютера представляет собой внешнюю шину, входящую в подсистему ввода-вывода. К параллельному порту можно подключать различные периферийные устройства, хотя в большинстве случаев такими устройствами являются принтеры или плоттеры.

Особенностью параллельного порта является одновременная передача сигналов по нескольким проводникам. Параллельный порт имеет несколько режимов работы, при которых информация может передаваться как в одном направлении, так и в двух направлениях с разными скоростями. За время существования параллельного порта было разработано несколько стандартов его работы, для выбора которых и служит опция Parallel port mode.

Режимом по умолчанию является вариант Normal (SPP, стандартный параллельный порт). Этот протокол передачи данных является наиболее старым и позволяет подключать к параллельному порту практически любые устройства.

Хотя первоначально протокол SPP поддерживал передачу данных лишь в одном направлении – к периферийному устройству, тем не менее, более поздняя версия протокола позволяет порту как передавать, так и принимать данные. Выходная скорость порта в режиме SPP составляет 150 КБ/c, а входная скорость, из-за программного ограничения, в несколько раз меньше – 50 КБ/c.

Для замены низкоскоростного стандартного параллельного порта компаниями Microsoft и Hewlett-Packard был разработан усовершенствованный ECP (Extended Capabilities Port). Порт ECP способен работать в режиме FIFO и поддерживает более высокую скорость передачи данных – до 2 МБ/c, как в направлении периферийного устройства, так и в обратную сторону. Также стандарт ECP поддерживает технологию DMA.

Кроме того, был разработан протокол EPP (стандарт IEEE 1284), рассчитанный на работу со стандартным параллельным портом. При этом скорость передачи данных по протоколу EPP также достигает 2 МБ/c, однако, в отличие от ECP передача данных осуществляется ассиметричным способом.

Какое значение опции выбрать?

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

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

В любом случае, прежде чем выбрать в BIOS вариант опции Parallel port mode, рекомендуется ознакомиться с инструкцией к подключаемому периферийному устройству – скорее всего, в ней указан режим работы, предпочтительный для данного устройства.

Разумеется, может случиться так, что вы не нашли инструкцию к периферийному устройству, или в этой инструкции не указан требуемый режим его работы. В таком случае лучше всего выбрать вариант опции ECP+EPP, поскольку он позволяет подключать устройства, поддерживающие какой-либо из этих протоколов. При подключении устройства в данном режиме BIOS автоматически выберет предпочтительный режим работы.

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

Читайте также: