======================================= Kernel UIO API — ядровой интерфейс ======================================= Введение --------- UIO API — это минималистичный и понятный интерфейс ядра Linux, позволяющий разработчику создать простой драйвер устройства с пользовательской логикой в пространстве пользователя. В ядре нужно только описать устройство, его память и (опционально) обработку прерываний — всё остальное можно реализовать в user space. --- Основная структура: struct uio_info ------------------------------------ UIO-ядро работает через структуру ``struct uio_info``, в которую вы записываете параметры вашего устройства. Обязательные поля: - ``const char *name`` Название драйвера. Отображается в `/sys/class/uio/uioX/name`. Лучше использовать имя модуля. - ``const char *version`` Версия драйвера. Показывается в `/sys/class/uio/uioX/version`. - ``struct uio_mem mem[MAX_UIO_MAPS]`` Массив отображаемых в user space областей памяти. Каждый элемент описывает одну mmap-область. - ``long irq`` Номер IRQ. Может быть: - Конкретный номер (например, 42) - ``UIO_IRQ_CUSTOM`` — если вы хотите вручную вызывать прерывание - ``UIO_IRQ_NONE`` — если прерывания не используются (редко) - ``unsigned long irq_flags`` Флаги для `request_irq()`, если используется аппаратное прерывание (например, `IRQF_SHARED`) --- Дополнительные (опциональные) поля ----------------------------------- - ``int (*mmap)(struct uio_info *info, struct vm_area_struct *vma)`` Своё поведение при `mmap()`. Если не задано — используется стандартное поведение. - ``int (*open)(struct uio_info *info, struct inode *inode)`` Вызывается при `open()` на `/dev/uioX`. Полезно, например, чтобы включать прерывания при использовании. - ``int (*release)(struct uio_info *info, struct inode *inode)`` Парный `close()` — для освобождения ресурсов. - ``int (*irqcontrol)(struct uio_info *info, s32 irq_on)`` Позволяет управлять прерываниями из user space: запись в `/dev/uioX` включает/выключает IRQ. --- Память: struct uio_mem ----------------------- Каждую область памяти, доступную через mmap, нужно описать через ``struct uio_mem``. Основные поля: - ``int memtype`` Тип области памяти: - ``UIO_MEM_PHYS`` — физическая память, доступная пользователю (через `mmap`) - ``UIO_MEM_LOGICAL`` — логическая память, выделенная через `kmalloc` - ``UIO_MEM_VIRTUAL`` — виртуальная память (редко) - ``unsigned long size`` Размер области. Если 0 — mapping не используется (нужно обнулять все неиспользуемые элементы `mem[]`) - ``phys_addr_t addr`` Адрес физической памяти. Только для `UIO_MEM_PHYS`. - ``void *internal_addr`` Адрес внутри ядра, например, из `ioremap()`. Хранится отдельно от `addr`, потому что `ioremap()` не может быть mmap-нут в userspace. --- Регистрация UIO-устройства --------------------------- После инициализации `struct uio_info`, модуль должен зарегистрировать устройство: .. code-block:: c ret = uio_register_device(&pdev->dev, &info); Это: - создаёт `/dev/uioX` - создаёт все соответствующие sysfs-файлы в `/sys/class/uio/uioX/` - начинает работу UIO-драйвера --- Удаление UIO ------------ При выгрузке модуля нужно обязательно вызвать: .. code-block:: c uio_unregister_device(&info); Это удалит `/dev/uioX` и все связанные sysfs-файлы. --- Минимальный пример ------------------- .. code-block:: c static struct uio_info my_uio_info = { .name = "my_uio", .version = "1.0", .irq = 42, .irq_flags = IRQF_SHARED, .mem[0] = { .memtype = UIO_MEM_PHYS, .addr = 0x3F200000, .size = 0x1000, }, }; static int my_probe(struct platform_device *pdev) { return uio_register_device(&pdev->dev, &my_uio_info); } --- Полезные определения -------------------- .. code-block:: c #define MAX_UIO_MAPS 5 #define UIO_IRQ_NONE (-1) #define UIO_IRQ_CUSTOM (-2) --- Заключение ----------- **UIO API** позволяет легко интегрировать простые устройства в Linux, используя ядро только как "мост", а всю основную логику реализуя в user space. Это снижает сложность, облегчает отладку и идеально подходит для экспериментов, FPGA, custom boards и embedded-разработки. Если вам не нужна сложная интеграция с подсистемами ядра — **UIO может быть лучшим выбором.**