Sul web girano migliaia di Moduli Kernel minimali come questo, pero’ la maggior parte di loro sviluppa solo la parte relativa alla creazione del Device Driver Char (Ex. /dev/chardev) e non la parte relativa alla stessa implementazione usando il Virtual FileSystem /proc.
Il seguente modulo implementa entrambe le soluzioni, sia la funzione di lettura
[sourcecode language=”bash”]$ cat /dev/chardevice[/sourcecode]
[sourcecode language=”bash”]$ cat /proc/chardevice [/sourcecode]
che di scrittura
[sourcecode language=”bash”]$ echo “prova” > /dev/chardevice [/sourcecode]
[sourcecode language=”bash”]$ echo “prova” > /proc/chardevice [/sourcecode]
del file virtuale in /proc/chardevice che il device driver in /dev/chardevice
Il Major Number viene generato a run-time, per cui non utilizzare un numero a “casacciao” ma leggete i log del kernel per vedere quale numero vi e’ stato assegnato dal kernel stesso.
chardev.c
[sourcecode language=”c”]
#include
#include
#include //header per la struct del file_operations
#include
#include
#include
#define DEVICE_NAME “chardevice” // /dev/chardevice
#define BUF_LEN 100
#define SUCCESS 0
// PROTOTIPI
int init_module(void);
void clean_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *,size_t, loff_t *);
static int procfile_write(struct file *,const char *, unsigned long, void *);
static int procfile_read(char *buffer,char ** buffer_location, off_t offset, int buffer_lenght, int *eof, void *data);
//Variabili statiche
static int major_number;
static int Device_open = 0;
static char msg[BUF_LEN];
static char msg_out[BUF_LEN]; // buffer usato per la scrittura sul device
static char *msg_Ptr;
static int cont=0;
static int cont_write=0;
static char procfs_buffer[BUF_LEN];
static unsigned long procfs_buffer_size = 0;
//File struct di /dev
static struct file_operations fops = {
.read= device_read,
.write= device_write,
.open= device_open,
.release= device_release
};
//file struct di /proc
static struct proc_dir_entry *Our_proc_file;
// FUNZIONI
int init_module(void){
// if major_number=0 lo assegna a run time
major_number=register_chrdev(0,DEVICE_NAME,&fops);
if(major_number<0){
printk("Registrazione Device FALLITA!");
return major_number; }
printk("Assegnato Major_Number: %d\n", major_number);
printk("Crea il nuovo device con il comando \n");
printk("'mknod /dev/%s c %d 0 '\n",DEVICE_NAME,major_number);
printk("Prova a leggere e scrivere sul device... /dev/%s\n",DEVICE_NAME); //Write file in /proc
Our_proc_file= create_proc_entry(DEVICE_NAME,0644,NULL);
Our_proc_file->read_proc = procfile_read;
Our_proc_file->write_proc = procfile_write;
//Our_proc_file->owner = THIS_MODULE;
Our_proc_file->mode = S_IFREG | S_IRUGO;
Our_proc_file->uid = 0;
Our_proc_file->gid = 0;
Our_proc_file->size = 37;
//proc_register_dynamic(&amp;amp;amp;proc_root,&amp;amp;amp; Our_proc_file);
printk(“Creato il file /proc/%s \n”,DEVICE_NAME);
return 0;
}
void cleanup_module(){
//int ret;
unregister_chrdev(major_number, DEVICE_NAME);
//if (ret < 0) printk("ERRORE in unregister_chrdev:");
remove_proc_entry(DEVICE_NAME, NULL);
return;
}
static int device_open(struct inode *inode, struct file *file){
if(Device_open) return -EBUSY;
Device_open++;
sprintf(msg,"File letto %d volte, File scritto %d volte\n",++cont,cont_write);
msg_Ptr=msg;
//MOD_INC_USE_COUNT;
return SUCCESS;
}
// ogni device e' visto dal kernel come un file, nel nostro caso filp
static ssize_t device_read(struct file *filp, char *buffer, size_t lenght,loff_t *offset){
int bytes_read=0;
if(msg_Ptr == 0) return 0;
while(lenght &amp;amp;amp;&amp;amp;amp; *msg_Ptr) {
//dallo spazio user a quello kernel
put_user(*(msg_Ptr++),buffer++);
lenght--;
bytes_read++;
}
return bytes_read;
}
static ssize_t device_write( struct file *filp, const char *buff, size_t len, loff_t *off){
// printk("<1> Mi spiace, operazione non permessa”);
// return -EINVAL;
// int i;
int err;
err=copy_from_user(msg_out,buff,len);
/* for(i=0; i 0 ) {
//abbiamo finito di leggere
ret =0;
}
else { //inserisco nel buffer e ritorno la grandezza dello stesso
memcpy(buffer,procfs_buffer, procfs_buffer_size);
ret= procfs_buffer_size;
}
return ret;
}
static int procfile_write(struct file *file, const char *buff, unsigned long count, void * data){
int err=copy_from_user(msg_out,buff,count);
return err;
}
static int device_release(struct inode *inode, struct file *file){
Device_open–;
return 0;
}
[/sourcecode]
Dopo aver compilato il modulo grazie al seguente Makefile:
[sourcecode language=”bash”]obj-m += chardev.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
[/sourcecode]
e caricato il modulo, basta interagire con esso per provare il suo reale funzionamento 😛
[sourcecode language=”bash”]
root@unicondor:~# cat /dev/chardevice
File letto 2 volte, File scritto 4 volte
root@unicondor:~# echo Flavio > /dev/chardevice
root@unicondor:~# dmesg | tail
Crea il nuovo device with
‘mknod /dev/chardevice c 245 0 ‘
Prova a leggere e scrivere sul device… /dev/chardevice
Creato il file /proc/chardevice
Scritto: Flavio
Scritto: lavio
Scritto: vio
o
Scritto:
io
o
Scritto: Flavio
Scritto: o
avio
[/sourcecode]
In questi casi credo sia obbligatorio precisare che Non mi assumo nessuna responsabilita’ su cio’ che puo’ causare il mio codice 😀 per cui fate attenzione, molta attenzione 😛