next up previous contents
Nächste Seite: Character Device Drivers Aufwärts: Linux Device Drivers Vorherige Seite: Verschiedene Arten der Treiber-Implementierung   Inhalt

Treiber Module

Ein einfacher Modul (kein Treiber Modul) ist im nachstehenden Programm gezeigt:
/*
 * $Id: hello.c,v 1.10 hp.oser 17-08-2004
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>


static int hello_init(void)  { printk(KERN_ALERT "Hello, world\n"); return 0; }

static void hello_exit(void) { printk(KERN_ALERT "Goodbye cruel world\n"); }
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
Dieses Programm kann unter Verwendung des nachfolgenden Makefile kompiliert werden:
#!/usr/bin/make
# Makefile for building hello driver as a module.
# $id$
# PREFIX may be set by the RPM build to set the effective root.
PREFIX=
ifeq ($(shell ls /lib/modules/$(shell uname -r)/build > /dev/null 2>&1 && echo build),)
  ifeq ($(shell ls /usr/src/linux > /dev/null 2>&1 && echo linux),)
    LINUX=
  else
    LINUX=/usr/src/linux
  endif
else
  LINUX=/lib/modules/$(shell uname -r)/build
endif
# check if 2.4 kernel or 2.5+ kernel
HELLO_KVER:=$(shell uname -r | cut -c1-3 | sed 's/2\.[56]/2\.6/')

ifeq ($(HELLO_KVER), 2.6)
# Makefile for 2.5+ kernel
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
EXTRA_CFLAGS = -DDBG=0
else
default:
        make -C $(LINUX) SUBDIRS=$(shell pwd) modules
endif
endif
clean:
        -rm -f *.o *.ko

Der Kernelmodul kann mit der folgenden Anweisung ins Betriebssystem geladen werden:

# insmod hello.ko
Die Meldung Hello, world wird normalerweise in die Datei /var/log/messages geschrieben. Das Entfernen des Moduls aus dem System erfolgt mit:
# rmmod hello
#
Die Meldung Goodbye cruel world wird ebenfalls in die Datei /var/log/messages geschrieben. Das Zusammenspiel zwischen dem Modul und dem Kernel wird in der Abbildung 8 gezeigt.
Abbildung 8: Zusammenhang Kernel Modul - Kernel
\begin{figure}\begin{center}
\epsfig{file=driver1.eps, width=14cm}
\end{center}\end{figure}
Ein mit insmod geladener Modul bleibt speicherresident bis dieser Modul wieder entfernt wird. Der Modul ist im Adressraum des Kernels, Programmfehler in einem Modul können zum Absturz des Betriebssystems führen. Zu einem Kernel Modul werden keine Libraries gelinkt, er darf aber (grundsätzlich) auf alle Dienste des Kernels direkt zugreifen. Damit ein Modul/Treiber richtig kompiliert müssen die Kernel Source Dateien installiert sein im Katalog /usr/src/linux. Module sind Kernel-Versionsabhängig und sollten für jede neue Kernelversion neu übersetzt werden. Ein Modul kann auf Symbole des Kernels oder anderer Module zugreifen. Zu diesem Zweck gibt es eine Kernel-Symboltabelle die in der Datei /proc/ksyms enthalten ist.

Fehlerbehandlung im init_module()
Bei Auftreten eines Fehlers müssen alle vorgängigen register() rückgängig gemacht werden sonst ist der Kernel in einem undefinierten Zustand.

Usage Count
Für jeden Modul unterhält das Linux bis Version 2.4 einen usage count. Mit folgenden Macros kann dieser Zähler angesprochen werden:

// to increment:
MOD_INC_USE_COUNT
// to decrement:
MOD_DEC_USE_COUNT
// to get TRUE if use count is zero:
MOD_INI_USE
Ab Version 2.6 wird der usage count nicht mehr im eigenen Modul verändert weil dies zu Fehlern führen kann. Ein fremder Modul, der einen anderen Modul braucht erhöht den usage count mit:
  int try_module_get(&module);
Das Freigeben des Moduls erfolgt mit:
int  module_put(&module);
Automatische oder manuelle Konfiguration
Normalerweise sprechen Gerätetreiber Hardware an. Diese Hardware hat bestimmte Adressen, die von System zu System an anderen Adressen liegen können. Es gibt zwei grundsätzliche Methoden einem Gerät die richtige Hardware-Adressen zuzuweisen: manuell durch Eingeben der Adresse beim Start des Treibers oder automatisch indem in der Initialisierung des Treibers ein Programm abläuft, das die Hardware Adressen richtig detektiert. Das automatische Detektieren ist nicht problemlos: es ist möglich, dass die Detektions-Software fehlerhaft arbeitet. Beispiel für die manuelle Konfiguration:
// Deklaration von Variabeln im Treiber Modul
int skull_ival=0;
char *skull_sval;
Anweisung zum Laden des Moduls://
# insmod skull skull_ival=99 skull_sval="mystring"
Damit werden die Variabelnwerte dieser beiden Variabeln mit den neuen Werten überschrieben.

Kritische Abschnitte in Kernel-Mode Programmen
Auch im Kernel Mode ist es möglich, dass der Prozessor dem aktuellen Prozess entzogen wird. Um sich vor allfälligen Problemen zu schützen sind folgende Massnahmen bei shared data nötig:

Nur lesender Zugriff:
Diese Variable ist als volatile zu deklarieren.
Lesend und schreibender Zugriff:
Hier müssen die Unterbrechungen ausgeschaltet werden. Dazu die nachstehende Programm Sequenz:
unsigned long flags;
local_save_flags(flags);
local_irq_disable();

/* critical section */

local_irq_enable();
local_restore_flags(flags);
besser, weil smp-safe:
typedef int   spinlock_t;
spinlock lock;

spin_lock(&lock); 

/* critical section */

spin_unlock(&lock);

User Mode Device Drivers
Es ist tatsächlich möglich mit einem user mode program Hardware direkt anzusprechen. Ein Beispiel für einen user mode device driver sind die X-Server der XFree-Version 3 und älter. Es gibt eine Reihe von Vor- und Nachteilen für die Benutzung von user mode device drivers
Vorteile:
Nachteile:

next up previous contents
Nächste Seite: Character Device Drivers Aufwärts: Linux Device Drivers Vorherige Seite: Verschiedene Arten der Treiber-Implementierung   Inhalt
Hans-Peter Oser 2007-10-30