Page principale | Structures de données | Liste des fichiers | Champs de donnée | Portée globale | Pages associées

Référence du fichier dummy.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/stat.h>
#include <linux/kdev_t.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/slab.h>
#include "dummy.h"

Aller au code source de ce fichier.

Fonctions

static int dummy_open (struct inode *inode, struct file *file)
 Fonction d'ouverture des fichiers speciaux.
static int dummy_release (struct inode *inode, struct file *file)
 Fonction de fermeture des fichiers speciaux.
static ssize_t dummy_write (struct file *file, const char *buffer, size_t size, loff_t *offset)
 Fonction d'ecriture sur les peripheriques.
static ssize_t dummy_read (struct file *file, char *buffer, size_t size, loff_t *offset)
 Fonction de lecture sur les peripheriques.
static int dummy_init (void)
 Fonction de création et d'initialisation des péripheriques.
static void dummy_cleanup (void)
 Fonction de fermeture des périphériques.
 module_init (dummy_init)
 module_exit (dummy_cleanup)
 MODULE_PARM (DeviceCount,"i")
 MODULE_PARM (DeviceName,"s")


Documentation des fonctions

static void dummy_cleanup void   )  [static]
 

Fonction de fermeture des périphériques.

Dans un premier temps, nous libérons la mémoire utilisée par les tableaux alloués et initialisés dans dummy_init. Puis nous supprimons tous les éléments sotckés dans les listes. Enfin nous supprimons les fichiers spéciaux de /dev et nous désenregistrons notre pilote auprès du noyau.

Définition à la ligne 680 du fichier dummy.c.

00683 {
00684         int i = 0;      
00685         int result;
00686         struct element_fifo *tmp_element = NULL;
00687         struct element_fifo *current_element = NULL;
00688 
00689         // liberation de la memoire du semaphore de protection du tableau d'etat des fichier speciaux ouverts
00690         kfree(open_critique);
00691         open_critique = NULL;
00692 
00693         kfree(already_opened);
00694         already_opened = NULL;
00695         
00696         // liberation de la memoire des piles de donnees
00697         for (i = 0; i < DeviceCount; i++) {
00698                 // recuperation de la tete de la pile
00699                 current_element = device_fifo[i].head;
00700                 
00701                 if(NULL != current_element) { //si la tete existe
00702                         // tant qu'il y a au moins une boite en plus de la tete
00703                         while(current_element != current_element->next) { 
00704                                 // positionnement sur l'element suivant
00705                                 tmp_element = current_element->next; 
00706 
00707                                 // suppression de liens de l'element courant
00708                                 tmp_element->prev =  current_element->prev;
00709                                 current_element->prev->next = tmp_element;
00710                                 
00711                                 // suppression de l'element courant
00712                                 kfree(current_element); 
00713                                 current_element = NULL; 
00714 
00715                                 // l'element courant devient l'ancien element suivant
00716                                 current_element = tmp_element; 
00717                                 DEBUG && printk (KERN_ALERT "supression d'un noeud !\n"); 
00718                         }
00719                 
00720                         // suppression du dernier element
00721                         kfree(current_element); 
00722                         current_element = NULL;
00723 
00724                         DEBUG && printk (KERN_ALERT "supression d'un noeud !\n"); 
00725                 }
00726         }
00727 
00728         // liberation de la memoire des pointeurs sur la structure de pile (un par peripherique)
00729         kfree(device_fifo);
00730         device_fifo = NULL;
00731         
00732         // suppression des peripheriques
00733         for (i = 0; i < DeviceCount; i++) {
00734                 devfs_remove("%s_R%d", DeviceName, i);
00735                 DEBUG && printk(KERN_ALERT "%s_R%d supprime\n", DeviceName, i);
00736         
00737                 devfs_remove("%s_W%d", DeviceName, i);
00738                 DEBUG && printk(KERN_ALERT "%s_W%d supprime\n", DeviceName, i);
00739         }
00740 
00741         // desenregistrement du pilote au niveau du noyau
00742         result = unregister_chrdev(dummy_major, "dummy"); 
00743         if (result < 0) {
00744                 DEBUG && printk (KERN_ALERT "desenregistrement %d rate\n", dummy_major); 
00745                 return; 
00746         } 
00747 

static int dummy_init void   )  [static]
 

Fonction de création et d'initialisation des péripheriques.

Dans un premier temps, nous enregistrons notre pilote auprès du noyau et nous lui demandons de nous affilier un numéro de majeur. Puis nous créons (grâce au système DevFS) les fichiers spéciaux dans /dev. Enfin, nous alloueons et initialisons les différents tableaux nécessaires au pilote.

Renvoie:
0 en cas de succès, -errno sinon.

Définition à la ligne 598 du fichier dummy.c.

00601 {
00602         int result;
00603         int i;
00604 
00605         // allocation dynamique d'un majeur pour le pilote dummy
00606         result = register_chrdev(DUMMY_MAJOR, DeviceName, &dummy_fops);
00607         if (result < 0) {
00608                 DEBUG && printk(KERN_ALERT "majeur %d indisponible\n", result);
00609                 return -ERESTARTSYS;
00610         }
00611         // recuperation du numero de majeur pour la creation des peripheriques
00612         if (0 == dummy_major) {
00613                 dummy_major = result;
00614         }
00615 
00616         // creation des peripheriques
00617         for (i = 0; i < DeviceCount; i++) {
00618                 // mineur pair => ecriture
00619                 devfs_mk_cdev(MKDEV(dummy_major, 2*i), S_IFCHR|S_IRUGO|S_IWUGO, "%s_W%d",
00620                               DeviceName, i);
00621                 DEBUG && printk(KERN_ALERT "%s_R%d cree\n", DeviceName, i);
00622 
00623                 // mineur impair => lecture
00624                 devfs_mk_cdev(MKDEV(dummy_major, 2*i+1), S_IFCHR|S_IRUGO|S_IWUGO, "%s_R%d",
00625                               DeviceName, i);
00626                 DEBUG && printk(KERN_ALERT "%s_W%d cree\n", DeviceName, i);
00627         }
00628 
00629         // allocation memoire du tableau d'etat des fichiers speciaux ouverts
00630         already_opened = kmalloc (DeviceCount*2*sizeof(int), GFP_KERNEL);
00631         if (already_opened == NULL)  {
00632                 DEBUG && printk (KERN_ALERT "allocation ratee");
00633                 return -ERESTARTSYS; 
00634         }
00635 
00636         // allocation memoire du semaphore de protection du tableau d'etat des fichier speciaux ouverts
00637         open_critique = kmalloc (DeviceCount*2*sizeof(struct semaphore), GFP_KERNEL);
00638         if (open_critique == NULL)  {
00639                 DEBUG && printk (KERN_ALERT "allocation ratee");
00640                 kfree(already_opened);
00641                 return -ERESTARTSYS; 
00642         }
00643 
00644         // inutile d'utiliser le semaphore (de protection) pour cette operation car il ne peut pas y avoir d'acces concurrent
00645         // initialisation du tableau d'etat des fichier speciaux ouvrerts et des sempahores de protection
00646         for(i = 0; i < DeviceCount*2 ; i++) {
00647                 already_opened[i] = 0;
00648                 sema_init(&open_critique[i], 1);
00649         }
00650 
00651         // allocation et initialisation des pointeurs sur la structure de pile (un par peripherique)
00652         device_fifo = kmalloc (DeviceCount*sizeof(struct private_dummy), GFP_KERNEL);
00653         if(NULL == device_fifo) {
00654                 DEBUG && printk (KERN_ALERT "allocation ratee");
00655                 kfree(already_opened);
00656                 kfree(open_critique);
00657                 return -ERESTARTSYS; 
00658         }
00659 
00660         for(i = 0; i < DeviceCount; i++) {
00661                 device_fifo[i].index = i;
00662                 device_fifo[i].head  = NULL;
00663                 device_fifo[i].in_use = 0;
00664                 sema_init(&device_fifo[i].in_use_critique, 1);
00665                 sema_init(&device_fifo[i].rw_critique, 1);
00666         }
00667 
00668         DEBUG && printk(KERN_ALERT "module %s charge gerant 2x%d peripheriques\n", DeviceName,
00669                         DeviceCount);
00670 
00671         // Une valeur de retour differente de 0 signifie un echec de init_module et donc du
00672         // chargement du module !

static int dummy_open struct inode *  inode,
struct file *  file
[static]
 

Fonction d'ouverture des fichiers speciaux.

Nous vérifions dans un premier temps si le mineur du fichier spécial est valide, c'est à dire qu'il appartient bien à ceux géré par notre pilote. Ensuite, nous prenons soin de vérifier que le fichier spécial n'est pas déjà ouvert (par un autre processus par exemple), auquel cas nous indiquons que la ressource est occupée. Dans un troisième temps nous empèchons qu'un fichier spécial de lecture ne soit ouvert en écriture, et vice-versa. Puis nous déclarons au noyau que le périphérique est utilisé (en incrémentant le compteur d'usage), et enfin nous associons le private_data du fichier spécial avec son private_dummy correspondant.

Renvoie:
0 en cas de succès, -errno sinon.

Définition à la ligne 239 du fichier dummy.c.

00242 {
00243         int minor_lu = -1;
00244         int index = 0;
00245 
00246         // recupere le numero de mineur du fichier special
00247         minor_lu = MINOR(inode->i_rdev);
00248 
00249         // verifie qu'il est valide
00250         if (minor_lu > (DeviceCount*2 - 1)) {
00251                 DEBUG && printk (KERN_ALERT "peripherique non supporte !\n");
00252                 return -ENODEV;
00253         }
00254 
00255         // debut de section critique (prise de semaphore)
00256         if( down_interruptible(&open_critique[minor_lu]) ) {
00257                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00258                 return -ERESTARTSYS;
00259         }
00260 
00261         // verifie que quelqu'un n'est pas en train d'utiliser le fichier special
00262         if(1 == already_opened[minor_lu]) {
00263                 DEBUG && printk (KERN_ALERT "deja ouvert !\n");
00264                 up(&open_critique[minor_lu]);
00265                 return -EBUSY; //errno : Resource busy
00266         }       
00267         already_opened[minor_lu] = 1;
00268 
00269         // verifie que sur le fichier special ecriture on ne demande pas de lecture
00270         if (0 == minor_lu % 2 && file->f_mode & FMODE_READ) {
00271                 DEBUG && printk (KERN_ALERT "ouverture non autorisee en lecture !\n");
00272                 up(&open_critique[minor_lu]);
00273                 return -EACCES;
00274         }
00275 
00276         // verifie que sur le fichier special de lecture on ne demande pas d'ecriture  
00277         if (1 == minor_lu % 2 && file->f_mode & FMODE_WRITE) {
00278                 DEBUG && printk (KERN_ALERT "ouverture non autorisee en ecriture !\n");
00279                 up(&open_critique[minor_lu]);
00280                 return -EACCES;
00281         }
00282 
00283         // incremente le compteur d'usage du module (premiere chose a faire)
00284         //MOD_INC_USE_COUNT;
00285         if(try_module_get(THIS_MODULE) < 0) {
00286                 DEBUG && printk (KERN_ALERT "erreur d'incrementation du compteur d'usage\n");
00287                 up(&open_critique[minor_lu]);
00288                 return -ERESTARTSYS;
00289         }
00290 
00291         // positionne le pointeur de pile sur le bon peripherique
00292         index = (int)minor_lu/2;
00293         file->private_data = &device_fifo[index];       
00294 
00295         // fin de section critique (relachement du semaphore)
00296         up(&open_critique[minor_lu]);
00297 
00298         DEBUG && printk (KERN_ALERT "ouverture autorisee !\n");
00299         DEBUG && printk (KERN_ALERT "utilisation de la file %d\n", index);
00300         

static ssize_t dummy_read struct file *  file,
char *  buffer,
size_t  size,
loff_t *  offset
[static]
 

Fonction de lecture sur les peripheriques.

Tout d'abord, nous regardons si le périphérique est déjà occupé, si c'est le cas et que l'utilisateur a demandé un accès non bloquant, nous quittons la fonction en précisant que la resource est momentanément inaccéssible, sinon nous bloquons le processus. Dans la lecture, nous réordonnançons le processus afin de libérer le système.

Renvoie:
0 en cas de succès, -errno sinon.

Définition à la ligne 482 du fichier dummy.c.

00485 {
00486         struct private_dummy *private_data = file->private_data;
00487         struct element_fifo *head_element = private_data->head;
00488         struct element_fifo *current_element = NULL;
00489         struct element_fifo *next_element = NULL;
00490         struct element_fifo *prev_element = NULL;
00491         size_t count = 0; // donnees lues par elements
00492         size_t total_length = 0; // total des donnees lues
00493         unsigned long ret_code = 0;
00494         size_t origin_size = size; // total des donnees a lire
00495         size_t retvalue = 0; // code de retour
00496 
00497         if( down_interruptible(&private_data->in_use_critique) ) {
00498                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00499                 return -ERESTARTSYS;
00500         }
00501 
00502         // gestion de la lecture non bloquante
00503         if (1 == private_data->in_use && O_NONBLOCK & file->f_flags) {
00504                 up(&private_data->in_use_critique);
00505                 return -EAGAIN;
00506         } 
00507 
00508         private_data->in_use = 1;
00509 
00510         up(&private_data->in_use_critique);
00511 
00512         // debut de section critique (prise de semaphore)       
00513         if( down_interruptible(&private_data->rw_critique) ) {
00514                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00515                 return -ERESTARTSYS;
00516         }
00517 
00518         //tant que le message n'est pas lu en entier ou qu'il n'y a plus rien a lire 
00519         while(total_length < origin_size && NULL != head_element) { 
00520                 current_element = head_element; 
00521 
00522                 // verifie que le buffer a lire est plus petit qu'un bloc
00523                 if (size < current_element->used_bytes) { 
00524                         count = size; 
00525                 } else { // sinon lire la taille du bloc
00526                         count = current_element->used_bytes; 
00527                 } 
00528 
00529                 // lecture de 'count' caracteres de l'element en cours a partir de 'position'
00530                 ret_code = copy_to_user(buffer,
00531                                         current_element->buffer+current_element->position,
00532                                         count); 
00533 
00534                 if (0 != ret_code) { 
00535                         DEBUG && printk(KERN_ALERT "erreur de lecture\n");
00536                         retvalue = -EFAULT; 
00537                         goto ret_read;
00538                 }  
00539 
00540                 DEBUG && printk(KERN_ALERT "lecture de %d octets sur %d\n", (int)count,
00541                                 (int)size); 
00542 
00543                 // mise a jour des pointeurs de buffer et du nombre de caracteres lus
00544                 buffer = buffer + count; 
00545                 size = size - count; 
00546                 total_length = total_length + count; 
00547                 current_element->used_bytes = current_element->used_bytes - count;
00548                 current_element->position = current_element->position + count;
00549                 DEBUG && printk(KERN_ALERT
00550                                 "occupation du noeud %d octets sur %d dans la file %d\n",
00551                                 current_element->used_bytes, BUF_SIZE, private_data->index);
00552 
00553                 //si element vide , desallouer la memoire sauf si c'est le dernier element  
00554                 if(0 == current_element->used_bytes) {
00555                         prev_element = current_element->prev;
00556                         next_element = current_element->next;
00557 
00558                         prev_element->next = next_element;
00559                         next_element->prev = prev_element;
00560 
00561                         if(current_element != current_element->next) {
00562                                 head_element = next_element;
00563                         } else {
00564                                 head_element = NULL;
00565                         }
00566                         
00567                         private_data->head = head_element;
00568  
00569                         kfree(current_element);                 
00570                         current_element = NULL;
00571                 }
00572                 
00573                 // force le reordonnacement du processus
00574                 schedule();
00575         } 
00576         retvalue = total_length;
00577 
00578 ret_read:
00579         // fin de section critique (relachement du semaphore)
00580         up(&private_data->rw_critique);
00581 
00582         if( down_interruptible(&private_data->in_use_critique) ) {
00583                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00584                 return -ERESTARTSYS;
00585         }
00586         private_data->in_use = 0;
00587         up(&private_data->in_use_critique);
00588 

static int dummy_release struct inode *  inode,
struct file *  file
[static]
 

Fonction de fermeture des fichiers speciaux.

On indique simplement que le fichier special est à nouveau accessible et nous décrémentons le compteur d'usage.

Renvoie:
0 en cas de succès, -errno sinon.

Définition à la ligne 308 du fichier dummy.c.

00311 {
00312         int minor_lu = -1;
00313         int index = 0;
00314 
00315         // recupere le numero de mineur du fichier special
00316         minor_lu = MINOR(inode->i_rdev);
00317         index = (int)minor_lu/2;
00318 
00319         DEBUG && printk (KERN_ALERT "fichier special ferme !\n");       
00320 
00321         if( down_interruptible(&open_critique[minor_lu]) ) {
00322                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00323                 return -ERESTARTSYS;
00324         }
00325         already_opened[minor_lu] = 0;
00326 
00327         module_put(THIS_MODULE); // (derniere chose a faire)
00328         //MOD_DEC_USE_COUNT;
00329         up(&open_critique[minor_lu]);
00330 

static ssize_t dummy_write struct file *  file,
const char *  buffer,
size_t  size,
loff_t *  offset
[static]
 

Fonction d'ecriture sur les peripheriques.

Tout d'abord, nous regardons si le périphérique est déjà occupé, si c'est le cas et que l'utilisateur a demandé un accès non bloquant, nous quittons la fonction en précisant que la resource est momentanément inaccéssible, sinon nous bloquons le processus. En ce qui concerne le remplissage de la liste des données, nous vérifions dans un premier temps que la liste n'est pas vide, si tel n'est pas le cas, nous alloueons un premier élément puis nous rentrons dans la boucle de remplissage. Dans cette dernière, nous réordonnançons le processus afin de libérer le système.

Renvoie:
0 en cas de succès, -errno sinon.

Définition à la ligne 343 du fichier dummy.c.

00346 {       
00347         struct private_dummy *private_data = file->private_data;
00348         struct element_fifo *last_element = NULL;
00349         struct element_fifo *new_element = NULL;
00350         struct element_fifo *current_element = NULL;
00351         struct element_fifo *head_element = private_data->head;
00352         size_t count = 0; // donnees ecrites par element
00353         size_t total_length = 0; // total des donnees ecrites
00354         unsigned long ret_code = 0;
00355         size_t origin_size = size; // total des donnees a ecrire
00356         size_t retvalue = 0; // code de retour
00357 
00358         if( down_interruptible(&private_data->in_use_critique) ) {
00359                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00360                 return -ERESTARTSYS;
00361         }
00362 
00363         // gestion de l'ecriture non bloquante
00364         if (1 == private_data->in_use && O_NONBLOCK & file->f_flags) {
00365                 up(&private_data->in_use_critique);
00366                 return -EAGAIN;
00367         } 
00368         private_data->in_use = 1;
00369         up(&private_data->in_use_critique);
00370 
00371         // debut de section critique (prise de semaphore)
00372         if( down_interruptible(&private_data->rw_critique) ) {
00373                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00374                 return -ERESTARTSYS;
00375         }
00376 
00377         // s'il n'y pas de tete , il faut la creer et l'initialiser (elle pointe (next et prev)
00378         // sur elle-meme)
00379         if(NULL == head_element) {
00380                 head_element = kmalloc (sizeof(struct element_fifo), GFP_KERNEL);
00381                 if(NULL == head_element) {
00382                         DEBUG && printk (KERN_ALERT "allocation ratee");
00383                         return -ERESTARTSYS;
00384                 }
00385 
00386                 DEBUG && printk(KERN_ALERT "allocation de l'element de tete\n");
00387         
00388                 head_element->used_bytes = 0;
00389                 head_element->position = 0;
00390                 head_element->prev = head_element;
00391                 head_element->next = head_element;
00392 
00393                 private_data->head = head_element;
00394         }
00395 
00396         // tant que les donnees ne sont pas toutes ecrites
00397         while(total_length < origin_size) {
00398                 // se positionner sur le dernier element.
00399                 current_element = head_element->prev;           
00400         
00401                 // verifie que le buffer a ecrire rentre dans la place restante du bloc
00402                 if (size < BUF_SIZE - current_element->used_bytes) {
00403                         count = size;
00404                 } else {
00405                         //sinon completer l'element avant d'en creer un autre
00406                         count = BUF_SIZE - current_element->used_bytes;
00407                 }
00408 
00409                 // ecriture de 'count' caracteres du buffer dans l'element en cours
00410                 ret_code = copy_from_user(current_element->buffer + current_element->used_bytes,
00411                                           buffer, count);
00412 
00413                 if (0 != ret_code) {
00414                         DEBUG && printk(KERN_ALERT "erreur d'ecriture\n");
00415                         retvalue = -EFAULT;
00416                         goto ret_write;
00417                 } 
00418 
00419                 DEBUG && printk(KERN_ALERT "ecriture de %d octets sur %d\n", (int)count, 
00420                                 (int)size);
00421 
00422                 // deplacement du pointeur sur le buffer du nombre de caracteres deja ecrits
00423                 buffer = buffer + count;
00424                 // mettre a jour le compteur de ce qu'il reste a ecrire
00425                 size = size - count;
00426                 // mettre a jour des compteurs de ce qui est ecrit
00427                 total_length = total_length + count;
00428                 current_element->used_bytes = count + current_element->used_bytes;
00429 
00430                 DEBUG && printk(KERN_ALERT
00431                                 "occupation du noeud %d octets sur %d dans la file %d\n",
00432                                 current_element->used_bytes, BUF_SIZE, private_data->index);
00433 
00434                 if (BUF_SIZE == current_element->used_bytes) { 
00435                         // allocation d'un nouvel element 
00436                         new_element = kmalloc (sizeof(struct element_fifo), GFP_KERNEL); 
00437                         if (new_element == NULL)  { 
00438                                 DEBUG && printk (KERN_ALERT "allocation ratee");
00439                                 retvalue = -ERESTARTSYS;
00440                                 goto ret_write;
00441                         } 
00442 
00443                         // creation des liens entre le nouvel element et le reste de la pile
00444                         last_element = head_element->prev; 
00445                         last_element->next = new_element; 
00446                         head_element->prev = new_element; 
00447 
00448                         // initialisation du nouvel element
00449                         new_element->used_bytes = 0; 
00450                         new_element->position = 0; 
00451                         new_element->prev = last_element; 
00452                         new_element->next = head_element; 
00453 
00454                         DEBUG && printk(KERN_ALERT "allocation d'un nouveau element\n"); 
00455                 } 
00456                 
00457                 // reordonnancement du processus, afin de liberer le systeme.
00458                 schedule();
00459         }       
00460         retvalue = total_length;
00461 
00462 ret_write:
00463         // fin de section critique (relachement du semaphore)
00464         up(&private_data->rw_critique);
00465 
00466         if( down_interruptible(&private_data->in_use_critique) ) {
00467                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00468                 return -ERESTARTSYS;
00469         }
00470         private_data->in_use = 0;
00471         up(&private_data->in_use_critique);
00472 

module_exit dummy_cleanup   ) 
 

module_init dummy_init   ) 
 

MODULE_PARM DeviceName  ,
"s" 
 

MODULE_PARM DeviceCount  ,
"i" 
 


Généré le Sun Oct 30 17:35:13 2005 pour Pilote de périphérique sous Linux par  doxygen 1.4.4