Maison >Tutoriel système >Linux >Linux Intermédiaire - 'Pilote' Connaissances de bas niveau qui doivent être apprises pour contrôler le matériel

Linux Intermédiaire - 'Pilote' Connaissances de bas niveau qui doivent être apprises pour contrôler le matériel

WBOY
WBOYavant
2024-02-12 15:21:131303parcourir
Linux中级——“驱动” 控制硬件必须学会的底层知识

Augmenter la notoriété

1. Qu'est-ce qu'un chauffeur

Le pilote encapsule les opérations du périphérique matériel sous-jacent et fournit des interfaces de fonction à la couche supérieure.

Classification des appareils : Le système Linux divise les appareils en 3 catégories : Appareils de caractère, appareils de blocage et appareils réseau.

  • Appareil de caractère : fait référence à un appareil qui ne peut lire et écrire qu'octet par octet. Il ne peut pas lire de manière aléatoire certaines données dans la mémoire de l'appareil. Les données doivent être lues dans l'ordre. Les périphériques de caractères sont des périphériques orientés flux. Les périphériques de caractères courants incluent les souris, les claviers, les ports série, les consoles et les périphériques LED Les pilotes de périphériques de caractères implémentent généralement au moins les appels système d'ouverture, de fermeture, de lecture et d'écriture, Terminal de caractères. (/dev/console) et le port série (/dev/ttyS0 et périphériques similaires) sont deux périphériques de caractères, qui peuvent bien illustrer le concept abstrait de « flux ».
  • Bloquer l'appareil : fait référence à un appareil capable de lire des données d'une certaine longueur à partir de n'importe quel emplacement de l'appareil. Les périphériques bloqués incluent les disques durs, les disques, les clés USB, les cartes SD, etc.
  • Périphérique réseau : Un périphérique réseau peut être un périphérique matériel, tel qu'une carte réseau ; mais il peut également s'agir d'un périphérique logiciel pur, tel qu'une interface de bouclage (lo). Une interface réseau est responsable de l'envoi et de la réception de paquets de données. . Linux中级——“驱动” 控制硬件必须学会的底层知识

Donnons un exemple pour expliquer le processus global d'appel

  1. Dans la couche supérieure, nous appelons la fonction open du langage C open("/dev/pin4",O_RDWR); et appelons pin4 sous /dev pour l'ouvrir de manière lisible et inscriptible. **== Lorsque la couche supérieure open est appelée au noyau, une interruption logicielle se produit. Le numéro d'interruption est 0X80, qui est saisi depuis l'espace utilisateur ==**
  2. .
  3. open appellera system_call (fonction du noyau) et system_call trouvera le numéro de périphérique souhaité en fonction du nom de périphérique /dev/pin4.
  4. Ensuite, ajustez le fichier virtuel VFS (Afin d'unifier le matériel exact pour l'appel de couche supérieure ), appelez sys_open dans VFS, sys_open se trouvera dans la liste des pilotes, et trouvez le pilote basé sur le numéro d'appareil majeur et numéro d'appareil mineur La fonction d'ouverture dans la broche 4, Notre ouverture dans la broche 4 consiste à faire fonctionner le registre

Insérer la description de l'image ici

«

Lorsque nous écrivons un pilote, nous faisons simplement Ajouter un pilote : À quoi sert l'ajout d'un pilote ?

  1. Nom de l'appareil
  2. Numéro d'appareil
  3. Fonction de pilote de périphérique (registre d'exploitation pour piloter le port IO)

==En résumé==Si vous souhaitez ouvrir dev ci-dessouspin4 pin, le processus est : dev下面的pin4引脚,过程是:用户态调用open“/de/pin4”,O_RDWR),对于内核来说,上层调用open函数会触发一个软中断(系统调用专用,中断号是0x80,0x80代表发生了一个系统调用),系统进入内核态,并走到system_call,可以认为这个就是此软中断的中断服务程序入口,然后通过传递过来的系统调用号来决定调用相应的系统调用服务程序(在这里是调用VFS中的sys_open)。sys_open会在内核的驱动链表里面根据设备名和设备号查找到相关的驱动函数每一个驱动函数是一个节点Appel en mode utilisateur ouvert

("/de/pin4",O_RDWR), pour le noyau Pour Par exemple, appeler la fonction open depuis la couche supérieure déclenchera une interruption logicielle (spécial pour les appels système, le numéro d'interruption est 0x80, 0x80 signifie qu'un appel système a eu lieu),

le système entre dans l'état du noyau et passe à system_call, vous pouvez considérer cela comme ceci L'entrée dans le programme de service d'interruption de l'interruption logicielle, puis détermine d'appeler le programme de service d'appel système correspondant via le numéro d'appel système transmis (ici, il est appelé<code style="font-size : 14px;remplissage : 2px 4px en VFS ;border-radius : 4px;margin : 0 2px;font-family : Operator Mono, Consolas, Monaco, Menlo, monospace;color: #10f5d6c">sys_open ). sys_open trouvera la fonction de pilote appropriée dans la liste des pilotes du noyau en fonction du nom du périphérique et du numéro de périphérique (<code style="font-size: 14px;padding: 2px 4px; border-radius: 4px; margin: 0 2px ; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;color: #10f5d6c">Chaque fonction du pilote est un nœud), **==La fonction du pilote contient du code pour contrôler le port IO via des registres, puis peut contrôler le port IO pour implémenter les fonctions associées ==**.

2. Explication détaillée de chaque composant

«

Profil utilisateur :

  • Il fait référence au niveau auquel les utilisateurs écrivent et exécutent des programmes. Le mode utilisateur nécessite la base du C et de la bibliothèque C pendant le développement. La bibliothèque C parle de fichiers, de processus, de communication inter-processus, de threads, de réseaux et d'interfaces (. GTk)open,read,write,fork,pthread,socket. Bibliothèque C (doit être incluse dans la bibliothèque standard Linux) : Il s'agit de Clibary, qui fournit une interface permettant au programme de contrôler le travail du noyau. L'appel est encapsulé et implémenté ici, et est appelé par l'application écrite. .
  • Diverses API dans la bibliothèque C Ce qu'on appelle est l'état du noyau, qui contrôle le fonctionnement du noyau
.

«

État du noyau :

🎜”🎜🎜
  • Lorsque les utilisateurs souhaitent utiliser un certain périphérique matériel, ils ont besoin d'un pilote de périphérique en mode noyau,puis de faire fonctionner le matériel, comme mentionné dans l'article précédentwiringPi库, fournit une interface permettant aux utilisateurs de contrôler les périphériques matériels, s'il n'y a pas de bibliothèque câblagePi, vous devez implémenter vous-même les fonctions de la bibliothèque câblagePi, c'est-à-dire écrire vous-même le pilote de périphérique. De cette façon, lorsque nous obtenons un autre type de carte, nous pouvons également terminer le développement.

  • Tout sous Linux est un fichier. Tous les types de fichiers et d'appareils (tels que la souris, le clavier, l'écran, la mémoire flash, la mémoire, la carte réseau, comme le montre la figure ci-dessous) sont tous des fichiers, doncpuisqu'il s'agit de fichiers, vous pouvez utiliser les fonctions d'exploitation de fichiers pour faire fonctionner ces appareils . Linux中级——“驱动” 控制硬件必须学会的底层知识

  • J'ai une question : comment les fonctions d'exploitation de fichiers telles que l'ouverture et la lecture savent-elles à quel périphérique matériel se trouve le fichier ouvert ? ①Entrez le nom du fichier correspondant dans la fonction ouvrir pour contrôler l'appareil correspondant. ②Pass ==numéro d'appareil (numéro d'appareil majeur et numéro d'appareil mineur)==. De plus, nous devons également comprendre l'emplacement de ces pilotes et comment les implémenter Chaque périphérique matériel correspond à un pilote différent (ces pilotes sont implémentés par nous-mêmes).

  • La gestion des appareils Linux est étroitement intégrée au système de fichiers Divers appareils sont stockés dans le répertoire /dev sous forme de fichiers, appelés ==device files==*. Les applications peuvent ouvrir, fermer, lire et écrire ces fichiers de périphérique, et effectuer des opérations sur le périphérique, tout comme si vous utilisiez des fichiers de données ordinaires. **Afin de gérer ces appareils, le système numérote les appareils**,*Chaque numéro d'appareil est divisé en ==numéro d'appareil majeur== et ==numéro d'appareil mineur==* (comme indiqué dans la figure ci-dessous : ). **Linux中级——“驱动” 控制硬件必须学会的底层知识***Le numéro d'appareil principal** est utilisé pour distinguer différents types d'appareils, tandis que le **numéro d'appareil mineur est utilisé pour distinguer plusieurs appareils du même type. Pour les appareils couramment utilisés, Linux a des numéros conventionnels. Par exemple, le numéro de périphérique principal d'un disque dur est 3. ****Un périphérique de caractère ou un périphérique de bloc a un numéro de périphérique majeur et un numéro de périphérique mineur. ==Le numéro d'appareil majeur et le numéro d'appareil mineur sont collectivement appelés numéro d'appareil==**.

    «

    Le numéro principal de l'appareil est utilisé pour représenter un pilote spécifique.
    Le numéro de périphérique mineur est utilisé pour représenter chaque périphérique utilisant ce pilote.

    Par exemple, un système intégré dispose de deux indicateurs LED et les lumières LED doivent être allumées ou éteintes indépendamment. Ensuite, vous pouvez écrire un pilote de périphérique de caractère pour une lumière LED et enregistrer son numéro de périphérique majeur en tant que périphérique n° 5, et ses numéros de périphérique mineurs en tant que 1 et 2 respectivement. Ici, les numéros de périphérique secondaire représentent respectivement deux voyants LED.

==Liste liée des pilotes==

«

Gérez les pilotes pour tous les appareils, ajoutez ou recherchez
L'ajout添加是发生在我们编写完驱动程序,加载到内核
查找 se produit une fois que nous avons fini d'écrire le pilote et de l'avoir chargé dans le noyau. Rechercher

appelle le pilote et l'espace utilisateur de la couche application utilise la fonction open pour le trouver

. L'ordre dans lequel le pilote est inséré dans la liste chaînée est récupéré par le numéro d'appareil, c'est-à-dire que le numéro d'appareil majeur et le numéro d'appareil mineur peuvent non seulement distinguer différents types d'appareils et différents types d'appareils , mais aussi charger le pilote à une certaine position dans la liste chaînée , le développement du code du pilote présenté ci-dessous n'est rien de plus que ajouter le pilote (ajouter le numéro de périphérique, le nom de l'appareil et la fonction du pilote de périphérique) et

appeler. le chauffeur

.

  • Comment la fonction system_call trouve-t-elle la routine détaillée du service d'appel système ? Trouvez la table d'appels système sys_call_table par le numéro d'appel système ! Lorsque l'instruction d'interruption logicielle INT 0x80 est en cours d'exécution, le numéro d'appel système sera placé dans le registre eax
  • La fonction system_call peut lire le registre eax pour l'obtenir, puis le multiplier par 4 pour générer une adresse de décalage, puis. utilisez sys_call_table comme adresse de base. En ajoutant l'adresse de base à l'adresse de décalage, vous pouvez obtenir l'adresse de la routine détaillée du service d'appel système ! Ensuite, il s’agit de la routine de service d’appel système.

Ajouté :
  1. Chaque appel système correspond à un numéro d'appel système, et le numéro d'appel système correspond à la fonction de traitement correspondante dans le noyau.
  2. Tous les appels système sont déclenchés via l'interruption 0x80.
  3. Lors de l'utilisation d'un appel système, le numéro d'appel système est transmis au noyau via le registre eax, et les paramètres d'entrée de l'appel système sont transmis au noyau via ebx, ecx... à son tour
  4. Comme les fonctions, la valeur de retour de l'appel système est stockée dans eax, et tout doit être retiré de eax

3. Principe de fonctionnement du pilote de périphérique de caractère

Principe de fonctionnement du pilote de périphérique de caractère Dans le monde Linux, tout est un fichier et toutes les opérations sur les périphériques matériels seront résumées en opérations sur les fichiers au niveau de la couche application. On sait que si la couche application veut accéder à un périphérique matériel, elle doit appeler le pilote correspondant au matériel. Il y a tellement de pilotes dans le noyau Linux. Comment une application peut-elle appeler avec précision le pilote sous-jacent ?

==Connaissances incontournables :==🎜🎜
  1. Dans le système de fichiers Linux, chaque fichier est décrit par une struct inode structure Cette structure enregistre toutes les informations du fichier, telles que le type de fichier, les droits d'accès, etc.
  2. Dans le système d'exploitation Linux, chaque pilote aura un fichier correspondant dans le répertoire /dev目录或者其他如/sys de la couche application.
  3. Dans le système d'exploitation Linux, chaque pilote possède un numéro de périphérique.
  4. Dans le système d'exploitation Linux, chaque fois qu'un fichier est ouvert, le système d'exploitation Linux allouera une ****struct filestructure au niveau de la couche VFS pour décrire le fichier ouvert.
Linux中级——“驱动” 控制硬件必须学会的底层知识

(1) Lorsque la fonction open ouvre un fichier de périphérique, vous pouvez connaître le type de périphérique à utiliser ensuite (périphérique de caractère ou périphérique de bloc) en fonction des informations décrites par la structure struct inode correspondant au fichier de périphérique, et une structure sera également allouée.

(2) Selon le numéro de périphérique enregistré dans la structure struct inode, le pilote correspondant peut être trouvé. Ici, nous prenons comme exemple les dispositifs de caractères. Dans le système d'exploitation Linux, chaque périphérique de caractères possède une structure struct cdev. Cette structure décrit toutes les informations du dispositif de caractère, dont la plus importante est l'interface de fonction d'exploitation du dispositif de caractère.

(3) Après avoir trouvé la structure struct cdev, le noyau Linux enregistrera la première adresse de l'espace mémoire où se trouve la structure struct cdev dans le membre i_cdev de la structure struct inode, et enregistrera l'adresse de l'interface d'opération de fonction enregistrée dans le Structure struct cdev. Dans le membre f_ops de la structure de fichier struct.

(4) Une fois la tâche terminée, la couche VFS renverra un descripteur de fichier (fd) à l'application. Ce fd correspond à la structure du fichier struct. Ensuite, l'application de couche supérieure peut trouver le fichier struct via fd, puis trouver l'interface de fonction file_operation pour faire fonctionner les périphériques de caractères dans le fichier struct.

Parmi eux, cdev_init et cdev_add ont été appelés dans la fonction d'entrée du pilote, complétant respectivement la liaison du périphérique de caractère et de l'interface d'opération de la fonction file_operation, et enregistrant le pilote de caractère dans le noyau.

Écrivez le code du pilote basé sur le framework :

  • Code d'appel de couche supérieure : Code de couche supérieure piloté par les opérations (pin4test.c) :
#include 
#include 
#include 
#include 

void main()
{
        int fd,data;
        fd = open("/dev/pin4",O_RDWR);
        if(fdprintf("open fail\n");
                perror("reson:");
        }
        else{
                printf("open successful\n");
        }
        fd=write(fd,'1',1);
}

-Pilote du noyau **==Le cadre de pilote de périphérique de caractères le plus simple==** :

Code du cadre du pilote de périphérique de caractère

#include    //file_operations声明
#include     //module_init  module_exit声明
#include       //__init  __exit 宏定义声明
#include   //class  devise声明
#include    //copy_from_user 的头文件
#include      //设备号  dev_t 类型声明
#include           //ioremap iounmap的头文件

static struct class *pin4_class;  
static struct device *pin4_class_dev;

static dev_t devno;                //设备号,devno是用来接收创建设备号函数的返回值,销毁的时候需要传这个参数
static int major =231;       //主设备号
static int minor =0;      //次设备号
static char *module_name="pin4";   //模块名

//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
    printk("pin4_open\n");  //内核的打印函数和printf类似   
    return 0;
}

//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
 
 printk("pin4_write\n");  //内核的打印函数和printf类似
    return 0;
}
//将上面的函数赋值给一个结构体中,方便下面加载到到驱动链表中去
static struct file_operations pin4_fops = {
//static防止其他文件也有同名pin4_fops
//static限定这个结构体的作用,仅仅只在这个文件。
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
};
/*
上面的代码等同于以下代码(但是在单片机keil的编译环境里面不允许以上写法):
里面的每个pin4_fops结构体成员单独赋值
static struct file_operations pin4_fops;  
    pin4_fops.owner = THIS_MODULE;
    pin4_fops.open  = pin4_open;
    pin4_fops.write = pin4_write;
*/
//static限定这个结构体的作用,仅仅只在这个文件。


int __init pin4_drv_init(void)   //真实的驱动入口
{

    int ret;
    devno = MKDEV(major,minor);  //2. 创建设备号
    ret   = register_chrdev(major, module_name,&pin4_fops);  
    //3. 注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中

    pin4_class=class_create(THIS_MODULE,"myfirstdemo");//由代码在dev下自动生成设备,创建一个类
    pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name); 
     //创建设备文件,先有上面那一行代码,创建一个类然后这行代码,类下面再创建一个设备。

 
    return 0;
}

void __exit pin4_drv_exit(void)
{

    device_destroy(pin4_class,devno);//先销毁设备
    class_destroy(pin4_class);//再销毁类
    unregister_chrdev(major, module_name);  //卸载驱动

}

module_init(pin4_drv_init);  //入口,内核加载驱动的时候,这个宏(不是函数)会被调用,去调用pin4_drv_init这个函数
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

Créer manuellement le nom de l'appareil

  • Le code du pilote de périphérique de caractères ci-dessus contient ce qui permet au code de générer automatiquement le périphérique sous devDe plus, nous pouvons également créer manuellement le nom du périphérique. Instructions : sudo mknod +设备名字 +设备类型(c表示字符设备驱动) +主设备号+次设备号 b : créer un fichier spécial bloc (bufferisé). c, u : crée un fichier spécial de caractères (sans tampon). p : créez un FIFO, Pour supprimer le nom de l'appareil créé manuellement, il suffit de rm. Comme le montre l'image ci-dessous :

Processus d'exécution du framework de pilotes :

  • Ouvrez un périphérique via le programme de couche supérieure. S'il n'y a pas de pilote, une erreur sera signalée lors de l'exécution. Dans le pilote du noyau, le système de couche supérieure appelle open,wirte函数会触发sys_call、sys_call会调用sys_open,sys_write, sys_open et sys_write transmettent le numéro majeur de périphérique. et placez le périphérique dans la liste des pilotes du noyau Recherchez le pilote et exécutez l'ouverture et l'écriture à l'intérieur Pour que l'ensemble du processus se déroule sans problème, nous devons d'abord préparer le pilote (fichier du pilote de périphérique).

  • Les fichiers du pilote de périphérique ont un cadre fixe :

    1. module_init(pin4_drv_init); //入口 去调用 pin4_drv_initFonction
    2. int __init pin4_drv_init(void) //Entrée réelle du conducteur
    3. Entrée conducteurdevno = MKDEV(major,minor); // Créer un numéro d'appareil
    4. register_chrdev(major, module_name,&pin4_fops); //Enregistrez le pilote et dites au noyau d'ajouter la structure préparée ci-dessus à la liste chaînée du pilote du noyau
    5. pin4_class=class_create(THIS_MODULE,"myfirstdemo");//Générer automatiquement l'appareil sous dev by code et créer une classe
    6. pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name); //Créer un fichier d'appareil.
    7. L'essentiel est de créer /devun fichier supplémentaire que notre couche supérieure pourra ouvrir
    8. Sinon, vous pouvez également créer l'appareil manuellementsudo mknod +设备名字 +设备类型(c表示字符设备驱动) +主设备号+次设备号

Compilation du code du module pilote

Compilation du code du module pilote

Compilation du code du module pilote (la compilation du module nécessite un code source du noyau configuré. Le suffixe du module du noyau généré après la compilation et la connexion est **.ko. Le processus de compilation ira d'abord dans le répertoire du code source du noyau, lira le niveau supérieur Makefile, puis retournez ensuite dans le répertoire où se trouve le code source du module) : **

.
  • 使用下面的的代码:(就是上面的驱动架构代码)
#include             //file_operations声明
#include     //module_init  module_exit声明
#include       //__init  __exit 宏定义声明
#include         //class  devise声明
#include    //copy_from_user 的头文件
#include      //设备号  dev_t 类型声明
#include           //ioremap iounmap的头文件


static struct class *pin4_class;
static struct device *pin4_class_dev;

static dev_t devno;                //设备号
static int major =231;                     //主设备号
static int minor =0;                       //次设备号
static char *module_name="pin4";   //模块名

//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
        printk("pin4_open\n");  //内核的打印函数和printf类似

        return 0;
}
//read函数
static int pin4_read(struct file *file,char __user *buf,size_t count,loff_t *ppos)
{
        printk("pin4_read\n");  //内核的打印函数和printf类似

        return 0;
}

//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{

        printk("pin4_write\n");  //内核的打印函数和printf类似
        return 0;
}

static struct file_operations pin4_fops = {

        .owner = THIS_MODULE,
        .open  = pin4_open,
        .write = pin4_write,
        .read  = pin4_read,
};
//static限定这个结构体的作用,仅仅只在这个文件。
int __init pin4_drv_init(void)   //真实的驱动入口
{

        int ret;
        devno = MKDEV(major,minor);  //创建设备号
  ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中

        pin4_class=class_create(THIS_MODULE,"myfirstdemo");//让代码在dev下自动>生成设备
        pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件


        return 0;
}

void __exit pin4_drv_exit(void)
{

        device_destroy(pin4_class,devno);
        class_destroy(pin4_class);
        unregister_chrdev(major, module_name);  //卸载驱动
}
module_init(pin4_drv_init);  //入口,内核加载驱动的时候,这个宏会被调用,去调用pin4_drv_init这个函数
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
  • 在导入虚拟机的内核代码中找到字符设备驱动的那一个文件夹:/SYSTEM/linux-rpi-4.19.y/drivers/char将以上代码复制到一个文件中,然后下一步要做的是就是:将上面的驱动代码编译生成模块,再修改Makefile。(你放那个文件下,就改哪个文件下的Makefile)
  • 文件内容如下图所示:(-y表示编译进内核,-m表示生成驱动模块,CONFIG_表示是根据config生成的) 所以只需要将obj-m += pin4drive.o添加到Makefile中即可。下图:Makefile文件图Linux中级——“驱动” 控制硬件必须学会的底层知识
  • 编译生成驱动模块,将生成的**.ko文件发送给树莓派**然后回/SYSTEM/linux-rpi-4.19.y下使用指令:ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules进行编译生成驱动模块。然后将生成的.ko文件发送给树莓派:scp drivers/char/pin4driver.ko pi@192.168.0.104:/home/pi编译生成驱动模块会生成以下几个文件:Linux中级——“驱动” 控制硬件必须学会的底层知识
  • .o的文件是object文件,.ko是kernel object,与.o的区别在于其多了一些sections,比如.modinfo.modinfo section是由kernel source里的modpost工具生成的, 包括MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE, device ID table以及模块依赖关系等等。depmod 工具根据.modinfo section生成modules.dep, modules.*map等文件,以便modprobe更方便的加载模块。

  • Pendant le processus de compilation, nous avons suivi les étapes suivantes :
  1. Entrez d'abord dans le répertoire où se trouve le noyau Linux et compilez le fichier pin4drive.o
  2. L'exécution de MODPOST générera un fichier temporaire pin4drive.mod.c, puis compilera pin4drive.mod.o basé sur ce fichier,
  3. Connectez ensuite les fichiers pin4drive.o et pin4drive.mod.o pour obtenir le fichier cible du module pin4drive.ko,
  4. Quittez enfin le répertoire où se trouve le noyau Linux.

Compilez de manière croisée pin4test.c (code d'appel de la couche supérieure) et envoyez-le au Raspberry Pi. Vous pouvez voir qu'il y a deux fichiers envoyés sous le répertoire pi, comme le montre la figure ci-dessous : .ko文件pin4test. Linux中级——“驱动” 控制硬件必须学会的底层知识

Charger le pilote du noyau

Ensuite, utilisez la commande :

Le pilote de périphérique (ceci est lié à la ligne de code static char *module_name=”pin4″; //nom du module dans le code du pilote), et le numéro de périphérique est également lié au code.

sudo insmod pin4drive.ko加载内核驱动(相当于通过insmod调用了module_init这个宏,然后将整个结构体加载到驱动链表中) 加载完成后就可以在dev下面看到名字为pin4

Vous pouvez vérifier que le pilote a été installé.

lsmod

    Nous exécutons ensuite ./pin4test pour exécuter le code de niveau supérieur
  • L'erreur suivante se produit lors de l'exécution du code de niveau supérieur : Cela signifie qu'il n'y a aucune autorisation Utilisez la commande : Donnez des autorisations à pin4 pour que tout le monde puisse l'ouvrir avec succès . Linux中级——“驱动” 控制硬件必须学会的底层知识sudo chmod 666 /dev/pin4
  • Ensuite, exécutez à nouveaupin4testEn surface, il n'y a aucune sortie d'informations. En fait, il y a des informations d'impression dans le noyau, mais elles ne peuvent pas être vues par la couche supérieure. Si vous souhaitez afficher les informations imprimées par le noyau , vous pouvez utiliser la commande : dmesg |grep pin4. Comme le montre l'image ci-dessous : cela signifie que l'appel du chauffeur a réussi

pin4test表面上看没有任何信息输出,其实内核里面有打印信息只是上层看不到如果想要查看内核打印的信息可以使用指令:dmesg |grep pin4Après avoir installé le pilote, vous pouvez utiliser la commande :

(pas besoin d'écrire ko) pour désinstaller le pilote. Linux中级——“驱动” 控制硬件必须学会的底层知识

Pourquoi le module pilote généré doit être généré sur une machine virtuelle

  • Pourquoi le module pilote généré doit-il être généré sur une machine virtuelle ? Le Raspberry Pi ne fonctionne-t-il pas ?

    La génération du module pilote nécessite un environnement de compilation (code source Linux et compilation, vous devez télécharger le code source du noyau Linux qui est le même que la version du système. Il peut également être compilé sur le Raspberry Pi, mais compilé sur le). Raspberry Pi sera très inefficace et nécessitera très longtemps . Cet article parle de la compilation locale du pilote Raspberry Pi.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer