Всем привет. В этой статье я хочу поделиться своим опытом создания простого модуля ядра Linux. Статья будет полезна тем, кто хотел бы понять, как писать модули ядра, но не знает, с чего начать.
Я давно хотел разобраться в этой теме, но до недавнего времени не знал, как к ней подойти.
Мне хотелось, чтобы модуль был достаточно простым, но более сложным, чем «Привет, мир!» сообщение.
вывод в файл журнала.
В итоге решил попробовать прошить светодиод. Дополнительной целью было вывести в sysfs параметр, отвечающий за частоту мигания.
Для проведения эксперимента я использовал плату Orange Pi One с Ubuntu Linux на борту (версия ядра 3.4.113).
Для сборки модуля ядра вам понадобится компилятор gcc, утилита make и файлы заголовков ядра.
Чтобы установить файлы заголовков, выполните следующую команду:
Далее я разберу, на мой взгляд, самые интересные части модуля.sudo apt-get install linux-headers-$(uname -r)
В целях экономии места я не буду приводить здесь весь код; он вместе с файлом make доступен на github .
В модуле я использовал заголовочные файлы: #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/hrtimer.h>
#include <linux/moduleparam.h>
kernel.h и mod.h всегда должны быть включены при написании модуля ядра, gpio.h фактически отвечает за работу с GPIO, hrtimer.h (таймер высокого разрешения) — это заголовочный файл таймера, для вывода параметров нужен модульparam.h в сисфс.
Чтобы не предоставлять доступ к ядру системы вашим переменным и функциям, все они должны быть описаны как статические.
На всякий случай отмечу, что ядро написано на C и статика, в отличие от C++, означает, что объект доступен только внутри исполняемого файла.
Точка входа: static int blink_module_init(void)
Здесь я инициализирую переменные, которые буду использовать в будущем, в том числе: gpio_timer_interval = ktime_set(gpio_blink_interval_s, 0);
ktime_set инициализирует тип данных ktime_t, присваивая ему желаемое количество секунд (gpio_blink_interval_s) и наносекунд (0).
В дальнейшем эта переменная будет использоваться таймером.
Далее идет запрос на использование GPIO: err = gpio_request(BLINK_PIN_NR, "blink_led");
Эта функция возвращает 0 в случае успеха, поэтому в будущем я проверю, что она вернула.
Затем выбранный контакт необходимо настроить на выход сигнала и указать значение по умолчанию.
err = gpio_direction_output(BLINK_PIN_NR, GPIOF_INIT_LOW);
Если ошибок не было, то инициализирую и запускаю таймер hrtimer_init(&gpio_blink_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
gpio_blink_timer.function = &gpio_blink_timer_callback;
hrtimer_start(&gpio_blink_timer, gpio_timer_interval, HRTIMER_MODE_REL);
Функция обратного вызова таймера будет gpio_blink_timer_callback. В этой функции я меняю значение пина на противоположное gpio_value ^= 0x01;
gpio_set_value(BLINK_PIN_NR, gpio_value);
Я установил, когда таймер должен сработать в следующий раз hrtimer_forward_now(&gpio_blink_timer, gpio_timer_interval);
и верните HRTIMER_RESTART.
Теперь давайте посмотрим, как показать некоторую переменную в sysfs. Для этого я использую макрос module_param_cb(gpio_blink_interval_s, &kp_ops, &gpio_blink_interval_s, 0660);
Первый параметр этого макроса — имя файла в sysfs. Второй — это структура данных, содержащая функции обратного вызова.
Третий параметр — это указатель на реальную переменную, а четвертый — права доступа к файлу в sysfs. Функции из kp_ops вызываются, когда пользователь меняет значения файла sysfs или читает его значение.
Вот как я их инициализировал: static const struct kernel_param_ops kp_ops =
{
Теги: #Сделай сам или Сделай сам #C++ #ядро Linux #GPIO
-
Компьютеры «Все В Одном» С Сенсорным Экраном
19 Oct, 24 -
Я Даю Тебе Идею
19 Oct, 24 -
Smf 2.0, Долгожданный Rc2 Public
19 Oct, 24 -
Интернет-Таблица Менделеева
19 Oct, 24 -
Gearman И Php 5.4 (5.6): Проблемы И Решения
19 Oct, 24