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/07_01
Jusqu'à la dernière fois, en plus des appels système de base (ouvrir, fermer, lire, écrire), nous avons implémenté ioctl. Cela couvre la plupart des interfaces minimales requises pour un pilote de périphérique (skip select / poll).
En fait, si vous développez pour contrôler un périphérique (par exemple, un capteur ou un actionneur), vous souhaiterez peut-être modifier ou obtenir des paramètres de débogage. Ce serait très pratique de pouvoir le faire depuis le shell. Ceci peut être réalisé en lisant / écrivant dans des fichiers dans le système de fichiers proc (procfs). Par exemple, supposons que vous créez le fichier suivant.
Vous pouvez vérifier la valeur du capteur en lisant la valeur de / proc / mydevice_sensor0
(par exemple, cat
), ou vous pouvez contrôler le moteur en écrivant la valeur de / proc / mydevice_motor0
(par exemple, ʻecho). ). Fondamentalement, c'est la même chose que la lecture / écriture du pilote de périphérique qui a été créé jusqu'à présent. Cependant, jusqu'à présent, il était en lecture / écriture pour le fichier de périphérique (
/ dev / mydevice`). Cette fois, nous le ferons pour le fichier procfs. Vous pouvez en fabriquer autant que vous le souhaitez. Ceci est utile lorsque vous avez un seul appareil et de nombreux paramètres que vous souhaitez vérifier.
Dans les commentaires, @rarul a souligné. Il semble qu'il soit recommandé d'utiliser procfs uniquement pour organiser les informations de processus et les débogages à des fins de débogage, comme mentionné ci-dessus. Je décrirai les debugfs la prochaine fois. Il ne devrait pas être utilisé pour le débogage, mais je pense que c'est un bon moyen de créer des procfs, je vais donc laisser cet article tel quel.
Pour créer une interface pour procfs, enregistrez simplement le nom du fichier et la fonction que vous souhaitez appeler en lecture / écriture avec la fonction proc_create
où le pilote est chargé (insmod). Lors de l'enregistrement, définissez la fonction de gestion de lecture / écriture dans la table struct file_operations
. En fait, il s'agit exactement de la même procédure que l'enregistrement d'un gestionnaire pour un pilote de périphérique normal. La seule différence est la fonction utilisée. Utilisez la fonction remove_proc_entry
pour le supprimer.
myDeviceDriver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
/***Informations sur cet appareil***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice" /* /proc/Nom de l'appareil affiché sur les appareils, etc.*/
#define PROC_NAME "MyDevice_test" /* /Le nom de procfs à créer dans proc*/
/*variables de test procfs*/
static char proc_test_string[16];
static int flag_read = 0;
/* /proc/MyDevice_Fonction appelée lors de l'accès au test*/
static int mydevice_proc_open(struct inode *inode, struct file *file)
{
printk("mydevice_proc_open\n");
flag_read = 0;
return 0;
}
/* /proc/MyDevice_Fonction appelée lors de la lecture du test*/
static ssize_t mydevice_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("mydevice_proc_read\n");
if (flag_read == 0) {
int len;
len = sprintf(buf, "%s\n", proc_test_string);
flag_read = 1;
return len;
} else {
return 0;
}
}
/* /proc/MyDevice_Fonction appelée lors de l'écriture du test*/
static ssize_t mydevice_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
printk("mydevice_proc_write\n");
if (count > sizeof(proc_test_string)) count = sizeof(proc_test_string) - 1;
if (copy_from_user(proc_test_string, buf, count)) {
return -EFAULT;
}
proc_test_string[count] = '\0';
return count;
}
/*Table des gestionnaires pour procfs*/
static struct file_operations mydevice_proc_fops = {
.owner = THIS_MODULE,
.open = mydevice_proc_open,
.read = mydevice_proc_read,
.write = mydevice_proc_write,
};
/*Route(insmod)Fonctions parfois appelées*/
static int mydevice_init(void)
{
printk("mydevice_init\n");
struct proc_dir_entry *entry;
/*Créer des procfs*/
entry = proc_create(PROC_NAME, S_IRUGO | S_IWUGO, NULL, &mydevice_proc_fops);
if (entry == NULL) {
printk(KERN_ERR "proc_create\n");
return -ENOMEM;
}
return 0;
}
/*Décharger(rmmod)Fonctions parfois appelées*/
static void mydevice_exit(void)
{
printk("mydevice_exit\n");
/*Débarrassez-vous de procfs*/
remove_proc_entry(PROC_NAME, NULL);
}
module_init(mydevice_init);
module_exit(mydevice_exit);
Créons un fichier appelé / proc / MyDevice_test
. Le traitement lors de la lecture de ce fichier (mydevice_proc_read
), le traitement lors de l'écriture ( mydevice_proc_write
) et le traitement lors de l'ouverture (mydevice_proc_open
) sont implémentés. Le processus à l'ouverture est toujours appelé à chaque fois que vous lisez ou écrivez à partir du shell. Je pense que ça va sans ça. En fait, close est omis.
mydevice_proc_write
contient la chaîne définie par l'utilisateur dans une variable statique interne ( proc_test_string
). Renvoie le contenu contenu par mydevice_proc_read
. Je veux que vous l'appeliez une seule fois par lecture (cat
), donc je gère le drapeau et l'efface au moment de l'ouverture. Je pense qu'il existe une meilleure façon de procéder.
Lors du chargement du module, utilisez la fonction proc_create
pour créer le fichier / proc / MyDevice_test
. S_IRUGO | S_IWUGO
est identique à 0666, donnant l'accès RW à tous les utilisateurs.
Construisez et chargez avec la commande suivante.
make
sudo insmod MyDeviceModule.ko
ls /proc/MyDevice_test
/proc/MyDevice_test
echo "abc" > /proc/MyDevice_test
cat /proc/MyDevice_test
abc
Après le chargement, / proc / MyDevice_test
sera créé. Pour cela, écrivez la valeur avec echo. Après cela, lorsque vous le lisez avec cat, la valeur que vous avez écrite précédemment est sortie.
Le contenu de cet article est en ligne avec le contenu de "Linux Device Driver Programming (Yutaka Hirata)".
Le livre utilisait create_proc_entry
pour s'enregistrer dans le système de fichiers proc. Cependant, il est désormais obsolète. Cet article utilise à la place proc_create
.
Comme vous l'avez souligné dans les commentaires, procfs échange initialement des informations sur le processus. Comme mentionné dans le prochain article, les debugfs échangeront des informations pour le débogage.
En dehors de ceux-ci, il existe un mécanisme d'échange de paramètres avec les modules. Vous pouvez vérifier les informations et les paramètres du module en tant que sysfs qui peuvent être placés sous le répertoire / sys. Cela ressemble à procfs, mais procfs est l'ancienne méthode, et comme je l'ai écrit dans cet article, les développeurs Devadora sont libres de l'ajouter. En conséquence, il est devenu chaotique. sysfs doit être enregistré de la manière correcte. Et chaque fichier est organisé et géré par répertoire.
Il existe différentes méthodes, mais si vous voulez juste afficher les paramètres, vous pouvez le faire avec une macro d'aide appelée module_param ()
. Cela vous permet de définir des paramètres et de lire les valeurs des paramètres (variables) lors du chargement d'un module. Cependant, il semble que les paramètres ne puissent pas être modifiés après le chargement du noyau.
Je vais vraiment l'utiliser. Tout ce que vous avez à faire est de déclarer la variable et de lire module_param ()
. Un exemple d'utilisation de la variable «param1» comme paramètre est présenté ci-dessous.
static int param1 = 10;
module_param(param1, int, S_IRUGO);
Vous pouvez vérifier la valeur de param1
en lisant / sys / module / MyDeviceModule / parameters / param1
. Vous pouvez également spécifier une valeur pendant insmod.
sudo insmod MyDeviceModule.ko
cat /sys/module/MyDeviceModule/parameters/param1
10
sudo rmmod MyDeviceModule
sudo insmod MyDeviceModule.ko param1=20
cat /sys/module/MyDeviceModule/parameters/param1
20
Recommended Posts