Внешние устройства

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

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

Обзор существующих
внешних устройств

Исторически одним из первых механизмов взаимодействия с пользователем был телетайп. Телетайп представляет собой электрическую пишущую машинку, которая может печатать символы, либо вводимые с клавиатуры, либо передаваемые ей по проводу. Такие машинки использовались для передачи телеграмм в США еще до второй мировой войны, поэтому в 50-е гг. телетайп был очень распространенным аппаратом.

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

Существование 6-битных символов оказало воздействие на архитектуру некоторых машин третьего поколения. Например, в 24-разрядных машинах линии ICL 1900 есть понятие 6-битного байта. Это понятие унаследовал и распространенный в Институте ядерной физики Одренок.

В более современных телетайпах используется 7- или 8-битная кодировка, позволяющая кодировать не только верхний регистр алфавита, но и нижний, а также различные экзотические символы вроде фигурных скобок. Примером такой кодировки является широко известный код ASCII (American Standard Code for Information Interchange - Американский стандартный код информационного обмена). 8-битная кодировка позволяет представлять не только набор символов ASCII, но и символы национальных алфавитов, например, кириллицы.

Независимо от кодировки обычный алфавитно-цифровой терминал, такой, как vt100 или IBM 3270, с точки зрения компьютера ничем не отличается от телетайпа - это тоже устройство, передающее и получающее по последовательной линии двоичные коды. Как правило, такие терминалы помимо алфавитно-цифровых и прочих печатаемых символов умеют обрабатывать специальные командные последовательности: позиционирование курсора, очистка экрана, прокрутка экрана, изменение яркости символов и т.д. В большинстве систем (Unix, VMS) генерация таких командных последовательностей возлагается на прикладную программу, а ОС выполняет только передачу сформированных команд на терминал.

Для подключения терминальных устройств был разработан протокол передачи двоичных данных по последовательной линии RS232 (Recommended Standard #232). Этот протокол определяет электрические параметры устройств, выполняющих немодулированнную передачу данных по витой паре проводов или по двум таким парам. Немодулированная передача означает, что битовые значения передаются строго последовательно и биту 1 соответствует высокое напряжение (обычно 5 В.), а биту 0 - низкое (обычно 0).

Такая передача относительно проста, но отличается низкой защищенностью от помех. Стандарт RS232 определяет один из простых способов защиты от помех - передачу вместе с каждой порцией данных так называемого бита четности. Аппаратура передатчика устанавливает этот бит так, чтобы общее число единиц в посылке было четным или нечетным, в зависимости от договоренности. Это позволяет обнаруживать ошибки при передаче, но не позволяет их исправлять. Исправление в таком случае возлагается на протокол более высокого уровня. Например, некоторые терминалы могут запросить повтор ошибочного байта. При передаче по протоколу SLIP (Serial Line Internet Protocol) вместе с пакетом данных передается контрольный код CRC (Cyclic Redundancy Code - циклический избыточный код), который позволяет исправлять единичные, а иногда и множественные ошибки.

Для передачи по длинным линиям, особенно по телефонным каналам, используются специальные устройства - модемы (модулятор/демодулятор), преобразующие передаваемые значения в звуковой сигнал различного тона. Модемы, как правило, умеют не только делать модулированную передачу, но и дозваниваться до заданного телефонного номера.

В настоящее время порты RS232 используются для подключения широкого спектра различной низкоскоростной аппаратуры. С их помощью подключаются мыши, модемы, различная измерительная аппаратура, даже принтеры. Практически любая современная вычислительная система имеет несколько последовательных портов. Например, в IBM PC под MS DOS последовательные порты видны как устройства COM с соответствующим номером. Система UNIX называет те же порты /dev/tty, тоже с номером. Современные RS232-порты обеспечивают передачу на скоростях до 115 кБод (килобит в секунду). Существуют также более скоростные стандарты, сверху вниз совместимые с RS232, например, RS422.

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

Некоторые многопортовые платы, например адаптер DL-11 фирмы DEC, могут сбрасывать получаемые данные в заданную область памяти, не прерывая работу центрального процессора, или, наоборот, передавать в порт заданное количество данных из памяти, начиная с заданного адреса. При этом центральный процессор должен только запрограммировать устройство на прием или передачу. Такой режим работы называется прямым доступом к памяти (ПДП) и часто используется в устройствах, передающих большие объемы данных, особенно в дисковых контроллерах. Словосочетание ПДП - это калька с англоязычного термина DMA (Direct Memory Access).

Для подключения более скоростных устройств, например принтеров или лентопротяжек, используются параллельные порты. В современных системах обычно используется стандарт de-facto, известный как Centronix. В первом приближении такой порт представляет собой восемь последовательных линий, в электрическом отношении очень похожих на RS232, и провода, по которым передаются синхронизационные сигналы. Понятно, что такая линия будет по крайней мере в восемь раз быстрее, чем последовательный порт.

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

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

Подключение устройства непосредственно к системной шине имеет два серьезных недостатка.

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

Поэтому еще в 60 гг. появились различные стандарты де-факто, позволяющие одному дисковому контроллеру работать с различными дисководами. Так, одни и те же дисковые накопители могли использоваться как с мэйнфрэймами фирмы IBM, так и с суперкомпьютерами Cray или CDC, или с VAX-11/780. А контроллер дисковой подсистемы поставлялся вместе с компьютером.

Такая организация дисковой подсистемы использовалась и в ранних моделях IBM PC. Имеются в виду так называемые MFM-винчестеры, у которых большая часть управляющей электроники расположена на плате, подключаемой к системной шине.

Однако электроника прогрессировала очень быстро, и контроллеры дешевели гораздо быстрее, чем механика. Поэтому в 80-е гг. выяснилось, что стоимость контроллера намного ниже стоимости самого дисковода. Оказалось целесообразным перенести весь контроллер на плату, привинченную к корпусу диска, а к системной шине подключать только относительно простой HBA (Host Bus Adapter - адаптер шины ``хозяина''). Наиболее простым примером такой организации являются диски IDE (Integrated Drive Electronic), используемые в большинстве современных дешевых клонов IBM PC/AT-AT386.

Более развитой архитектурой такого типа обладают устройства, выполненные в стандарте SCSI (Small Computer System Interface - интерфейс [для] малых компьютерных систем, читается ``скази"). SCSI представляет собой высокоскоростную параллельную шину, к которой может подключаться до семи устройств. По этой шине передаются высокоуровневые команды, например - выдать состояние устройства; перевести считывающую головку к заданному сектору; считать блок данных. Система команд достаточно широка, чтобы к этой шине можно было подключать не только магнитные диски, но и лентопротяжки, оптические дисководы и даже устройства, вообще не являющиеся устройствами внешней памяти, например сканеры, или даже сетевые адаптеры Ethernet.

Устройства SCSI бывают двух типов - устанавливаемые внутри корпуса компьютера и внешние. Внешние устройства имеют свой корпус, свой блок питания и даже свой сетевой шнур, поэтому они заметно дороже внутрикорпусных. Внешние устройства очень полезны, если внутри корпуса мало места, как в случае настольных рабочих станций Sun или x86 - low profile. Соответственно есть два типа кабелей SCSI - для внешних устройств (круглый кабель, заключенный в экран и оболочку из толстой пластмассы) и для внутренних - обычный плоский кабель, внешне похожий на кабели для подключения IDE-дисков и флопповодов, но намного шире.

Большинство современных рабочих станций и мощных персональных компьютеров имеют SCSI-адаптеры.

Говоря о стандартах подключения внешних устройств, нельзя не упомянуть о различных стандартных шинах для измерительной аппаратуры, например, о стандарте CAMAC. Этот стандарт по своей структуре похож на системную шину компьютера с низкой производительностью. Более того, существует компьютер с такой системной шиной: известный в ИЯФе Одренок. Однако большинство компьютеров подключается к шине CAMAC через более или менее сложный HBA. Существует и ряд других стандартов магистрально-модульной аппаратуры - VME, Multibus и т.д.

Следует четко разделять магистрально-модульные стандарты, такие как CAMAC, VME или SCSI, и стандарты системной шины ISA, EISA, MCA, VLB, PCI для IBM PC и ее клонов, NuBus для Macintosh UNIBUS и Q-bus для техники фирмы DEC: PDP-11 и семейства VAX.

Системная шина представляет собой способ непосредственного подключения устройств к центральному процессору. Поэтому такие интерфейсы отличаются:

Магистрально-модульные устройства, как правило, подключаются к центральному процессору через HBA. Скорость работы такого интерфейса может быть ненамного ниже, чем у системной шины, особенно в случае VME или SCSI, но доступ к устройствам из процессора осуществляется не напрямую через адресное пространство, а путем программирования HBA. Любопытно, что такое косвенное программирование может в итоге оказаться проще прямого программирования контроллера, особенно если HBA хорошо спроектирован.

Некоторые HBA магистрально-модульных систем, однако, отображают управляющие регистры устройств в адресное пространство процессора. Для VME и даже для CAMAC существуют даже специализированные машины-контроллеры, у которых системная шина совпадает с требуемым интерфейсом. Понятно, что для машины общего назначения такой подход часто может оказаться неприемлемым, например, потому что потребуется выделить окно в несколько мегабайт в физическом адресном пространстве в 16 М (IBM PC AT386/ISA) или просто по стоимости.

Стандарты можно также разделить по принципу: открытый стандарт или фирменный. Например, стандарт NuBus является фирменным стандартом Apple, и получить его описание или лицензию на приобретение соответствующих микросхем не так то просто. Стандарты же SCSI или CAMAC полностью открытые, т.е. любой может получить полную документацию и создать собственное устройство. Если его интерфейс соответствует документации, то оно будет работать совместно с любым ``правильным'' HBA. Как правило, открытые стандарты создаются в исследовательских центрах, (например, CAMAC был разработан в CERN) или разрабатываются правительственными или межправительственными организациями. Однако иногда и фирмы делают свои внутренние стандарты открытыми, как это произошло со стандартом SCSI.

Открытые стандарты особенно выгодны небольшим фирмам и командам разработчиков, у которых нет денег на проталкивание на рынок ``фирменной'', ни на что не похожей системы со своим шлейфом периферийных устройств. Например, за счет открытых стандартов VME и SCSI выросла фирма Sun Microsystems, начинавшая с изготовления рабочих станций на процессоре 680x0 с системной шиной VME. Однако, когда они выросли, они тут же выпустили рабочие станции линии SPARCStation с фирменной шиной S-bus.

Драйверы внешних устройств

Драйвер (driver) представляет собой специализированный программный модуль, управляющий внешним устройством. Драйверы обеспечивают единый интерфейс к различным устройствам, тем самым ``отвязывая'' пользовательские программы и ядро ОС от особенностей аппаратуры.

Слово driver происходит от глагола to drive (вести) и переводится с английского языка как извозчик или шофер: тот, кто ведет транспортное средство.

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

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

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

Нельзя также забывать о неприятностях более высокого уровня - например, смешивании вывода разных процессов на печати или устройстве внешней памяти. Поэтому оказывается необходимо связать с каждым внешним устройством какой-то разграничитель доступа во времени. В современных ОС эта функция возлагается именно на драйвер. Обычно один из модулей драйвера представляет собой процесс-монитор (fork-процесс в VAX/VMS, стратегическую функцию в Unix, OS/2 и Windows NT), выполняющий асинхронно поступающие запросы на доступ к устройству. Подробнее этот механизм обсуждается в разделах 7.3.3 и 7.3.5.

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

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

При определении интерфейса драйвера разработчики ОС должны найти правильный баланс между противоречивыми требованиями:

Функции драйверов

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


*
При желании можно обойтись только последовательными устройствами, но скорость работы дисковой подсистемы очень важна для производительности всей машины. UNIX использует различные методы для работы с разными типами устройств. Механизм доступа к блочным устройствам подробнее обсуждается в 7.3.4
*

Для последовательных устройств определен следующий набор операций:

Речь в данном случае идет не о функциях самого драйвера, а о системных вызовах, доступных прикладной программе. В классическом UNIX и некоторых более поздних системах, например в Linux, эти функции непосредственно отображаются на функции драйвера. Однако вместо целочисленной ``ручки" драйвер в этих системах получает два указателя на структуры данных ядра. Например, прототип функции драйвера write (цитируется по [13]) выглядит в системе Linux как:

Example:

static int foo_write(struct inode * inode, struct file * file,
                     char * buf, int count)

При открытии файла ядро создает экземпляр struct file и struct inode в таблицах, размещенных в так называемой пользовательской области (user area - .) Пользовательская область является атрибутом задачи, но размещена в адресном пространстве ядра и задаче непосредственно не доступна. Передаваемый программе целочисленный идентификатор-``ручка" является индексом структур file и inode в соответствующих таблицах.

Структура inode используется файловой системой UNIX для определения устройства. Эта структура хранит права доступа к устройству, ряд сведений, большая часть из которых имеет смысл только для дисковых файлов, и два числа, идентифицирующих устройство: major и minor. Права доступа проверяются ядром еще до вызова функций дравера. Major задает номер драйвера в таблицах ядра, а minor - номер устройства, управляемого данным драйвером. Например, последовательные порты /dev/tty0 и /dev/tty1 будут управляться одним драйвером последовательных портов и иметь значения minor, соответственно, 0 и 1. Ядро использует значение major для того, чтобы выбрать нужный драйвер.

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

Структура file используется для хранения дескриптора открытого файла. Если несколько задач обращается к одному устройству или одна задача открывает устройство несколько раз, создается несколько копий структуры file. Наиболее важным, с точки зрения драйвера, полем структуры file является положение текущего указателя чтения-записи устройства. Для таких устройств, как последовательные порты, которые не имеют функции lseek, это поле смысла не имеет.

Нужно отметить, что многие последовательные драйверы не позволяют открывать устройство несколько раз. При последующих вызовах verb`open` для таких устройств будет возвращаться ошибка EBUSY - ``Устройство занято''. Например, для лентопротяжек такое поведение представляется вполне разумным. У драйвера, разрешающего создание нескольких дескрипторов файла для одного устройства, все функции должны быть реентерабельными. В классическом Unix и в Linux обеспечение такой реентерабельности возлагается на разработчика драйвера.

Подробнее интерфейс драйвера в Linux обсуждается в документе [13].

Как уже говорилось, для последовательных драйверов в системах семейства Unix системные вызовы отображаются в функции драйвера, хотя во многих случаях вместо прямого вызова драйвера используются более сложные механизмы, обсуждаемые в разделах 7.3.3 и 7.3.5. Чаще всего это делается для того, чтобы обеспечить иллюзию реентерабельности функций драйвера и, таким образом, обеспечить возможность одновременного использования драйвера несколькими процессами.

Понятно, что систему команд лазерного принтера, плоттера или даже просто терминала с позиционированием курсора, вроде vt100, нельзя свести к операциям read и write, использование функции lseek выглядит несколько искусственно, а соответствующих команд ioctl получилось бы неприемлемо много. В системах семейства UNIX эта проблема решается очень просто: система берет на себя только передачу данных между компьютером и устройством, а за формирование вывода (возможно, это будут не только данные, но и команды) и, напротив, интерпретацию введенных данных отвечает пользовательская программа.

Отчасти этот подход оправдан тем, что к одному и тому же последовательному порту RS232 можно подключить огромное количество разнообразных устройств:

и вообще, практически любое достаточно медленное устройство.

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

Тогда проблема была решена путем создания системной базы данных по системам команд разных терминалов. Эта база данных представляет собой текстовый файл с именем /etc/termcap. Причины, по которым этот файл называется именно так, точно неизвестны. Легенда гласит, что имя происходит от сокращения слов terminal capabilities (возможности терминала). Файл состоит из абзацев. Заголовок абзаца представляет собой имя терминала, а текст состоит из фраз вида Name=value, разделенных символом ':'. При этом Name представляет собой символическое имя того или иного свойства, а value - его значение. Это может быть последовательность символов, формирующих соответствующую команду или генерируемых терминалом при нажатии соответствующей клавиши. Кроме того, это может быть именно значение, например, ширина экрана терминала, измеренная в символах.

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

Для терминалов описанный подход оказался если и не идеальным, то, во всяком случае, приемлемым. Но, например, для графических устройств он не подошел - системы команд различных устройств оказались слишком непохожими и не сводимыми к единой системе ``свойств''. Первым приближением к решению этой проблемы стало создание специализированных программ-фильтров. При использовании фильтров пользовательская программа генерирует графический вывод в виде последовательности команд некоторого языка. Фильтр принимает эти команды, синтезирует на их основе изображение, и выводит его на графическое устройство. Вся поддержка различных устройств вывода возлагается на фильтр, пользовательская программа должна лишь знать его входной язык.

Самым удачным вариантом языка графического вывода в наше время считается PostScript - язык управления интеллектуальными принтерами, разработанный фирмой Adobe. PostScript предоставляет богатый набор графических примитивов, но основное его преимущество состоит в том, что это полнофункциональный язык программирования с условными операторами, циклами и подпрограммами. Первоначально этот язык использовался только для управления дорогими моделями лазерных принтеров, но потом появились интерпретаторы этого языка, способные выводить PostScript на более простые устройства. Наиболее известной программой этого типа является GhostScript - программа, реализованная в рамках проекта GNU и доступная как freeware. GhostScript поставляется в виде исходных текстов на языке C, способен работать во многих операционных системах: практически во всех ОС семейства Unix, OS/2, MS/DR DOS и т.д. и поддерживает практически все популярные модели графических устройств, принтеров, плоттеров и прочего оборудования.

Аналогичный подход используется в оконной системе X Window. В этой системе весь вывод на терминал осуществляется специальной программой-сервером. На сервер возлагается задача поддержки различных графических устройств. В большинстве реализаций сервер исполняется как обычная пользовательская программа, осуществляя доступ к устройству при помощи функций ioctl ``установить видеорежим'' и ``отобразить видеопамять в адресное пространство процесса''.

В обоих случаях ``драйвер'' оказывается разбит на две части: собственно драйвер, исполняющийся в режиме ядра, который занимается только обменом данными с устройством, и программу, интерпретирующую полученные данные и/или формирующую команды для устройства. Эта программа может быть довольно сложной, но ошибка в ней не будет фатальной для системы, так как она исполняется в пользовательском кольце доступа.

Напротив, в операционных системах OS/2 и Windows NT существует несколько типов драйверов с различными наборами функций. Так, в OS/2 используются драйверы физических устройств следующих типов:

На функциях DMD следует остановиться подробнее. Рассмотрим достаточно типичную конфигурацию, содержащую HBA магистрально-модульного стандарта SCSI, к которому подключены пять устройств: жесткий диск, привод CD-ROM, магнитооптический диск, лентопротяжка и сканер. При этом каждое из устройств обладает достаточно серьезной спецификой, так что их сложно свести к общему набору функций.

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

CD-ROM, в свою очередь, нельзя рассматривать как удаляемый диск, доступный только для записи: ведь практически все CD-ROM приводы, кроме функции считывания данных, еще имеют функцию проигрывания музыкальных компакт-дисков.

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

Когда OS/2 управляет описанной аппаратной конфигурацией, оказываются задействованы несколько DMD:

OS2DASD.DMD
управляет классом запоминающих устройств прямого доступа (DASD - Direct Access Storage Device), и предоставляет стандартные функции для доступа к дискам.
OPTICAL.DMD
обеспечивает управление устройствами прямого доступа с удаляемыми носителями. Основная его задача - обработка аппаратного сигнала смены носителя и оповещение других модулей системы (дискового кэша, файловой системы) об этой смене.
OS2CDROM.DMD
обеспечивает специфические для приводов CD-ROM функции, например проигрывание аудизаписей.

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

В случае SCSI ситуация дополнительно усложняется тем, что все запросы к устройствам должны быть оформлены в виде команд SCSI и пройти через HBA, доступ к которому нужно синхронизовать, не допуская попыток одновременно передать в HBA две команды. Именно эти функции, то есть:

исполняет четвертый DMD: OS2SCSI.DMD. Этот DMD передает запросы на отправку команд SCSI ADD (Adapter Device Driver - драйверу устройства-адаптера), то есть собственно драйверу HBA. От ADD требуется только умение передавать команды в шину SCSI и производить первичный анализ пришедших на команды ответов: какой из ранее переданных команд соответствует ответ, чем завершилась операция - успехом или ошибкой, пришли ли в ответ данные и если пришли, то сколько именно и куда их положить и т.д.

Пятый DMD - OS2ASPI.DMD - обеспечивает сервис ASPI (Advanced SCSI Programming Interface - продвинутый интерфейс для программирования SCSI). Этот сервис дает возможность прикладным программам и другим драйверам формировать произвольные команды SCSI и таким образом осуществлять доступ к устройствам, которые не являются дисками. Сервисом ASPI пользуются драйверы лентопротяжки и сканера.

Видно, что разработчики Unix и OS/2 совершенно по-разному подошли к решению проблемы, поставленной в начале данного раздела. Впрочем, нужно отметить, что большинство современных систем семейства Unix сделали не один шаг на пути к аналогичной многослойной структуре драйвера.

Например, в Linux и системах линии BSD Unix за управление устройствами SCSI отвечает специализированный модуль ядра, по функциям вполне аналогичный вышеперечисленным пяти DMD. Он изображает из себя группу драйверов блочных и последовательных устройств (дисков, приводов CD-ROM, лентопротяжек и т.д.) и транслирует запросы ко всем этим устройствам в вызовы достаточно простого драйвера HBA, который аналогичен драйверу адаптера в OS/2 и непосредственно недоступен для прикладных программ.

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

В Unix System V Release 3 драйверы последовательных устройств реализуются с использованием модуля STREAMS. С каждым драйвером последовательного устройства связан абстрактный поток данных, на который можно повесить практически неограниченное количество промежуточных фильтров пред- и постобработки данных и модулей обработки команд ioctl.

Однако такой многослойно-модульный подход не охватывает всей подсистемы ввода/вывода, что порой приводит к неприятным последствиям. Например, системы семейства Unix традиционно имеют проблемы с удаляемыми носителями в устройствах памяти произвольного доступа. Проблема состоит в том, что ядро Unix вообще не имеет представления о том, что устройство может быть внезапно заменено. При смене устройства оператор должен явным образом сообщить об этом системе, используя команды umount и mount. Если, к примеру, заменить смонтированную дискету, не сообщив об этом системе, то можно ожидать совершенно неожиданных результатов, начиная от чтения содержимого удаленной дискеты и кончая порчей данных на новой дискете и даже разрушением системы.

Впрочем, обработка смены носителя является гораздо более сложной проблемой, чем просто написание эквивалента OPTICAL.DMD, который детектирует сигнал смены носителя. Ведь этот сигнал должен быть передан модулям управления дисковым кэшем и файловой системой, которые, в свою очередь, должны разумно обработать его: как минимум, дисковый кэш должен объявить все связанные с диском буферы неактуальными, а менеджер файловой системы должен сбросить все свои внутренние структуры данных, связанные с удаленным диском, и объяснить всем пользовательским программам, работавшим с этим диском, что их данные пропали. Другие аспекты работы с удаляемыми носителями обсуждаются в разделе 8.4.


Next: Вызов функций драйвера Up: Contents

 
Т.Б.Большаков: tbolsh@inp.nsk.su
Д.В.Иртегов fat@cnit.nsu.ru
latex2html conversion Thu Mar 27 14:44:19 NSK 1997