Linux device drivers по русски

Linux device drivers по русски

Библиотека сайта rus-linux.net

Русский вариант Linux Device Driver 2-nd edition

Дата создания документа: 03.08.2004
Дата последнего изменения: 03.12.2004
Автор: Князев Алексей. knzsoft@mail.ru
ICQ: 194144861

Представляю вам часть работы над переводом известного фундаментального труда по написанию драйверов в Linux — Linux Device Driver 2-nd edition от Alessandro Rubini & Jonatan Corbet. В процессе чтения оригинального материала я принял решение построить русский вариант этого материала не в виде дословного перевода, а скорее «по мотивам» перевода. Из-за отсутствия фантазии и серьезного опыта в разработке драйверов под Linux я придерживаюсь оригинального материала, но с некоторыми, иногда обширными отступлениями. Эти отступления относятся, во-первых, к ядру 2.6.x, которое просто не представлено в оригинале по причине относительной давности материала, а, во-вторых, я попытался, на свой взгляд, ввести дополнения к оригиналу, в целях упрощения усвоения материала новичками. Ну, возможно, есть и будет что-то еще. Вообще, я собираюсь дополнить материал дополнительными примерами.

Надеюсь на вашу помощь в тестировании и исправлении ошибок материала.

Просьба. Поскольку я не имею возможности средствами сайта определять посещаемость данного материала, то у меня будет просьба к тем, кому этот материал нужен. Отписывайтесь мне на e-mail. Так я смогу оценить востребованность материала. Присылайте, также, номера еще не переведенных глав, которые были бы вам интересны. Я буду стараться акцентировать внимание на наиболее востребованных главах. Кроме того, мне было бы интересно знать: какими задачами вы занимаетесь, для души или по работе, и как вы попали на эту страницу моего перевода. Также, напишите, считаете ли вы полезным публикацию данного материала в виде печатного издания — С уважением, Князев Алексей.

Источник

Как написать свой первый Linux device driver

Здравствуйте, дорогие хабрачитатели.

Цель данной статьи — показать принцип реализации драйверов устройств в системе Linux, на примере простого символьного драйвера.

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

Это моя первая статья, пожалуйста не судите строго!

Получилось слишком много букв, поэтому я принял решение разделить статью на три части:

Часть 1 — Введение, инициализация и очистка модуля ядра.
Часть 2 — Функции open, read, write и trim.
Часть 3 — Пишем Makefile и тестируем устройство.

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

Подготовительные работы

Спасибо Kolyuchkin за уточнения.

Символьный драйвер (Char driver) — это, драйвер, который работает с символьными устройствами.
Символьные устройства — это устройства, к которым можно обращаться как к потоку байтов.
Пример символьного устройства — /dev/ttyS0, /dev/tty1.

К вопросу про проверсию ядра:

Драйвер представляет каждое символьное устройство структурой scull_dev, а также предостовляет интерфейс cdev к ядру.

Устройство будет представлять связный список указателей, каждый из которых указывает на структуру scull_qset.

Для наглядности посмотрите на картинку.

Для регистрации устройства, нужно задать специальные номера, а именно:

MAJOR — старший номер (является уникальным в системе).
MINOR — младший номер (не является уникальным в системе).

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

После того как мы определили номера для нашего устройства, мы должны установить связь между этими номерами и операциями драйвера. Это можно сделать используя структуру file_operations.

В ядре есть специальные макросы module_init/module_exit, которые указывают путь к функциям инициализации/удаления модуля. Без этих определений функции инициализации/удаления никогда не будут вызваны.

Здесь будем хранить базовую информацию об устройстве.

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

Инициализация

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

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

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

Выделяем память, делая вызов функции kmalloc и обязательно проверяем указатель на NULL.

Стоит упомянуть, что вместо вызова двух функций kmalloc и memset, можно использовать один вызов kzalloc, который выделят область памяти и инициализирует ее нулями.

Продолжаем инициализацию. Главная здесь функция — это scull_setup_cdev, о ней мы поговорим чуть ниже. MKDEV служит для хранения старший и младших номеров устройств.

Возвращаем значение или обрабатываем ошибку и удаляем устройство.

Выше были представлены структуры scull_dev и cdev, которые реализуют интерфейс между нашим устройством и ядром. Функция scull_setup_cdev выполняет инициализацию и добавление структуры в систему.

Удаление

Функция scull_cleanup_module вызывается при удалении модуля устройства из ядра.
Обратный процесс инициализации, удаляем структуры устройств, освобождаем память и удаляем выделенные ядром младшие и старшие номера.

С удовольствием выслушаю конструктивную критику и буду ждать feedback’a.

Если вы нашли ошибки или я не правильно изложил материал, пожалуйста, укажите мне на это.
Для более быстрой реакции пишите в ЛС.

Источник

Драйверы устройств в Linux

Часть 1: Драйверы устройств Linux для вашей знакомой

Оригинал: «Device Drivers, Part 1: Linux Device Drivers for Your Girl Friend»
Автор: Anil Kumar Pugalia
Дата публикации: November 1, 2010
Перевод: Н.Ромоданов
Дата перевода: июнь 2012 г.

Цель этой серии статей о драйверах Linux — рассказать об обычной технической теме так, чтобы она была интересна более широкому кругу читателей.

«После недели напряженной работы, мы, наконец, добились, что теперь наш driver (драйвер / водитель) работает» — были первые слова Пагса, когда он встретил свою знакомую Светлану.

«Почему? Какой твой driver (драйвер / водитель)? Что, он был болен? И что за тяжелую работу ты сделал?», — спросила Светлана. Растерявшись, Пагс, в свою очередь, спросил: «О чем ты говоришь?»

Теперь настала очередь Светланы быть озадаченной и она ответила: «Почему ты меня спрашиваешь? Ты сказал мне — о каком из твоих driver (драйверов / водителей) ты говоришь? «

Когда Пагс понял, о чем идет речь, он застонал: «Ах, да! Это не driver (драйвер / водитель) моей машины — я говорю о driver (драйвере / водителе) устройства на моем компьютере «.

«Я знаю о driver (драйверах / водителах) машин и автобусов, о летчиках и даже об отвертках; но что это за «driver (драйвер / водитель) устройства» — озадаченно спросила Светлана.

Этого было достаточно, чтобы Пагс погрузился в страстное объяснение драйверов устройств для новичка — в частности, драйверов устройств для Linux, с которыми он работал на протяжении многих лет.

Этот диалог мог в англоязычной среде вызвать непонимание между собеседниками. Дело в том, что в обыденной речи в англоязычной среде слово driver означает — водитель, например, водитель машины, тогда как если слово driver употребляется при обсуждении оборудования и программного обеспечения компьютеров, то оно почти наверняка означает — драйвер, т. е. специальный модуль, с помощью которого происходит управление некоторым устройством, для которого написан конкретный драйвер. Т.е., в некотором смысле это тоже «водитель» устройства, с помощью которого происходит управление, но в русскоязычной среде для этого используется прямая калька с английского driver — драйвер.

Аналогичное смешение понятий может вызвать английское слово bus, которое в обыденной речи переводится как «автобус», например, school-bus – школьный автобус или автобус для школьников. Но при обсуждении компьютерного оборудования термином bus называют шину, которая обычно представляет собой некоторое количество соединительных линий, к которым подключаются отдельные устройства.

О драйверах / водителях (drivers) и шинах / автобусах (buses)

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

Кроме того, «водителем» может быть человек или даже автоматическая система, управление которой возложено на человека (например, система автопилота в самолете). Аналогичным образом управление определенной частью аппаратных средств может осуществляться некоторой частью программного обеспечения (драйвером устройства), или может осуществляться другим устройством, управление которым, в свою очередь, может выполняться программой — драйвером устройства. В последнем случае, такое управляющее устройство обычно называется контроллером устройств. Для него, поскольку оно само является устройством, необходим драйвер, который обычно называют bus driver или драйвер шины (термин bus driver, если он используется в контексте обычного разговора, можно перевести и как «водитель автобуса» — прим.пер.).

К числу обычных примеров контроллеров устройств относятся контроллеры жестких дисков, контроллеры дисплеев и контроллеры аудиоустройств, с помощью которых осуществляется управление устройствами, подключаемыми к контроллерам. В качестве более подробных технических примеров можно рассмотреть контроллер IDE, контроллер PCI, USB-контроллер, контроллер SPI, контроллер I2C и т.д. Графически, вся эта концепция может быть изображена так, как показано на рис.1.

Рис.1: Взаимодействие устройств и драйверов

Контроллеры устройств, как правило, подключаются к процессору через шины, имеюшие определенное название (набор физичсеких линий подключения) — например, шина PCI, шина IDE, и т.д. В современном мире встроенных технологий мы чаще сталкиваемся с микроконтроллерами, а не процессорами; это те же самые процессоры и плюс контроллеры различных устройств, реализованные на одном чипе. Такая встроенная реализация контроллеров устройств в первую очередь снижает стоимость и уменьшает занимаемое пространство, что делает микроконтроллер удобным для использования во встраиваемых системах. В таких случаях шины интегрированы в сам чип. Меняет ли это что-либо для драйверов или, в более общем случае, в используемом программном обеспечении?

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

Драйверы состоят из двух частей

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

Рис.2: Отдельные части драйвера Linux

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

Позже я также приведу несколько примеров расшифровки спецификации. Тем не менее, та часть драйвера, которая зависит от ОС, тесно взаимодействует с механизмами ОС, реализующими пользовательский интерфейс, и, поэтому, она будет отличаться в драйверах устройств для Linux, в драйверах устройств для Windows и в драйверах устройств для MacOS.

Вертикали

В Linux драйвер устройства предоставляет пользователю интерфейс «системного вызова»; в Linux это граница между так называемым пространством ядра и пользовательским пространством, что и показано на рис.2. На рис.3 представлена более подробная классификации.

Рис.3: Общая схема ядра Linux

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

  • Пакетно-ориентированная или сетевая вертикаль
  • Блочно-ориентированная вертикаль или вертикаль хранения данных
  • Байт-ориентированная вертикаль или вертикаль работы с символами

Вертикаль процессора и вертикаль памяти, рассматриваемые вместе с этим тремя вертикалями, дают полное представление о ядре Linux, соответствующее определению ОС, которое есть в любом учебнике: «В операционной системе реализуется 5 основных функций управления: управление процессором / процессом, памятью, сетью, средствами хранения данных, устройствами ввода / вывода». Хотя эти вертикали процессора и памяти можно классифицировать как драйверы устройств, где процессор и память будут соответствующими устройствами, их, по ряду причин, трактуют по-другому.

Таковы основные функциональные возможности любой ОС, будь то микроядро или монолитное ядро. Чаще всего добавление кода именно в эти области представляет собой основную часть работы по портированию Linux, что обычно делается для нового процессора и архитектуры. Более того, код в этих двух вертикалях нельзя, в отличие от трех других вертикалей, загружать или выгружать «на лету». Так что когда мы теперь будем говорить о драйверах устройств в Linux, мы будем говорить только о тех трех вертикалях, которые расположены на рис.3 справа.

Давайте заглянем немного глубже внутрь этих трех вертикалей. Сетевая вертикаль состоит из двух частей: а) стек сетевых протоколов и б) драйверы устройств карт сетевых интерфейсов (NIC) или просто драйверы сетевых устройств, которые могут предназначаться для Ethernet, Wi-Fi или любой другой сетевой горизонтали. Вертикаль хранения данных, опять же, состоит из двух частей: а) драйверов файловых систем, предназначенных для декодирования разнообразных форматов данных в различных разделах файловых систем, и б) драйверов блочных устройств для различных (аппаратных) протоколов хранения данных, т.е. горизонталей, таких как IDE, SCSI, MTD и т.д.

При этом, вы можете задать вопрос, действительно ли это только набор устройств, для которых нужны драйвера (или, для которых в Linux драйвера уже есть). Имейте терпение, вам, конечно, нужны драйверы для всей этой массы устройств, которые взаимодействуют с системой, и в Linux действительно есть для них драйверы. Однако из-за их байт-ориентированного доступа все они попадают в вертикаль работы с символами — их, на самом деле, огромное количество. В действительности из-за огромного количества драйверов в этой вертикали, для драйверов, предназначенных для работы с символьными устройствами, используется дополнительная подклассификация — так что у вас есть драйверы терминалов, драйверы ввода/вывода, драйверы консоли, драйверы фрейм-буфера, звуковые драйверы и т.д. Типичными горизонталями здесь будут RS232, PS/2, VGA, I2C, I2S, SPI и т.д.

Драйверы со множественными вертикалями

Последнее замечание относительно полной картины (размещения всех драйверов в экосистеме драйверов Linux): такие горизонтали, как USB, PCI и т.д., расширяются ниже на несколько вертикалей. Почему это происходит?

Очень просто — вы уже знаете, что у вас может быть флешка-ключ USB Wi-Fi, флешка USB и преобразователь USB-последовательный порт, но все эти три устройства USB попадают в три различные вертикали!

В Linux драйвера шин или горизонтали часто подразделяются на две части, или даже на два драйвера: а) контроллер конкретного устройства и б) абстрактный слой, находящийся над ним и используемый в качестве интерфейсам к вертикалям, обычно называемыми ядрами. Классическим примером могут быть драйвера USB-контроллера ohci, ehci и т.д. и USB-абстракция — usbcore.

Подведем итог

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

«Эй, Пагс, остановись; мы опаздываем на занятия, и ты знаешь, какие из-за этого могут возникнуть проблемы. Давай позже продолжим с этого места» — воскликнула Светлана.

Вскочив, Пагс закончил свое объяснение: «Хорошо. Это основа теории о драйверах устройств. Если тебе интересно, я позже могу показать тебе код, и все, что мы делали для различных драйверов». И они поспешили к своей аудитории.

Источник

Читайте также:  Сетевой мост openvpn windows
Оцените статью