View Single Post
Old 07-01-2005, 12:08   #7
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Esempio di interfaccia con lo userspace: i miscdevice

Esistono diversi modi di interfacciarsi con lo userspace. La scelta dell'interfaccia è una scelta di design, prima che tecnica. I modi più comuni sono:
- syscall
- char device
- block device
Le syscall non possono essere gestite da un modulo esterno; è improbabile che vi capiterà mai di aggiungerne una. Non ne parleremo.
I char device sono dispositivi molto semplici, tramite i quali lo scambio di dati (tramite read/write/ioctl) è molto intuitivo.
I block device sono molto più complicati, ne parleremo più avanti.
Per ora parleremo di un tipo particolare di char device, i misc device: sono a tutti gli effetti dei char device (con major fisso pari a 10), ma con alcune semplificazioni per lo sviluppatore. Sono l'ideale per la creazione di driver semplici, oppure per iniziare a capire di cosa si sta parlando.
Questo codice crea un misc device che stampa un messaggio in syslog ogniqualvolta qualcuno apre e chiude il dispositivo. Visto che ho detto al sistema di assegnare un minor automatico, è consigliabile utilizzarlo con il devfs o udev:
Codice:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>

static int kmisc_open(struct inode *ino, struct file *filp)
{
	printk(KERN_INFO "%s\n", __func__);
	return 0;
}

static int kmisc_release(struct inode *ino, struct file *filp)
{
	printk(KERN_INFO "%s\n", __func__);
	return 0;
}

static struct file_operations kops = {
	.owner		= THIS_MODULE,
	.open		= kmisc_open,
	.release	= kmisc_release,
};

static struct miscdevice kmisc = {
	.minor 	= MISC_DYNAMIC_MINOR,
	.name 	= "kmisc",
	.fops	= &kops
};

static int __init kmisc_init(void)
{
	int ret = misc_register(&kmisc);
	if (!ret)
		printk(KERN_INFO "kmisc registered on minor %d\n", kmisc.minor);
	return ret;
}

static void __exit kmisc_exit(void)
{
	misc_deregister(&kmisc);
}


module_init(kmisc_init);
module_exit(kmisc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ilsensine");
MODULE_DESCRIPTION("miscdevice module");
Tramite devfs/udev, il kernel si occupa della creazione del device (con devfs avrà il nome /dev/misc/kmisc). Il fulcro del driver è la struttura file_operations, ovvero la definizione dei metodi che possono essere invocati da userspace:
Codice:
static struct file_operations kops = {
	.owner		= THIS_MODULE,
	.open		= kmisc_open,
	.release	= kmisc_release,
};
Questa struttura, contenente in realtà parecchi altri metodi, è dichiarata in kernel/fs.h. Normalmente dovremo preoccuparci di scrivere solo alcuni dei metodi. Il campo "owner" indica il modulo proprietario del dispositivo; consente al kernel di tracciare i reference count dei moduli quando un programma utilizza un dispositivo. Gli altri due metodi implementati vengono invocati tramite la sys_open e la sys_close: notate che release viene chiamato solo quando l'ultima reference al file viene rilasciata dal programma (più reference possono aversi in seguito a un dup ad esempio).
A queste funzioni vengono passati due parametri: l'inode e il file. L'inode è il "dispositivo": ne esiste uno solo per il nostro miscdevice, comune a tutto il sistema. Il "file" è una istanza dell'inode, ovvero un inode aperto. E' direttamente legato al concetto di "file descriptor" ritornato dalla open: dentro al kernel infatti la "open" viene effettuata su un "inode", e restituisce un "file" (aperto). Possono ovviamente esistere più istanze "file" per un dato "inode".
A questo punto vi consiglio di dare una occhiata a fs.h (uno dei file più importanti del kernel), per avere una idea di come siano definite le strutture "inode", "file", "file_operations".

Compilato e inserito il modulo, potete forzare la stampa dei messaggi tramite un semplice "cat" sul dispositivo. Il cat ovviamente ritornerà errore, in quanto non abbiamo ancora implementato alcun metodo di lettura, ma in syslog potremo vedere i messaggi stampati all'apertura e chiusura del device.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12

Ultima modifica di ilsensine : 23-02-2006 alle 16:45.
ilsensine è offline