Ce chapitre présente les concepts nécessaires à l'installation de cartes filles additionnelles et à la configuration des périphériques complémentaires sous Linux. La procédure d'installation des disques durs, graveurs, cartes son, cartes graphiques, cartes vidéo et cartes réseau sera donc décrite, ainsi que la manière de les configurer pour obtenir un fonctionnement correct sous Linux.
Comme il l'a déjà été expliqué dans les chapitres précédents, Linux gère tous les périphériques comme des fichiers spéciaux. De plus, la plupart des gestionnaires de périphériques peuvent être chargés dynamiquement, sous la forme de modules du noyau. Cette section présentera donc les notions de base concernant les fichiers spéciaux de périphériques, les modules du noyau ainsi que leurs rôles respectifs dans la configuration d'un nouveau matériel.
La notion de fichier spécial de périphérique simplifie énormément l'utilisation du matériel par les programmes d'application, puisque la plupart des opérations sur un périphérique reviennent simplement à réaliser une écriture ou une lecture. Évidemment, l'écriture sur un fichier spécial de disque permet d'enregistrer les données sur ce disque, et la lecture permet de les récupérer. Mais cela ne s'arrête pas là ! Par exemple, la communication avec le modem se fait simplement en écrivant et en lisant les données sur le fichier spécial du port série sur lequel le modem est connecté. De même, jouer un fichier son revient simplement à l'écrire dans le fichier spécial qui gère la carte son. Il est même possible d'accéder à la mémoire vidéo par l'intermédiaire d'un fichier spécial de périphérique...
Bien entendu, certaines fonctionnalités avancées des périphériques ne peuvent pas être accédées simplement par une une écriture ou une lecture dans un fichier spécial. Le système fournit donc aux applications d'autres moyens d'accéder à ces fonctionnalités, par l'intermédiaire d'appels systèmes spécifiques (pour ceux qui sont intéressés par la programmation système, cet appel système est réalisé par la fonction ioctl, dont le nom provient de l'abréviation de l'anglais « Input / Output ConTroL »). Évidemment, cette méthode n'est utilisée que par les programmes qui connaissent bien le fonctionnement du gestionnaire du périphériques, car ils doivent spécifier une requête que seul ce gestionnaire comprend en général. Quoi qu'il en soit, les requêtes de ce type utilisent elles aussi un descripteur de fichier spécial de périphérique, ce qui fait que tous les accès au matériel ont lieu par l'intermédiaire de ces fichiers.
Il existe deux principaux types de fichiers spéciaux de périphériques. Le premier type correspond aux périphériques de type bloc, dont les données ne peuvent être lues que par blocs (c'est le cas des disques durs, des lecteurs de CD et de disquettes en particulier). Le deuxième type correspond aux périphériques de type caractère, dont les données peuvent être lues caractère par caractère (cartes son, ports série, etc.). En plus de son type, chaque fichier spécial de périphérique est caractérisé par deux codes permettant d'identifier le type et le modèle du périphérique auquel il donne accès. Ces deux codes portent le nom de code majeur et de code mineur. Comme nous le verrons plus tard, c'est par l'intermédiaire de ces codes que le noyau est capable de retrouver le gestionnaire de périphériques à utiliser pour satisfaire aux requêtes des clients qui accèdent à un fichier spécial de périphérique. Il y a donc, en général, une association unique entre ces codes et les gestionnaires de périphériques. La liste des codes majeurs et mineurs déjà affectés à des périphériques est donnée dans le fichier /usr/src/linux/Documentation/devices.txt (ce fichier vous donnera donc une idée des périphériques qui peuvent être ou qui seront gérés par Linux).
Les fichiers spéciaux de périphériques sont tous stockés dans le répertoire /dev/. En général, ce répertoire contient un grand nombre de fichiers spéciaux de périphériques, même pour des périphériques inexistants sur votre machine. Ces fichiers sont installés automatiquement par les distributions, qui laissent au noyau le soin de signaler que le périphérique est absent lorsqu'un programme tente d'accéder à un fichier spécial auquel aucun matériel ne correspond. Les fichiers fournis par les distributions sont donc, en théorie, susceptibles de couvrir toutes les gammes de périphériques courants, et vous n'aurez pas à toucher au répertoire /dev/. Cependant, si vous devez créer un fichier spécial de périphérique vous-même, vous devrez utiliser la commande mknod. Sa syntaxe est relativement simple :
mknod fichier type majeur mineuroù fichier est le nom du fichier spécial de périphérique à créer, type est une lettre indiquant le type du fichier spécial ('c' pour les fichiers de type caractère et 'b' pour les fichiers de type bloc), et majeur et mineur sont les codes majeur et mineur du périphérique.
Depuis la version 2.4.0 du noyau, il est également possible que le répertoire /dev/ contienne un système de fichiers virtuel, géré par le noyau. Ce système de fichiers est peuplé automatiquement par le noyau avec les fichiers spéciaux de périphériques de tous les périphériques détectés lors de l'initialisation du système. Cette technique permet de résoudre plusieurs problèmes concernant les fichiers spéciaux de périphériques. Le plus évident pour l'utilisateur est que seuls les fichiers spéciaux des périphériques effectivement présents apparaissent dans le répertoire /dev/, ce qui élimine la présence de tous les fichiers spéciaux inutiles.
Le gros avantage du système de fichiers virtuel /dev/ est que les fichiers spéciaux sont créés par les gestionnaires de périphériques eux-mêmes. Cela implique que l'association entre les fichiers spéciaux et les gestionnaires de périphériques du noyau qui en ont la charge est directe, et ne nécessite plus d'utiliser les codes majeurs et mineurs. Cela a plusieurs conséquences :
il n'y a plus besoin d'avoir recours à une autorité centrale pour obtenir les valeurs de codes mineurs et majeurs. Les fichiers spéciaux de périphériques continuent d'avoir des codes majeurs et mineurs bien qu'ils ne soient plus nécessaires, mais les valeurs de ces codes sont attribuées dynamiquement de manière unique par le noyau lorsque les gestionnaires de périphériques s'initialisent. Il n'y a donc plus de risques de conflit entre deux périphériques ;
la limitation du nombre de périphériques due au nombre limité de codes majeurs et mineurs n'existe plus (il suffit de consulter la liste du fichier /usr/src/linux/Documentation/devices.txt pour constater qu'il reste peu de codes libres pour les périphériques à venir) ;
les performances sont supérieures, puisque la recherche du gestionnaire de périphériques associé à un fichier spécial de périphérique n'a plus lieu ;
la configuration du système en est simplifiée.
Par ailleurs, le système de fichiers virtuel est beaucoup plus structuré que le répertoire /dev/ classique, car les fichiers spéciaux de périphériques sont classés par type et par nature. Ce système de fichiers constitue donc une image logique et cohérente de l'architecture matérielle de l'ordinateur. Ainsi, la recherche d'un périphérique est beaucoup plus facile. En revanche, les chemins sur les fichiers spéciaux de périphériques sont nettement plus longs que les chemins classiques. Par exemple, le fichier spécial de périphérique /dev/hda1 permettant d'accéder à la première partition du premier disque IDE sera accessible avec le chemin /dev/ide/host0/bus0/target0/lun0/part1 dans le système de fichiers virtuel.
Ce changement dans la structure du répertoire /dev/ est un changement de taille, propre à empêcher la plupart des applications système de fonctionner normalement. C'est pour résoudre ce problème que le démon devfsd a été écrit. Ce démon, s'il est lancé juste après que le système de fichiers virtuel a été créé (donc, en pratique, dans les premiers scripts de démarrage du système), surveille la création des fichiers spéciaux de périphériques dans le système de fichiers virtuel et permet ainsi d'effectuer des actions spécifiques lorsqu'un gestionnaire de périphériques s'enregistre ou se décharge du noyau. Les actions à effectuer sont spécifiées dans le fichier de configuration /etc/devfsd.conf. Par défaut, le démon devfsd crée des liens symboliques portant les noms des anciens fichiers spéciaux de périphériques vers les fichiers du système de fichiers virtuel. Ainsi, les anciennes applications peuvent continuer à utiliser les anciens noms de fichiers spéciaux pour accéder aux périphériques. La suite de ce document utilisera donc les noms de fichiers spéciaux de périphériques classiques. Vous devrez faire la transcription pour toutes les commandes manipulant les périphériques si vous utilisez le système de fichiers virtuel avec sa nouvelle structure.
Note : Un démon est un processus qui tourne en arrière plan dans le système. Les démons fonctionnent souvent dans le compte root et offrent des services de base que les autres programmes utilisent. Le terme « démon » provient de la traduction littérale « daemon », ce qui signifie « ange » en réalité. Le démon se place donc en tant qu'intermédiaire entre Dieu (c'est-à-dire le noyau) et les hommes (c'est-à-dire les applications normales). Le terme « daemon » a été ensuite éclairci et défini comme l'acronyme de l'anglais « Disk And Execution MONitor ».
Même si votre distribution utilise le système de fichiers virtuel /dev/, il se peut que vous ayez à créer des fichiers spéciaux manuellement. Cela peut être nécessaire pour créer un fichier spécial de périphérique pour un gestionnaire qui ne gère pas encore le système de fichiers virtuel /dev/. La syntaxe à utiliser est strictement la même que dans le cas des fichiers spéciaux classiques.
Je vous invite à consulter la page de manuel de la commande mknod si vous devez créer vous-même un fichier spécial de périphérique. Ce ne sera normalement pas nécessaire. Vous pouvez également obtenir de plus amples informations sur le démon devfsd et son fichier de configuration dans la page de manuel devfsd.
Les modules du noyau sont des bibliothèques que l'on peut charger dans le noyau lorsque celui-ci a besoin d'une certaine fonctionnalité. Une fois chargés, les modules font partie intégrante du noyau et ajoutent leurs fonctions à celles existantes. Ces bibliothèques sont normalement stockées dans le répertoire /lib/modules/version/, où version est le numéro de version du noyau pour lequel ces modules ont été créés. Beaucoup de fonctionnalités du noyau peuvent être configurées pour être utilisées sous la forme de modules. Certains pilotes ne fonctionnent que sous la forme de modules, aussi faut-il savoir les manipuler.
Les modules peuvent être chargés manuellement à l'aide des commandes insmod et modprobe. modprobe est un peu plus évoluée, car elle gère les dépendances entre les modules et est capable de charger les modules utilisés par le module demandé. Leur utilisation est des plus simple :
insmod moduleou :
modprobe moduleoù module est le nom du module à charger.
En réalité, la commande modprobe appelle la commande insmod pour chaque module qui doit être chargé, dans l'ordre des dépendances des modules. De cette manière, chaque module peut être chargé sans problèmes, car toutes les fonctionnalités qu'il utilise sont déjà présentes dans le noyau lors de son chargement. La commande modprobe va chercher les informations de dépendances dans le fichier modules.dep, situé dans le répertoire /lib/module/version/. Ce fichier utilise une syntaxe très simple, et spécifie pour chaque module les modules dont il dépend. Bien qu'il puisse parfaitement être écrit à la main, cela nécessiterait d'avoir une connaissance approfondie des modules du noyau. C'est donc pour cela que l'outil depmod a été écrit. Cet outil permet de générer le fichier modules.dep automatiquement, pourvu qu'on l'appelle avec l'option -a en ligne de commande :
Il faudra donc appeler cette commande après chaque installation ou suppression de module dans le système.La liste de modules qui ont été chargés peut être obtenue aisément avec la commande lsmod :
Enfin, la commande rmmod permet de décharger un module, avec la ligne de commande suivante :
La plupart des modules peuvent prendre un certain nombre d'options lors de leur chargement. Ces options sont en quelque sorte l'équivalent des options que l'on communique au noyau lors de l'amorçage, pour préciser par exemple la configuration matérielle utilisée. Toutes ces options sont définies dans le fichier de configuration/etc/modules.conf. Lors du chargement d'un module, modprobe consulte ce fichier et passe les paramètres indiqués au module à charger.
Les options des modules sont spécifiées dans le fichier module.conf à l'aide du mot clé option, suivi du nom du module pour lequel ces options sont définies, lui-même suivi des paramètres de chargement du module. La syntaxe est donc la suivante :
option module paramètresLa liste des paramètres que l'on peut passer à un module dépend bien évidemment du module. Nous verrons par la suite des exemples de passage de paramètres pour les modules les plus courant.
Le fichier module.conf permet également de définir des opérations complémentaires qui doivent être effectuées lors du chargement et du déchargement d'un module. Ces opérations sont introduites par les mots clés pre-install, post-install, pre-remove ou post-remove. Selon le mot clé utilisé, elles sont exécutées respectivement avant et après le chargement du module, et avant et après son déchargement. Ces quatre mots clés utilisent tous la même syntaxe :
xxx-install module opérationoù xxx-install est le mot clé indiquant les conditions d'application de l'opération, module est le nom du module pour lequel une opération complémentaire doit être effectuée, et opération est la ligne de commande de l'opération en question.
Ainsi, si le port parallèle est utilisé pour accéder à un périphérique nécessitant une opération d'initialisation quelconque, celle-ci peut être exécutée après le chargement du module à l'aide du mot clé post-install :
(en supposant que la commande initperiph permet d'initialiser le périphérique en question). Évidemment, ce type d'opération dépend du matériel connecté sur le port parallèle, mais le principe est là.Dans la plupart des cas, ces options sont facultatives, car modprobe utilise un jeu de valeurs par défaut qui permettent d'utiliser les modules même si le fichier de configuration modules.conf est absent. Vous pouvez visualiser ces options en renommant le fichier de configuration modules.conf et en tapant la commande suivante :
Cette commande vous permettra également de recréer un nouveau fichier de configuration si d'aventure vous perdiez celui fourni avec votre distribution.
Il n'est normalement pas nécessaire d'utiliser ces commandes pour charger les modules. En effet, il est possible de faire en sorte que les modules soient chargés à la demande, lorsqu'une de leurs fonctionnalités est demandée au niveau du noyau. Pour cela, le noyau utilise lui-même la commande modprobe pour charger les modules, ce qui assure la gestion correcte des dépendances entre les modules. À chaque fois que le noyau a besoin d'une fonctionnalité qui n'est pas encore chargée, il effectue une requête à modprobe en lui demandant de charger le module manquant.
Le nom du module dont le noyau demande le chargement à modprobe dépend évidemment de la fonctionnalité demandée et ne correspond pas forcément à un nom de module existant. modprobe doit donc faire la correspondance entre le nom de module demandé par le noyau et le nom d'un module réel. C'est encore une fois dans le fichier de configuration /etc/modules.conf que cette correspondance est stockée. Par exemple, lorsque le noyau désire accéder au port parallèle, il utilise la commande suivante :
où parport_lowlevel est le nom que le noyau utilise pour référencer le port parallèle. Ce nom est identique quelle que soit la plate-forme sur laquelle le noyau fonctionne, qu'il s'agisse d'un PC, d'un Mac ou d'une station de travail Sun. Sur les ordinateurs dont l'architecture est de type PC, le véritable module à utiliser est le module parport_pc. Il faut donc donner indiquer l'association entre les noms parport_lowlevel et parport_pc dans le fichier modules.conf.Cette association est réalisée par la définition d'un certain nombre d'alias de modules réels. Chaque alias est introduit par le mot clé alias, dont la syntaxe est donnée ci-dessous :
alias nom moduleoù nom est le nom de l'alias, et module est le nom du module réel. Lorsque la commande modprobe est appelée avec le nom d'un alias en paramètre, elle commence par rechercher le nom du module réel dans le fichier modules.conf, puis elle le charge en mémoire. Pour le port parallèle, on aura donc la définition suivante dans le fichier modules.conf :
L'option -k passée en paramètre à modprobe par le noyau n'est quant à elle utilisée que par le noyau. Elle permet de marquer le module comme étant automatiquement déchargeable, lorsque plus personne n'utilisera ses fonctionnalités. Cette technique permet de minimiser la consommation mémoire du noyau sur les machines dont les ressources sont très limitées. Les modules qui sont chargés automatiquement par le noyau sont en effet marqués comme étant automatiquement déchargeables, et on peut effectivement les supprimer à l'aide de la commande suivante :
Cette commande décharge les modules inutilisés automatiquement, dans l'ordre inverse de leur chargement. Cette commande respecte donc les dépendances entre modules, et seuls les modules inutilisés sont réellement déchargés. Il est recommandé de placer cette commande dans le fichier /etc/crontab de votre système, afin que les modules inutilisés soient déchargés à intervalle de temps régulier. Vous aurez donc sans doute à placer une ligne telle que celle-ci : dans votre fichier /etc/crontab. Le déchargement des modules inutilisés aura lieu toutes les deux minutes.Vous pouvez constater que le mécanisme d'alias permet de rendre le noyau indépendant des modules utilisés, puisque l'association entre le nom du module utilisé par le noyau et le module réel et ses paramètres est maintenu dans le fichier de configuration modules.conf. L'inconvénient de cette méthode est en revanche qu'il faut connaître les noms de modules utilisés par le noyau. Ces noms sont assez variables et dépendent de la fonctionnalité demandée. Toutefois, les noms utilisés par le noyau peuvent facilement être déterminés pour les modules gérant les fichiers spéciaux de périphériques. En effet, il est possible de construire un nom unique pour chaque fichier spécial de périphérique, qui pourra être utilisé par le noyau pour spécifier le module capable de gérer les fonctionnalités de ce fichier. La manière de construire ces noms varie selon que le fichier spécial de périphérique accédé, et selon qu'il s'agit d'un fichier réel ou d'un fichier du système de fichiers virtuel /dev/ du noyau.
S'il s'agit d'un vrai fichier spécial de périphérique, il est parfaitement identifié par sa nature (disque, périphérique de type caractère, interface réseau...) et ses deux codes majeur et mineur. Le noyau peut donc construire un nom à partir de ces informations. Ainsi, pour un fichier spécial de périphérique de type caractère, le nom généré par le noyau est en général de la forme « char-major-xxxx ». Pour les périphériques de type bloc, il est de la forme « block-major-xxxx ». Les caractères xxxx identifient le code majeur de ce périphérique, plus rarement son code mineur. Par exemple, pour les cartes son, le nom de module char-major-14 sera utilisé, parce que les cartes sons utilisent toutes le code majeur 14. Le code mineur n'est actuellement pas utilisé pour les cartes son.
Même si les noms de modules sont toujours construit plus ou moins selon ce schéma pour les fichiers spéciaux de périphériques réels, il reste difficile de déterminer le nom exact du module associé à un fichier spécial de périphérique. Par exemple, nous avons vu que le nom de module utilisé pour le port parallèle (accessible via le fichier spécial de périphérique /dev/lp0) est parport_lowlevel. De même, le nom utilisé pour les interfaces réseau de type Ethernet est eth0, eth1, etc. Il n'est donc pas toujours évident de savoir quel est le nom que le noyau utilisera. Le plus simple dans ce cas est encore de regarder dans la configuration utilisée par modprobe à l'aide de son option -c.
En revanche, si le fichier spécial de périphérique est un fichier virtuel, le mécanisme de nommage est complètement différent. En effet, le système de fichiers virtuel /dev/ crée les fichiers spéciaux de périphériques à la demande, lorsque les gestionnaires de périphériques s'enregistrent au niveau du noyau. Il n'est donc pas possible de déterminer les codes majeurs et mineurs des fichiers spéciaux de périphériques si les modules qui les gèrent ne sont pas chargés, parce que ces fichiers n'existent pas encore d'une part, et parce que ces codes sont déterminés dynamiquement et ne sont donc jamais fixes d'autre part.
Le chargement des modules à la demande est en fait réalisé par le démon devfsd, que nous avons déjà décrit dans la Section 8.1.1. Outre la création des liens symboliques permettant d'accéder aux fichiers spéciaux de périphériques sous leur nom classique, ce démon est capable d'effectuer des actions diverses lorsqu'un événement se produit dans le système de fichiers virtuel /dev/. Toutes ces actions sont décrites dans le fichier de configuration /etc/devfsd.conf. En particulier, il est possible d'effectuer une action lorsqu'un programme recherche un fichier spécial de périphérique dans le système de fichiers, chose que tous les programmes qui utilisent les fichiers spéciaux de périphériques font, ne serait-ce que pour pouvoir les ouvrir. C'est lors de cette recherche que le démon devfsd va demander le chargement du module correspondant au fichier spécial de périphérique demandé.
Pour que ce mécanisme fonctionne, il faut avant tout l'activer. Cela se fait simplement en ajoutant la ligne suivante dans le fichier devfsd.conf :
qui signifie que le chargement dynamique de module (action « MODLOAD ») doit être effectuée lorsqu'une recherche (événement « LOOKUP ») a lieu dans le système de fichiers virtuel /dev/, et ce pour n'importe quel nom de fichiers spécial de périphérique (expression réguière « .* », qui représente n'importe quelle séquence de caractères).Bien entendu, les noms de module utilisés par le démon devfsd ne peuvent pas se baser sur les codes majeur et mineur du fichier spécial de périphérique pour les raisons que l'on a indiqué ci-dessus. Mais pourquoi faire compliqué quand on peut faire simple ? Le démon devfsd ne s'embarrasse pas de détails, et demande tout simplement le chargement du module dont le nom est exactement le chemin du fichier spécial de périphérique recherché ! Il suffit donc tout simplement de définir les alias correspondant dans le fichier modules.conf pour éventuellement trouver le bon nom de module à charger.
En fait, le démon devfsd utilise un autre fichier de configuration, le fichier /etc/modules.devfs, afin de simplifier l'écriture du fichier modules.conf. Ce fichier lui permet d'associer un ensemble de noms de fichiers spéciaux de périphériques à un seul module. Par exemple, tous les ports série d'une machine utilisent, en général, le même gestionnaire, bien qu'ils soient accessibles par l'intermédiaire des fichiers spéciaux de périphériques /dev/ttySn, où n est le numéro du port série (0 pour le port COM1, 1 pour le port COM2, etc.). Le fichier modules.devfs regroupe donc tous les noms de modules /dev/ttyS* en un seul nom de module, à savoir serial. C'est donc ce nom là qui sera communiqué à modprobe pour le chargement du module de gestion des ports série.
De manière générale, vous n'aurez pas à modifier les fichiers devfsd.conf et modules.devfs, car ceux fournis avec les distributions conviennent parfaitement. En revanche, vous modifierez certainement le fichier modules.conf. Il s'agit là d'un opération délicate, car elle nécessite de bien connaître les mécanismes de nommage utilisés par le noyau, les noms des modules réels et leurs paramètres de configuration. En général, vous trouverez les informations sur les entrées à ajouter ou à modifier dans le fichier d'aide du module correspondant, que vous pourrez trouver dans les sources du noyau (dans le répertoire /usr/src/linux/Documentation/).
Quoi qu'il en soit, la modification de modules.conf peut générer de nouvelles dépendances entre les modules. Il est donc nécessaire d'exécuter la commande depmod -a après chaque modification de ce fichier.