символьное устройство arm-linux с операцией ввода-вывода дерева устройств

Содержимое дерева устройств выглядит следующим образом

 

Помимо необходимости /* функция работы устройства */

Также нужно /* структура устройства */

например:

структура dtsled_dev{

    dev_t devid; /* номер устройства */

    структура cdev cdev; /* cdev */

    класс структуры *класс; /* код */

    struct device *device; /* устройство */

    int major; /* старший номер устройства */

    int minor; /* младший номер устройства */

    struct device_node *nd;/* узел устройства */

};

Функцию регистрации инициализации также необходимо изменить

Функция инициализации должна использовать функцию of_find_node_by_path для поиска узла дерева устройств:

    /* 1. Получить узел устройства: alphaled */

    dtsled.nd = of_find_node_by_path("/alphaled");

Функция инициализации должна использовать функцию of_find_property, чтобы найти свойство совместимости дерева устройств.

    /* 2. Получить содержимое совместимого свойства */

    правильное = of_find_property (dtsled.nd, "совместимый", NULL);

/* 3. Получить содержимое атрибута статуса */

    ret = of_property_read_string(dtsled.nd, "status", &str);

Очень важно получить содержимое реестра! ! !

/* 4. Получить содержимое атрибута reg */

    ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);

Необходимо настроить сопоставление ввода-вывода

IMX6U_CCM_CCGR1 = of_iomap (dtsled.nd, 0);

    SW_MUX_GPIO1_IO03 = of_iomap (dtsled.nd, 1);

    SW_PAD_GPIO1_IO03 = of_iomap (dtsled.nd, 2);

    GPIO1_DR = of_iomap(dtsled.nd, 3);

    GPIO1_GDIR = of_iomap(dtsled.nd, 4);

of_iomap
void __iomem *of_iomap (struct device_node *node, int index);

ioremap() диапазона памяти устройства выполняется непосредственно через узел устройства дерева устройств, а index — это индекс сегмента памяти. Если атрибут reg узла устройства имеет несколько разделов, вы можете использовать индекс, чтобы указать, какой раздел вы хотите переназначить.Если есть только один раздел, индекс равен 0.

После использования дерева устройств большое количество драйверов устройств сопоставляется с помощью of_iomap() вместо традиционных

ссылок ioremap: https://blog.csdn.net/alimingh/article/details/111666429.

Используйте MKDEV, чтобы получить основной и дополнительный номера устройств в зарегистрированном драйвере.

Версия: линукс-2.6.24.4

макрос:

MKDEV(MAJOR, MINOR);  

Описание: Получить позицию устройства в таблице устройств.

MAJOR старший номер устройства

MINOR младший номер устройства

   

Файл описания номера версии, используемый ядром:

    Инструкции находятся в файле devices.txt в каталоге kernel/Documentation.

    обычно зарезервировано на месте

        ГЛАВНЫЙ

234-239 НЕ НАЗНАЧЕН

240–254 символа МЕСТНОЕ/ЭКСПЕРИМЕНТАЛЬНОЕ ИСПОЛЬЗОВАНИЕ

Блок 240-254 МЕСТНОЕ/ЭКСПЕРИМЕНТАЛЬНОЕ ИСПОЛЬЗОВАНИЕ  

        НЕЗНАЧИТЕЛЬНЫЙ

от 1 до 250 (0 младшего номера устройства использовать нельзя)

     

Создание файла статического устройства:

    mknod /dev/gpio_led c 240 

Зарегистрируйтесь с помощью функции register_chrdev_region

Функция register_chrdev_region() используется для выделения указанного диапазона номеров устройств. Если запрошенный диапазон номеров устройств охватывает основной номер устройства, он разделит номера в выделенном диапазоне на меньшие поддиапазоны по основному номеру устройства и вызовет __register_chrdev_region() для каждого поддиапазона. Если одно из выделений не удается, будут возвращены все предыдущие успешные распределения.

После версии 2.4 в ядро ​​были добавлены следующие функции для регистрации символьных устройств:

Он разделен на статическую регистрацию (регистрация с указанием номера устройства), динамическое распределение (регистрация без указания номера устройства) и диапазон вторичных номеров устройств с непрерывной регистрацией, что позволяет избежать потери ресурсов в register_chrdev().   

2.1: 

/*Укажите номер устройства для статической регистрации символьного устройства*/
int register_chrdev_region(dev_t from, unsigned count, const char *name);   

from:  Зарегистрированный указанный начальный номер устройства, например: MKDEV(100, 0), означает, что начальный основной номер устройства равен 100, а начальный дополнительный номер устройства равен 0.

count: количество номеров вторичных устройств, которые необходимо зарегистрировать последовательно, например: начальный номер вторичных устройств равен 0, count=100, что означает, что номера вторичных устройств от 0 до 99 должны быть привязаны к одному и тому же методу операции file_operations. состав

*name: имя символьного устройства

Когда возвращаемое значение меньше 0, это означает, что регистрация не удалась.

2.2:

/* Динамически выделить символьное устройство, успешно зарегистрировать и поместить назначенные первичный и вторичный номера устройств в *dev*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);

*dev:  указатель для хранения начального номера устройства.При успешной регистрации *dev будет равен присвоенному начальному номеру устройства.Старший и младший номера устройств можно извлечь с помощью функций MAJOR() и MINNOR()

baseminor: базовый адрес младшего номера устройства, то есть начальный дополнительный номер устройства

count: количество вторичных номеров устройств, которые необходимо зарегистрировать последовательно, например: начальный вторичный номер устройства (основной минор) равен 0, базовый минор = 2, что означает, что номера устройств от 0 до 1 должны быть привязаны к одному и тому же файлу_операций. структура метода работы

*name: имя символьного устройства

Когда возвращаемое значение меньше 0, это означает, что регистрация не удалась.

например:

    /* Зарегистрировать драйвер символьного устройства */

    /* 1. Создать номер устройства*/

    if (dtsled.major) { /* определяет номер устройства */

        dtsled.devid = MKDEV(dtsled.major, 0);

        register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);

    } else { /* номер устройства не определен */

        alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME); /* Подать заявку на номер устройства*/

        dtsled.major = MAJOR(dtsled.devid);/* Получить старший номер устройства для назначенного номера*/

        dtsled.minor = MINOR(dtsled.devid);/* Получить младший номер устройства для назначенного номера*/

    }

    /* 2. Инициализировать cdev */

Функция cdev_init() используется для инициализации статически размещенной структурной переменной cdev.Функция cdev_init автоматически инициализирует объект cdev->ops, присвоит объекту второй входной параметр функции cdev->opsи не будет инициализировать cdev->ownerобъект.Поэтому после функции cdev_alloc () и функция cdev_init() После обработки структурной переменной cdev ей нужно только присвоить значение объекту в прикладной программе cdev->owner, и эту структурную переменную можно вставить в систему ядра Linux и использовать как доступное символьное устройство .

    dtsled.cdev.owner = ЭТОТ_МОДУЛЬ;

    cdev_init(&dtsled.cdev, &dtsled_fops);

#include <linux/cdev.h>

После инициализации cdev  его необходимо добавить в систему. Для этого можно вызвать функцию cdev_add(). Передайте указатель на структуру cdev, начальный номер устройства и диапазон номеров устройств.

Сначала функция сохраняет выделенный номер устройства и номер устройства в структуру cdev. Затем структура cdev записывается в переменную cdev_map структуры kobj_map.

/* 3. Добавляем cdev */

    cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

    /* 4. Создать класс*/

    dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);

    если (IS_ERR(dtsled.class)) {

        вернуть PTR_ERR (dtsled.class);

    }

    /* 5. Создать устройство*/

    dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);

    если (IS_ERR(dtsled.device)) {

        вернуть PTR_ERR (dtsled.device);

    }

отменить регистрацию драйвера устройства

/*

 * @description : Функция экспорта драйвера

 * @параметр: нет

 * @возврат : нет

 */

статическая пустота __exit led_exit (пустота)

{

    /* отменить сопоставление */

    iounmap (IMX6U_CCM_CCGR1);

    iounmap (SW_MUX_GPIO1_IO03);

    iounmap (SW_PAD_GPIO1_IO03);

    iounmap (GPIO1_DR);

    iounmap (GPIO1_GDIR);

    /* Отменить регистрацию драйвера символьного устройства */

    cdev_del(&dtsled.cdev);/* удалить cdev */

    unregister_chrdev_region(dtsled.devid, DTSLED_CNT);/* Отменить регистрацию номера устройства*/

    device_destroy(dtsled.class, dtsled.devid);

    class_destroy(dtsled.class);

}

Supongo que te gusta

Origin blog.csdn.net/L1153413073/article/details/125486527
Recomendado
Clasificación