So erstellen Sie einen eingebetteten Linux-Gerätetreiber (8)

8. Schnittstelle für Debugfs

Über diese Serie

HowTo-Artikel zum Entwickeln eingebetteter Linux-Gerätetreiber als Kernelmodule. Der gesamte Inhalt dieses Artikels kann auf Raspberry Pi ausgeführt werden.

Der gesamte Quellcode, der in diesem Artikel angezeigt wird

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

Inhalt dieser Zeit

Beim letzten Mal habe ich procfs verwendet, um eine Schnittstelle für das Debuggen von Gerätetreibern zu erstellen. Procfs ist jedoch im Wesentlichen ein Ort, an dem Informationen über Prozesse abgelegt werden können, und es ist nicht gut, sie zum Debuggen zu verwenden. Es wird empfohlen, debugfs zum Debuggen zu verwenden. (Vielen Dank für den Hinweis von @rarul.)

Dieses Mal werde ich versuchen, dasselbe wie beim letzten Mal mit diesen Debugfs zu implementieren. Speziell,

/sys/kernel/debug/MyDevice/prm1

Ermöglicht das Lesen und Schreiben von Debug-Parametern durch Zugriff. Bitte beachten Sie, dass sich dieser Pfad je nach Umgebung ändern kann.

Implementierung der Schnittstelle für Debugfs

Es gibt zwei Möglichkeiten, eine Debugfs-Schnittstelle zu erstellen. Ich werde jede Methode beschreiben.

Methode 1: Verwenden Sie file_operations

Um eine Schnittstelle für Debugfs zu erstellen, registrieren Sie einfach den Dateinamen und die Funktion, die Sie beim Lesen / Schreiben aufrufen möchten, mit der Funktion "debugfs_create_file ()", in die der Treiber geladen wird (insmod). Stellen Sie bei der Registrierung die Lese- / Schreibhandlerfunktion in der Tabelle struct file_operations ein. Dies ist genau das gleiche wie bei den vorherigen Prozessen und der normalen Registrierung des Gerätetreiber-Handlers.

Dadurch wird jedoch eine Datei für den Debugfs-Zugriff im Stammverzeichnis von Debugfs erstellt. Natürlich gibt es auch Dateien für andere Kernelmodule, also organisieren Sie sie in einem Verzeichnis. Verwenden Sie debugfs_create_dir (), um ein Verzeichnis für debugfs zu erstellen. Indem Sie den Rückgabewert (Eintrag) von "debugfs_create_dir ()" in das dritte Argument von "debugfs_create_file ()" einfügen, wird eine Datei unter dem erstellten Verzeichnis erstellt.

Methode 2: Verwenden Sie Hilfsfunktionen

Manchmal möchten Sie nur Parameter zum Debuggen lesen und schreiben, aber das Definieren einer Lese- / Schreibfunktion jedes Mal kann mühsam sein. Wenn Sie nur Lese- / Schreibvorgänge benötigen, können Sie Debugfs mit nur einer Hilfsfunktion erstellen. Um beispielsweise auf eine 32-Bit-Variable zuzugreifen, verwenden Sie debugfs_create_u32 () (die Definition war ohne Vorzeichen, aber ich konnte negative Zahlen eingeben und ausgeben). Wenn Sie hexadezimal lesen und schreiben möchten, verwenden Sie debugfs_create_x32 (). Es gibt auch Bool-Typen, Registersätze (Adressen und Nummern) und Funktionen für Blobs, die für Binärdaten verwendet werden können. Vorerst werde ich nur 32-Bit-Zahlen verwenden.

Verarbeitung beenden

Wenn Sie den Kernel entladen, müssen Sie die von Ihnen erstellte Debugfs-Datei löschen. Verwenden Sie zum Entfernen debugfs_remove (). Sie können jetzt die erstellte Datei löschen. Es ist jedoch mühsam, sie einzeln zu löschen. Vor allem ist es schwierig, sich die Eintragsinformationen zu merken, als sie erstellt wurden. Zu diesem Zweck wird debugfs_remove_recursive () bereitgestellt. Wenn Sie den Eintrag (Rückgabewert von debugfs_create_dir ()) des erstellten Verzeichnisses in diese Funktion einfügen, werden die Dateien darunter auch rekursiv gelöscht.

Code

Der Code sieht folgendermaßen aus: Es hat debug_prm1 statisch als Parameter für das Debuggen. Erstellen Sie Ihr eigenes Verzeichnis unter dem Debugfs-Stammverzeichnis als "MyDevice" und behalten Sie die Eintragsinformationen in "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>

/***Informationen zu diesem Gerät***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"				/* /proc/Gerätename in Geräten usw. angezeigt.*/

/*Debug-Variablen*/
struct dentry *debug_entry_dir;		/*debugfs Verzeichniseintrag*/
static int debug_prm1;				/*Debug-Parameter(zum Test) */
static int  debug_read_size = 0;	/*Anzahl der zu lesenden Bytes in einem Open*/

/* /sys/kernel/debug/MyDevice/debug_Funktion, die beim Zugriff auf prm1 aufgerufen wird*/
static int mydevice_debug_open(struct inode *inode, struct file *file)
{
	printk("mydevice_proc_open\n");
	debug_read_size = 4;	//Lesen Sie jeweils 4 Bytes
	return 0;
}

/* /sys/kernel/debug/MyDevice/debug_Funktion, die beim Lesen von prm1 aufgerufen wird*/
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) {
		/*Wenn noch Daten ausgegeben werden müssen*/
		/*Ganzzahlige Typnummer, die gehalten wird(debug_prm1)Wird als Zeichenkette ausgegeben*/
		int len;
		len = sprintf(buf, "%d\n", debug_prm1);	//Eigentlich kopieren_to_sollte Benutzer sein
		debug_read_size -= 4;
		return len;
	} else {
		return 0;
	}
}

/* /sys/kernel/debug/MyDevice/debug_Funktion, die beim Schreiben von prm1 aufgerufen wird*/
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");

	/*Die eingegebene Zeichenfolge ist eine Ganzzahl(debug_prm1)Halten Sie als*/
	sscanf(buf, "%d", &debug_prm1);			//Eigentlich kopieren_from_sollte Benutzer sein
	return count;	
}

/*Handlertabelle für Debugfs*/
static struct file_operations debug_debug_prm1_fops = {
	.owner = THIS_MODULE,
	.open  = mydevice_debug_open,
	.read  = mydevice_debug_read,
	.write = mydevice_debug_write,
};

/*Straße(insmod)Funktionen, die manchmal aufgerufen werden*/
static int mydevice_init(void)
{
	printk("mydevice_init\n");

	/*Erstellen Sie ein Verzeichnis für Debufs*/
	debug_entry_dir = debugfs_create_dir(DRIVER_NAME, NULL);
	if (debug_entry_dir == NULL) {
		printk(KERN_ERR "debugfs_create_dir\n");
		return -ENOMEM;
	}

	/*Methode 1:Registrierungsmethode für Handlertabellen*/
	debugfs_create_file("prm1", S_IRUGO | S_IWUGO, debug_entry_dir, NULL, &debug_debug_prm1_fops);

	/*Methode 2:Hilfsfunktionsmethode*/
	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;
}

/*Entladen(rmmod)Funktionen, die manchmal aufgerufen werden*/
static void mydevice_exit(void)
{
	printk("mydevice_exit\n");

	/*Für Debufs loswerden(Untergeordnete Dateien werden ebenfalls automatisch gelöscht) */
	debugfs_remove_recursive(debug_entry_dir);
}

module_init(mydevice_init);
module_exit(mydevice_exit);

Methode 1 erforderte die Definition der Eingabefunktion und der Handlertabelle, Methode 2 endet jedoch mit einer Zeile. Natürlich ist Methode 2 einfach, aber wenn Sie etwas gleichzeitig mit dem Umschreiben der Parameter verarbeiten müssen, müssen Sie anscheinend Methode 1 verwenden. (Zum Beispiel beim Ändern der Register (Parameter) des über i2c angeschlossenen Geräts.)

Versuchen Sie, Parameter über Debugfs zu lesen und zu schreiben

Erstellen und laden Sie mit dem folgenden Befehl.

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

Dann können Sie sehen, dass "prm1", "_prm1" und "_prm1_hex" unter "/ sys / kernel / debug / MyDevice" erstellt werden. "prm1" wird durch Methode 1 implementiert, und "_prm1" und "_prm1_hex" werden durch Methode 2 implementiert. Greifen Sie auf dieselben Variablen zu. (Da der Name auf diese Weise implementiert wurde, wurde er nur zu prm1 und hat keine besondere Bedeutung.)

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'

Danach können Sie mit Katze und Echo lesen und schreiben. Das Ergebnis ist das gleiche, da alle Werte derselben Variablen eingegeben und ausgegeben werden. Es scheint, dass 0x automatisch hinzugefügt wird, wenn es sich um eine Hexadezimalzahl handelt.

Informationen zu Zugriffsrechten

Dies kann nur eine Raspeltorte sein. Dieses Mal habe ich beim Erstellen jeder Debugfs-Datei "S_IRUGO | S_IWUGO" als Zugriffsrecht angegeben. Dies sollte für alle Benutzer lesbar und beschreibbar sein. Aber in Wirklichkeit musste ich beim Laufen "sudo" hinzufügen. Dies liegt daran, dass den übergeordneten Verzeichnissen "/ sys", "/ sys / kernel" und "/ sys / kernel / debug" keine allgemeinen Benutzerzugriffsrechte gewährt werden.

Ich denke, dies kann geändert werden, indem die Mount-Optionen für diese Verzeichnisse geändert werden (wahrscheinlich irgendwo im Skript, das beim Start ausgeführt wird). Aber ich habe es nicht tief verfolgt und ich denke nicht, dass es geändert werden sollte.

Recommended Posts

So erstellen Sie einen eingebetteten Linux-Gerätetreiber (11)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (8)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (1)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (4)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (7)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (2)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (3)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (6)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (5)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (10)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (9)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (12) (vollständig)
Wie man Yubico Yubikey von Manjaro Linux erkennt
So erstellen Sie ein interaktives CLI-Tool mit Golang
So erstellen Sie einen HTTPS-Server mit Go / Gin
[Python] Erstellen einer Adjazenzmatrix / Adjazenzliste [Graphentheorie]
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit Teil 2-
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit-Edition -
Wie erstelle ich ein Python-Paket (geschrieben für Praktikanten)
So erstellen Sie eine ISO-Datei (CD-Image) unter Linux
Wie erstelle ich eine japanisch-englische Übersetzung?
Wie man einen lockeren Bot macht
So installieren Sie VMware-Tools unter Linux
Wie erstelle ich einen Crawler?
So erstellen Sie eine rekursive Funktion
So installieren Sie MBDyn (Linux Ubuntu)
[Blender] So erstellen Sie ein Blender-Plug-In
[Blender] So erstellen Sie Blender-Skripte mehrsprachig
Wie erstelle ich einen Crawler?
So erstellen Sie den MongoDB C-Sprachtreiber
So überprüfen Sie die Linux-Betriebssystemversion
So machen Sie einen String in Python zu einem Array oder ein Array zu einem String
So bringen Sie den Druckertreiber für Oki Mac in Linux
So machen Sie Word Cloud-Zeichen monochromatisch
Wie baue ich meinen eigenen Linux-Server?
Wie man Selen so leicht wie möglich macht
[Linux] Unterteilen von Dateien und Ordnern
So erstellen Sie einen LINE-Bot mit künstlicher Intelligenz mit der Flask + LINE Messaging-API
So installieren Sie das aws-session-manager-Plugin unter Manajro Linux
[Python] Wie man eine Klasse iterierbar macht
python3 So installieren Sie ein externes Modul
So erstellen Sie eine NVIDIA Docker-Umgebung
So konvertieren Sie Python in eine exe-Datei
Ich möchte wissen, wie LINUX funktioniert!
[Linux] Verwendung des Befehls echo
So aktualisieren Sie PHP unter Amazon Linux 2
So zeigen Sie Piktogramme unter Manjaro Linux an
So installieren Sie Pakete unter Alpine Linux
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 2)
So bedienen Sie Linux von der Konsole aus
So installieren Sie das Windows-Subsystem für Linux
So schalten Sie Linux unter Ultra96-V2 aus
So aktualisieren Sie die Sicherheit unter CentOS Linux 8
Ich möchte ein Automatisierungsprogramm erstellen!