28. 5.27 Драйверы платформенных устройств в пространстве пользователя
28.1. Обзор
В Linux-драйверах существует два основных подхода к взаимодействию с оборудованием:
через пространство ядра (kernel space)
через пространство пользователя (user space)
В этом разделе рассматривается практический способ реализации драйвера для RGB-светодиодов через platform_device, при этом управление осуществляется из пространства пользователя через sysfs или shell-скрипт.
Подход не требует патчей ядра, поддерживает перезагрузку модуля (rmmod/insmod) и легко расширяется.
28.2. Сценарий
На практике на Raspberry Pi подключены три светодиода к GPIO, и через простой платформенный драйвер мы:
выделяем пины для каждого цвета (можно через параметры модуля);
регистрируем устройства LED-класса (
led_classdev);получаем доступ к ним из /sys/class/leds/….
Это создаёт мост между пространством ядра и пользователя, при этом вся логика управления находится в пользовательских скриптах (bash, sh, Python, C).
28.3. Преимущества и недостатки
28.4. Пользовательское пространство (User Space)
Преимущества:
Удобная отладка — доступны обычные инструменты (gdb, strace, printf)
Можно использовать любые языки (например, Python)
Не требует пересборки ядра
Быстрый доступ к устройству (без системных вызовов на каждом шаге)
Интерфейс API в Linux стабилен
Недостатки:
Нельзя обрабатывать прерывания
Нет прямого доступа к регистрам и ядровым фреймворкам
Без ядровой части пользовательская часть не может «поднять» устройство
28.5. Пространство ядра (Kernel Space)
Преимущества:
Прямой доступ к железу и прерываниям
Использование инфраструктуры ядра (platform_device, led_classdev, pm, kobject)
Возможность одновременного доступа из нескольких процессов
Поддержка шины и автоматической загрузки через udev и modprobe
Недостатки:
Сложная отладка (dmesg, printk, падения ядра)
Системные вызовы при каждом обращении
Частые изменения API между версиями ядра
28.6. Связь между пространствами
Наиболее стабильной и простой связкой между ядром и пользователем является интерфейс sysfs:
/sys/class/leds/rgb:red/brightness
/sys/class/leds/rgb:green/brightness
/sys/class/leds/rgb:blue/brightness
Из bash или любого пользовательского кода можно просто писать:
echo 1 > /sys/class/leds/rgb:red/brightness
Физически за этим стоит регистрация устройства led_classdev в драйвере, который работает как платформенное устройство (см. platform_driver API в ядре).
28.7. Управление из shell
Можно реализовать управление драйвером из обычного sh-скрипта, используя файл, например:
echo "red=1" > ./pin
echo "green=0" > ./pin
А фоновый скрипт run.sh будет считывать команды и применять их к sysfs.
Это создаёт удобную прослойку между интерфейсом и железом, где драйвер отвечает за инициализацию, а пользователь — за поведение.
28.8. Пример архитектуры
+---------------------------+
| Пользовательский код |
| run.sh / Python / Bash |
+---------------------------+
|
v
+---------------------------+
| sysfs (/sys/class) |
+---------------------------+
|
v
+---------------------------+
| platform_driver |
| led_classdev_register() |
+---------------------------+
|
v
+---------------------------+
| GPIO-пины |
+---------------------------+
28.9. Вывод
> Пространство пользователя в связке с ядровыми драйверами — мощный и гибкий подход: логика остаётся на стороне пользователя, а стабильная регистрация устройств и доступ к железу — на стороне ядра.
Такой подход особенно актуален в системах на базе Raspberry Pi, где разработка ведётся быстро и гибко, без пересборки ядра и перезаписи dtb.
—
Если нужно — можно дополнить примерами .ko модуля, bash-интерфейса, udev-автозапуска или /dev/pin интерфейса через miscdevice.