Мигание Светодиода Модуля Ядра Linux

Всем привет. В этой статье я хочу поделиться своим опытом создания простого модуля ядра 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

Вместе с данным постом часто просматривают: