doc/fr_FR.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml
2003-01-12 12:16:07 +00:00

383 lines
14 KiB
Text

<!--
The FreeBSD Documentation Project
The FreeBSD French Documentation Project
$FreeBSD$
$Id: chapter.sgml,v 1.2 2003-01-12 12:16:07 blackend Exp $
Original revision: 1.5
-->
<chapter id="driverbasics">
<title>Ecrire des pilotes de p&#233;riph&#233;riques pour FreeBSD</title>
<para>Ce chap&icirc;tre a &eacute;t&eacute; &eacute;crit par &a.murray; avec des s&eacute;lections
depuis une vari&eacute;t&eacute; de codes source inclus dans la page de manuel d'&man.intro.4; de Joerg
Wunsch.</para>
<sect1>
<title>Introduction</title>
<para>Ce chap&icirc;tre fournit une br&ecirc;ve introduction sur l'&eacute;criture
de pilotes de p&eacute;riph&eacute;riques pour FreeBSD.
Un p&eacute;riph&eacute;rique, dans ce contexte, est un terme utilis&eacute;
le plus souvent pour tout ce qui est li&eacute; au mat&eacute;riel et qui d&eacute;pend
du syst&egrave;me, comme les disques, imprimantes, ou un &eacute;cran avec son clavier.
Un pilote de p&eacute;riph&eacute;rique est un composant logiciel du syst&egrave;me
d'exploitation qui contr&ocirc;le un p&eacute;riph&eacute;rique sp&eacute;cifique. Il y a aussi
ce que l'on apelle les pseudo-p&eacute;riph&eacute;riques (&ldquo;pseudo-devices&rdquo;) o&ugrave; un pilote
de p&eacute;riph&eacute;rique &eacute;mule le comportement d'un p&eacute;riph&eacute;rique dans un logiciel sans
mat&eacute;riel particulier sous-jacent. Les pilotes de p&eacute;riph&eacute;riques peuvent &ecirc;tre compil&eacute;s
dans le yst&egrave;me statiquement ou charg&eacute; &agrave; la demande via l'&eacute;diteur de liens dynamique du
noyau &ldquo;kld&rdquo;.</para>
<para>La plupart des p&eacute;riph&eacute;riques dans un syst&egrave;me d'exploitation de type Unix
sont accessibles au travers de fichiers sp&eacute;ciaux de p&eacute;riph&eacute;rique (device-nodes), appel&eacute;s parfois
fichiers sp&eacute;ciaux. Ces fichiers sont habituellement stock&eacute;s dans le r&eacute;pertoire
<filename>/dev</filename> de la hi&eacute;rarchie du syst&egrave;me de fichiers. Jusqu'&agrave; ce que
devfs soit totalement int&eacute;gr&eacute; dans FreeBSD, chaque fichier sp&eacute;cial de p&eacute;riph&eacute;rique doit &ecirc;tre
cr&eacute;&eacute; statiquement et ind&eacute;pendamment de l'existence du pilote de p&eacute;riph&eacute;rique associ&eacute;.
La plupart des fichiers sp&eacute;ciaux de p&eacute;riph&eacute;rique du syst&egrave;me sont cr&eacute;&eacute;s en ex&eacute;cutant <command>MAKEDEV</command>.</para>
<para>Les pilotes de p&eacute;riph&eacute;rique peuvent &ecirc;tre en gros s&eacute;par&eacute;s en deux cat&eacute;gories;
les pilotes de p&eacute;riph&eacute;rique en mode caract&egrave;re et les pilotes de p&eacute;riph&eacute;riques r&eacute;seau.</para>
</sect1>
<sect1>
<title>L'&#233;diteur de liens dynamiques du noyau - KLD</title>
<!-- Traduction &agrave; v&eacute;rifier
Dynamic Kernel Linker Facility - KLD</title> -->
<para>L'interface kld permet aux administrateurs syst&egrave;me d'ajouter
et d'enlever dynamiquement une fonctionnalit&eacute; &agrave; un syst&egrave;me en marche.
Cela permet aux d&eacute;veloppeurs de pilote de p&eacute;riph&eacute;rique de charger leurs nouveaux changements
dans le noyau en fonctionnement sans red&eacute;marrer constamment pour tester ces derniers.
</para>
<para>L'interface kld est utilis&eacute; au travers des commandes d'administrateur suivantes :
<itemizedlist>
<listitem><simpara><command>kldload</command> - charge un nouveau module dans le noyau</simpara></listitem>
<listitem><simpara><command>kldunload</command> - d&eacute;charge un module du noyau</simpara></listitem>
<listitem><simpara><command>kldstat</command> - liste les modules charg&eacute;s dans le noyau</simpara></listitem>
</itemizedlist>
</para>
<para>Structure squelettique d'un module de noyau</para>
<programlisting>/*
* Squelette KLD
* Inspir&eacute; de l'article d'Andrew Reiter paru sur Daemonnews
*/
#include &lt;sys/types.h&gt;
#include &lt;sys/module.h&gt;
#include &lt;sys/systm.h&gt; /* uprintf */
#include &lt;sys/errno.h&gt;
#include &lt;sys/param.h&gt; /* defines utilise dans kernel.h */
#include &lt;sys/kernel.h&gt; /* types utilise dans le module d'initialisation */
/*
* charge le gestionnaire quit traite du chargement et d&eacute;chargement d'un KLD.
*/
static int
skel_loader(struct module *m, int what, void *arg)
{
int err = 0;
switch (what) {
case MOD_LOAD: /* kldload */
<!-- D&eacute;sol&eacute;, les accents n'existent pas dans la console alors je ne les ai pas mis l&agrave; non plus
-->
uprintf("Skeleton KLD charge.\n");
break;
case MOD_UNLOAD:
uprintf("Skeleton KLD decharge.\n");
break;
default:
err = EINVAL;
break;
}
return(err);
}
/* Declare ce module au reste du noyau */
DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY);</programlisting>
<sect2>
<title>Makefile</title>
<para>FreeBSD fournit un fichier d'inclusion "makefile" que vous pouvez utiliser pour
compiler rapidement votre ajout au noyau.</para>
<programlisting>SRCS=skeleton.c
KMOD=skeleton
.include &lt;bsd.kmod.mk&gt;</programlisting>
<para>Lancer simplement la commande <command>make</command> avec ce fichier Makefile
cr&eacute;era un fichier <filename>skeleton.ko</filename> qui peut
&ecirc;tre charg&eacute; dans votre syst&egrave;me en tapant :
<screen> &prompt.root
kldload -v ./skeleton.ko
</screen>
</para>
</sect2>
</sect1>
<sect1>
<title>Acc&#233;der au pilote d'un p&#233;riph&#233;rique</title>
<para>Unix fournit un ensemble d'appels syt&egrave;me communs utilisable par
les applications de l'utilisateur. Les couches sup&eacute;rieures du noyau renvoient
ces appels au pilote de p&eacute;riph&eacute;rique correspondant quand un utilisateur
acc&egrave;de au fichier sp&eacute;cial de p&eacute;riph&eacute;rique. Le script <command>/dev/MAKEDEV</command>
cr&eacute;e la plupart des fichiers sp&eacute;ciaux de p&eacute;riph&eacute;rique pour votre syst&egrave;me mais si vous
faites votre propre d&eacute;veloppement de pilote, il peut &ecirc;tre n&eacute;cessaire de cr&eacute;er
vos propres fichiers sp&eacute;ciaux de p&eacute;riph&eacute;rique avec la commande <command>mknod</command>
</para>
<sect2>
<title>Cr&#233;er des fichiers sp&#233;ciaux de p&#233;riph&#233;riques statiques</title>
<para>La commande <command>mknod</command> n&eacute;cessite quatre
arguments pou cr&eacute;er un fichier sp&eacute;cial de p&eacute;riph&eacute;rique. Vous devez sp&eacute;cifier le nom
de ce fichier sp&eacute;cial de p&eacute;riph&eacute;rique, le type de p&eacute;riph&eacute;rique, le num&eacute;ro majeur
et le num&eacute;ro mineur du p&eacute;riph&eacute;rique.</para>
</sect2>
<sect2>
<title>Les fichiers sp&#233;ciaux de p&#233;riph&#233;rique dynamiques</title>
<para>Le p&eacute;riph&eacute;rique syst&egrave;me de fichiers, ou devfs, fournit l'acc&egrave;s &agrave;
l'espace des noms des p&eacute;riph&eacute;riques du noyau dans l'espace du syst&egrave;me de fichiers global.
Ceci &eacute;limine les probl&egrave;mes de pilote sans fichier sp&eacute;cial statique, ou de fichier sp&eacute;cial sans pilote install&eacute;.
Devfs est toujours un travail en cours mais il fonctionne d&eacute;j&agrave; assez bien.</para>
</sect2>
</sect1>
<sect1>
<title>Les p&#233;riph&#233;riques caract&#232;res</title>
<para>Un pilote de p&eacute;riph&eacute;rique caract&egrave;re est un pilote qui tranf&egrave;re les donn&eacute;es
directement au processus utilisateur ou vers celui-ci. Il s'agit du plus commun
des types de pilote de p&eacute;riph&eacute;rique et il y en a plein d'exemples simples dans
l'arbre des sources.</para>
<para>Cet exemple simple de pseudo-p&eacute;riph&eacute;rique enregistre toutes les valeurs
que vous lui avez &eacute;crites et peut vous les renvoyer quand vous les lui
demandez.</para>
<programlisting>/*
* un simple pseudo-p&eacute;riph&eacute;rique `echo' KLD
*
* Murray Stokely
*/
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#include &lt;sys/types.h&gt;
#include &lt;sys/module.h&gt;
#include &lt;sys/systm.h&gt; /* uprintf */
#include &lt;sys/errno.h&gt;
#include &lt;sys/param.h&gt; /* defines utilises dans kernel.h */
#include &lt;sys/kernel.h&gt; /* types utilises dans me module d'initialisation */
#include &lt;sys/conf.h&gt; /* cdevsw struct */
#include &lt;sys/uio.h&gt; /* uio struct */
#include &lt;sys/malloc.h&gt;
#define BUFFERSIZE 256
/* Prototypes des fonctions */
d_open_t echo_open;
d_close_t echo_close;
d_read_t echo_read;
d_write_t echo_write;
/* Points d'entr&eacute;e du p&eacute;riph&eacute;rique Caract&egrave;re */
static struct cdevsw echo_cdevsw = {
echo_open,
echo_close,
echo_read,
echo_write,
noioctl,
nopoll,
nommap,
nostrategy,
"echo",
33, /* reserve pour lkms - /usr/src/sys/conf/majors */
nodump,
nopsize,
D_TTY,
-1
};
typedef struct s_echo {
char msg[BUFFERSIZE];
int len;
} t_echo;
/* variables */
static dev_t sdev;
static int len;
static int count;
static t_echo *echomsg;
MALLOC_DECLARE(M_ECHOBUF);
MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "cache pour le module echo");
/*
* Cette fonction est appele par les appels systeme kld[un]load(2) pour
* determiner quelles actions doivent etre faites quand le
* module est charge ou decharge
*/
static int
echo_loader(struct module *m, int what, void *arg)
{
int err = 0;
switch (what) {
case MOD_LOAD: /* kldload */
sdev = make_dev(<literal>&</literal>echo_cdevsw,
0,
UID_ROOT,
GID_WHEEL,
0600,
"echo");
/* aloocation de m&eacute;moire noyau pour l'utilisation de ce module */
/* malloc(256,M_ECHOBUF,M_WAITOK); */
MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK);
printf("Peripherique Echo charge.\n");
break;
case MOD_UNLOAD:
destroy_dev(sdev);
FREE(echomsg,M_ECHOBUF);
printf("Peripherique Echo decharge.\n");
break;
default:
err = EINVAL;
break;
}
return(err);
}
int
echo_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
int err = 0;
uprintf("Peripherique \"echo\" ouvert avec succes.\n");
return(err);
}
int
echo_close(dev_t dev, int fflag, int devtype, struct proc *p)
{
uprintf("Fermeture du peripherique \"echo.\"\n");
return(0);
}
/*
* La fonction read prend juste comme parametre
* le cache qui a ete sauve par l'appel &agrave; echo_write()
* et le retourne a l'utilisateur pour acces.
* uio(9)
*/
int
echo_read(dev_t dev, struct uio *uio, int ioflag)
{
int err = 0;
int amt;
/* De quelle taille est cette operation read ? Aussi grande que l'utilisateur le veut,
ou aussi grande que les donnees restantes */
amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0);
if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) {
uprintf("uiomove echoue!\n");
}
return err;
}
/*
* echo_write prend un caractere en entree et le sauve
* dans le cache pour une utilisation ulterieure.
*/
int
echo_write(dev_t dev, struct uio *uio, int ioflag)
{
int err = 0;
/* Copie la chaine d'entree de la memoire de l'utilisateur a la memoire du noyau*/
err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE));
/* Maintenant nous avons besoin de terminer la chaine par NULL */
*(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0;
/* Enregistre la taille */
echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE);
if (err != 0) {
uprintf("Ecriture echouee: mauvaise adresse!\n");
}
count++;
return(err);
}
DEV_MODULE(echo,echo_loader,NULL);</programlisting>
<para>Pour installer ce pilote, vous devrez d'abord cr&eacute;er un fichier sp&eacute;cial dans
votre syst&egrave;me de fichiers avec une commande comme : </para>
<screen>
&prompt.root mknod /dev/echo c 33 0
</screen>
<para>Avec ce pilote charg&eacute;, vous devriez maintenant &ecirc;tr capable de taper
quelque chose comme :</para>
<screen>
&prompt.root echo -n "Test Donnees" > /dev/echo
&prompt.root cat /dev/echo
Test Donnees
</screen>
<para>P&eacute;riph&eacute;riques r&eacute;els dans le chap&icirc;tre suivant.</para>
<para>Informations additionnelles
<itemizedlist>
<listitem><simpara><ulink
url="http://www.daemonnews.org/200010/blueprints.html">Dynamic
Kernel Linker (KLD) Facility Programming Tutorial</ulink> -
<ulink url="http://www.daemonnews.org">Daemonnews</ulink> October 2000</simpara></listitem>
<listitem><simpara><ulink
url="http://www.daemonnews.org/200007/newbus-intro.html">How
to Write Kernel Drivers with NEWBUS</ulink> - <ulink
url="http://www.daemonnews.org">Daemonnews</ulink> July
2000</simpara></listitem>
</itemizedlist>
</para>
</sect1>
<sect1>
<title>Pilotes R&#233;seau</title>
<para>Les pilotes pour p&eacute;riph&eacute;rique r&eacute;seau n'utilisent pas les fichiers sp&eacute;ciaux pour
pouvoir &ecirc;tre acessibles. Leur s&eacute;lection est bas&eacute;e sur d'autres d&eacute;cisions
faites &agrave; l'int&eacute;rieur du noyau et plut&ocirc;t que d'appeler open(), l'utilisation
d'un p&eacute;riph&eacute;rique r&eacute;seau se fait g&eacute;n&eacute;ralement en se servant de l'appel syst&egrave;me
&man.socket.2;.</para>
<para>man ifnet(), p&eacute;riph&eacute;rique "en boucle", drivers de Bill Paul,
etc..</para>
</sect1>
</chapter>