Update Code authored by Christian Eckl's avatar Christian Eckl
## 2.2 sevenseg.c ## 2.2 sevenseg.c
### 2.2.1 Header-Files und Definition von Makros ### 2.2.1 Header-Files und Definition von Makros
Damit alle Funktionen der im Code verwendeten Funktionen funktionieren müssen einige Header-Files eingebunden werden: Damit alle der im Code verwendeten Funktionen funktionieren müssen einige Header-Files eingebunden werden:
``` ```
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,21 +19,21 @@ Damit alle Funktionen der im Code verwendeten Funktionen funktionieren müssen e ...@@ -19,21 +19,21 @@ Damit alle Funktionen der im Code verwendeten Funktionen funktionieren müssen e
- linux/kernel.h : Headerfile für die KERN_INFO Ausgabe - linux/kernel.h : Headerfile für die KERN_INFO Ausgabe
``` ```
#define A1 17 // Pin 17 wird durch A1 ersetzt (7SEG a) #define Sa 17 // Pin 17 wird durch Sa ersetzt (7SEG a)
#define A2 27 // Pin 27 wird durch A2 ersetzt (7SEG b) #define Sb 27 // Pin 27 wird durch Sb ersetzt (7SEG b)
#define A3 22 // Pin 12 wird durch A3 ersetzt (7SEG c) #define Sc 22 // Pin 12 wird durch Sc ersetzt (7SEG c)
#define A4 5 // Pin 5 wird durch A4 ersetzt (7SEG d) #define Sd 5 // Pin 5 wird durch Sd ersetzt (7SEG d)
#define A5 6 // Pin 6 wird durch A5 ersetzt (7SEG e) #define Se 6 // Pin 6 wird durch Se ersetzt (7SEG e)
#define A6 13 // Pin 13 wird durch A6 ersetzt (7SEG f) #define Sf 13 // Pin 13 wird durch Sf ersetzt (7SEG f)
#define A7 19 // Pin 19 wird durch A7 ersetzt (7SEG g) #define Sg 19 // Pin 19 wird durch Sg ersetzt (7SEG g)
#define A8 26 // Pin 26 wird durch A8 ersetzt (7SEG dot) #define Sp 26 // Pin 26 wird durch Sp ersetzt (7SEG dot)
#define SUCCESS 0 #define SUCCESS 0
#define DEVICE_NAME "sevenseg" // Device-Name #define DEVICE_NAME "sevenseg" // Device-Name
#define BUF_LEN 1 /* Maximale Länge der Nachricht vom Treiber */ #define BUF_LEN 1 // Maximale Länge einer Nachricht
``` ```
### 2.2.2 Lizensierung und Modul Dokumentation ### 2.2.2 Lizensierung und Modul-Dokumentation
```c ```c
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -64,43 +64,43 @@ vermagic: 4.9.62-v7+ SMP mod_unload modversions ARMv7 p2v8 ...@@ -64,43 +64,43 @@ vermagic: 4.9.62-v7+ SMP mod_unload modversions ARMv7 p2v8
Um die 7-Segemntanzeige an einem Raspberry Pi zu betreiben müssen die GPIO-Pins (engl. GPIO – general purpose input/output) über den Treiber angesprochen und verwaltet werden dies geschieht im folgenden Abschnitt. Um die 7-Segemntanzeige an einem Raspberry Pi zu betreiben müssen die GPIO-Pins (engl. GPIO – general purpose input/output) über den Treiber angesprochen und verwaltet werden dies geschieht im folgenden Abschnitt.
Als erstes müssen die Pins initialisiert werden: Als erstes müssen die Pins initialisiert werden:
```c ```c
void seven_gpio_init(void) { void seven_gpio_init(void) { //Initialisiert die GPIO-Pins (gpio_request)
printk(KERN_INFO "SEVENSEG: starting gpio..."); printk(KERN_INFO "SEVENSEG: starting gpio...");
gpio_request(A1, "A1"); gpio_request(Sa, "Sa");
gpio_request(A2, "A2"); gpio_request(Sb, "Sb");
gpio_request(A3, "A3"); gpio_request(Sc, "Sc");
gpio_request(A4, "A4"); gpio_request(Sd, "Sd");
gpio_request(A5, "A5"); gpio_request(Se, "Se");
gpio_request(A6, "A6"); gpio_request(Sf, "Sf");
gpio_request(A7, "A7"); gpio_request(Sg, "Sg");
gpio_request(A8, "A8"); gpio_request(Sp, "Sp");
gpio_direction_output(A1, 0); gpio_direction_output(Sa, 0); //Legt fest das der Pin als Output-Pin ansprechbar ist (gpio_direction_output)
gpio_direction_output(A2, 0); gpio_direction_output(Sb, 0);
gpio_direction_output(A3, 0); gpio_direction_output(Sc, 0);
gpio_direction_output(A4, 0); gpio_direction_output(Sd, 0);
gpio_direction_output(A5, 0); gpio_direction_output(Se, 0);
gpio_direction_output(A6, 0); gpio_direction_output(Sf, 0);
gpio_direction_output(A7, 0); gpio_direction_output(Sg, 0);
gpio_direction_output(A8, 0); gpio_direction_output(Sp, 0);
printk(KERN_INFO "SEVENSEG: starting gpio done."); printk(KERN_INFO "SEVENSEG: starting gpio done.");
} }
``` ```
Die GPIO-Pins müssen zuerst für das Modul reserviert werden, dies wird mit `gpio_request(unsigned int gpio, const char *label)` erreicht. Die GPIO-Pins müssen zuerst für das Modul reserviert werden, dies wird mit `gpio_request(unsigned int gpio, const char *label)` erreicht.
Um mit den Pins arbeiten zu können muss noch festgelegt werden, dass es Output-Pins sind was, mit `gpio_direction_output(unsigned int gpio, int value)` bewerkstelligt wird. Um mit den Pins arbeiten zu können muss noch festgelegt werden, dass es Output-Pins sind, was mit `gpio_direction_output(unsigned int gpio, int value)` bewerkstelligt wird.
Wenn man das Modul entladen will müssen die GPIO-Pins wieder freigegeben werden was im folgenden Codeabschnitt durch `gpio_free(const int gpio)` realisiert wurde: Wenn man das Modul entladen will müssen die GPIO-Pins wieder freigegeben werden was im folgenden Codeabschnitt durch `gpio_free(const int gpio)` realisiert wurde:
```c ```c
void seven_gpio_exit(void) { //Beim Rausladen des LKM werden die Pins wieder freigegeben (gpio_free) void seven_gpio_exit(void) { //Beim Rausladen des LKM werden die Pins wieder freigegeben (gpio_free)
printk(KERN_INFO "SEVENSEG: stopping gpio..."); printk(KERN_INFO "SEVENSEG: stopping gpio...");
gpio_free(A1); gpio_free(Sa);
gpio_free(A2); gpio_free(Sb);
gpio_free(A3); gpio_free(Sc);
gpio_free(A4); gpio_free(Sd);
gpio_free(A5); gpio_free(Se);
gpio_free(A6); gpio_free(Sf);
gpio_free(A7); gpio_free(Sg);
gpio_free(A8); gpio_free(Sp);
printk(KERN_INFO "SEVENSEG: stopping gpio done."); printk(KERN_INFO "SEVENSEG: stopping gpio done.");
} }
``` ```
...@@ -112,117 +112,185 @@ void seven_status(int display) { //Switch-case fuer die Anzeigemoeg ...@@ -112,117 +112,185 @@ void seven_status(int display) { //Switch-case fuer die Anzeigemoeg
switch (display) { switch (display) {
case 0 : case 0 :
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 0 an gpio_set_value(Se, 0); // 7-Segment zeigt 0 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 1);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 1: case 1:
gpio_set_value(A1, 1); gpio_set_value(Sa, 1);
gpio_set_value(A2, 1); gpio_set_value(Sb, 0);
gpio_set_value(A3, 1); gpio_set_value(Sc, 0);
gpio_set_value(A4, 1); gpio_set_value(Sd, 1);
gpio_set_value(A5, 1); // 7-Segment zeigt 1 an gpio_set_value(Se, 1); // 7-Segment zeigt 1 an
gpio_set_value(A6, 1); gpio_set_value(Sf, 1);
gpio_set_value(A7, 1); gpio_set_value(Sg, 1);
gpio_set_value(A8, 1); gpio_set_value(Sp, 1);
break; break;
case 2: case 2:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 1);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 2 an gpio_set_value(Se, 0); // 7-Segment zeigt 2 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 1);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 3: case 3:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 3 an gpio_set_value(Se, 1); // 7-Segment zeigt 3 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 1);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 4: case 4:
gpio_set_value(A1, 0); gpio_set_value(Sa, 1);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 1);
gpio_set_value(A5, 0); // 7-Segment zeigt 4 an gpio_set_value(Se, 1); // 7-Segment zeigt 4 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 5: case 5:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 1);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 5 an gpio_set_value(Se, 1); // 7-Segment zeigt 5 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 6: case 6:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 1);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 6 an gpio_set_value(Se, 0); // 7-Segment zeigt 6 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 0);
break; break;
case 7: case 7:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 1);
gpio_set_value(A5, 0); // 7-Segment zeigt 7 an gpio_set_value(Se, 1); // 7-Segment zeigt 7 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 1);
gpio_set_value(A7, 0); gpio_set_value(Sg, 1);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 8: case 8:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 8 an gpio_set_value(Se, 0); // 7-Segment zeigt 8 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 9: case 9:
gpio_set_value(A1, 0); gpio_set_value(Sa, 0);
gpio_set_value(A2, 0); gpio_set_value(Sb, 0);
gpio_set_value(A3, 0); gpio_set_value(Sc, 0);
gpio_set_value(A4, 0); gpio_set_value(Sd, 0);
gpio_set_value(A5, 0); // 7-Segment zeigt 9 an gpio_set_value(Se, 1); // 7-Segment zeigt 9 an
gpio_set_value(A6, 0); gpio_set_value(Sf, 0);
gpio_set_value(A7, 0); gpio_set_value(Sg, 0);
gpio_set_value(A8, 0); gpio_set_value(Sp, 1);
break; break;
case 'a':
gpio_set_value(Sa, 1);
gpio_set_value(Sb, 1);
gpio_set_value(Sc, 0);
gpio_set_value(Sd, 0);
gpio_set_value(Se, 0); // 7-Segment zeigt a an
gpio_set_value(Sf, 1);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
case 'b':
gpio_set_value(Sa, 1);
gpio_set_value(Sb, 1);
gpio_set_value(Sc, 0);
gpio_set_value(Sd, 0);
gpio_set_value(Se, 0); // 7-Segment zeigt b an
gpio_set_value(Sf, 0);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
case 'c':
gpio_set_value(Sa, 1);
gpio_set_value(Sb, 1);
gpio_set_value(Sc, 1);
gpio_set_value(Sd, 0);
gpio_set_value(Se, 0); // 7-Segment zeigt c an
gpio_set_value(Sf, 1);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
case 'd':
gpio_set_value(Sa, 1);
gpio_set_value(Sb, 0);
gpio_set_value(Sc, 0);
gpio_set_value(Sd, 0);
gpio_set_value(Se, 0); // 7-Segment zeigt d an
gpio_set_value(Sf, 1);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
case 'e':
gpio_set_value(Sa, 0);
gpio_set_value(Sb, 1);
gpio_set_value(Sc, 1);
gpio_set_value(Sd, 0);
gpio_set_value(Se, 0); // 7-Segment zeigt e an
gpio_set_value(Sf, 0);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
case 'f':
gpio_set_value(Sa, 0);
gpio_set_value(Sb, 1);
gpio_set_value(Sc, 1);
gpio_set_value(Sd, 1);
gpio_set_value(Se, 0); // 7-Segment zeigt f an
gpio_set_value(Sf, 0);
gpio_set_value(Sg, 0);
gpio_set_value(Sp, 1);
break;
default: default:
gpio_set_value(A1, 1); gpio_set_value(Sa, 1);
gpio_set_value(A2, 1); gpio_set_value(Sb, 1);
gpio_set_value(A3, 1); gpio_set_value(Sc, 1);
gpio_set_value(A4, 1); gpio_set_value(Sd, 1);
gpio_set_value(A5, 1); //default alle Pins auf LOW gesetzt gpio_set_value(Se, 1); //default alle Pins auf LOW gesetzt
gpio_set_value(A6, 1); gpio_set_value(Sf, 1);
gpio_set_value(A7, 1); gpio_set_value(Sg, 1);
gpio_set_value(A8, 1); gpio_set_value(Sp, 1);
break; break;
} }
}
``` ```
Nachdem die Funktion mit der gewünschten Ausgabe `seven_status(int display)` aufgerufen wurde, werden in der switch-case-Funktion die GPIO-Pins angesprochen Nachdem die Funktion mit der gewünschten Ausgabe `seven_status(int display)` aufgerufen wurde, werden in der switch-case-Funktion die GPIO-Pins angesprochen
...@@ -234,7 +302,7 @@ Quelle: [GPIO in the kernel] (https://lwn.net/Articles/532714/) ...@@ -234,7 +302,7 @@ Quelle: [GPIO in the kernel] (https://lwn.net/Articles/532714/)
Um später mit dem Treiber im Kernel-Space kommunizieren zu können, wird ein Character Device Driver benötigt, der im Kernel-Space eine Node-Datei erstellt, auf die der User Um später mit dem Treiber im Kernel-Space kommunizieren zu können, wird ein Character Device Driver benötigt, der im Kernel-Space eine Node-Datei erstellt, auf die der User
mit `& echo "display" >> /dev/sevenseg` schreiben kann und das Modul die Eingabe verarbeitet. mit `& echo "display" >> /dev/sevenseg` schreiben kann und das Modul die Eingabe verarbeitet.
Als erstes wird hierzu folgende globale Variablen und Strukturfunktionen: Als erstes werden hierzu folgende globale Variablen und Strukturfunktionen erstellt:
```c ```c
/* Globale Variablen für die Chracter-Device-Schnittstelle */ /* Globale Variablen für die Chracter-Device-Schnittstelle */
static ssize_t seven_write(struct file *, const char *, size_t, loff_t *); static ssize_t seven_write(struct file *, const char *, size_t, loff_t *);
...@@ -256,16 +324,16 @@ Man kann seine eigene Major Nummer bestimmen muss aber darauf achten das sie noc ...@@ -256,16 +324,16 @@ Man kann seine eigene Major Nummer bestimmen muss aber darauf achten das sie noc
`register_chrdev(unsigned int major, const char *name, struct file_operations *fops)` bei `unsigned int major` 0 ein und lässt sich dann durch die Rückgabe eine freie Major Nummer zuteilen `register_chrdev(unsigned int major, const char *name, struct file_operations *fops)` bei `unsigned int major` 0 ein und lässt sich dann durch die Rückgabe eine freie Major Nummer zuteilen
wie im folgenden Code-Abschnitt: wie im folgenden Code-Abschnitt:
```c ```c
int seven_dev_init(void) int seven_dev_init(void) //Wird aufgerufen wenn das Modul geladen wird
{ {
Major = register_chrdev(0, DEVICE_NAME, &seven_fops); Major = register_chrdev(0, DEVICE_NAME, &seven_fops); //Registrierung eines Chardevice
if (Major < 0) { if (Major < 0) {
printk(KERN_ALERT "SEVENSEG: Registering char device failed with %d\n", Major); printk(KERN_ALERT "SEVENSEG: Registering char device failed with %d\n", Major);
return Major; return Major;
} }
printk(KERN_INFO "SEVENSEG: sevenseg driver loaded with major %d\n", Major); printk(KERN_INFO "SEVENSEG: sevenseg driver loaded with major %d\n", Major);
printk(KERN_INFO "SEVENSEG: >> $ mknod /dev/%s c %d 0\n", DEVICE_NAME, Major); //Info welche Nodedatei mit welchen Parametern erstellt werden soll printk(KERN_INFO "SEVENSEG: >> $ mknod /dev/%s c %d 0\n", DEVICE_NAME, Major); //Info welche Nodedatei mit welchen parametern erstellt werden soll
msg = (char *)kmalloc(32, GFP_KERNEL); //Speicherreservierung fuer die Uebertragung von Kernelspace zu Userspace msg = (char *)kmalloc(32, GFP_KERNEL); //Speicherreservierung fuer die Uebertragung von Kernelspace zu Userspace
if (msg != NULL) if (msg != NULL)
...@@ -275,11 +343,11 @@ int seven_dev_init(void) ...@@ -275,11 +343,11 @@ int seven_dev_init(void)
``` ```
Mit der KERN_INFO lassen wir uns hier den genauen Pfad ausgeben in der die Node Datei erstellt werden soll in unserem Fall wird mit Mit der KERN_INFO lassen wir uns hier den genauen Pfad ausgeben in der die Node Datei erstellt werden soll in unserem Fall wird mit
> $ mknod /dev/sevenseg 257 0 > $ mknod /dev/sevenseg 243 0
eine Datei mit Majornummer 257 und Minor-Nummer 0 angelegt. Die Minor Nummer wird nur verwendet wenn ein Treiber mehrere Geräte ansprechen soll. eine Datei mit Major Nummer 243 und Minor-Nummer 0 angelegt. Die Minor Nummer wird nur verwendet wenn ein Treiber mehrere Geräte ansprechen soll.
Zu guter letzt muss noch Speicher für die Übertragung des Puffers reserviert werden da die Eingaben in die Nodedatei nur indirekt ausgelesen werden können. Zu guter Letzt muss noch Speicher für die Übertragung des Puffers reserviert werden da die Eingaben in die Node Datei nur indirekt ausgelesen werden können.
In der folgenden Funktion verwenden wir die bereits erstellte Struktur der write-Funktion: In der folgenden Funktion verwenden wir die bereits erstellte Struktur der write-Funktion:
```c ```c
...@@ -290,7 +358,7 @@ static ssize_t seven_write(struct file *filep, const char *buffer, size_t len, l ...@@ -290,7 +358,7 @@ static ssize_t seven_write(struct file *filep, const char *buffer, size_t len, l
memset(msg, 0, 32); memset(msg, 0, 32);
count = copy_from_user(msg, buffer, len); // Kopieren des Strings aus dem User-Space which open and write this device count = copy_from_user(msg, buffer, len); // Kopieren des Strings aus dem User-Space
if (msg[0] == '1') { if (msg[0] == '1') {
seven_status(1); seven_status(1);
...@@ -316,9 +384,30 @@ static ssize_t seven_write(struct file *filep, const char *buffer, size_t len, l ...@@ -316,9 +384,30 @@ static ssize_t seven_write(struct file *filep, const char *buffer, size_t len, l
else if (msg[0] == '8') { else if (msg[0] == '8') {
seven_status(8); seven_status(8);
} }
else if (msg[0] == '9') {
seven_status(9);
}
else if (msg[0] == 'a') {
seven_status('a');
}
else if (msg[0] == 'b') {
seven_status('b');
}
else if (msg[0] == 'c') {
seven_status('c');
}
else if (msg[0] == 'd') {
seven_status('d');
}
else if (msg[0] == 'e') {
seven_status('e');
}
else if (msg[0] == 'f') {
seven_status('f');
}
else else
{ {
seven_status(0); seven_status('default');
} }
return len; return len;
...@@ -344,13 +433,13 @@ void seven_dev_exit(void) ...@@ -344,13 +433,13 @@ void seven_dev_exit(void)
} }
``` ```
Hier wird durch die Funktion `unregister_chrdev(unsigned int major, const char *name)` der Treiber abgemeldet in den Parametern wird die Majornummer und der DEVICE_NAME angegeben. Hier wird durch die Funktion `unregister_chrdev(unsigned int major, const char *name)` der Treiber abgemeldet, in den Parametern wird die Major Nummer und der DEVICE_NAME angegeben.
Quelle: [Linux Loadable Kernel Module HOWTO] (http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569) Quelle: [Linux Loadable Kernel Module HOWTO] (http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569)
### 2.2.5 Die Modulfunktionen ### 2.2.5 Die Modulfunktionen
Zu guter letzt müssen alle Initialisierungsfunktionen über die Modulinitialiesierung aufgerufen werden damit beim Laden des Treibers alle Funktionen garantiert sind: Zu guter Letzt müssen alle Initialisierungsfunktionen über die Modulinitialisierung aufgerufen werden damit beim Laden des Treibers alle Funktionen garantiert sind:
```c ```c
static int __init seven_init(void) { static int __init seven_init(void) {
printk(KERN_INFO "SEVENSEG: starting..."); printk(KERN_INFO "SEVENSEG: starting...");
...@@ -370,3 +459,11 @@ static void __exit seven_exit(void) { ...@@ -370,3 +459,11 @@ static void __exit seven_exit(void) {
module_init(seven_init); //Alle Funktionen in led_init werden im Modul geladen module_init(seven_init); //Alle Funktionen in led_init werden im Modul geladen
module_exit(seven_exit); //Alle Funktionen in led_init werden entladen module_exit(seven_exit); //Alle Funktionen in led_init werden entladen
``` ```
Die Makros `module_init(seven_init)` und `module_exit(seven_exit)` ermöglichen es die Initialisierungs-Funktionen seperat in eigene Funktionen zu schreiben. Man muss beachten,
dass die Funktionen `seven_init()` und `seven_exit()` ein __init und __exit in der Deklaration haben und vor den Modulmakros aufgerufen werden müssen, da sonst Probleme beim Kompilieren entstehen.
Quelle: [Linux Loadable Kernel Module HOWTO] (http://tldp.org/HOWTO/Module-HOWTO/index.html)
Die ganze sevenseg.c Datei:
[Gesamter Code](https://mygit.th-deg.de/ce12213/Kernelmodul_Sevenseg/blob/master/Sevenseg/sevenseg.c)