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

dummy.c

Aller à la documentation de ce fichier.
00001 /*
00002   Copyright (C) 2005 MARTIN Loïc & VINCENT Cedric
00003   
00004   This program is free software; you can redistribute it and/or
00005   modify it under the terms of the GNU General Public License
00006   as published by the Free Software Foundation; either version 2
00007   of the License, or (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details.
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00217 #include <linux/init.h>
00218 #include <linux/module.h>
00219 #include <linux/kernel.h>
00220 #include <linux/sched.h>
00221 #include <linux/fs.h>
00222 #include <asm/uaccess.h>
00223 #include <linux/stat.h>
00224 #include <linux/kdev_t.h>
00225 #include <linux/devfs_fs_kernel.h>
00226 #include <linux/slab.h>
00227 #include "dummy.h"
00228 
00241 static int dummy_open (struct inode *inode, struct file *file)
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         
00301         return 0;
00302 }
00303 
00310 static int dummy_release (struct inode *inode, struct file *file)
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 
00331         return 0;
00332 }
00333 
00345 static ssize_t dummy_write (struct file *file, const char *buffer, size_t size, loff_t *offset)
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 
00473         return retvalue;
00474 }
00475 
00484 static ssize_t dummy_read (struct file *file, char *buffer, size_t size, loff_t *offset)
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 
00589         return retvalue;
00590 } 
00591 
00600 static int dummy_init(void)
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 !
00673         return 0;
00674 }
00675 
00682 static void dummy_cleanup(void)
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 
00748         DEBUG && printk(KERN_ALERT "dummy decharge\n");
00749 }
00750 
00751 module_init(dummy_init);
00752 module_exit(dummy_cleanup);
00753 
00754 MODULE_PARM (DeviceCount, "i");
00755 MODULE_PARM (DeviceName, "s");

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