Article HowTo pour développer des pilotes de périphériques Linux embarqués en tant que modules de noyau. Tout le contenu de cet article peut être exécuté sur Raspberry Pi.
https://github.com/take-iwiw/DeviceDriverLesson/tree/master/02_01
Autorisez les utilisateurs à accéder aux pilotes de périphériques à l'ancienne (?) Manière.
La dernière fois, j'ai créé une chose semblable à Hello World qui ne fournit des gestionnaires que lorsqu'un module est chargé / déchargé (insmod / rmmod). Cette fois, ouvrez / fermez à partir du programme ou du shell réel afin que la valeur puisse être lue / écrite.
Pour ce faire, implémentez le traitement des appels système tels que ouvrir / fermer / lire / écrire. De plus, l'utilisateur enregistre le périphérique dans le noyau afin d'accéder à ce pilote de périphérique en tant que fichier de périphérique (/ dev / XXX
). Cette fois, l'appareil est enregistré de manière fixe de manière statique. Cette méthode est ancienne et semble être obsolète maintenant, mais je vais faire cette étape pour la comprendre.
Puisqu'il n'y a qu'un seul fichier, préparez le Makefile suivant. Créez MyDeviceModule.ko à partir du code source myDeviceDriver.c.
CFILES = myDeviceDriver.c
obj-m := MyDeviceModule.o
MyDeviceModule-objs := $(CFILES:.c=.o)
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
myDeviceDriver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#define DRIVER_NAME "MyDevice_NAME"
#define DRIVER_MAJOR 63
/*Fonction appelée à l'ouverture*/
static int myDevice_open(struct inode *inode, struct file *file)
{
printk("myDevice_open\n");
return 0;
}
/*Fonction appelée à la fermeture*/
static int myDevice_close(struct inode *inode, struct file *file)
{
printk("myDevice_close\n");
return 0;
}
/*Fonction appelée lors de la lecture*/
static ssize_t myDevice_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("myDevice_read\n");
buf[0] = 'A';
return 1;
}
/*Fonction appelée au moment de l'écriture*/
static ssize_t myDevice_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
printk("myDevice_write\n");
return 1;
}
/*Table des gestionnaires pour divers appels système*/
struct file_operations s_myDevice_fops = {
.open = myDevice_open,
.release = myDevice_close,
.read = myDevice_read,
.write = myDevice_write,
};
/*Route(insmod)Fonctions parfois appelées*/
static int myDevice_init(void)
{
printk("myDevice_init\n");
/*★ Enregistrez ce pilote dans le noyau*/
register_chrdev(DRIVER_MAJOR, DRIVER_NAME, &s_myDevice_fops);
return 0;
}
/*Décharger(rmmod)Fonctions parfois appelées*/
static void myDevice_exit(void)
{
printk("myDevice_exit\n");
unregister_chrdev(DRIVER_MAJOR, DRIVER_NAME);
}
module_init(myDevice_init);
module_exit(myDevice_exit);
Définissez une fonction de gestionnaire pour les appels système (ouvrir, fermer, lire, écrire) de l'utilisateur. Cette fois, pour le moment, je vais simplement sortir un journal ou renvoyer une valeur fixe. Stockez ces fonctions dans s_myDevice_fops
.
Lorsque le module est chargé (c'est-à-dire dans myDevice_init
), la fonction register_chrdev
enregistre ce pilote de périphérique dans le noyau en tant que périphérique de caractères. "Le numéro principal de ce pilote de périphérique est DRIVER_MAJOR (63) et le nom est DRIVER_NAME (" MyDevice_NAME "). La table des gestionnaires pour chaque appel système est dans s_myDevice_fops
», dit-il. Le nombre majeur spécifié ici est un nombre très important utilisé pour identifier l'appareil.
À propos, les nombres majeurs 60-63, 120-127, 240-254 semblent être des numéros réservés aux expériences locales. Par conséquent, j'ai utilisé 63 cette fois.
Construisez et chargez avec la commande suivante.
make
sudo insmod MyDeviceModule.ko
Après cela, vérifiez la liste des appareils enregistrés. Ensuite, comme enregistré dans le code, vous pouvez voir que cet appareil ("MyDevice_NAME") est enregistré sous le numéro de mesure 63 à la place des appareils Character.
cat /proc/devices
Character devices:
1 mem
réduction
63 MyDevice_NAME
Les utilisateurs accèdent généralement aux pilotes de périphérique à l'aide de fichiers de périphérique. Je vais préparer le fichier de l'appareil. Utilisez la commande mknod
pour cela. Le premier argument est le nom du fichier de périphérique. C'est OK avec n'importe quoi. Le deuxième argument est le type de périphérique. Cette fois, il s'agit d'un périphérique de caractères, alors définissez c. Le troisième argument est le numéro majeur du périphérique correspondant au fichier de périphérique à créer. Cela doit correspondre au numéro de pilote de périphérique que vous avez créé précédemment. Cette fois, c'était 63, alors précisez 63. Le quatrième argument est le nombre mineur. Il est utilisé pour distinguer lors de la création de plusieurs fichiers de périphérique pour le même périphérique. Mettez 1 pour le moment.
Après avoir créé / dev / myDevice
avec mknod
, modifiez le droit d'accès pour que tout le monde puisse y accéder.
sudo mknod /dev/myDevice c 63 1
sudo chmod 666 /dev/myDevice
ls -la /dev
crw-rw-rw- 1 root root 63, 1 Dec 17 23:08 myDevice
Pour vérifier l'opération, vous pouvez écrire du code C qui ouvre le / dev / myDevice
créé cette fois, le lit / l'écrit et le ferme, mais par souci de simplicité, vérifiez-le depuis le shell.
Tout d'abord, vérifiez l'écriture avec la commande suivante
echo "a" > /dev/myDevice
dmesg
Si vous regardez le journal avec dmesg après avoir émis la commande, vous pouvez voir que la fonction d'écriture implémentée est appelée. Je pense qu'il est appelé deux fois à cause de "a" et "\ 0". En outre, ouvrir et fermer sont appelés automatiquement.
[11974.888831] myDevice_open
[11974.888934] myDevice_write
[11974.888944] myDevice_write
[11974.888968] myDevice_close
Ensuite, vérifiez la lecture avec la commande suivante.
cat /dev/myDevice
Si vous tapez cette commande, 'A' sera affiché à l'infini sur la console, veuillez donc l'arrêter avec Ctrl-c. En effet, la fonction myDevice_read renvoie toujours une valeur. En fait, il devrait renvoyer 0 lorsqu'il n'y a plus de valeurs à lire.
Lorsque vous avez fini de l'utiliser, utilisez la commande suivante pour décharger le pilote de périphérique et supprimer le fichier de périphérique. Puisqu'il s'agit d'un pilote de périphérique, je ne pense pas que ce soit un cas d'utilisation réel pour finir de l'utiliser, mais je pense qu'il sera utilisé lors du débogage. Si vous créez un fichier de périphérique (/ dev / myDevice
) une fois, le noyau appellera le pilote de périphérique nouvellement chargé tant qu'il a le même numéro majeur, quel que soit le nombre de pilotes de périphérique rmmod et insmod. Il semble qu'il sortira.
sudo rmmod MyDeviceModule
sudo rm /dev/myDevice
Recommended Posts