HowTo-Artikel zum Entwickeln eingebetteter Linux-Gerätetreiber als Kernelmodule. Der gesamte Inhalt dieses Artikels kann auf Raspberry Pi ausgeführt werden.
https://github.com/take-iwiw/DeviceDriverLesson/tree/master/02_01
Ermöglichen Sie Benutzern den Zugriff auf Gerätetreiber auf die alte (?) Weise.
Letztes Mal habe ich eine Halo-Welt-ähnliche Sache erstellt, die nur Handler bereitstellt, wenn ein Modul geladen / entladen wird (insmod / rmmod). Öffnen / schließen Sie diesmal das eigentliche Programm oder die Shell, damit der Wert gelesen / geschrieben werden kann.
Implementieren Sie dazu die Verarbeitung für Systemaufrufe wie Öffnen / Schließen / Lesen / Schreiben. Außerdem registriert der Benutzer das Gerät im Kernel, um auf diesen Gerätetreiber als Gerätedatei (/ dev / XXX
) zuzugreifen. Dieses Mal ist das Gerät fest statisch registriert. Diese Methode ist alt und scheint jetzt veraltet zu sein, aber ich werde diesen Schritt unternehmen, um sie zu verstehen.
Da es nur eine Datei gibt, bereiten Sie das folgende Makefile vor. Erstellen Sie MyDeviceModule.ko aus dem Quellcode 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
/*Funktion beim Öffnen aufgerufen*/
static int myDevice_open(struct inode *inode, struct file *file)
{
printk("myDevice_open\n");
return 0;
}
/*Funktion wird beim Schließen aufgerufen*/
static int myDevice_close(struct inode *inode, struct file *file)
{
printk("myDevice_close\n");
return 0;
}
/*Funktion beim Lesen aufgerufen*/
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;
}
/*Funktion zum Zeitpunkt des Schreibens aufgerufen*/
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;
}
/*Handlertabelle für verschiedene Systemaufrufe*/
struct file_operations s_myDevice_fops = {
.open = myDevice_open,
.release = myDevice_close,
.read = myDevice_read,
.write = myDevice_write,
};
/*Straße(insmod)Funktionen, die manchmal aufgerufen werden*/
static int myDevice_init(void)
{
printk("myDevice_init\n");
/*★ Registrieren Sie diesen Treiber im Kernel*/
register_chrdev(DRIVER_MAJOR, DRIVER_NAME, &s_myDevice_fops);
return 0;
}
/*Entladen(rmmod)Funktionen, die manchmal aufgerufen werden*/
static void myDevice_exit(void)
{
printk("myDevice_exit\n");
unregister_chrdev(DRIVER_MAJOR, DRIVER_NAME);
}
module_init(myDevice_init);
module_exit(myDevice_exit);
Definieren Sie eine Handlerfunktion für Systemaufrufe (Öffnen, Schließen, Lesen, Schreiben) des Benutzers. Dieses Mal werde ich vorerst nur ein Protokoll ausgeben oder einen festen Wert zurückgeben. Speichern Sie diese Funktionen in s_myDevice_fops
.
Wenn das Modul geladen wird (dh in myDevice_init
), wird dieser Gerätetreiber von der Funktion register_chrdev
im Kernel als Zeichengerät registriert. "Die Hauptnummer dieses Gerätetreibers ist DRIVER_MAJOR (63) und der Name ist DRIVER_NAME (" MyDevice_NAME "). Die Handlertabelle für jeden Systemaufruf befindet sich in" s_myDevice_fops "", sagt er. Die hier angegebene Hauptnummer ist eine sehr wichtige Nummer zur Identifizierung des Geräts.
Übrigens scheinen die Hauptnummern 60-63, 120-127, 240-254 reservierte Nummern für lokale Experimente zu sein. Deshalb habe ich diesmal 63 verwendet.
Erstellen und laden Sie mit dem folgenden Befehl.
make
sudo insmod MyDeviceModule.ko
Überprüfen Sie danach die Liste der registrierten Geräte. Dann können Sie, wie im Code registriert, sehen, dass dieses Gerät ("MyDevice_NAME") anstelle von Zeichengeräten als Kennzahl 63 registriert ist.
cat /proc/devices
Character devices:
1 mem
Kürzung
63 MyDevice_NAME
Benutzer greifen normalerweise über Gerätedateien auf Gerätetreiber zu. Ich werde die Gerätedatei vorbereiten. Verwenden Sie dazu den Befehl mknod
. Das erste Argument ist der Name der Gerätedatei. Das ist mit allem in Ordnung. Das zweite Argument ist der Gerätetyp. Diesmal ist es ein Zeichengerät, also setze c. Das dritte Argument ist die Hauptnummer des Geräts, die der zu erstellenden Gerätedatei entspricht. Dies sollte mit der zuvor erstellten Gerätetreibernummer übereinstimmen. Diesmal war es 63, also geben Sie 63 an. Das vierte Argument ist die kleine Zahl. Es wird verwendet, um zu unterscheiden, wenn mehrere Gerätedateien für dasselbe Gerät erstellt werden. Setzen Sie vorerst 1.
Ändern Sie nach dem Erstellen von / dev / myDevice
mit mknod
das Zugriffsrecht, damit jeder darauf zugreifen kann.
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
Um den Vorgang zu überprüfen, können Sie C-Code schreiben, der das diesmal erstellte / dev / myDevice
öffnet, es liest / schreibt und schließt. Der Einfachheit halber überprüfen Sie es jedoch über die Shell.
Überprüfen Sie zunächst das Schreiben mit dem folgenden Befehl
echo "a" > /dev/myDevice
dmesg
Wenn Sie sich das Protokoll mit dmesg nach der Ausgabe des Befehls ansehen, können Sie sehen, dass die implementierte Schreibfunktion aufgerufen wird. Ich denke, es wird zweimal wegen 'a'und' \ 0 'aufgerufen. Auch Öffnen und Schließen werden automatisch aufgerufen.
[11974.888831] myDevice_open
[11974.888934] myDevice_write
[11974.888944] myDevice_write
[11974.888968] myDevice_close
Überprüfen Sie als Nächstes das Lesen mit dem folgenden Befehl.
cat /dev/myDevice
Wenn Sie diesen Befehl eingeben, wird 'A' endlos auf der Konsole ausgegeben. Beenden Sie ihn daher bitte mit Strg-c. Dies liegt daran, dass die Funktion myDevice_read immer einen Wert zurückgibt. Tatsächlich sollte es 0 zurückgeben, wenn keine Werte mehr zu lesen sind.
Wenn Sie damit fertig sind, entladen Sie den Gerätetreiber mit dem folgenden Befehl und löschen Sie die Gerätedatei. Da es sich um einen Gerätetreiber handelt, denke ich nicht, dass es ein tatsächlicher Anwendungsfall ist, um die Verwendung zu beenden, aber ich denke, dass er beim Debuggen verwendet wird. Sobald die Gerätedatei (/ dev / myDevice
) erstellt wurde, ruft der Kernel den neu geladenen Gerätetreiber auf, solange die Hauptnummer dieselbe ist, unabhängig davon, wie viele Gerätetreiber rmmod und insmod sind. Es scheint, dass es herauskommen wird.
sudo rmmod MyDeviceModule
sudo rm /dev/myDevice
Recommended Posts