Добавление драйверов устройств
Категория: Драйверы и ядро | Автор: admin | 31-01-2010, 01:22 | Просмотров: 5522

Драйвер устройства — это программа, которая обеспечивает взаимодействие системы с определенным компонентом аппаратной среды. Драйвер выполняет роль переводчика команд конкретного устройства на "язык" API-функций ядра. Благодаря наличию драйверов обеспечивается приемлемый уровень независимости UNIX от внешних устройств.

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

Раньше, во времена хаоса, для большинства аппаратных устройств требовались интерфейсная плата и специальный драйвер. Затем, когда многие системы стали поддерживать технологию SCSI в качестве стандартного интерфейса подключения дисков, лент и дисководов CD-ROM, а поставщики интегрировали в свои системы поддержку стандартных технологий, в частности Ethernet, появилась надежда на стабильность.

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

  • в Linux поддерживается более 30 различных наборов микросхем SCSI для персональных компьютеров, и каждый из них продается в два раза большим числом поставщиков;
  • существует более 200 сетевых интерфейсов для персональных компьютеров; эти интерфейсы предлагаются различными поставщиками под разными именами;
  • все время разрабатываются и выпускаются новые, улучшенные, более дешевые устройства; для каждого из них нужен свой драйвер, работающий с требуемой версией UNIX.

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

Изготовители оборудования обращают все больше внимания на рынок UNIX и даже иногда создают UNIX-версии драйверов. Если повезет, для имеющегося устройства в системе будет и драйвер, и инструкции по его инсталляции. Но вероятнее всего, нужный драйвер можно будет найти только на какой-нибудь неофициальной Web-странице.

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

 

Номера устройств

 

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

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

Узнать номера устройств можно с помощью команды ls -1:

% ls -1 /dev/sda

brw-rw  1 root       disk       8,      0 Mar    3    1999 /dev/sda

 

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

Файлы устройств бывают двух типов: блок-ориентированные и байт-ориентированные. Чтение из блок-ориентированного устройства и запись в него осуществляется по одному блоку (группа байтов, размер которой обычно кратен 512) за раз, тогда как чтение из байт-ориентированного устройства и запись в него может производиться по одному байту. Для некоторых устройств предусматривается доступ как через блок-ориентированные, так и через байт-ориентированные файлы. Например, диски и ленты ведут "двойную жизнь", в отличие от терминалов и принтеров.

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

attach    close         dump       ioctl     open     probe

psize     read          receive    reset     select   stop

strategy  timeout       transmit   write

 

Отдельные системные функции удобно реализовывать, используя некий драйвер устройства, даже если связанное с ним устройство отсутствует в системе. Такие устройства-"призраки" называют псевдоустройствами. Например, пользователю, вошедшему в систему по сети, назначается псевдотерминал  (PTY),  который с точки  зрения  высокоуровневого  программного обеспечения ничем не отличается от обычного последовательного порта. Благодаря такому подходу программы, написанные в те времена, когда все пользователи еще работали на алфавитно-цифровых терминалах, могут продолжать функционировать в мире окон и сетей.

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

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

 

Таблица 12.8. Местоположение драйверов и конфигурационных файлов

 

Система

Конфигурационные файлы

Драйверы

Solaris

/kernel/drv/*conf

/kernel/drv/*

HP-UX

/stand/system

/usr/conf/*

Linux

/usr/src/linux/.config

/usr/src/linux/drivers/*

FreeBSD

/usr/src/sys/i386/conf/ЯДРО 

/sys/i386/conf/files*

 

Ниже мы рассмотрим три примера добавления драйвера к ядру: для Solaris, Linux и FreeBSD. Мы не будем описывать эту процедуру для операционной системы HP-UX, поскольку в ней редко присутствуют сторонние устройства (а для всех устройств Hewlett-Packard драйверы входят в состав системы).

 

Добавление драйвера устройства в Solaris

 

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

Драйверы Solaris всегда поставляются в виде объектных файлов, а не в исходных текстах, как во FreeBSD и Linux. В нашем примере мы добавим к системе устройство "snarf". Его драйвер должен быть представлен как минимум двумя файлами: snarf.o (собственно драйвер) и snarf.conf (файл конфигурации). Оба должны находиться в каталоге /platform/sun4u/kernel/drv.

После копирования конфигурационного файла можно отредактировать его, чтобы задать параметры конкретного устройства. Обычно этого делать не требуется, но иногда некоторые параметры доступны для "тонкой' настройки.

Далее нужно загрузить модуль. Модули подключаются к работающему ядру командой add_drv (подробнее о загружаемых модулях речь пойдет в параграфе 12.11). В нашем случае команда имеет вид add_drv snarf. Вот и все! Более простую процедуру трудно себе представить.

 

Добавление драйвера устройства в Linux

 

В Linux драйверы устройств распространяются в одной из трех форм:

  • “заплата” к конкретной версии ядра;
  • загружаемый модуль;
  • инсталляционный сценарий, устанавливающий соответствующие "заплаты".

 

Чаще  всего  встречаются  именно  "заплаты".  Установить их можно следующим образом:

# cd /usr/src/linux ; patch –p1 < driver.diff

 

Ниже мы рассмотрим, как вручную добавить к ядру драйвер сетевого устройства "snarf'. Это очень сложный и утомительный процесс, особенно если сравнивать его с другими тестовыми операционными системами.

По существующему соглашению исходные файлы ядра Linux хранятся в каталоге /usr/src/linux. В подкаталоге drivers нужно найти еще один подка­талог, соответствующий типу добавляемого устройства. Вот как выглядит список имеющихся подкаталогов:

% ls -F /usr/src/linux/drivers

Makefile     cdrom/     i2o/       nubus/     sbus/     telephony/

acorn/       char/      isdn/      parport/   scsi/     usb/

apl000/      dio/       macintosh/ pci/       sgi/      video/

atm/         fc4/       misc/      pcmcia/    sound/    zorro/

block/       i2c/       net/       pnp/       tc/

 

Чаще всего драйверы добавляются в каталоги block, char, net, usb, sound и scsi. В них содержатся драйверы блок-ориентированных устройств (например, IDE-дисков), байт-ориентированных устройств (например, последовательных портов), сетевых устройств, USB-устройств, звуковых плат и SCSI-плат соответственно. В других каталогах находятся, в частности драйверы для самих шин (pci, nubus и zorro); маловероятно, чтобы потребовалось добавлять в них файлы. Некоторые каталоги предназначены для хранения платформно-зависимых драйверов (Macintosh, acorn, ap1000). Есть каталоги для специализированных драйверов (atm, isdn, telephony).

Поскольку наше устройство является сетевым, мы поместим его драйвер в каталог drivers/net. Потребуется модифицировать следующие файлы:

  • drivers/net/Makefile, чтобы драйвер мог быть скомпилирован;
  • drivers/net/Config.in, чтобы устройство появилось в списке конфигурируемых настроек;
  • drivers/net/Space.c, чтобы устройство искалось на этапе начальной загрузки.

 

После размещения файлов с расширениями и .h в каталоге drivers/net нужно добавить запись о драйвере в файл drivers/net/Makefile. Вот эти строки (они располагаются ближе к концу файла):

ifeq  ($(CONFIG_SNARF),у)

L_OBJS += snarf.о

else

if eq  ($ (CONFIG_SNARF) , m)

M_OBJS += snarf.о endif

endif

 

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

Когда запись добавлена в файл Makefile, нужно убедиться, что устройстве будет доступно для конфигурирования при настройке ядра. Все сетевые устройства должны быть перечислены в файле drivers/net/Config.in. В нашем случае требуется добавить приведенную ниже строку, чтобы драйвер был встроен либо как загружаемый модуль, либо как интегрированная часть ядра (в соответствии с тем, что было заявлено в файле Makefile):

tristate  'Snarf device support'  CONFIG_SNARF

 

Ключевое слово tristate означает, что драйвер станет загружаемым модулем. Если это невозможно, необходимо указать ключевое слово bool. Следующий элемент инструкции — строка, которая будет отображаться в окне конфигурации. Это может быть произвольный текст, но он должен идентифицировать для пользователя конфигурируемое устройство. Последний элемент инструкции — это конфигурационная макроконстанта. Она должна быть такой же, как и та, что проверяется в ветви ifeq файла Makefile.

Наконец, нужно отредактировать файл drivers/net/Space.c. В нем содержатся ссылки на подпрограммы опроса устройств, а также определяется очередность опроса. Нам понадобится отредактировать файл в двух разных местах. Во-первых, нужно добавить ссылку на функцию опроса, а затем внести устройство в список опрашиваемых устройств.

В верхней части файла Space.с находится группа ссылок на функции. Добавим следующую строку:

extern int snarf_probe(struct device *) ;

 

Прежде чем вносить устройство в список опроса, нужно определить, какой именно список нас интересует. Существуют отдельные списки для каждого типа шины (PCI, EISA, SBUS, MCA, ISA, параллельный порт и т.д.). Устройство “snarf” является PCI-устройством, поэтому нужный нам список называется pci_probes. За строкой

struct devprobe pci_probes[] ___initdata = {

 

следует упорядоченный список устройств. Устройства, стоящие выше, опрашиваются раньше. Порядок опроса не имеет особого значения для РСI-устройств, но для некоторых устройств он важен. Нужно просто убедиться, что устройство “snarf” обнаруживается, поэтому в начало списка мы поместим такие строки:

struct devprobe pci_probes[] ___initdata = {

#ifdef CONFIG_SNARF

snarf_probe, 0),

#endif

 

 

Теперь устройство добавлено к ядру Linux. При следующем конфигурировании ядра устройство должно появиться в списке конфигурируемых настроек в группе "Network devices" (сетевые устройства).

 

Добавление драйвера устройства во FreeBSD

 

Добавление совершенно нового драйвера во FreeBSD предполагает включение его описания в файлы конфигурации и редактирование исходного текста ядра с целью включения ссылок на подпрограммы драйвера. Эта процедура — не для слабонервных!

В качестве примера рассмотрим систему FreeBSD. Следует заметить, что все BSD-системы (в том числе NetBSD и OpenBSD) функционируют схожим образом, за исключением того, что местонахождение файлов может быть разным. Для примера добавим в систему устройство "scarf" (псевдосетевое устройство).

В первую очередь нужно скопировать исходные файлы в соответствующий каталог:

# ср ~bbraun/snarf.с /sys/pci/snarf

 

Так как наше устройство относится к PCI-устройствам, мы поместим исходные файлы в каталог SYS/pci ко всем остальным PCI-драйверам. Если устройство не попадает ни в одну из существующих категорий, следует создать для файлов новый каталог и отредактировать файл SYS/i386/conf/files.i386. К нашему драйверу это не относится, поэтому он будет автоматически скомпилирован и подключен к ядру.

Далее необходимо добавить запись об устройстве в конфигурационный файл ядра. Мы включим следующую запись в конфигурацию EXAMPLE:

device snf0      # Snarf, псевдо-сетевое устройство

 

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

Когда инсталлируется драйвер стороннего поставщика, нужно поискать в документации к нему старший и младший номера устройства. Следует использовать только номера, упомянутые в документации, иначе возможны конфликты с другими устройствами. Старшие номера устройств задаются в файле SYS/i386/conf/majors.i386. Запись, добавляемая в этот файл, зависит от устройства Получить информацию можно в документации к драйверу.

Следующие этапы предусматривают:

  • запуск команды config и построение нового ядра;
  • создание резервной копии старого ядра и инсталляцию нового ядра;
  • перезагрузку и тестирование нового ядра.
Эти операции рассматривались выше в настоящей главе. В самом конце может потребоваться создать файлы устройства (см. следующий параграф) и протестировать само устройство.


 (голосов: 0)
Версия для печати | Комментариев: 0
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии в данной новости.


 
Логин
Пароль
 

 
Locations of visitors to this page