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


Драйвер (driver) представляет собой специализированный программный модуль, управляющий внешним устройством. Слово driver происходит от глагола to drive (вести) и переводится с английского языка как извозчик или шофер: тот, кто ведет транспортное средство. Драйверы обеспечивают единый интерфейс для доступа к различным устройствам, тем самым устраняя зависимость пользовательских программ и ядра ОС от особенностей аппаратуры. Драйвер не обязательно должен управлять каким-либо физическим устройством. Многие ОС предоставляют также драйверы виртуальных устройств или псевдоустройств – объектов, которые ведут себя аналогично устройству ввода-вывода, но не соответствуют никакому физическому устройству. В виде псевдоустройств реализуются трубы в системах семейства Unix и почтовые ящики в VMS. Еще одним примером полезного псевдоустройства являются устройства /dev/null в Unix и аналогичное ему \DEV\NUL в MS DOS\Windows\OS/2.

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

Большинство ОС общего назначения запрещают пользовательским программам непосредственный доступ к аппаратуре. Это делается для повышения надежности и обеспечения безопасности в многопользовательских системах. В таких системах драйверы являются для прикладных программ единственным способом доступа к внешнему миру. Еще одна важная функция драйвера – это взаимоисключение доступа к устройству в средах с вытесняющей многозадачностью. Допускать одновременный неконтролируемый доступ к устройству нескольких параллельно исполняющихся процессов просто нельзя, потому что для большинства внешних устройств даже простейшие операции ввода-вывода не являются атомарными. Например, в большинстве аппаратных реализации последовательного порта RS232 передача байта состоит из четырех шагов: записи значения в регистр данных, записи команды “передавать” в регистр команды, ожидания прерывания по концу передачи и проверки успешности передачи путем считывания статусного регистра устройства. Нарушение последовательности шагов может приводить к неприятным последствиям – например, перезапись регистра данных после подачи команды, но до завершения передачи, может привести к остановке передачи или, что еще хуже, передаче искаженных данных и т. д. Нельзя также забывать о неприятностях более высокого уровня – например, смешивании вывода разных процессов на печати или данных – на устройстве внешней памяти. Поэтому оказывается необходимо связать с каждым внешним устройством какой-то разграничитель доступа во времени. В современных ОС эта функция возлагается именно на драйвер. Обычно одна из нитей драйвера представляет собой процесс-монитор, выполняющий асинхронно поступающие запросы на доступ к устройству. В Unix, OS/2 и Windows NT/2000/XP этот процесс называется стратегической функцией. При определении интерфейса драйвера разработчики ОС должны найти правильный баланс между противоречивыми требованиями:

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

2. желанием предоставить гибкий и интеллектуальный интерфейс к разнообразным устройствам.

Драйверы обычно разрабатываются не поставщиками операционной системы, а сторонними фирмами – разработчиками и изготовителями периферийного оборудования. Поэтому интерфейс драйвера является ничуть не менее внешним, чем то, что обычно считается внешним интерфейсом ОС – интерфейс системных вызовов. Соответственно, к нему предъявляются те же требования, что и к любому другому внешнему интерфейсу: он должен быть достаточно простым, исчерпывающе документированным и стабильным – не меняться непредсказуемо от одной версии ОС к другой. Идеальным вариантом была бы полная совместимость драйверов хотя бы снизу вверх, чтобы драйвер предыдущей версии ОС мог использоваться со всеми последующими версиями. Потеря совместимости в данном случае означает, что все независимые изготовители оборудования должны будут обновить свои драйверы. Организация такого обновления оказывается сложной, неблагодарной и часто попросту невыполнимой задачей – например, потому, что изготовитель оборудования уже не существует как организация или отказался от поддержки данного устройства. Таким образом, интерфейс драйвера часто оказывается наиболее консервативной частью ОС. К сожалению – несмотря даже на то, что в общих чертах архитектура драйвера в большинстве современных ОС удивительно похожа – идея эта, по-видимому, нереализуема. Даже для близкородственных ОС – например, систем семейства Unix – драйверы одного и того же устройства не всегда могут быть легко перенесены из одной ОС в другую, не говоря уж о возможности использования без модификаций. Еще более удивительным является тот факт, что две линии ОС – Windows 95/98/МЕ и Windows NT/2000/XP – поставляемых одной и той же компанией Microsoft и реализующих почти один и тот же интерфейс системных вызовов, – Win32 – имеют совсем разный интерфейс драйвера. Проблема здесь в том, что интерфейс между драйвером и ядром ОС всегда двусторонний: не только прикладные программы и ядро вызывают функции драйвера, но и, наоборот, драйвер должен вызывать функции ядра. Таким образом, до тех пор, пока используются ОС различной архитектуры, разработка универсального интерфейса драйвера, если теоретически и возможна, то практически вряд ли осуществима.

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

Прежде всего, драйвер должен иметь функции, вызываемые ядром при загрузке и выгрузке модуля и при подключении модуля к конкретным устройствам. Например, в Sun Solaris это перечисленные функции:

1. – инициализация драйвера. Эта функция вызывается при загрузке модуля. Драйвер должен зарезервировать все необходимые ему системные ресурсы и проинициализировать собственные глобальные переменные. Инициализация устройства на этом этапе не происходит.

2. – проверить наличие устройства в системе. Во многих системах эта функция реализуется не самим драйвером, а специальным модулем-“сниффером” (sniffer – дословно, “нюхач”), используемым программой автоконфигурации.

3. – инициализация копии драйвера, управляющей конкретным устройством. Эту функцию можно рассматривать как аналог конструктора объекта в объектноориентированном программировании. Если в системе присутствует несколько устройств, управляемых одним драйвером, некоторые ОС загружают несколько копий кода драйвера, но в системах семейства Unix эта функция просто вызывается многократно.Каждая из инициализированных копий драйвера имеет собственный блок локальных переменных, в которых хранятся переменные состояния устройства. При вызове инициализации драйвер должен прочитать конфигурационный файл, где записаны параметры устройства (номенклатура этих параметров зависит от устройства и от драйвера), разместить и проинициализировать блок переменных состояния, зарегистрировать обработчики прерываний, проинициализировать само устройство и, наконец, зарегистрировать устройство как доступное для пользовательских программ, создав для него минорную запись (minor node). В ряде случаев драйвер создает для одного устройства несколько таких записей. Пример: в большинстве систем семейства Unix лентопротяжные устройства имеют две минорные записи. Одно из этих устройств при открытии перематывает ленту к началу, другое не перематывает. В действительности оба устройства управляются одним и тем же драйвером, который определяет текущий режим работы в зависимости от указанной минорной записи.

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

5. – выгрузка драйвера. Драйвер обязан освободить все ресурсы, которые он занял на этапе инициализации модуля, а также все ресурсы, занятые им во время работы на уровне модуля (не привязанные к конкретному управляемому устройству).

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



Дата добавления: 2017-05-02; просмотров: 3758;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.009 сек.