Драйверы устройств в Linux
Часть 2: Пишем в классе наш первый драйвер для Linux
Оригинал: «Device Drivers, Part 2: Writing Your First Linux Driver in the Classroom»
Автор: Anil Kumar Pugalia
Дата публикации: December 1, 2010
Перевод: Н.Ромоданов
Дата перевода: июнь 2012 г.
В этой статье, которая является частью серии статей о драйверах устройств в Linux, речь идет о концепции динамической загрузки драйверов — сначала мы перед тем, как собирать драйвер, напишем драйвер для Linux, а затем, после сборки, загрузим его.
Светлана и Пагс добрались в свой класс с опозданием и увидели, что их профессор уже начал читать лекцию. Светлана робко попросила разрешения войти. Раздраженный профессор Гопи ответил: «Входите! Вы, друзья, опять сегодня опоздали, и по какой причине»?
Пагс поспешно ответил, что они обсуждали именно ту тему, которую сегодня изучают в классе — драйверы устройств в Linux. Пагс был более, чем счастлив, когда профессор сказал: «Хорошо! Тогда что-нибудь скажите о динамической загрузке в Linux. Если вы справитесь, то я прощу вас обоих!». Пагс знал, что один из способов сделать профессора счастливым, это — покритиковать Windows.
Он объяснил: «Как известно, при обычной установке драйверов в Windows для того, чтобы их активировать, необходимо перезагрузить систему. А если это, предположим, действительно неприемлемо в случае, если это нужно делать на сервере? Вот где выигрывает Linux. В Linux можно загружать и выгружать драйверы на лету, и это активно используется сразу после загрузки системы. Кроме того, драйвер мгновенно отключается после его выгрузки. Это называется динамической загрузкой и выгрузкой драйверов в Linux «.
Это впечатлило профессора. «Хорошо! Идите на свои места, но больше не опаздывайте». Профессор продолжил лекцию: «Теперь, когда вы уже знаете, что такое динамическая загрузка и выгрузка драйверов, я, прежде, чем мы перейдем к написанию нашего первого драйверов, покажу вам, как загружать и выгружать драйвера».
Динамическая загрузка драйверов
Эти динамически загружаемые драйвера чаще всего называют модулями, которые собираются в виде отдельных модулей с расширением .ko (объект ядра). В каждой системе Linux в корне файловой системы (/) есть стандартное место для всех предварительно собранных модулей. Они организованы аналогично древовидной структуре исходных кодов ядра и находятся в директории /lib/modules/ /kernel , где результат вывода системной команды uname -r (см.рис.1).
Рис.1: Предварительно собранные модули Linux
Чтобы динамически загружать и выгружать драйверы, воспользуйтесь следующими командами, которые находятся в директории /sbin и должны выполняться с привилегиями пользователя root:
- lsmod — список модулей, загруженных в текущий момент
- insmod — добавление / загрузка указанного файла модуля
- modprobe — добавление / загрузка модуля вместе со всеми его зависимостями
- rmmod — удаление / выгрузка модуля
Давайте в качестве примера рассмотрим соответствующие драйвера файловой системы FAT. На рис.2 показан весь процесс нашего эксперимента. Файлы с модулями будут fat.ko , vfat.ko и т.д., находящиеся в директории fat (в vfat для старых версий ядра) в /lib/modules/`uname -r`/kernel/fs . Если они представлены в сжатом формате .gz , вам нужно будет распаковать их с помощью команды gunzip , прежде чем вы сможете выполнить операцию insmod .
Рис.2: Операции с модулями Linux
Модуль vfat зависит от модуля fat , так что первым должен быть загружен модуль fat.ko . Чтобы автоматически выполнить распаковку и загрузку зависимостей, воспользуйтесь командой modprobe . Обратите внимание, что когда вы пользуетесь командой modprobe , вы не должны в имени модуля указывать расширение .ko . Команда rmmod используется для выгрузки модулей.
Наш первый драйвер для Linux
Перед тем, как написать наш первый драйвер, давайте рассмотрим некоторые понятия. Драйвер никогда не работает сам по себе. Он похож на библиотеку, загружаемую из-за функций, которые будут вызваны из работающего приложения. Он написан на языке C, но в нем отсутствует функция main() . Кроме того, он будет загружаться / компоноваться с ядром, поэтому он должен компилироваться аналогично тому, как было откомпилировано ядро, и вы можете в качестве заголовочных файлов использовать только те, что есть в исходном коде ядра, а не из стандартного директория /usr/include .
Интересный факт, касающийся ядра, это то, что оно, как мы видим даже на примере нашего первого драйвера, представляет собой объектно-ориентированную реализацию на языке C. В любом драйвере есть конструктор и деструктор. Когда модуль успешно загружается в ядро, то вызывается конструктор модуля, а дескруктор модуля вызывается, когда команде rmmod удается успешно выгрузить модуль. Это в драйвере две обычные функции, разве что они называются init и exit, соответственно, и вызываются с помощью макросов module_init() и module_exit() , которые определены в заголовков ядра module.h .
С учетом вышесказанного это полный код нашего первого драйвера; назовем его ofd.c. Обратите внимание, что отсутствует заголовок stdio.h (заголовок пользовательского пространства), вместо него мы используем аналог kernel.h (заголовок пространства ядра). Функция printk() эквивалентна функции printf() . Кроме того, для обеспечения совместимости версии модуля с ядром, в которое будет загружен модуль, добавлен заголовок version.h . С помощью макроса MODULE_* заполняется информация, относящаяся к модулю, которая будет использована как «подпись» модуля.
Сборка нашего первого драйвера
Т.к. у нас есть код на языке C, настало время его скомпилировать и создать файл модуля ofd.ko . Для этого мы используем систему сборки ядра. В приведенном ниже файле Makefile происходит обращение к системе сборки ядра из исходных кодов, а файл Makefile ядра, в свою очередь, обращается к файлу Makefile нашего нового драйвера с тем, чтобы собрать драйвер.
Чтобы собрать драйвер для Linux, у вас в системе должен быть исходный код ядра (или, по крайней мере, заголовки ядра). Предполагается, что исходный код ядра будет находиться в директории /usr/src/linux . Если в вашей системе он находится в каком-нибудь другом месте, то укажите это место в переменной KERNEL_SOURCE в файле Makefile .
Когда есть код на языке C ( ofd.c ) и готов файл Makefile , то все, что нам нужно сделать для сборки нашего первого драйвера ( ofd.ko ), это вызвать команду make .
Подведем итог
Как только у нас будет файл ofd.ko , мы в роли пользователя root или с помощью команды sudo выполним обычные действия.
Команда lsmod должна вам сообщить о том, что драйвер ofd загружен.
Пока студенты экспериментировали со своим первым модулем, прозвенел звонок, сообщивший об окончании урока. Профессор Гопи подвел итог: «В настоящий момент мы не увидели ничего, кроме того, что модуль lsmod сообщил о загрузке драйвера. Куда выводит информацию команда printk ? Найдите это самостоятельно на лабораторных занятиях и познакомьте меня с своими выводами. Также учтите, что наш первый драйвер будет шаблоном для любого драйвера, который можно написать для Linux. Написание специализированных драйверов это всего лишь вопрос о том, чем будет заполнен конструктор и деструктор драйвера. Поэтому дальнейшее изучение будет представлять собой расширение данного драйвера с целью получить драйвер с конкретными функциональными возможностями».
Источник
Самые полезные настройки и команды Linux
Автор: Igor Ljubuncic, перевод: С.Русинов
Установка драйверов
Драйверы — это программы подобные обычному программному обеспечению. Разница лишь в том, что для их работы не требуется постоянное вмешательство пользователя. Они служат для взаимодействия ваших аппаратных средств между собой. Как все просто. Вам необходимо улучшить их использование операционной системой.
Чаще всего, необходимые драйвера включаются в дистрибутив и устанавливаются в процессе установки. Иногда бывает все не так удачно, и только что собранная рабочая станция будет идти без звука, сети или видео драйверов.
Я не буду вдаваться в детали, поясняя установку специфических драйверов. Для получения этой информации вам необходимо обратиться к поставщикам оборудования. Я поясню, как установить драйверы, как загрузить их, а затем как добавить их в автозагрузку, чтобы они загружались автоматически каждый раз при запуске системы.
Установка
Подобно любому программному обеспечению, драйверы могут быть скомпилированными или нет. Обычно они не скомпилированы. Драйверы обычно распространяются в виде исходных текстов, с целью достижения максимально возможной совместимости аппаратных средств на установленной платформе. Это значит, что вам придется компилировать их из исходных текстов. Элементарно! Мы уже знаем как это сделать.
Если поставщик оборудования является щедрым, он, возможно, дополнит поставляемый драйвер само-устанавливающим скриптом. Другими словами, вам будет нужно только запустить одну команду, которая выполнит: распаковку архива, компиляцию, установку и загрузку драйвера. Но это может не работать. Я был свидетелем как само-устанавливающийся скрипт драйвера работал неверно. По этой причине, для всех практических задач, вам следует устанавливать драйвер вручную.
После успешной распаковки из архива и компиляции исходников (./configure, make, make install), вы, скорее всего, столкнетесь с выбором из трех вариантов:
- Драйвер будет полностью сконфигурирован и скопирован в папки, выбранные по умолчанию, и системные пути будут обновлены. В этом случае, вам не нужно ничего делать, чтобы использовать драйвер.
- Драйвер будет сконфигурирован автоматически, и системные пути будут обновлены. Это значит, что вы только добавите имя драйвера в список загружаемых драйверов начальной загрузки, чтобы он загружался автоматически при запуске системы.
- Драйвер будет готов к использованию, но не будет сконфигурирован, системные пути не будут обновлены. Вам придется вручную загрузить драйвер и затем обновить список загружаемых драйверов начальной загрузки, чтобы он загружался автоматически при запуске системы.
При втором варианте, процесс установки, будет выглядеть следующим образом:
Теперь только остается добавить этот драйвер в список загружаемых драйверов при запуске системы. В Linux драйвера часто называют модулями .
Вам нужно открыть конфигурационный файл, содержащий список модулей. Также необходимо знать его точное имя и размещение файла в вашем дистрибутиве. В Ubuntu этот файл называется modules.conf и размещается в /etc каталоге ( /etc/modules.conf ). Мы обновим этот файл, но вначале мы сделаем его резервную копию. Пожалуйста помните, что для изменения конфигурационных файлов нужны права суперпользователя.
Так будет выглядеть эта процедура:
Приведенные выше команды откроют файл modules.conf в текстовом редакторе gedit. Теперь, просто добавьте драйвер в пустую строку ниже существующих драйверов, сохраните файл, выйдите из текстового редактора и перезагрузите систему, чтобы изменения вступили в силу. Это все!
Вот пример, файла modules.conf для Kubuntu Linux, установленной на виртуальной машине. Добавим новый драйвер. Мы просто запишем его имя ниже существующих записей. Конечно, необходимо знать ТОЧНОЕ имя соответствующего драйвера.
Третий вариант немного более сложный.
Загрузка драйверов
Вы успешно скомпилировали драйвер, но ничего не произошло. Это получилось потому, что драйвер еще не включен. Посмотрев внутрь каталога, вы заметите файл с расширением .ko . Это и есть ваш драйвер, и его необходимо загрузить вручную.
Нам нужно установить драйвер в ядро. Это можно сделать с помощью команды insmod .
После загрузки драйвера его можно конфигурировать. Вы можете убедиться в том, что драйвер действительно присутствует в списке всех доступных модулей:
Если вы случайно сделали серьезную ошибку и хотите удалить драйвер, то можете воспользоваться командой rmmod :
Конфигурирование драйверов
Конфигурирование драйвера требует немного знаний о его функциональности. Чаще всего инструкции находятся в текстовых файлах how-to руководства.
Ниже приведенный пример показывает как конфигурировать сетевую карту после загрузки сетевого драйвера. Сетевой карте присвоен идентификатор и IP адрес. В данном случае, eth0 — имя выбранного устройства, но оно может быть другим, например: eth1, eth2 и т. д. . Назначенный IP адрес показывает нам, что машина будет частью локальной сети.
После перезагрузки вы увидите, что сетевое подключение отсутствует. Это происходит из-за того, что драйвер отсутствует в общем каталоге по умолчанию, и система не знает, где его искать. Вам придется повторить всю процедуру снова:
Теперь становится понятно, что применение скрипта для автоматизации этих действий было бы отличной идеей. И это именно то, что мы собираемся сделать — написать скрипт и добавить его в начальную загрузку системы.
Скрипты
Как и в системах DOS и Windows, скрипты могут быть написаны в текстовом редакторе. Учитывая внутренние различия между текстовыми файлами и скриптами, необходимо различать текстовые файлы и скрипты. В системе Windows достаточно изменить расширение .txt на .bat и файл станет скриптом. В Linux немного по-другому.
Командная строка Linux находится внутри оболочки или, точнее сказать, и есть сама оболочка или Шелл (Shell). Существует несколько оболочек, каждая со своим уникальным набором команд. Самая популярная (устанавливается по умолчанию) оболочка Linux это BASH . Нам необходимо добавить информацию в наш скрипт, если хотим сделать его связанным с нашей оболочкой.
Таким образом, записав в файл приведенные выше команды плюс ссылка на оболочку, получим следующий скрипт:
Можно сделать это короче:
Теперь у нас есть рабочий скрипт. Или точнее текстовый файл, который содержит соответствующие команды. Нам необходимо сделать его исполняемым файлом. Во-первых, нужно сохранить этот файл. Назовем его network_script .
Сделаем скрипт исполняемым.
Теперь у нас есть работающий скрипт. Нам нужно разместить его в каталоге /etc/init.d и он будет запускаться во время начальной загрузки системы.
В завершение нужно обновить систему для активации скрипта.
После перезагрузки вы поймете, что драйвер загружен автоматически и сетевая карта сконфигурирована! Возможен и другой вариант, make install и драйвер будет помещен в каталог по умолчанию:
Или вы могли разместить драйвер в этом каталоге сами. Таким образом, вы могли бы избежать написания скрипта.
Однако мой метод, даже если и менее изящный, имеет одно преимущество. Драйверы, которые вы скомпилировали вручную и поместили в каталоги по умолчанию, будут потеряны при обновлении ядра системы. Это значит, что вам будет необходимо их переустанавливать каждый раз после такого обновления. Мой неэлегантный метод позволяет избежать этой проблемы.
Источник