Как написать драйвер ядра Linux для UART? [закрыто]

Вопрос или проблема

Как написать драйвер ядра Linux для UART?

Через UART я получаю непрерывный и асинхронный поток данных: главная проблема здесь – не упустить ни одной данные.

Я использую serdev (http://events17.linuxfoundation.org/sites/events/files/slides/serdev-elce-2017-2.pdf), чтобы получать входящие данные, реализуя receive_buf в драйвере. Обратите внимание, что я не знаю, как получить номер IRQ, связанный с этим IRQ receive_buf (в противном случае я бы мог использовать потоковый IRQ, как объяснено ниже).

Теперь, в драйвере ядра Linux, я знаю про IRQ и механизмы верхней и нижней половины: коротко говоря, когда срабатывает IRQ, верхняя половина вызванного обращения должна обрабатывать все, что можно обработать быстро (чтобы сделать прерывание возможным снова как можно скорее, чтобы не пропустить входящие данные), и передать остальную работу нижней половине (которая будет вызвана позже).

Для нижней половины, насколько я понимаю, существуют разные возможные механизмы: потоковые IRQ, рабочие очереди, softirq, tasklet. Softirq и tasklet, похоже, являются кандидатами на устаревание в ближайшем будущем https://lwn.net/Articles/960041/, поэтому я оставляю их позади. Рабочие очереди, похоже, позволяют добавлять в очередь только один элемент работы за раз, поскольку функция queue_work из API возвращает false, если работа уже находится в очереди, так что я не совсем уверен, могу ли я использовать эти очереди для накопления 1 элемента работы для каждого куска данных. Наконец, потоковые IRQ, по всей видимости, являются лучшими кандидатами, но для создания потокового IRQ нужен номер IRQ: как уже было объяснено, я не знаю, как получить его из serdev.

Какой “хороший или предпочтительный” способ действовать?

Используя serdev, как я могу инициализировать потоковый IRQ из колбека receive_buf (т.е. как получить IRQ, связанный с этим колбеком)? Насколько я понимаю, это был бы лучший способ, верно?

Есть ли другие варианты?

Существует ли пример, с которого я мог бы начать? (ничего не нашел)

Я работаю на Raspberry Pi с ядром 6.1.x.

Ответ или решение

Как написать драйвер ядра Linux для UART

Написание драйвера для UART (Universal Asynchronous Receiver-Transmitter) в ядре Linux представляет собой важную задачу, особенно когда необходимо гарантировать, что не пропустите ни одного полученного байта данных. В этой статье вы узнаете основные шаги, касающиеся разработки драйвера для UART с использованием инфраструктуры serdev, а также обсудим методы обработки прерываний и рабочие очереди.

Основные компоненты ядра и работа с прерываниями

  1. Понимание архитектуры UART: UART управляет асинхронным вводом-выводом данных и может работать с различными контурами передачи данных. Убедитесь, что вы хорошо понимаете спецификации устройства, которое будет использоваться.

  2. Используйте интерфейс serdev: serdev значительно упрощает написание драйверов для серийных устройств. Он инкапсулирует работу с UART, позволяя сосредоточиться на обработке данных. Основной методом для обработки входящих данных будет receive_buf, который будет вызываться при поступлении новых данных.

  3. Инициализация и управление прерываниями: Прерывания играют ключевую роль в системе обработки данных. Когда вы используете serdev, вам не нужно напрямую получать IRQ номер. Вместо этого следует следовать стандартному протоколу, позволяющему serdev обрабатывать привязку прерываний и соответствующие вызовы.

Обработка входящих данных

При написании receive_buf:

  • Соблюдайте высокую производительность. Ваша задача здесь – быстро считывать данные в буфер и разбудить поток для более детальной обработки.
  • Если вы используете асинхронный поток, постарайтесь минимизировать время блокировки IRQ. Используйте меньше работы в обработчике прерываний.

Методики управления очередью

Для обработки задач, не требующих немедленного исполнения, рассмотрите различные подходы:

  1. Threaded IRQ: Используйте встроенные функции для создания потокового прерывания. Хотя вам и не нужно явно получать IRQ для serdev, вы можете использовать функцию devm_request_irq в рамках serdev, чтобы настроить обработчик прерываний как поток.

  2. Рабочие очереди (workqueues): Это хороший вариант для обработки большего объёма данных с задержкой. В отличие от threaded IRQ, workqueue позволяет обрабатывать несколько задач последовательно.

Пример простого драйвера для UART

Вот упрощенный пример, который демонстрирует как можно реализовать драйвер, используя serdev:

#include <linux/module.h>
#include <linux/serdev.h>
#include <linux/string.h>

struct my_uart_data {
    struct serdev_device *serdev;
};

static int my_uart_receive_buf(struct serdev_device *serdev, const void *buf, size_t len) {
    // Обработка полученных данных
    printk(KERN_INFO "Received %zu bytes\n", len);
    return len; // Возвращаем количество обработанных байт
}

static const struct serdev_device_ops my_uart_ops = {
    .receive_buf = my_uart_receive_buf,
};

static int my_uart_probe(struct serdev_device *serdev) {
    struct my_uart_data *data;

    data = devm_kzalloc(&serdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->serdev = serdev;
    serdev->dev.driver_data = data; // Сохраняем данные драйвера

    serdev_set_drvdata(serdev, data);
    serdev_device_register(serdev);
    return 0;
}

static int my_uart_remove(struct serdev_device *serdev) {
    // Освобождение ресурсов
    return 0;
}

static struct serdev_driver my_uart_driver = {
    .driver = {
        .name = "my_uart_driver",
    },
    .probe = my_uart_probe,
    .remove = my_uart_remove,
    .ops = &my_uart_ops,
};

module_serdev_driver(my_uart_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ваше имя");
MODULE_DESCRIPTION("Драйвер UART на основе serdev");

Заключение

Создание драйвера для UART в ядре Linux — задача, требующая тщательной проработки. Использование serdev для абстрагирования и управления прерываниями значительно упростит процесс. Следуя рекомендованным подходам и примерному коду, вы сможете разработать надежное решение для обработки асинхронно получаемых данных.

Дополнительно рекомендуем обратиться к документации по serdev и изучить существующие драйвера, чтобы повысить свои знания в этой области.

Оцените материал
Добавить комментарий

Капча загружается...