original in en Dr. B. Thangaraju
en to fr Guy Passemard
Le principal souci du d�veloppeur de pilote de p�riph�rique est l'allocation des ressources. Ces ressources sont les ports d'entr�e/sortie, la m�moire et la gestion des interruptions (IRQ). Cet article essaie d'expliquer les notions fondamentales du sous-syst�me de gestion des entr�es/sorties et l'importance de l'allocation des ressources aux ports d'entr�es/sorties. Cet article distingue clairement les �tapes de contr�les, d'affectation et de lib�ration des adresses de ports de p�riph�riques.
Les �lements mat�riel de base d'un ordinateur, tels que les ports, les bus et les contr�leurs, permettent de connecter la plupart des p�riph�riques d'E/S. Les pilotes de p�riph�riques offrent un acc�s uniformis� au sous-syst�me d'E/S, comparable aux appels syst�me qui proposent une interface standard entre les applications et le syst�me d'exploitation. Ainsi de nombreux p�riph�riques sont reli�s � l'ordinateur : par exemple, les dispositifs de stockage tels que les unit�s de disques, de bandes, les CD-ROM, et les disquettes, ou les interfaces avec l'utilisateur comme le clavier, la souris et l'�cran, sans oublier le mat�riel de communication comme les cartes r�seau et les modems. Malgr� la vari�t� des p�riph�riques propos�s, nous avons seulement besoin de comprendre quelques principes g�n�raux sur leur connexion et sur la mani�re dont le logiciel contr�le le mat�riel.
Un p�riph�rique est compos� de deux parties : l'une �lectronique appel�e contr�leur de p�riph�rique, et l'autre qui est m�canique. Le contr�leur communique avec l'ordinateur � travers le bus syst�me. Habituellement, un groupe d'adresses de ports (sans conflit) est affect� � chaque contr�leur. Les ports d'entr�e/sortie utilisent quatre jeux de registres nomm�s "status", "control", "data-in", "data-out". A la lecture des bits contenus dans le registre "status", l'ordinateur sait : si la commande en cours est termin�e, si un octet est pr�t � �tre lu ou �crit, ou s'il y a erreur. Le registre "control" est mis � jour par l'h�te lors du lancement d'une commande ou lors du changement de mode du p�riph�rique. Le syst�me peut acc�der aux donn�es gr�ce au registre "data-in" pour les entr�es et inversement en sortie avec le registre "data-out".
Donc, l'interface de base, entre le processeur et le p�riph�rique, est un ensemble de registres de contr�le et d'�tats. Quand le processeur ex�cute un programme et qu'il rencontre une instruction relative � un p�riph�rique, il ex�cute l'instruction en lan�ant une commande destin�e au p�riph�rique appropri�. Le contr�leur traite l'action demand�e et positionne les bits correspondants dans le registre "status" et attend. C'est le processeur qui doit v�rifier l'�tat du p�riph�rique jusqu'� la fin de l'op�ration. Par exemple, le pilote du port parall�le (utilis� par une imprimante) va p�riodiquement scruter l'�tat de l'imprimante pour v�rifier qu'elle est pr�te � recevoir des donn�es sinon il se mettra en attente laissant le processeur libre pour effectuer d'autres t�ches et recommencera jusqu'� ce que l'imprimante soit pr�te. Ce m�canisme de scrutation am�liore les performances et �vite au syst�me d'attendre inutilement l'activation du p�riph�rique sans rien faire d'autre.
Les registres ont des adresses fixes d�finies dans l'espace d'E/S. G�n�ralement celles-ci sont affect�es au d�marrage du syst�me, en fonction des param�tres d�finis dans un fichier de configuration d'installation du syst�me, ainsi une plage d'adresses peut �tre allou�e � chaque p�riph�rique statique. Le noyau contient donc les pilotes des p�riph�riques pr�sents et les plages d'adresses E/S de ports d'E/S peuvent �tre stock�es dans le r�pertoire proc. Vous pouvez v�rifier les plages d'adresses de ports des p�riph�riques pr�sents sur votre syst�me avec la commande $cat /proc/interrupts. La premi�re colonne affich�e indique la plage d'adresses des ports et la seconde le p�riph�rique propri�taire des ports. Certains OS sont capables de charger dynamiquement les pilotes en cours de fonctionnement du syst�me. Ainsi tout nouveau p�riph�rique peut �tre reconnu par le syst�me et contr�l� ou acc�d� par le module du pilote dynamiquement charg�.
Le concept de pilote de p�riph�rique est relativement abstrait, et il se situe au plus bas niveau du logiciel fonctionnant sur un ordinateur, puisqu'il est directement li� aux caract�ristiques mat�rielles du p�riph�rique . Un pilote ne g�re qu'un seul type de p�riph�rique. Ce type peut �tre caract�re, bloc ou r�seau. Si une application appelle un p�riph�rique, le noyau contacte le pilote de ce p�riph�rique. Le pilote envoie alors une commande � ce p�riph�rique. Le pilote n'est qu'une collection de fonctions avec de nombreux points d'entr�e comme open, close, read, write, ioctl, llseek, etc. Quand vous ins�rer un module la fonction "init_module()" est appel�e et lorsque le module est retir� c'est la fonction "cleanup_module()" qui est execut�e. Le p�riph�rique est enregistr� dans un pilote de la routine "init_module".
Un fois le p�riph�rique enregistr� dans init_module(), ses ressources telles que les ports E/S, la m�moire et les niveaux d'IRQ sont allou�s dans la fonction m�me, afin de permettre un fonctionnement correct du pilote. Si une adresse erron�e est allou�e, le noyau envoie un message segmentation fault. Par contre, dans le cas des ports E/S, le noyau n'enverra pas de message comme wrong I/O port. Pourtant, assigner des ports d�j� utilis�s par des p�riph�riques existants fera "tomber" le syst�me. Lorsque vous retirez le module, le p�riph�rique ne doit plus �tre enregistr�, c'est-�-dire que le nombre majeur redevient disponible et que les ressources sont lib�r�es dans la fonction clean_up module ( ).
Le travail le plus fr�quemment execut� par un pilote de p�riph�rique est la lecture et l'�criture sur les ports d'E/S. Ainsi il faut s'assurer que pour le pilote, l'usage des adresses de ports soit exclusif. Aucun autre p�riph�rique ne doit utiliser cette plage d'adresses. Pour en �tre certain le premier pilote devra v�rifier si l'adresse est disponible ou non. Lorsque le pilote constate que l'adresse est inutilis�e, il demande au noyau d'assigner la plage d'adresses � son p�riph�rique.
int check_region (unsigned long start, unsigned long len);
La fonction renvoie z�ro si la plage d'adresses est disponible, sinon un nombre n�gatif ou un code erreur ( -EBUSY ou -EINVAL). La fonction accepte deux arguments : start est l'adresse de d�part d'une plage de ports, len est le nombre de ports dans la plage.Une fois le port disponible, il doit �tre allou� au p�riph�rique par la fonction request_region.
struct resource *request_region (unsigned long start, unsigned long len, char *name);
Les deux premiers arguments sont les m�mes que ceux vus pr�c�demment, le pointeur de la variable caract�re name sert � d�finir le nom du p�riph�rique auquel l'adresse du port est allou�e. La fonction renvoie le type de pointeur � la structure "resource". Cette structure permet de d�crire l'�tendue des ressources et elle est d�clar�e dans le fichier <linux/ioport.h>. Voici la syntaxe de la structure :struct resource { const char *name; unsigned long start, end; unsigned long flags; struct resource *parent, *sibiling, *child; };Lorsqu'un module est retir� du noyau, le port doit �tre lib�r� pour pouvoir �tre utilis� par d'autres p�riph�riques. Pour cela il faut utiliser la fonction release_region ( ) dans cleanup_module ( ). La syntaxe de la fonction est :
void release_region ( unsigned long start, unsigned long len);
Les arguments de cette fonction sont les m�mes que pr�c�demment. Il faut savoir que ces trois fonctions sont en fait des macros d�clar�es dans le fichier <linux/ioport.h>.#include <linux/fs.h.> #include <linux/ioport.h.> struct file_operations fops; unsigned long start, len; int init_module (void) { int status; start = 0xff90; len = 0x90; register_chrdev(254,"your_device",&fops); status = check_region (start, len); if (status == 0) { printk ("The ports are available in that range\n"); request_region(start,len,"your_device"); } else { printk ("The ports are already in use. Try other range.\n"); return (status); } return 0; } void cleanup_module (void) { release_region(start, len); printk ("ports are freed successfully\n"); unregister_chrdev(254,"your_device");} printk (" your device is unregistered\n"); }
__u8 inb (unsigned int port);
void outb (__u8 data, unsigned int port);
__u16 inw (unsigned int port);
void outw(__u16 data, unsigned int port);
__u32 inl (unsigned int prot);
void outl (__u32 data, unsigned int port);
void insb(unsigned int port, void *addr, unsigned long
count);
void outsb(unsigned int port, void *addr, unsigned long
count);
void insw(unsigned int port, void *addr, unsigned long
count);
void outsw(unsigned int port, void *addr, unsigned long
count);
void insl(unsigned int port, void *addr, unsigned long
count);
void outsl(unsigned int port, void *addr, unsigned long
count);