périphérique de caractères arm-linux avec opération io d'arborescence de périphériques

Le contenu de l'arborescence des appareils est le suivant

 

En plus du besoin /* fonction de fonctionnement de l'appareil */

Besoin également de /* structure de l'appareil */

par exemple:

structure dtsled_dev{

    dev_t devid; /* numéro de périphérique */

    structure cdev cdev; /* cdev */

    classe de structure * classe ; /* 类 */

    struct appareil *appareil; /* appareil */

    int majeur ; /* numéro de périphérique principal */

    int mineur ; /* numéro de périphérique mineur */

    struct device_node *nd ; /* nœud de périphérique */

} ;

La fonction d'enregistrement d'initialisation doit également être modifiée

La fonction d'initialisation doit utiliser la fonction of_find_node_by_path pour trouver le nœud de l'arborescence des périphériques :

    /* 1. Récupère le nœud du périphérique : alphaled */

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

La fonction d'initialisation doit utiliser la fonction of_find_property pour trouver la propriété de compatibilité de l'arborescence des périphériques

    /* 2. Obtenir le contenu de la propriété compatible */

    propre = of_find_property(dtsled.nd, "compatible", NULL);

/* 3. Obtenir le contenu de l'attribut d'état */

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

Il est très important d'obtenir le contenu du registre ! ! !

/* 4. Obtenir le contenu de l'attribut reg */

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

Besoin de configurer le mappage IO

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);

Le ioremap() de la plage de mémoire du périphérique est directement exécuté via le nœud de périphérique de l'arborescence des périphériques, et index est l'index du segment de mémoire. Si l'attribut reg du nœud de périphérique comporte plusieurs sections, vous pouvez utiliser l'index pour indiquer quelle section vous souhaitez ioremap. S'il n'y a qu'une seule section, l'index est 0.

Après avoir utilisé Device Tree, un grand nombre de pilotes de périphériques sont mappés via of_iomap() au lieu des

références ioremap traditionnelles : https://blog.csdn.net/alimingh/article/details/111666429

Utilisez MKDEV pour obtenir les numéros de périphérique majeur et mineur dans le pilote enregistré

Version : linux-2.6.24.4

macro :

MKDEV(MAJEUR, MINEUR);  

Description : obtenir la position de l'appareil dans la table des appareils.

MAJOR numéro d'appareil majeur

MINEUR numéro d'appareil mineur

   

Le fichier de description du numéro de version utilisé par le noyau :

    Les instructions se trouvent dans devices.txt dans le répertoire kernel/Documentation.

    généralement réservé localement

        MAJEUR

234-239 NON ASSIGNÉ

240-254 car UTILISATION LOCALE/EXPÉRIMENTALE

Bloc 240-254 USAGE LOCAL/EXPERIMENTAL  

        MINEURE

1 à 250 (0 du numéro de périphérique mineur ne peut pas être utilisé)

     

Création de fichier de périphérique statique :

    mknod /dev/gpio_led c 240 

Enregistrez-vous avec la fonction register_chrdev_region

La fonction register_chrdev_region() est utilisée pour allouer la plage de numéros de périphérique spécifiée. Si la plage de numéros de périphérique demandée couvre le numéro de périphérique principal, elle divisera les numéros de la plage allouée en sous-plages plus petites par numéro de périphérique principal et appellera __register_chrdev_region() sur chaque sous-plage. Si l'une des allocations échoue, toutes les allocations précédentes réussies seront renvoyées.

Après la version 2.4, les fonctions suivantes ont été ajoutées au noyau pour enregistrer également les périphériques de caractères :

Il est divisé en enregistrement statique (enregistrement en spécifiant le numéro de périphérique), allocation dynamique (enregistrement sans spécifier le numéro de périphérique) et la plage de numéros de périphériques secondaires avec enregistrement continu, ce qui évite l'inconvénient de gaspiller des ressources dans register_chrdev()   

2.1 : 

/*Spécifiez le numéro de périphérique pour enregistrer statiquement un périphérique de caractères*/ 
int register_chrdev_region(dev_t from, unsigned count, const char *name);   

de :  numéro de périphérique de démarrage spécifié enregistré, par exemple : MKDEV(100, 0), signifie que le numéro de périphérique majeur de démarrage est 100 et que le numéro de périphérique mineur de démarrage est 0

count : le nombre de numéros de périphériques secondaires qui doivent être enregistrés consécutivement, par exemple : le numéro de périphérique secondaire initial est 0, count=100, ce qui signifie que les numéros de périphériques secondaires de 0 à 99 doivent être liés à la même méthode d'opération file_operations structure

*name : nom de l'appareil de caractère

Lorsque la valeur de retour est inférieure à 0, cela signifie que l'enregistrement a échoué

2.2 :

/* Alloue dynamiquement un périphérique de caractères, s'enregistre avec succès et place les numéros de périphériques primaires et secondaires alloués dans *dev*/ 
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

*dev :  un pointeur pour stocker le numéro de périphérique initial. Lorsque l'enregistrement est réussi, *dev sera égal au numéro de périphérique initial attribué. Les numéros de périphérique majeur et mineur peuvent être extraits via les fonctions MAJOR() et MINNOR()

baseminor : l'adresse de base du numéro de périphérique mineur, c'est-à-dire le numéro de périphérique mineur de départ

count : le nombre de numéros de périphériques secondaires qui doivent être enregistrés consécutivement, par exemple : le numéro de périphérique secondaire initial (baseminor) est 0, baseminor=2, ce qui signifie que les numéros de périphérique de 0 à 1 doivent être liés au même file_operations structure de la méthode de fonctionnement

*name : nom de l'appareil de caractère

Lorsque la valeur de retour est inférieure à 0, cela signifie que l'enregistrement a échoué

par exemple:

    /* Enregistrer le pilote de périphérique de caractères */

    /* 1. Créer un numéro de périphérique*/

    if (dtsled.major) { /* définit le numéro de périphérique */

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

        register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);

    } else { /* le numéro de périphérique n'est pas défini */

        alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME); /* Demander le numéro d'appareil*/

        dtsled.major = MAJOR(dtsled.devid); /* Récupère le numéro d'appareil principal du numéro attribué*/

        dtsled.minor = MINOR(dtsled.devid); /* Récupère le numéro de périphérique mineur du numéro attribué*/

    }

    /* 2. Initialiser cdev */

La fonction cdev_init() est utilisée pour initialiser une variable de structure cdev allouée statiquement. La fonction cdev_init initialisera automatiquement l' cdev->opsobjet, affectera le deuxième paramètre d'entrée de la fonction à cdev->opsl'objet et n'initialisera pas cdev->ownerl'objet. Par conséquent, après la fonction cdev_alloc () et la fonction cdev_init () Une fois la variable de structure cdev traitée, il suffit d'attribuer une valeur à l'objet dans le programme d'application cdev->owner, et cette variable de structure peut être insérée dans le système du noyau Linux et utilisée comme périphérique de caractère disponible .

    dtsled.cdev.owner = CE_MODULE ;

    cdev_init(&dtsled.cdev, &dtsled_fops);

#include <linux/cdev.h>

Après avoir initialisé cdev  , il doit être ajouté au système. Pour ce faire, la fonction cdev_add() peut être appelée. Transmettez le pointeur vers la structure cdev, le numéro de périphérique de départ et la plage de numéros de périphériques.

La fonction enregistre d'abord le numéro d'appareil attribué et le numéro d'appareil dans la structure cdev. Ensuite, la structure cdev est enregistrée dans la variable cdev_map d'une structure kobj_map.

/* 3. Ajouter un cdev */

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

    /* 4. Créer une classe*/

    dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);

    si (IS_ERR(dtsled.class)) {

        return PTR_ERR(dtsled.class);

    }

    /* 5. Créer un appareil*/

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

    si (IS_ERR(dtsled.device)) {

        retourner PTR_ERR(dtsled.device);

    }

désenregistrer le pilote de périphérique

/*

 * @description : Fonction d'exportation du pilote

 * @param : Aucun

 * @return : aucun

 */

vide statique __exit led_exit(void)

{

    /* démapper */

    iounmap(IMX6U_CCM_CCGR1);

    iounmap(SW_MUX_GPIO1_IO03);

    iounmap(SW_PAD_GPIO1_IO03);

    iounmap(GPIO1_DR);

    iounmap(GPIO1_GDIR);

    /* Désenregistrer le pilote de périphérique caractère */

    cdev_del(&dtsled.cdev);/* supprimer cdev */

    unregister_chrdev_region(dtsled.devid, DTSLED_CNT); /* Désenregistrer le numéro de périphérique*/

    device_destroy(dtsled.class, dtsled.devid);

    class_destroy(dtsled.class);

}

Je suppose que tu aimes

Origine blog.csdn.net/L1153413073/article/details/125486527
conseillé
Classement