Logiciels Libres et Systèmes Embarqués

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 
00215 #include <linux/init.h>
00216 #include <linux/module.h>
00217 #include <linux/kernel.h>
00218 #include <linux/sched.h>
00219 #include <linux/fs.h>
00220 #include <asm/uaccess.h>
00221 #include <linux/stat.h>
00222 #include <linux/kdev_t.h>
00223 #include <linux/devfs_fs_kernel.h>
00224 #include <linux/slab.h>
00225 #include "dummy.h"
00226 
00239 static int dummy_open (struct inode *inode, struct file *file)
00240 {
00241         int minor_lu = -1;
00242         int index = 0;
00243 
00244         // recupere le numero de mineur du fichier special
00245         minor_lu = MINOR(inode->i_rdev);
00246 
00247         // verifie qu'il est valide
00248         if (minor_lu > (DeviceCount*2 - 1)) {
00249                 DEBUG && printk (KERN_ALERT "peripherique non supporte !\n");
00250                 return -ENODEV;
00251         }
00252 
00253         // debut de section critique (prise de semaphore)
00254         if( down_interruptible(&open_critique[minor_lu]) ) {
00255                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00256                 return -ERESTARTSYS;
00257         }
00258 
00259         // verifie que quelqu'un n'est pas en train d'utiliser le fichier special
00260         if(1 == already_opened[minor_lu]) {
00261                 DEBUG && printk (KERN_ALERT "deja ouvert !\n");
00262                 up(&open_critique[minor_lu]);
00263                 return -EBUSY; //errno : Resource busy
00264         }       
00265         already_opened[minor_lu] = 1;
00266 
00267         // verifie que sur le fichier special ecriture on ne demande pas de lecture
00268         if (0 == minor_lu % 2 && file->f_mode & FMODE_READ) {
00269                 DEBUG && printk (KERN_ALERT "ouverture non autorisee en lecture !\n");
00270                 up(&open_critique[minor_lu]);
00271                 return -EACCES;
00272         }
00273 
00274         // verifie que sur le fichier special de lecture on ne demande pas d'ecriture  
00275         if (1 == minor_lu % 2 && file->f_mode & FMODE_WRITE) {
00276                 DEBUG && printk (KERN_ALERT "ouverture non autorisee en ecriture !\n");
00277                 up(&open_critique[minor_lu]);
00278                 return -EACCES;
00279         }
00280 
00281         // incremente le compteur d'usage du module (premiere chose a faire)
00282         //MOD_INC_USE_COUNT;
00283         if(try_module_get(THIS_MODULE) < 0) {
00284                 DEBUG && printk (KERN_ALERT "erreur d'incrementation du compteur d'usage\n");
00285                 up(&open_critique[minor_lu]);
00286                 return -ERESTARTSYS;
00287         }
00288 
00289         // positionne le pointeur de pile sur le bon peripherique
00290         index = (int)minor_lu/2;
00291         file->private_data = &device_fifo[index];       
00292 
00293         // fin de section critique (relachement du semaphore)
00294         up(&open_critique[minor_lu]);
00295 
00296         DEBUG && printk (KERN_ALERT "ouverture autorisee !\n");
00297         DEBUG && printk (KERN_ALERT "utilisation de la file %d\n", index);
00298         
00299         return 0;
00300 }
00301 
00308 static int dummy_release (struct inode *inode, struct file *file)
00309 {
00310         int minor_lu = -1;
00311         int index = 0;
00312 
00313         // recupere le numero de mineur du fichier special
00314         minor_lu = MINOR(inode->i_rdev);
00315         index = (int)minor_lu/2;
00316 
00317         DEBUG && printk (KERN_ALERT "fichier special ferme !\n");       
00318 
00319         if( down_interruptible(&open_critique[minor_lu]) ) {
00320                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00321                 return -ERESTARTSYS;
00322         }
00323         already_opened[minor_lu] = 0;
00324 
00325         module_put(THIS_MODULE); // (derniere chose a faire)
00326         //MOD_DEC_USE_COUNT;
00327         up(&open_critique[minor_lu]);
00328 
00329         return 0;
00330 }
00331 
00343 static ssize_t dummy_write (struct file *file, const char *buffer, size_t size, loff_t *offset)
00344 {       
00345         struct private_dummy *private_data = file->private_data;
00346         struct element_fifo *last_element = NULL;
00347         struct element_fifo *new_element = NULL;
00348         struct element_fifo *current_element = NULL;
00349         struct element_fifo *head_element = private_data->head;
00350         size_t count = 0; // donnees ecrites par element
00351         size_t total_length = 0; // total des donnees ecrites
00352         unsigned long ret_code = 0;
00353         size_t origin_size = size; // total des donnees a ecrire
00354         size_t retvalue = 0; // code de retour
00355 
00356         if( down_interruptible(&private_data->in_use_critique) ) {
00357                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00358                 return -ERESTARTSYS;
00359         }
00360 
00361         // gestion de l'ecriture non bloquante
00362         if (1 == private_data->in_use && O_NONBLOCK & file->f_flags) {
00363                 up(&private_data->in_use_critique);
00364                 return -EAGAIN;
00365         } 
00366         private_data->in_use = 1;
00367         up(&private_data->in_use_critique);
00368 
00369         // debut de section critique (prise de semaphore)
00370         if( down_interruptible(&private_data->rw_critique) ) {
00371                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00372                 return -ERESTARTSYS;
00373         }
00374 
00375         // s'il n'y pas de tete , il faut la creer et l'initialiser (elle pointe (next et prev)
00376         // sur elle-meme)
00377         if(NULL == head_element) {
00378                 head_element = kmalloc (sizeof(struct element_fifo), GFP_KERNEL);
00379                 if(NULL == head_element) {
00380                         DEBUG && printk (KERN_ALERT "allocation ratee");
00381                         return -ERESTARTSYS;
00382                 }
00383 
00384                 DEBUG && printk(KERN_ALERT "allocation de l'element de tete\n");
00385         
00386                 head_element->used_bytes = 0;
00387                 head_element->position = 0;
00388                 head_element->prev = head_element;
00389                 head_element->next = head_element;
00390 
00391                 private_data->head = head_element;
00392         }
00393 
00394         // tant que les donnees ne sont pas toutes ecrites
00395         while(total_length < origin_size) {
00396                 // se positionner sur le dernier element.
00397                 current_element = head_element->prev;           
00398         
00399                 // verifie que le buffer a ecrire rentre dans la place restante du bloc
00400                 if (size < BUF_SIZE - current_element->used_bytes) {
00401                         count = size;
00402                 } else {
00403                         //sinon completer l'element avant d'en creer un autre
00404                         count = BUF_SIZE - current_element->used_bytes;
00405                 }
00406 
00407                 // ecriture de 'count' caracteres du buffer dans l'element en cours
00408                 ret_code = copy_from_user(current_element->buffer + current_element->used_bytes,
00409                                           buffer, count);
00410 
00411                 if (0 != ret_code) {
00412                         DEBUG && printk(KERN_ALERT "erreur d'ecriture\n");
00413                         retvalue = -EFAULT;
00414                         goto ret_write;
00415                 } 
00416 
00417                 DEBUG && printk(KERN_ALERT "ecriture de %d octets sur %d\n", (int)count, 
00418                                 (int)size);
00419 
00420                 // deplacement du pointeur sur le buffer du nombre de caracteres deja ecrits
00421                 buffer = buffer + count;
00422                 // mettre a jour le compteur de ce qu'il reste a ecrire
00423                 size = size - count;
00424                 // mettre a jour des compteurs de ce qui est ecrit
00425                 total_length = total_length + count;
00426                 current_element->used_bytes = count + current_element->used_bytes;
00427 
00428                 DEBUG && printk(KERN_ALERT
00429                                 "occupation du noeud %d octets sur %d dans la file %d\n",
00430                                 current_element->used_bytes, BUF_SIZE, private_data->index);
00431 
00432                 if (BUF_SIZE == current_element->used_bytes) { 
00433                         // allocation d'un nouvel element 
00434                         new_element = kmalloc (sizeof(struct element_fifo), GFP_KERNEL); 
00435                         if (new_element == NULL)  { 
00436                                 DEBUG && printk (KERN_ALERT "allocation ratee");
00437                                 retvalue = -ERESTARTSYS;
00438                                 goto ret_write;
00439                         } 
00440 
00441                         // creation des liens entre le nouvel element et le reste de la pile
00442                         last_element = head_element->prev; 
00443                         last_element->next = new_element; 
00444                         head_element->prev = new_element; 
00445 
00446                         // initialisation du nouvel element
00447                         new_element->used_bytes = 0; 
00448                         new_element->position = 0; 
00449                         new_element->prev = last_element; 
00450                         new_element->next = head_element; 
00451 
00452                         DEBUG && printk(KERN_ALERT "allocation d'un nouveau element\n"); 
00453                 } 
00454                 
00455                 // reordonnancement du processus, afin de liberer le systeme.
00456                 schedule();
00457         }       
00458         retvalue = total_length;
00459 
00460 ret_write:
00461         // fin de section critique (relachement du semaphore)
00462         up(&private_data->rw_critique);
00463 
00464         if( down_interruptible(&private_data->in_use_critique) ) {
00465                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00466                 return -ERESTARTSYS;
00467         }
00468         private_data->in_use = 0;
00469         up(&private_data->in_use_critique);
00470 
00471         return retvalue;
00472 }
00473 
00482 static ssize_t dummy_read (struct file *file, char *buffer, size_t size, loff_t *offset)
00483 {
00484         struct private_dummy *private_data = file->private_data;
00485         struct element_fifo *head_element = private_data->head;
00486         struct element_fifo *current_element = NULL;
00487         struct element_fifo *next_element = NULL;
00488         struct element_fifo *prev_element = NULL;
00489         size_t count = 0; // donnees lues par elements
00490         size_t total_length = 0; // total des donnees lues
00491         unsigned long ret_code = 0;
00492         size_t origin_size = size; // total des donnees a lire
00493         size_t retvalue = 0; // code de retour
00494 
00495         if( down_interruptible(&private_data->in_use_critique) ) {
00496                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00497                 return -ERESTARTSYS;
00498         }
00499 
00500         // gestion de la lecture non bloquante
00501         if (1 == private_data->in_use && O_NONBLOCK & file->f_flags) {
00502                 up(&private_data->in_use_critique);
00503                 return -EAGAIN;
00504         } 
00505 
00506         private_data->in_use = 1;
00507 
00508         up(&private_data->in_use_critique);
00509 
00510         // debut de section critique (prise de semaphore)       
00511         if( down_interruptible(&private_data->rw_critique) ) {
00512                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00513                 return -ERESTARTSYS;
00514         }
00515 
00516         //tant que le message n'est pas lu en entier ou qu'il n'y a plus rien a lire 
00517         while(total_length < origin_size && NULL != head_element) { 
00518                 current_element = head_element; 
00519 
00520                 // verifie que le buffer a lire est plus petit qu'un bloc
00521                 if (size < current_element->used_bytes) { 
00522                         count = size; 
00523                 } else { // sinon lire la taille du bloc
00524                         count = current_element->used_bytes; 
00525                 } 
00526 
00527                 // lecture de 'count' caracteres de l'element en cours a partir de 'position'
00528                 ret_code = copy_to_user(buffer,
00529                                         current_element->buffer+current_element->position,
00530                                         count); 
00531 
00532                 if (0 != ret_code) { 
00533                         DEBUG && printk(KERN_ALERT "erreur de lecture\n");
00534                         retvalue = -EFAULT; 
00535                         goto ret_read;
00536                 }  
00537 
00538                 DEBUG && printk(KERN_ALERT "lecture de %d octets sur %d\n", (int)count,
00539                                 (int)size); 
00540 
00541                 // mise a jour des pointeurs de buffer et du nombre de caracteres lus
00542                 buffer = buffer + count; 
00543                 size = size - count; 
00544                 total_length = total_length + count; 
00545                 current_element->used_bytes = current_element->used_bytes - count;
00546                 current_element->position = current_element->position + count;
00547                 DEBUG && printk(KERN_ALERT
00548                                 "occupation du noeud %d octets sur %d dans la file %d\n",
00549                                 current_element->used_bytes, BUF_SIZE, private_data->index);
00550 
00551                 //si element vide , desallouer la memoire sauf si c'est le dernier element  
00552                 if(0 == current_element->used_bytes) {
00553                         prev_element = current_element->prev;
00554                         next_element = current_element->next;
00555 
00556                         prev_element->next = next_element;
00557                         next_element->prev = prev_element;
00558 
00559                         if(current_element != current_element->next) {
00560                                 head_element = next_element;
00561                         } else {
00562                                 head_element = NULL;
00563                         }
00564                         
00565                         private_data->head = head_element;
00566  
00567                         kfree(current_element);                 
00568                         current_element = NULL;
00569                 }
00570                 
00571                 // force le reordonnacement du processus
00572                 schedule();
00573         } 
00574         retvalue = total_length;
00575 
00576 ret_read:
00577         // fin de section critique (relachement du semaphore)
00578         up(&private_data->rw_critique);
00579 
00580         if( down_interruptible(&private_data->in_use_critique) ) {
00581                 DEBUG && printk (KERN_ALERT "impossible de prendre le semaphore\n");
00582                 return -ERESTARTSYS;
00583         }
00584         private_data->in_use = 0;
00585         up(&private_data->in_use_critique);
00586 
00587         return retvalue;
00588 } 
00589 
00598 static int dummy_init(void)
00599 {
00600         int result;
00601         int i;
00602 
00603         // allocation dynamique d'un majeur pour le pilote dummy
00604         result = register_chrdev(DUMMY_MAJOR, DeviceName, &dummy_fops);
00605         if (result < 0) {
00606                 DEBUG && printk(KERN_ALERT "majeur %d indisponible\n", result);
00607                 return -ERESTARTSYS;
00608         }
00609         // recuperation du numero de majeur pour la creation des peripheriques
00610         if (0 == dummy_major) {
00611                 dummy_major = result;
00612         }
00613 
00614         // creation des peripheriques
00615         for (i = 0; i < DeviceCount; i++) {
00616                 // mineur pair => ecriture
00617                 devfs_mk_cdev(MKDEV(dummy_major, 2*i), S_IFCHR|S_IRUGO|S_IWUGO, "%s_W%d",
00618                               DeviceName, i);
00619                 DEBUG && printk(KERN_ALERT "%s_R%d cree\n", DeviceName, i);
00620 
00621                 // mineur impair => lecture
00622                 devfs_mk_cdev(MKDEV(dummy_major, 2*i+1), S_IFCHR|S_IRUGO|S_IWUGO, "%s_R%d",
00623                               DeviceName, i);
00624                 DEBUG && printk(KERN_ALERT "%s_W%d cree\n", DeviceName, i);
00625         }
00626 
00627         // allocation memoire du tableau d'etat des fichiers speciaux ouverts
00628         already_opened = kmalloc (DeviceCount*2*sizeof(int), GFP_KERNEL);
00629         if (already_opened == NULL)  {
00630                 DEBUG && printk (KERN_ALERT "allocation ratee");
00631                 return -ERESTARTSYS; 
00632         }
00633 
00634         // allocation memoire du semaphore de protection du tableau d'etat des fichier speciaux ouverts
00635         open_critique = kmalloc (DeviceCount*2*sizeof(struct semaphore), GFP_KERNEL);
00636         if (open_critique == NULL)  {
00637                 DEBUG && printk (KERN_ALERT "allocation ratee");
00638                 kfree(already_opened);
00639                 return -ERESTARTSYS; 
00640         }
00641 
00642         // inutile d'utiliser le semaphore (de protection) pour cette operation car il ne peut pas y avoir d'acces concurrent
00643         // initialisation du tableau d'etat des fichier speciaux ouvrerts et des sempahores de protection
00644         for(i = 0; i < DeviceCount*2 ; i++) {
00645                 already_opened[i] = 0;
00646                 sema_init(&open_critique[i], 1);
00647         }
00648 
00649         // allocation et initialisation des pointeurs sur la structure de pile (un par peripherique)
00650         device_fifo = kmalloc (DeviceCount*sizeof(struct private_dummy), GFP_KERNEL);
00651         if(NULL == device_fifo) {
00652                 DEBUG && printk (KERN_ALERT "allocation ratee");
00653                 kfree(already_opened);
00654                 kfree(open_critique);
00655                 return -ERESTARTSYS; 
00656         }
00657 
00658         for(i = 0; i < DeviceCount; i++) {
00659                 device_fifo[i].index = i;
00660                 device_fifo[i].head  = NULL;
00661                 device_fifo[i].in_use = 0;
00662                 sema_init(&device_fifo[i].in_use_critique, 1);
00663                 sema_init(&device_fifo[i].rw_critique, 1);
00664         }
00665 
00666         DEBUG && printk(KERN_ALERT "module %s charge gerant 2x%d peripheriques\n", DeviceName,
00667                         DeviceCount);
00668 
00669         // Une valeur de retour differente de 0 signifie un echec de init_module et donc du
00670         // chargement du module !
00671         return 0;
00672 }
00673 
00680 static void dummy_cleanup(void)
00681 {
00682         int i = 0;      
00683         int result;
00684         struct element_fifo *tmp_element = NULL;
00685         struct element_fifo *current_element = NULL;
00686 
00687         // liberation de la memoire du semaphore de protection du tableau d'etat des fichier speciaux ouverts
00688         kfree(open_critique);
00689         open_critique = NULL;
00690 
00691         kfree(already_opened);
00692         already_opened = NULL;
00693         
00694         // liberation de la memoire des piles de donnees
00695         for (i = 0; i < DeviceCount; i++) {
00696                 // recuperation de la tete de la pile
00697                 current_element = device_fifo[i].head;
00698                 
00699                 if(NULL != current_element) { //si la tete existe
00700                         // tant qu'il y a au moins une boite en plus de la tete
00701                         while(current_element != current_element->next) { 
00702                                 // positionnement sur l'element suivant
00703                                 tmp_element = current_element->next; 
00704 
00705                                 // suppression de liens de l'element courant
00706                                 tmp_element->prev =  current_element->prev;
00707                                 current_element->prev->next = tmp_element;
00708                                 
00709                                 // suppression de l'element courant
00710                                 kfree(current_element); 
00711                                 current_element = NULL; 
00712 
00713                                 // l'element courant devient l'ancien element suivant
00714                                 current_element = tmp_element; 
00715                                 DEBUG && printk (KERN_ALERT "supression d'un noeud !\n"); 
00716                         }
00717                 
00718                         // suppression du dernier element
00719                         kfree(current_element); 
00720                         current_element = NULL;
00721 
00722                         DEBUG && printk (KERN_ALERT "supression d'un noeud !\n"); 
00723                 }
00724         }
00725 
00726         // liberation de la memoire des pointeurs sur la structure de pile (un par peripherique)
00727         kfree(device_fifo);
00728         device_fifo = NULL;
00729         
00730         // suppression des peripheriques
00731         for (i = 0; i < DeviceCount; i++) {
00732                 devfs_remove("%s_R%d", DeviceName, i);
00733                 DEBUG && printk(KERN_ALERT "%s_R%d supprime\n", DeviceName, i);
00734         
00735                 devfs_remove("%s_W%d", DeviceName, i);
00736                 DEBUG && printk(KERN_ALERT "%s_W%d supprime\n", DeviceName, i);
00737         }
00738 
00739         // desenregistrement du pilote au niveau du noyau
00740         result = unregister_chrdev(dummy_major, "dummy"); 
00741         if (result < 0) {
00742                 DEBUG && printk (KERN_ALERT "desenregistrement %d rate\n", dummy_major); 
00743                 return; 
00744         } 
00745 
00746         DEBUG && printk(KERN_ALERT "dummy decharge\n");
00747 }
00748 
00749 module_init(dummy_init);
00750 module_exit(dummy_cleanup);
00751 
00752 MODULE_PARM (DeviceCount, "i");
00753 MODULE_PARM (DeviceName, "s");