Comment créer un pilote de périphérique Linux intégré (8)

8ème: Interface pour debugfs

À propos de cette série

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.

Le code source complet qui apparaît dans cet article

https://github.com/take-iwiw/DeviceDriverLesson/tree/master/08_01

Contenu de cette époque

La dernière fois, j'ai utilisé procfs pour créer une interface pour le débogage du pilote de périphérique. Cependant, procfs est essentiellement un endroit pour mettre des informations sur les processus, et il n'est pas bon de l'utiliser pour le débogage. Il est recommandé d'utiliser debugfs pour le débogage. (Merci d'avoir signalé @rarul.)

Cette fois, je vais essayer d'implémenter la même chose que la dernière fois en utilisant ce debugfs. En particulier,

/sys/kernel/debug/MyDevice/prm1

Vous permet de lire et d'écrire des paramètres de débogage en accédant à. Veuillez noter que ce chemin peut changer en fonction de l'environnement.

Implémentation de l'interface pour les debugfs

Il existe deux manières principales de créer une interface debugfs. Je décrirai chaque méthode.

Méthode 1: utilisez file_operations

Pour créer une interface pour debugfs, enregistrez simplement le nom du fichier et la fonction que vous voulez appeler en lecture / écriture avec la fonction debugfs_create_file () 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. C'est exactement la même chose que le procfs précédent et l'enregistrement normal du gestionnaire de pilote de périphérique.

Cependant, cela créera un fichier pour l'accès à debugfs dans le répertoire racine de debugfs. Bien sûr, il existe également des fichiers pour d'autres modules du noyau, alors organisez-les dans un répertoire. Utilisez debugfs_create_dir () pour créer un répertoire pour debugfs. En mettant la valeur de retour (entrée) de debugfs_create_dir () dans le troisième argument de debugfs_create_file (), le fichier sera créé sous le répertoire créé.

Méthode 2: utiliser les fonctions d'assistance

Parfois, vous voulez simplement lire et écrire des paramètres pour le débogage, mais définir une fonction de lecture / écriture à chaque fois peut être fastidieux. Si vous n'avez besoin que d'opérations de lecture / écriture, vous pouvez créer des débogages avec une seule fonction d'assistance. Par exemple, pour accéder à une variable 32 bits, utilisez debugfs_create_u32 () (la définition n'était pas signée, mais j'ai pu entrer et sortir des nombres négatifs). Si vous voulez lire et écrire en hexadécimal, utilisez debugfs_create_x32 (). Il existe également des types booléens, des ensembles de registres (adresses et nombres) et des fonctions pour les objets blob qui peuvent être utilisés pour les données binaires. Pour le moment, je n'utiliserai que des nombres 32 bits.

Terminer le traitement

Lorsque vous déchargez le noyau, vous devez supprimer le fichier debugfs que vous avez créé. Pour le supprimer, utilisez debugfs_remove (). Vous pouvez maintenant supprimer le fichier créé. Cependant, il est difficile de les effacer un par un. Surtout, il est difficile de se souvenir des informations d'entrée lors de leur création. C'est pourquoi debugfs_remove_recursive () est fourni. En mettant l'entrée (valeur de retour de debugfs_create_dir ()) du répertoire créé dans cette fonction, les fichiers en dessous seront également supprimés de manière récursive.

code

Le code ressemble à ceci: Il a debug_prm1 statiquement comme paramètre de débogage. Créez votre propre nom de répertoire sous le répertoire racine de debugfs "MyDevice" et conservez les informations d'entrée dans debug_entry_dir.

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>
#include <linux/debugfs.h>

/***Informations sur cet appareil***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"				/* /proc/Nom de l'appareil affiché sur les appareils, etc.*/

/*Variables de débogage*/
struct dentry *debug_entry_dir;		/*entrée de répertoire debugfs*/
static int debug_prm1;				/*Paramètres de débogage(pour le test) */
static int  debug_read_size = 0;	/*Nombre d'octets à lire dans une ouverture*/

/* /sys/kernel/debug/MyDevice/debug_Fonction appelée lors de l'accès à prm1*/
static int mydevice_debug_open(struct inode *inode, struct file *file)
{
	printk("mydevice_proc_open\n");
	debug_read_size = 4;	//Lire 4 octets à la fois
	return 0;
}

/* /sys/kernel/debug/MyDevice/debug_Fonction appelée lors de la lecture de prm1*/
static ssize_t mydevice_debug_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	printk("mydevice_proc_read\n");

	if (debug_read_size > 0) {
		/*Lorsqu'il reste des données à sortir*/
		/*Numéro de type entier conservé(debug_prm1)Est sortie sous forme de chaîne de caractères*/
		int len;
		len = sprintf(buf, "%d\n", debug_prm1);	//Copier en fait_to_devrait être un utilisateur
		debug_read_size -= 4;
		return len;
	} else {
		return 0;
	}
}

/* /sys/kernel/debug/MyDevice/debug_Fonction appelée lors de l'écriture de prm1*/
static ssize_t mydevice_debug_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	printk("mydevice_proc_write\n");

	/*La chaîne de caractères saisie est un nombre de type entier(debug_prm1)Tenir comme*/
	sscanf(buf, "%d", &debug_prm1);			//Copier en fait_from_devrait être un utilisateur
	return count;	
}

/*Table des gestionnaires pour les débogages*/
static struct file_operations debug_debug_prm1_fops = {
	.owner = THIS_MODULE,
	.open  = mydevice_debug_open,
	.read  = mydevice_debug_read,
	.write = mydevice_debug_write,
};

/*Route(insmod)Fonctions parfois appelées*/
static int mydevice_init(void)
{
	printk("mydevice_init\n");

	/*Créer un répertoire pour debufs*/
	debug_entry_dir = debugfs_create_dir(DRIVER_NAME, NULL);
	if (debug_entry_dir == NULL) {
		printk(KERN_ERR "debugfs_create_dir\n");
		return -ENOMEM;
	}

	/*Méthode 1:Méthode d'enregistrement de la table du gestionnaire*/
	debugfs_create_file("prm1", S_IRUGO | S_IWUGO, debug_entry_dir, NULL, &debug_debug_prm1_fops);

	/*Méthode 2:Méthode de la fonction d'assistance*/
	debugfs_create_u32("_prm1", S_IRUGO | S_IWUGO, debug_entry_dir, &debug_prm1);
	debugfs_create_x32("_prm1_hex", S_IRUGO | S_IWUGO, debug_entry_dir, &debug_prm1);

	return 0;
}

/*Décharger(rmmod)Fonctions parfois appelées*/
static void mydevice_exit(void)
{
	printk("mydevice_exit\n");

	/*Débarrassez-vous de pour debufs(Les fichiers enfants sont également supprimés automatiquement) */
	debugfs_remove_recursive(debug_entry_dir);
}

module_init(mydevice_init);
module_exit(mydevice_exit);

La méthode 1 nécessitait de définir la fonction d'entrée et la table des gestionnaires, mais la méthode 2 se termine par une ligne. Bien sûr, la méthode 2 est simple, mais si vous avez besoin de traiter quelque chose en même temps que la réécriture des paramètres, il semble que vous deviez utiliser la méthode 1. (Par exemple, lors du changement des registres (paramètres) de l'appareil connecté par i2c.)

Essayez de lire et d'écrire des paramètres via debugfs

Construisez et chargez avec la commande suivante.

make
sudo insmod  MyDeviceModule.ko
sudo ls /sys/kernel/debug/MyDevice
prm1  _prm1  _prm1_hex

Ensuite, vous pouvez voir que prm1, _prm1 et _prm1_hex sont créés sous / sys / kernel / debug / MyDevice. «prm1» est implémenté par la méthode 1, et «_prm1» et «_prm1_hex» sont implémentés par la méthode 2. Accédez à toutes les mêmes variables. (Puisque le nom a été implémenté de cette manière, il est simplement devenu prm1 et n'a pas de signification particulière.)

sudo bash -c 'echo 12 >  /sys/kernel/debug/MyDevice/prm1'
sudo cat /sys/kernel/debug/MyDevice/prm1
12
sudo cat /sys/kernel/debug/MyDevice/_prm1
12
sudo cat /sys/kernel/debug/MyDevice/_prm1_hex
0x0000000c

sudo bash -c 'echo 13 >  /sys/kernel/debug/MyDevice/_prm1'
sudo bash -c 'echo 0x0f >  /sys/kernel/debug/MyDevice/_prm1_hex'

Après cela, vous pouvez lire et écrire avec chat et écho. Le résultat sera le même car toutes les valeurs de la même variable sont entrées et sorties. Il semble que 0x soit automatiquement ajouté lorsqu'il s'agit d'un nombre hexadécimal.

À propos des droits d'accès

Ce n'est peut-être qu'une tarte à la râpe. Cette fois, lors de la création de chaque fichier debugfs, j'ai spécifié S_IRUGO | S_IWUGO comme droit d'accès. Cela devrait être lisible et inscriptible par tous les utilisateurs. Mais en réalité, j'ai dû ajouter sudo lors de l'exécution. Cela est dû au fait que les répertoires parents, / sys, / sys / kernel et / sys / kernel / debug ne bénéficient pas d'un accès utilisateur général.

Je pense que cela peut être changé en modifiant les options de montage pour ces répertoires (probablement quelque part dans le script qui s'exécute au démarrage). Mais je ne l'ai pas suivi profondément et je ne pense pas qu'il devrait être changé.

Recommended Posts

Comment créer un pilote de périphérique Linux intégré (11)
Comment créer un pilote de périphérique Linux intégré (8)
Comment créer un pilote de périphérique Linux intégré (1)
Comment créer un pilote de périphérique Linux intégré (4)
Comment créer un pilote de périphérique Linux intégré (7)
Comment créer un pilote de périphérique Linux intégré (2)
Comment créer un pilote de périphérique Linux intégré (3)
Comment créer un pilote de périphérique Linux intégré (6)
Comment créer un pilote de périphérique Linux intégré (5)
Comment créer un pilote de périphérique Linux intégré (10)
Comment créer un pilote de périphérique Linux intégré (9)
Comment créer un pilote de périphérique Linux intégré (12) (Terminé)
Comment faire reconnaître Yubico Yubikey par Manjaro Linux
Comment créer un outil CLI interactif avec Golang
Comment créer un serveur HTTPS avec Go / Gin
[Python] Comment créer une matrice de contiguïté / liste de contiguïté [Théorie des graphes]
Comment créer un laboratoire de piratage - Kali Linux (2020.1) VirtualBox 64 bits Partie 2-
Comment créer un laboratoire de piratage - Kali Linux (2020.1) VirtualBox 64-bit edition -
Comment créer un package Python (écrit pour un stagiaire)
Comment créer un fichier ISO (image CD) sous Linux
Comment faire une traduction japonais-anglais
Comment créer un bot slack
Comment installer VMware-Tools sur Linux
Comment créer un robot - Avancé
Comment créer une fonction récursive
Comment installer MBDyn (Linux Ubuntu)
[Blender] Comment créer un plug-in Blender
[Blender] Comment rendre les scripts Blender multilingues
Comment créer un robot - Basic
Comment créer un pilote de langage MongoDB C
Comment vérifier la version du système d'exploitation Linux
Comment transformer une chaîne en tableau ou un tableau en chaîne en Python
Comment obtenir le pilote d'imprimante pour Oki Mac sous Linux
Comment rendre les caractères de Word Cloud monochromatiques
Comment créer mon propre serveur Linux
Comment rendre le sélénium aussi léger que possible
[Linux] Comment subdiviser des fichiers et des dossiers
Comment créer un bot LINE à intelligence artificielle avec l'API de messagerie Flask + LINE
Comment installer aws-session-manager-plugin sur Manajro Linux
[Python] Comment rendre une classe itérable
python3 Comment installer un module externe
Comment créer un environnement NVIDIA Docker
Comment convertir Python en fichier exe
Je veux savoir comment fonctionne LINUX!
[Linux] Comment utiliser la commande echo
Comment mettre à jour PHP sur Amazon Linux 2
Comment afficher des pictogrammes sur Manjaro Linux
Comment installer des packages sur Alpine Linux
[Cocos2d-x] Comment créer une liaison de script (partie 2)
Comment faire fonctionner Linux depuis la console
Comment installer le sous-système Windows pour Linux
Comment mettre hors tension de Linux sur Ultra96-V2
Comment mettre à jour la sécurité sur CentOS Linux 8
Je veux faire un programme d'automatisation!