Questo articolo vuole essere una guida pratica al porting dei moduli. Per chi volesse approfondire
consiglio di leggere una serie di articoli su 
http://lwn.net/Articles/driver-porting/, scritti da Jonathan Corbet, 
autore insieme a Alessandro Rubini del libro 
Linux Device Drivers, 2nd Edition edito dalla O'Reilly.
Un'occhiata al source tree del kernel 2.6.0 può essere molto utile per approfondire ulteriormente.
Il Makefile
Partiamo con le modifiche da apportare al Makefile per funzionare con kbuild. 
Il nuovo sistema di build del kernel semplifica un po' la scrittura dei Makefile, forzando inoltre una 
maggiore uniformità del codice fra gli sviluppatori:
CONFIG_MODULE=m
obj-$(CONFIG_MODULE) := module.o
 
Le righe sopra riportate sono sufficienti a compilare un modulo di un solo file. Se si vuole che il modulo sia "linkato"
staticamente al kernel, occorre sostituire 
m con 
y nella dichiarazione di 
CONFIG_MODULE.
Sorgenti Multipli
Se il proprio modulo è composto da più file sorgente, supponiamo 
"module1.c", 
"module2.c", 
"module3.c", allora 
occorre far sapere a kbuild di quali file è composto:
CONFIG_MODULE=m
obj-$(CONFIG_MODULE) := module.o
module-objs := module1.o module2.o module3.o
 
Da notare, in terza riga, il simbolo 
module-objs: la sintassi è 
<nomemodulo>-objs := <elenco file>. 
Un esempio tratto direttamente dal kernel può essere utile per chiarire, quindi riporto un estratto dal Makefile per il driver della scheda wifi Aironet Arlan 655:
obj-$(CONFIG_ARLAN) := arlan.o 
arlan-objs := arlan-main.o arlan-proc.o
 
dove CONFIG_ARLAN sarà valutato 
y o 
m, a seconda che si scelga di compilare il supporto della scheda come dinamico o built-in.
Sottodirectory
Se i sorgenti del proprio modulo sono organizzati in sottodirectory, allora occorre dire a kbuild di richiamare i Makefile ricorsivamente
nelle sottodirectory:
obj-$(CONFIG_MODULE) := module/
 
In questo modo verranno compilate prima tutte le sottodirectory e solo al termine verrà "linkato" il modulo vero e proprio.
Flag di compilazione
Si possono definire flag usando le variabili 
EXTRA_CFLAGS, 
EXTRA_LDFLAGS, 
EXTRA_AFLAGS rispettivamente come opzioni per il compilatore (di norma gcc), il linker o l'assembler .
Kbuild aggiungerà queste flag al relativo comando 
applicandole a tutto il Makefile.
ifdef DEBUG
  EXTRA_CFLAGS += -DDEBUG_HIGH
endif
 
Per applicare delle flag ai singoli file sorgente, si possono usare le flag 
CFLAGS_$@ e 
AFLAGS_$@.  
CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o    =   -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
                     -DGDTH_STATISTICS
CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
Compilare i moduli
Per compilare e "linkare" il tutto è sufficiente lanciare:
$ make -C /path/to/source SUBDIRS=$PWD modules
 
dove 
"/path/to/source" è il percorso alla root directory del kernel target (ad esempio 
"/usr/src/linux-2.6.0/"). 
Alla fine del processo di compilazione si otterrà un file con estensione 
.o e uno con estensione 
.ko.
Il modulo da caricare è quello con estensione 
.ko, a differenza dei moduli per kernel fino al 2.4.
Infatti gli sviluppatori del kernel 2.6 hanno scelto di differenziare gli oggetti
(kernel objects, dalle cui iniziali l'estensione 
.ko) dai normali file oggetto (estensione 
.o).
Per caricare il modulo è sufficiente lanciare:
mentre per rimuoverlo dal kernel:
I sorgenti
Ottenuto il Makefile, prima di poter compilare il modulo, bisogna modificare il codice e portarlo alle nuove specifiche
del kernel 2.6.
Innanzitutto, la consueta riga
non è più necessaria perché sarà kbuild a generarla.
Un'altra piccola modifica, risalente già alla release del kernel 2.4.10, è la dichiarazione di licenza del modulo:
Sono previste varie licenze, tutte segnalate nel file 
"include/linux/module.h" dei sorgenti del kernel. È importante
definire la licenza dei moduli in quanto, se proprietaria (
MODULE_LICENSE("Proprietary")), non ci sarà supporto dalla comunità di sviluppatori del
kernel, e il modulo non avrà accesso ai simboli esportati con la macro 
EXPORT_SYMBOL_GPL().
Per un elenco completo dei simboli esportati con questa macro consiglio di usare 
cscope oppure un grep ricorsivo 
sul kernel source tree
$ grep -e EXPORT_SYMBOL_GPL -h -R linux-2.6.0/
 
supponendo che 
"linux-2.6.0/" sia la dir root del kernel tree.
Un'altra modifica a cui probabilmente si è abituati, se recentemente si è sviluppato per il kernel 2.4, è la dichiarazione
delle funzioni di inizializzazione e cleanup usando 
module_init() e 
module_exit() definite in 
"include/linux/init.h".
Prendiamo il solito modulo di esempio:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int mymodule_init(void)
{
  printk(KERN_ALERT "Mymodule loaded!\n");
  return 0;
}
static void mymodule_exit(void)
{
  printk(KERN_ALERT "Mymodule unloaded!\n");
}
module_init(mymodule_init);
module_exit(mymodule_exit);
MODULE_LICENSE("GPL");
 
Ora non è più sufficiente scrivere le funzioni di inizializzazione e cleanup nominandole 
init_module e 
cleanup_module, ma è obbligatorio
passare i puntatori alle funzioni come parametro di 
module_init e 
module_exit. 
A questo punto si è liberi di scegliere il nome delle funzioni...
Passare parametri al modulo
La vecchia macro 
MODULE_PARM va in pensione. Al suo posto subentra 
module_param(name, type, perm), definita in 
"include/linux/moduleparam.h". 
Il parametro 
name è ovviamente il nome, mentre 
type è il tipo di parametro definito, e può essere del tipo 
byte, 
short, 
ushort,
int, 
uint, 
long, 
ulong, 
charp, 
bool, 
invbool.
perm indica i permessi  del file associato al parametro nel nuovo sysfs (
"/sys"): zero indica che il parametro non è visibile, gli altri valori 
indicano permessi di lettura e scrittura, e vengono definiti con i classici valori ottali (tipo 
0644) o con le macro standard riportate di seguito
(tratte da 
"include/linux/stat.h"):
#define S_IRUSR 00400   // user read
#define S_IWUSR 00200   // user write
#define S_IRGRP 00040   // group read
#define S_IWGRP 00020   // group write
#define S_IROTH 00004   // other read
#define S_IWOTH 00002   // other write
 
Ne sono state definite poi altre per comodità, che sono semplici combinazioni delle precedenti:
#ifdef __KERNEL__
#define S_IRUGO         (S_IRUSR|S_IRGRP|S_IROTH)   // all read
#define S_IWUGO         (S_IWUSR|S_IWGRP|S_IWOTH)   // all write
#endif
 
Occorre ricordare che i permessi consentiti sono lettura e scrittura. L'esecuzione non avrebbe senso.
Poiché siamo agli albori del sysfs, consiglio di fare esperimenti.
Se è necessario registrare il valore di un parametro in una variabile con un nome diverso dal nome del parametro, si può usare la seguente variante della
module_param():
module_param_name(name, value, type, perm)
 
dove 
name è il nome del parametro visibile all'esterno e 
value è il nome della variabile interna al proprio modulo.
Questo può essere comodo per i programmatori nell'assegnare nomi significativi alle variabili interne,
e per l'utente del modulo, per il quale i programmatori possono associare ai parametri esterni nomi più significativi per un utente "profano".
Per comodità, l'uso delle stringhe è stato semplificato ed ora è possibile avere una stringa copiata direttamente all'interno di un
array di 
char usando la funzione:
module_param_string(name, string, len, perm)
 
string è un puntatore ad un array di char preallocato di lunghezza 
len.
Ad esempio:
char sa[10];
        
module_param_string(stringa, sa, 10, 0);
 
si ottiene, così, un parametro 
stringa, il cui valore, se definito, verrà registrato nell'array puntato da 
sa, per un massimo di 10 caratteri.
Parametri multipli
I parametri multipli, forniti al modulo come liste di valori separati da virgole, vengono dichiarati usando:
module_param_array(name, type, num, perm)
 
num viene settato al numero di parametri passati al parametro 
name.
Ad esempio:
int count[10];
int n;
module_param_array(count, int, n, 0);
 
eseguendo:
$ insmod ./hello.ko count=1,2,3,4,5
 
fornirà il valore 5 alla variabile 
n. Se invece fornissimo un numero di parametri maggiore della lunghezza dell'array dichiarato, la
funzione scarterà quelli in eccesso.
Passare parametri ai moduli a boot time
È possibile passare parametri ai moduli direttamente dalla stringa di boot del kernel: è sufficiente scrivere il nome del modulo, seguito da un punto,
dal nome del parametro, dal segno uguale e infine dal valore. 
Ad esempio, se usate GRUB:
kernel /boot/bzImage <...> mymodule.count=1,2,3,4,5
 
Alias di un modulo
È possibile definire un nome alternativo con cui identificare un modulo usando la funzione:
MODULE_ALIAS("nome-alternativo");
 
Contatore d'uso
La gestione del contatore d'uso nel kernel 2.4, che usava macro come 
MOD_INC_USE_COUNT, era scomoda e soggetta ad errori.
Per questo motivo, nel kernel 2.6  è stata fatta una scelta differente, portando all'esterno del modulo la gestione del contatore.
Un frammento di codice che debba usare le risorse messe a disposizione dal modulo deve prima chiamare la funzione
int try_module_get(&module);
 
un valore di ritorno uguale a zero significa che la funzione ha avuto esito negativo e le risorse del modulo non dovrebbero essere usate.
Questo potrebbe accadere quando il modulo sta eseguendo le funzioni di inizializzazione o cleanup. 
Per comunicare al modulo che non si ha più bisogno dei suoi servizi è sufficiente chiamare 
dove 
&module è l'indirizzo alla istanza della 
struct module che descrive il modulo di cui si ha bisogno.
Occorre ricordare che è possibile usare 
THIS_MODULE per riferirsi al modulo da cui si sta chiamando la 
try_module_get() o la 
module_put().
Esportare i simboli
Nel nuovo kernel 2.6, solo i simboli esplicitamente esportati sono visibili, a differenza della serie 2.4 dove, se non diversamente indicato, venivano
tacitamente esportati tutti i simboli presenti nel modulo.
Per esportare un simbolo è sufficiente usare la macro
EXPORT_SYMBOL(symbol-to-export)