Modulo Driver Kernel Chardev – /proc e /dev

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;amp;proc_root,&amp;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;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 😛

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.