Auch bei Modulen bringt Linux 2.6 im Vergleich zu 2.4 kleine Veränderungen mit: Kernelprogrammierer müssen Parameter nun anders implementieren, können aber eigene Datentypen definieren. Wenn der neue Kernel dynamische Module lädt und dabei Parameter übergeben bekommt, kann er sie auf ihre Gültigkeit überprüfen. IO-Adressen, Speicherbereiche, Gerätemerkmale und Betriebsarten sind nur einige Anwendungsbeispiele dafür.
Die Parameter eines Moduls bestehen aus zwei Komponenten: dem Namen und dem Wert. Die dafür vordefinierten Datentypen zeigt Tabelle 1. Den Datentyp »byte«, im Kernel 2.4 noch vorhanden, gibt es in 2.6 nicht mehr. Um in einem eigenen Modul einen Parameter zu implementieren, muss der Programmierer Folgendes tun:
-
Eine Variable definieren, die im laufenden Modul den
Parameterwert aufnimmt.
-
Eine Beschreibung des Parameters erstellen, die der Anwender
des Moduls auslesen kann.
- Per Makro den Parameter dem Kernel bekannt geben.
|
|
|
Bezeichnung
|
Beschreibung
|
|
short
|
Short-Wert mit Vorzeichen
|
|
ushort
|
Short-Wert ohne Vorzeichen
|
|
int
|
Integer-Wert mit Vorzeichen
|
|
uint
|
Integer-Wert ohne Vorzeichen
|
|
long
|
Long-Wert mit Vorzeichen
|
|
ulong
|
Long-Wert ohne Vorzeichen
|
|
charp
|
Zeiger auf einen String
|
|
bool
|
boolescher Wert, mögliche Werte sind »y«,
»Y«, »n«, »N«, »0«, »1«
|
|
Array
|
Feld eines der Standard-Datentypen
|
|
String
|
Zeichenfeld
|
Die Definition der Variablen ist trivial. Hier ist nur zu beachten, dass der Datentyp der Variablen mit dem des Parameters übereinstimmt. Die Beschreibung des Parameters ist zwar nicht zwingend notwendig, aber für den Modulbenutzer oft nützlich, deshalb sollte der Kernelprogrammierer diese Zusatzarbeit leisten. Dazu übergibt er dem Makro »MODULE_PARM_DESCR()« den beschreibenden Text. Der Anwender liest diese Beschreibung mit dem Programm »mod_info«.
Makros für alle
Um den Parameter dem Kernel bekannt zu machen, stehen gleich zwei Makros zur Auswahl. Am einfachsten ist es, wenn der Name des Parameters mit dem Namen der Variablen übereinstimmt. In diesem Fall kommt das Makro »module_param()« zum Einsatz. Es bekommt den Variablen- beziehungsweise den Parameternamen übergeben, den Datentyp (siehe Tabelle 1) und einen Dateizugriffsmodus. In einer der kommenden Kernelversionen wird das Gerätemodell[1] nämlich eine Gerätedatei mit dem Namen des Parameters erstellen. Der Zugriffsmodus auf diese Gerätedatei wird dann dem an dieser Stelle angegebenen Zugriffsmodus entsprechen.
Die Funktionen und Makros für Modulparameter sind in »linux/moduleparam .h« definiert. Listing 1 zeigt hierzu ein Beispiel: ein Modul, dem der Benutzer beim Laden den Parameter »myint« vom Typ »int« übergeben kann. Aus »param1 .c« (Listing 1) erzeugt der Compiler nach Anleitung des Makefile (Listing 2) das Modul »param1.ko«, das der Befehl »insmod« in den laufenden Kernel lädt (Abbildung 1). Liegt der angegebene Parameter außerhalb des Definitionsbereichs, wird das Modul nicht geladen. So entspricht der Wert »abcd« nicht der Definition eines Integer-Parameters.
Nur mit einem gültigem Parameter wie »myint=1234« lässt sich das Modul laden. Das Syslog (meist »/var/log/messages«) zeigt den Wert des Parameters, den das Modul mit »printk()« ausgibt (Listing 1, Zeile 12). Der Befehl »rmmod param1« entfernt das Modul wieder.
Stimmen die Namen von Variable und Parameter hingegen nicht überein, hilft das Makro »module_param_named()« weiter. Es besitzt als erstes Argument den Namen des Modulparameters, als zweites den Variablennamen im Modul. Die letzten beiden Parameter von »module_param_named()« repräsentieren wieder den zugehörigen Datentyp und die Zugriffsrechte. Listing 3 zeigt die Verwendung des Makros.
Für einen Test lässt sich das Modul wieder wie oben beschrieben laden. Nur lautet jetzt der Name des Modulparameters »maxtime«, während die modulinterne Variable den alten Namen »myint« weiterhin behält.
01 #include <linux/module.h>
02 #include <linux/moduleparam.h>
03
04 MODULE_LICENSE("GPL");
05 MODULE_PARM_DESC(myint, "Testparameter");
06
07 static int myint;
08 module_param( myint, int, 666 );
09
10 static int __init mod_init(void)
11 {
12 printk("myint = %dn", myint);
13 return 0;
14 }
15
16 static void __exit mod_exit(void)
17 {
18 }
19 module_init( mod_init );
20 module_exit( mod_exit );
|
01 TARGET=param1
02
03 ifneq ($(KERNELRELEASE),)
04 obj-m := ${TARGET}.o
05
06 else
07 KDIR := /lib/modules/$(shell uname -r)/build
08 PWD := $(shell pwd)
09
10 default:
11 $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
12 endif
|
01 ...
02 static int myint;
03 module_param_named(maxtime, myint, int, 666);
04
05 static int __init mod_init(void)
06 {
07 printk("myint = %dn", myint);
08 return 0;
09 }
10 ...
|
Abbildung 1: Der Versuch, mit »insmod« das Beispiel aus Listing 1 in den laufenden Kernel zu laden, funktioniert nur, wenn der Parameter innerhalb des definierten Wertebereichs liegt.
Felder und Strings
Wie Tabelle 1 zeigt, stehen neben den Standarddatentypen auch Feld- beziehungsweise String-Datentypen zur Auswahl. Sie in einem Kernelmodul einzusetzen ist etwas schwieriger, doch auch für sie existieren jeweils eigene Makros. Außerdem braucht das Modul für Strings und Felder zwei Variablen, denn der Kernel muss über Feld- und Stringlänge Buch führen.
Zusätzlich teilt er dem Treiber mit, wie viele Elemente des Parameters der Anwender tatsächlich beim Aufruf verwendet hat. Leider ist hierbei nicht zu unterscheiden, ob der Benutzer sämtliche Elemente vorbelegt hat oder ob der Parameter gänzlich unbesetzt blieb.
Das Makro zur Übergabe eines Felds als Modulparameter heißt »module_param _array()«. Es besitzt ebenfalls vier Parameter: Variablen- beziehungsweise Parametername, Datentyp des Feldes, Anzahl der Feldelemente und schließlich die Zugriffsrechte. Eine Variante, bei der Variablenname und Parametername nicht übereinstimmen müssen, existiert ebenfalls, und zwar »module_param_array _named()«. Listing 4 zeigt den Einsatz der Makros anhand eines Beispiels. Es wertet die Zählervariable aus und zeigt die Anzahl der vom Anwender übergebenen Variablen an.
01 #include <linux/module.h>
02 #include <linux/moduleparam.h>
03
04 MODULE_LICENSE("GPL");
05
06 static int intarray[4];
07 static int intarraycount=4;
08 module_param_array(intarray, int, intarraycount, 666);
09 MODULE_PARM_DESC(intarray, "Ein Feld mit bis zu 4 Int");
10
11 static int __init mod_init(void)
12 {
13 printk("intarraycount=%dn", intarraycount);
14 for(; intarraycount; intarraycount--)
15 printk("%d: %dn", intarraycount,
16 intarray[intarraycount - 1]);
17 return 0;
18 }
19
20 static void __exit mod_exit(void)
21 {
22 }
23 module_init(mod_init);
24 module_exit(mod_exit);
|
Für Strings als Modulparameter stehen die beiden Makros »module_param_string()« und »module_param_string_named()« zur Verfügung. Ihre Parameter entsprechen denen der Feldmakros. Listing 5 zeigt ihre Anwendung.
01 ...
02 static char string[10];
03 module_param_string( optionname, string, sizeof(string), 666 );
04
05 static int __init mod_init(void)
06 {
07 if( string[0] )
08 printk("string: %sn", string);
09 ...
|