Eigener Treiber für Linux
-
Hallo zusammen,
ich habe vor einigen Tagen angefangen mir etwas Wissen über Linux Treiber anzulesen (in erster Linie für mein Raspberry Pi etc.) und hatte mir überlegt dieses Wissen mit einem eigenen GPIO Treiber zu testen (soll danach ausgebaut werden).
Dazu habe ich diesen Grundtreiber entwickelt:#include <linux/fs.h> #include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <asm/uaccess.h> #include <linux/ioctl.h> #include <asm/io.h> // Peripherieinformationen #define Peripherie_Basis 0x7E000000 // Virtuelle Startadresse der Peripherie #define GPIO_Basis (Peripherie_Basis + 0x200000) // Treiberinformationen #define NAME "TestTreiber" // Name des Treibers #define DRIVER_MAJOR 240 // Major Nummer // IO-Controls #define IOCTL_GETVALUE 0x0001 // Programmierer MODULE_AUTHOR("Daniel Kampert"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LED Treiber"); MODULE_SUPPORTED_DEVICE("none"); static volatile uint32_t *gpioRegs; char Array[5]; static int driver_open( struct inode *geraete_datei, struct file *instanz ) { gpioRegs = (uint32_t *)ioremap(0x20200000, 0xB4); *(gpioRegs + 1) = (1 << 21); *(gpioRegs + 7) = (1 << 17); printk("Treiber geoeffnet\n"); return 0; } /*static int my_ioctl(struct inode *geraetedatei, struct file *instanz, unsigned int cmd, unsigned long arg) { switch(cmd) { case IOCTL_GETVALUE: printk("Funktioniert!\n"); break; default: printk("Keine Funktion\n"); } return 0; }*/ static int driver_close(struct inode *geraete_datei, struct file *instanz ) { printk(NAME); printk(" wird beendet....\n"); *(gpioRegs + 10) = (1 << 17); return 0; } static ssize_t driver_read( struct file *instanz, char *user, size_t count, loff_t *offset ) { return count; } static ssize_t driver_write( struct file *instanz, const char __user *Buffer, size_t count, loff_t *offs) { return count; } // Fileoperations static struct file_operations fops = { .owner= THIS_MODULE, .read= driver_read, .write= driver_write, .open= driver_open, .release= driver_close, //.unlocked_ioctl= my_ioctl, }; // Treiber beim Betriebssystem anmelden static int __init mod_init(void) { if(register_chrdev(DRIVER_MAJOR, NAME, &fops) == 0) { printk(NAME); printk(" erfolgreich angemeldet!\n"); return 0; } else { printk("Anmeldung fehlgeschlagen!\n"); return -EIO; } } // Treiber vom Betriebssystem abmelden static void __exit mod_exit(void) { unregister_chrdev(DRIVER_MAJOR, NAME); } module_init( mod_init ); module_exit( mod_exit );
Der funktioniert an sich auch ganz gut....hatte auch mal was mit IO-Controls versucht, aber das klappte noch nicht....das ist auch erst einmal egal.
Nun möchte ich das der Treiber die LED nicht beim Öffnen einschaltet, sondern wenn ich eine "1" in den Treiber schreibe, sprich in meine driver_write() Funktion muss etwas passendes rein.
Funktioniert da ein einfacher String-Compare bzw. sonstige String-Funktionen? Oder muss man das auf Kernelebene anders machen? (Wie gesagt, ich bin noch nicht ganz fit da drin und mache das eigentlich auch nur aus "Spaß an der Freude" ).Vielen Dank für eure Hilfe
Gruß
Daniel
-
Ein string Vergleich dürfte ganz normal funktionieren. Sowas wie malloc darfst du natürlich nicht aufrufen, aber Vergleichen sollte ganz normal funktionieren.
-
Hallo,
danke für die Antwort.
Aber ich verstehe jetzt noch nicht, wie ich einzelne Zeichen an den Treiber schicken kann und er die direkt weiter verarbeitet?
Weil ich habe ein Python Programm, welches diesen Treiber öffnet und dann eine "1", eine "0" und einen ungültigen Wert reinschreiben soll. In dem Treiber lasse ich mir die Eingabe über printk() ausgeben, aber ich erhalte immer sowas hier:Jul 20 01:37:10 MyRaspberry kernel: [293198.859801] TestTreiber erfolgreich angemeldet!
Jul 20 01:37:10 MyRaspberry kernel: [293199.065573] Treiber geoeffnet
Jul 20 01:37:13 MyRaspberry kernel: [293202.072006] 10ga
TestTreiber wird beendet....kernel: [293202.072006]Normalerweise sollte da sowas stehen wie:
Jul 20 01:37:13 MyRaspberry kernel: [293202.072006] 1
Jul 20 01:37:13 MyRaspberry kernel: [293202.072007] 0
Jul 20 01:37:13 MyRaspberry kernel: [293202.072008] gaUm dieses Problem zu umgehen müsste ich den Treiber öffnen, was rein schreiben, Treiber schließen und das ganze für einen anderen Wert wiederholen.
Wie kann ich es so machen, dass er die Eingaben aus dem Userspace Programm direkt verarbeitet?Hier nochmal mein Code
#include <linux/fs.h> #include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <asm/uaccess.h> #include <linux/ioctl.h> #include <asm/io.h> // Peripherieinformationen #define Peripherie_Basis 0x7E000000 // Virtuelle Startadresse der Peripherie #define GPIO_Basis (Peripherie_Basis + 0x200000) // Treiberinformationen #define NAME "TestTreiber" // Name des Treibers #define DRIVER_MAJOR 240 // Major Nummer // IO-Controls #define IOCTL_GETVALUE 0x0001 // Programmierer MODULE_AUTHOR("Daniel Kampert"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LED Treiber"); MODULE_SUPPORTED_DEVICE("none"); static volatile uint32_t *gpioRegs; char Array[5]; static int driver_open( struct inode *geraete_datei, struct file *instanz ) { gpioRegs = (uint32_t *)ioremap(0x20200000, 0xB4); *(gpioRegs + 1) = (1 << 21); *(gpioRegs + 7) = (1 << 17); printk("Treiber geoeffnet\n"); return 0; } /*static int my_ioctl(struct inode *geraetedatei, struct file *instanz, unsigned int cmd, unsigned long arg) { switch(cmd) { case IOCTL_GETVALUE: printk("Funktioniert!\n"); break; default: printk("Keine Funktion\n"); } return 0; }*/ static int driver_close(struct inode *geraete_datei, struct file *instanz ) { printk(NAME); printk(" wird beendet....\n"); *(gpioRegs + 10) = (1 << 17); return 0; } static ssize_t driver_read( struct file *instanz, char *user, size_t count, loff_t *offset ) { return count; } static ssize_t driver_write( struct file *Instanz, const char *Buffer, size_t Count, loff_t *offs) { char Input_Buffer[6] = ""; int ret; // Daten vom Userspace in den Kernelspace kopieren ret = copy_from_user(Input_Buffer, Buffer, Count); printk(Input_Buffer); printk("\n\r"); return Count; } // Fileoperations static struct file_operations fops = { .owner= THIS_MODULE, .read= driver_read, .write= driver_write, .open= driver_open, .release= driver_close, //.unlocked_ioctl= my_ioctl, }; // Treiber beim Betriebssystem anmelden static int __init mod_init(void) { if(register_chrdev(DRIVER_MAJOR, NAME, &fops) == 0) { printk(NAME); printk(" erfolgreich angemeldet!\n"); return 0; } else { printk("Anmeldung fehlgeschlagen!\n"); return -EIO; } } // Treiber vom Betriebssystem abmelden static void __exit mod_exit(void) { unregister_chrdev(DRIVER_MAJOR, NAME); } module_init( mod_init ); module_exit( mod_exit );
-
Vermutlich benutzt dein Python-Programm Buffered-IO? Also ruft write(2) erst auf, wenn du die Datei schließt, der Puffer voll ist oder du explizit Flush aufrufst? Probier mal ein C-Programm, das direkt die Systemcalls open/read/write benutzt.
-
Hallo,
danke für den Hinweis. Ja, das scheint wirklich so zu sein. Habe das Python Programm nun durch ein C-Programm mit Systemcalls ersetzt.
Nun klappt es. Im Systemlog steht nun folgendes:Jul 20 12:13:20 MyRaspberry kernel: [331369.501798] Treiber geoeffnet
Jul 20 12:13:20 MyRaspberry kernel: [331369.503536] 1
Jul 20 12:13:21 MyRaspberry kernel: [331370.505379] 2
Jul 20 12:13:22 MyRaspberry kernel: [331371.508955] fdf
Jul 20 12:13:23 MyRaspberry kernel: [331372.510625] TestTreiber wird beendet....Aber schön wieder was gelernt
Nicht gewusst das Python explizite Bedingungen hat bevor es in eine Datei schreibt.
Vielen Dank für die Hilfe!Gruß
Daniel
-
So ich habe direkt eine neue Frage....
Ich habe mir ein Skript geschrieben, welches den Treiber kompiliert, ihn anmeldet und eine Gerätedatei anlegt.
Ich teile mit dem Unterprogramm// Treiber beim Betriebssystem anmelden static int __init mod_init(void) { if(register_chrdev(DRIVER_MAJOR, NAME, &fops) == 0) { printk(NAME); printk(" erfolgreich angemeldet!\n"); return 0; } else { printk("Anmeldung fehlgeschlagen!\n"); return -EIO; } }
Dem Betriebssystem ja mit wie der Treiber angemeldet werden muss. Er wird auch unter "lsmod" als "Treiber" angezeigt.
Wenn ich aber nun "modinfo Treiber" angebe, bekomme ich einen Error, dass das Modul nicht gefunden wurde.
Habe ich da an der Funktion was falsch verstanden?
-
Was sagt modinfo denn, wenn du als Parameter direkt die Datei übergibst?
Irgendwo muss modinfo ja die Datei finden können. Hast du dein Modul in die entsprechenden Standard-Pfade kopiert oder lädst du es von wo anders? Modinfo liest nicht aus dem RAM, sondern aus den .ko-Dateien.
-
Hey,
ahh. Der Fehler lag im Aufruf. Ich hab es immer
modinfo Treiber
aufgerufen, aber es muss
modinfo Treiber.ko
heißen
Danke für den Denkanstoß