#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") |
|
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
|
|
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.
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 !
|
|
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.
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
|
|
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.
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
|
|
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.
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
|
|
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.
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
|
|
|
|
|
|
|
|
|