Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
В качестве компилятора мы будем использовать компилятор gcc ($CC), ему будут переданы параметры $MODFLAGS и –c module.c. module.c – это имя файла нашего модуля. Опции компилятора означают следующее:
n O3: будет использован третий уровень оптимизации (что это такое, вы узнаете в справочной системе gcc: man gcc);
n Wall: включаем все предупреждения;
n DLINUX: генерируем код для Linux;
n I$(PATH): определяем путь поиска заголовочных файлов. По умолчанию компилятор ищет файлы заголовков в каталоге /usr/include, но там может и не быть нужных файлов, например, для дистрибутива ALT Linux (ядро 2.4.21) файлы заголовков находятся в каталоге /usr/include/linux-2.4.21rel-std-up/.
Makefile поместите в один каталог с файлом module.c и выполните команду make. После ее выполнения вы получите файл module.o, который будет находиться в одном каталоге с файлом module.c.
Если вы по каким-либо причинам не хотите использовать утилиту make, для компилирования модуля введите команду:
gcc –O3 -DMODULE -D__KERNEL__ -I/usr/include -c module.c
После того, как наш модуль откомпилирован, его можно установить:
insmod module.o
Вы увидите сообщение My module: Starting... Это же сообщение будет записано в файл протокола /var/log/messages.
Мы только что написали модуль ядра, который можно установить, удалить, который выводит сообщения, но он ничего полезного не делает. Усложним нашу задачу: напишем драйвер для некоторого устройства /dev/device. Данного устройства в нашей системе нет, поэтому нам его нужно создать, но этим мы займемся чуть позже.
Перед тем как приступить к написанию драйвера устройства, нужно поговорить о самих устройствах. Устройства бывают трех типов:
n Символьные: чтение и запись устройства выполняются посимвольно. Примером такого устройства может послужить последовательный порт.
n Блочные: чтение и запись устройства выполняются блоками, как правило, по 512 или 1024 байта. Самый яркий пример блочного устройства – жесткий диск.
n Сетевые: файлов этих устройств вы не найдете в каталоге /dev, поскольку использование файловой системы, то есть работа с этими устройствами как с файлами, неэффективно. Пример – сетевая карта (ethX).
Чтобы сделать устройство доступным для системы и пользовательских программ, нужно его зарегистрировать. В заголовочном файле fs.h определены функции для регистрации символьных и блочных устройств. Все они начинаются с префикса register. Наше устройство будет символьным, поэтому для его регистрации мы будем использовать функцию register_chrdev. Вот ее прототип:
extern int register_chrdev(unsigned int, const char *, struct file_operations *);
Разберемся, что означает каждый параметр. Первый параметр – это старший номер (major number) устройства, определяющий его тип. Если старший номер равен 0, то функция возвратит свободный старший номер для устройства нашего вида (символьное устройство).
Чтобы понять, для чего нужен старший номер, вспомним каталог /dev, содержащий файлы устройств. Возьмем файл /dev/tty1 – это терминал с номером 1. Старший номер определяет тип устройства – терминал (tty), а младший – его номер в системе (1). Человеку проще работать не с номерами, а с символьными именами устройств, поэтому каждому старшему номеру соответствует символьное обозначение.
При регистрации устройства нужно указать его тип – старший номер устройства. Но откуда мы знаем, какой номер занят, а какой – нет? Проще всего указать 0 в качестве первого параметра функции register_chrdev(). В этом случае функция возвратит свободный старший номер символьного устройства для нашей системы. Если же явно указать старший номер, может возникнуть конфликт номеров, и наше устройство не будет зарегистрировано.
Второй параметр определяет имя устройства («device»). Последний параметр очень важен. Это структура указателей на функции для работы с нашим устройством. Наш драйвер (модуль) содержит таблицу доступных функций, а операционная система вызывает нужную функцию, когда пользовательской программе нужно выполнить операцию с файлом устройства (открытие/закрытие, чтение/запись). Таблица функций символьного устройства хранится в структуре file_operations, которая передается при регистрации устройства.
После регистрации драйвера устройства происходит поиск устройств данного типа. Причем этот поиск должен произвести сам драйвер. Для простоты будем считать, что у нас всего два устройства. Нам нужно создать эти два устройства, но перед этим нам нужно вычислить старший номер устройства. Напишем драйвер, который помимо регистрации устройства выводил бы его старший номер – потом мы его будем использовать при создании устройства.
Листинг 7. Драйвер устройства /dev/device (без структуры file_operations)
#define MODULE
#define __KERNEL__