================================================== 5.28 Пользовательский I/O (UIO) в Linux ================================================== Введение -------- UIO (User-defined I/O) — это инфраструктура Linux, предназначенная для упрощения создания драйверов устройств в пространстве пользователя. Она предоставляет минимальную поддержку со стороны ядра, позволяя основную логику взаимодействия с оборудованием реализовать **в user space**. UIO особенно полезен, когда: - Устройство не требует сложной логики в прерываниях - Достаточно прямого доступа к регистрам через память (mmap) - Требуется быстрая отладка, без пересборки ядра --- Архитектура ------------ UIO состоит из двух частей: 1. **Ядровая часть**: - Упрощённый драйвер (`uio_pdrv_genirq`, `uio_platform`) - Регистрирует устройство `/dev/uioX` - Предоставляет mmap-доступ к регистрам и интерфейс прерываний 2. **Пользовательская часть**: - Программа на C, Python или любом другом языке - Открывает `/dev/uioX`, мапит память, обрабатывает события --- Преимущества и ограничения ========================== Преимущества: - Простой доступ к I/O-регистрам через mmap - Отладка средствами user space (gdb, valgrind, printf) - Нет необходимости писать полноценный драйвер ядра - Возможность реализации на любом языке (не только C) - Позволяет обрабатывать простые прерывания через `read()` Ограничения: - Нет доступа к подсистемам ядра (I2C, SPI, DRM и др.) - Обработка прерываний ограничена (только уведомление) - Ответственность за безопасность и синхронизацию — на приложении --- Регистрация устройства ---------------------- Пример через Device Tree: .. code-block:: dts mydevice@0x10000000 { compatible = "generic-uio"; reg = <0x10000000 0x1000>; interrupt-parent = <&gpio>; interrupts = <42 0>; }; Пример в коде ядра: .. code-block:: c struct resource res[] = { { .start = 0x10000000, .end = 0x10000FFF, .flags = IORESOURCE_MEM, }, }; platform_device_register_simple("uio_pdrv_genirq", -1, res, 1); --- Работа с UIO из пространства пользователя ------------------------------------------ Пример на C: .. code-block:: c int fd = open("/dev/uio0", O_RDWR); void *map = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // Чтение/запись регистра uint32_t val = *((volatile uint32_t *)map + 0); *((volatile uint32_t *)map + 0) = 0x01; // Ожидание прерывания uint32_t irqcount; read(fd, &irqcount, sizeof(irqcount)); --- Интерфейсы ----------- После загрузки UIO-драйвера создаются: **Устройство:** .. code-block:: shell /dev/uio0 **Sysfs:** .. code-block:: shell /sys/class/uio/uio0/ ├── maps/map0/addr ├── maps/map0/size ├── name └── version --- Когда использовать UIO ----------------------- UIO — хороший выбор, если: - Устройство предоставляет прямой доступ к регистрам - Требуется быстрая реализация и отладка - Прерывания можно обрабатывать просто (уведомление, не логика) - Нет необходимости в глубокой интеграции с подсистемами ядра --- Сравнение UIO и Platform Driver -------------------------------- .. list-table:: Сравнение UIO и Platform Driver :widths: 25 35 35 :header-rows: 1 * - Характеристика - UIO (User-space I/O) - Platform Driver (в пространстве ядра) * - Простота разработки - Очень высокая (пишется как обычное приложение) - Средняя/низкая (требует знания API ядра) * - Прямой доступ к регистрам - Да, через `mmap` - Да, через `ioremap` * - Обработка прерываний - Только уведомление через `read()` - Полная логика внутри IRQ handler * - Безопасность и синхронизация - На ответственности приложения - Контролируется ядром * - Поддержка подсистем - Нет - Полная (I2C, SPI, GPIO, LED, DMA, и др.) * - Отладка - Простая (`gdb`, `valgrind`, `printf`) - Сложнее (`printk`, `dmesg`, `kprobe`) * - Языки разработки - Любые (C, Python, Rust и др.) - Только C (ядровый стиль) * - Применение - Прототипирование, FPGA, простые устройства - Интеграция с системными шинами, сложные драйверы --- Заключение ----------- UIO позволяет реализовать драйверы для простых устройств в user space, существенно упрощая разработку, отладку и поддержку. Это особенно полезно при работе с самодельным оборудованием, отладочными платами, FPGA, а также в образовательных и экспериментальных целях. Если вам не требуется использовать возможности подсистем ядра, UIO — это простой и надёжный путь к созданию пользовательских драйверов в Linux.