Пример порта ввода/вывода
Мы используем код примера, чтобы показать как порт ввода/вывода внутри драйвера устройства взаимодействует с цифровыми портами ввода/вывода общего назначения; такие порты имеются в большинстве компьютерных систем.
Цифровой порт ввода/вывода в самом общем воплощении является адресом байта для ввода/вывода, связанным либо с памятью, либо с портом. Когда вы записываете значение по адресу вывода, электрический сигнал, видимый на выходных контактах, изменяется в соответствии с отдельными записанными битами. Когда вы читаете значения из входного адреса, текущий логический уровень, видимый на входных контактах, возвращается в виде отдельных битовых значений.
Фактическая реализация и программный интерфейс таких портов ввода/вывода изменяется от системы к системе. Большую часть времени контакты ввода/вывода управляются двумя адресами ввода/вывода: один, который позволяет выбрать, какие контакты используются для ввода данных и какие для вывода, и второй, по которому можно действительно читать или писать логические уровни. Иногда, однако, всё ещё проще и биты в оборудовании либо входные, либо выходные (но этом случае они больше не называются "вводом/выводом общего (универсального) назначения"); параллельный порт, имеющийся на всех персональных компьютерах является одним из таких портов ввода/вывода не столь общего назначения. В любом случае, контакты ввода/вывода пригодны для использования кодом примера, который мы представим в ближайшее время.
Поскольку мы ожидаем, что большинство читателей используют платформу x86 в виде так называемого "персонального компьютера", мы считаем, что стоит объяснить, каким образом разработан параллельный порт ПК. Параллельный порт является тем периферийным интерфейсом, который выбран для запуска кода примера цифрового ввода/вывода на персональном компьютере. Хотя большинству читателей спецификации параллельного порта, вероятно, доступны, для вашего удобства мы просуммируем их здесь.
Параллельный интерфейс в минимальной конфигурации (мы рассматриваем режимы ECP и EPP) состоит из трех 8-ми разрядных портов. Стандарт ПК располагает порты ввода/вывода для первого параллельного интерфейса с 0x378, а второго с 0x278. Первый порт является двунаправленным регистром данных; он непосредственно связан с контактами 2 - 9 на физическом разъёме. Второй порт является доступным только для чтения регистром статуса; когда параллельный порт используется для принтера, этот регистр сообщает ряда аспектов состояния принтера, таких как "подключён", "нет бумаги", или "занят". Третий порт является только выходным регистром управления, который, среди прочего, контролирует, разрешены ли прерывания.
Уровни сигналов, используемые в параллельных соединениях, являются стандартными уровнями транзисторно-транзисторной логики (ТТЛ): 0 и 5 вольт, с логическим порогом около 1.2 вольта. Вы можете рассчитывать на порты по крайней мере соответствующие требованиям стандарту тока нагрузки для TTL LS, хотя наиболее современные параллельные порты делаются лучше для обоих значений токов и напряжений.
- Параллельный разъём не изолирован от внутренней схемы компьютера, что
было бы полезно, если вы хотите соединить логические формирователи прямо
к порту. Но надо быть осторожным, чтобы сделать подключение правильно;
схема параллельного порта легко повреждается, когда вы играете с собственной
схемой, пока вы не добавите оптоизоляторы к вашей схеме. Вы можете выбрать
использование подключаемых параллельных портов, если боитесь, что можете
повредить материнскую плату.
Назначение битов показано на Рисунке 9-1. Вы можете получить доступ к 12 выходным битам и 5 входным битам, некоторые из которых являются логически инвертированными по пути своего сигнала. Одним из битов, не связанным с сигнальным контактом, является бит 4 (0x10) порта 2, который разрешает прерывания от параллельного порта. Мы используем этот бит в рамках реализации нами обработчика прерываний в Главе 10.
Рисунок 9-1. Назначение выводов параллельного порта
Драйвер, который мы представляем, называется short (Simple Hardware Operations and Raw Tests, Простые Аппаратные Операции и Сырые Тесты). Всё это делается через чтение и запись нескольких 8-ми разрядных портов, начиная с выбранного во время загрузки. По умолчанию он использует диапазон портов, определённых для параллельного интерфейса ПК. Каждый узел устройства (с уникальным младшим номером) обращается к своему порту. Драйвер short не делает ничего полезного; для внешнего использования он просто представляет одну инструкцию, воздействующую на порт. Если вы не работали с портом ввода/вывода, вы можете использовать short, чтобы познакомиться с ним; вы можете измерить время, которое требуется для передачи данных через порт или поиграть в другие игры.
Для работы short на вашей системе он должен иметь свободный доступ к нижележащему аппаратному устройству (по умолчанию, параллельному интерфейсу); поэтому никакой другой драйвер не сможет получить его. Большинство современных дистрибутивов устанавливают драйверы параллельного порта как модули, загружаемые только когда это необходимо, так что обычно нет борьбы за адреса ввода/вывода. Однако, если вы получаете ошибку "невозможно получить адрес ввода/вывода" от short (в консоли или в файле системного журнала), какой-то другой драйвер, наверное, уже забрал порт. Быстрый просмотр /proc/ioports обычно сообщает, какой драйвер мешает. То же предостережение относится и к другим устройствам ввода/вывода, если вы не используете параллельный интерфейс. С этого момента мы просто ссылаемся на "параллельный интерфейс" для упрощения обсуждения. Однако, вы можете установить базовый параметр модуля во время загрузки для перенаправления short на другие устройства ввода/вывода. Эта функция позволяет коду примера работать на любой платформе Linux, где у вас есть доступ к цифровому интерфейсу ввода/вывода, который доступен через outb и inb (даже при том, что реальное оборудование является отображённым на память на всех платформах, кроме x86). Позже, в разделе "Использование памяти ввода/вывода", мы покажем также, как short может быть использован универсальным связанным с памятью цифровым вводом/выводом.
Чтобы посмотреть, что происходит на параллельном разъёме и если у вас есть небольшая наклонность для работы с оборудованием, вы можете припаять на выходные контакты несколько светодиодов. Каждый светодиод должен быть подключен последовательно с 1 кОм резистором, подключенным к земляному контакту (если, конечно, ваши светодиоды не имеют встроенного резистора). Если вы подключите выходной контакт ко входному, вы будете генерировать собственный входной сигнал для чтения из входных портов.
Обратите внимание, что вы не можете просто подключить принтер к параллельному порту и посмотреть данные, передаваемые в short. Этот драйвер реализует простой доступ к портам ввода/вывода и не выполняет установку связи, необходимую принтеру для работы с данными. В следующей главе мы покажем образец драйвера (названного shortprint), который способен управлять параллельными принтерами; однако, такой драйвер использует прерывания, поэтому мы ещё не можем добраться до него.
Если вы собираетесь смотреть параллельные данные, припаяв светодиоды к разъёму D типа, мы рекомендуем вам не использовать контакты 9 и 10, потому что мы соединим их вместе, чтобы позднее запускать код примера, показанный в Главе 10.
По отношению к short, /dev/short0 пишет и читает из 8-ми разрядного порта, расположенного по адресу ввода/вывода base (0x378, если не изменено во время загрузки). /dev/short1 пишет в 8-ми разрядный порт, расположенный по base + 1, и так далее до base + 7.
Фактические операции вывода выполняются /dev/short0, основанного на плотном цикле, использующем outb. Используется инструкция барьера памяти, чтобы гарантировать, что операция вывода действительно имеет место и не оптимизирована снаружи:
while (count--) {
outb(*(ptr++), port);
wmb( );
}
Чтобы зажечь ваши светодиоды, вы можете выполнить следующую команду:
echo -n "any string" > /dev/short0
Каждый светодиод мониторит один бит выходного порта. Помните, что только последний записанный символ остаётся стоящим на выходных контактах достаточно долго, чтобы быть воспринятым вашими глазами. По этой причине мы рекомендуем вам предотвратить автоматическую вставку завершающей команды новой строки, передав в echo опцию -n.
Чтение выполняется аналогичной функцией, построенной вокруг inb вместо outb. Для чтения "значимых" значений из параллельного порта вы должны иметь какое-то оборудование, подключенное к входным выводам разъёма для генерации сигналов. Если нет сигнала, читается бесконечный поток одинаковых байтов. Если вы решили читать выходной порт, вы, скорее всего, получите обратно последнее значение, записанное в порт (это относится и к параллельному интерфейсу и к большинству других схем цифрового ввода/вывода общего назначения). Таким образом, те, кто не склонен выключать свои паяльники, смогут прочитать текущее выходное значение порта 0x378, выполнив такую команду:
dd if=/dev/short0 bs=1 count=1 | od -t x1
Чтобы продемонстрировать использование всех инструкций ввода/вывода, есть три варианта каждого устройства short: /dev/short0 выполняет только что показанный цикл, /dev/short0p использует outb_p и inb_p вместо "быстрых" функций и /dev/short0s использует строковые инструкции. Есть восемь таких устройств, от short0 до short7. Хотя интерфейс параллельного имеет только три порта, может потребоваться больше, если для запуска ваших тестов используется другое устройство ввода/вывода.
Драйвер short выполняет абсолютный минимум управления оборудованием, но достаточен для показа использования инструкций ввода/вывода порта. Заинтересованные читатели могут захотеть посмотреть исходники модулей parport и parport_pc, чтобы увидеть, насколько сложным это устройство может получиться в реальной жизни, чтобы поддерживать на параллельном порту целый ряд устройств (принтеры, ленточные накопители для резервного копирования, сетевые интерфейсы).
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.