1869 lines
63 KiB
Text
1869 lines
63 KiB
Text
<!--
|
||
The FreeBSD Documentation Project
|
||
The FreeBSD French Documentation Project
|
||
|
||
$Id: article.sgml,v 1.6 2007-01-20 13:34:48 blackend Exp $
|
||
$FreeBSD$
|
||
Original revision: n.nn
|
||
-->
|
||
|
||
<!DOCTYPE ARTICLE PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
|
||
<!ENTITY % man PUBLIC "-//FreeBSD//ENTITIES DocBook Manual Page Entities//EN"> %man;
|
||
<!ENTITY % urls PUBLIC "-//FreeBSD//ENTITIES Common Document URL Entities//FR"> %urls;
|
||
<!ENTITY % abstract PUBLIC "-//FreeBSD//ENTITIES DocBook Abstract Entities//FR"> %abstract;
|
||
<!ENTITY % artheader PUBLIC "-//FreeBSD//ENTITIES DocBook ArtHeader Entities//FR"> %artheader;
|
||
<!ENTITY % translators PUBLIC "-//FreeBSD//ENTITIES DocBook Translator Entities//FR"> %translators;
|
||
|
||
<!ENTITY % authors PUBLIC "-//FreeBSD//ENTITIES DocBook Author Entities//EN"> %authors
|
||
<!ENTITY % mailing-lists SYSTEM "../../share/sgml/mailing-lists.ent"> %mailing-lists;
|
||
|
||
|
||
|
||
<!-- French Build Only -->
|
||
<!-- <!ENTITY % authors SYSTEM "../../../en_US.ISO8859-1/books/handbook/authors.ent"> %authors; -->
|
||
<!-- <!ENTITY % mailing-lists PUBLIC "-//FreeBSD//ENTITIES DocBook Mailing List Entities//FR"> %mailing-lists; -->
|
||
|
||
<!ENTITY rel.current CDATA "3.2">
|
||
]>
|
||
|
||
|
||
<article lang="fr">
|
||
<articleinfo>
|
||
<title>Le guide de l'auteur de pilotes de périphériques pour FreeBSD</title>
|
||
<authorgroup>
|
||
<author>
|
||
<firstname>Eric L.</firstname>
|
||
<surname>Hernes</surname>
|
||
</author>
|
||
</authorgroup>
|
||
&artheader.copyright;
|
||
<abstract>
|
||
<para><email>erich@rrnet.com</email></para>
|
||
<para>29 Mai 1996</para>
|
||
<para>Ce document décrit comment ajouter un module de gestion de
|
||
périphérique à FreeBSD. Il <emphasis>n'est pas</emphasis> destiné pour être un
|
||
cours d'instruction sur des modules de gestion de périphérique
|
||
d'Unix en général. Il est destiné pour les auteurs de module de
|
||
gestion de périphérique, au courant du modèle de module de gestion
|
||
de périphérique d'Unix, pour travailler sur FreeBSD.
|
||
</para>
|
||
&abstract.license;
|
||
&abstract.disclaimer;
|
||
&trans.a.dntt;
|
||
</abstract>
|
||
</articleinfo>
|
||
|
||
|
||
<sect1>
|
||
<title>Spécificité de FreeBSD2.x</title>
|
||
|
||
<para>Dû aux changements de FreeBSD avec le temps, ce guide est
|
||
seulement précis en ce qui concerne FreeBSD 2.x. Un guide de
|
||
rechange pour FreeBSD 3.x et au-delà est en train d'être écrit.
|
||
Contactez Jeroen Ruigrok <email>asmodai@wxs.nl</email> si
|
||
vous voulez l'aider à ce sujet.
|
||
</para>
|
||
</sect1>
|
||
|
||
|
||
<sect1>
|
||
<title>Généralité</title>
|
||
|
||
<para> <emphasis>Le noyau de FreeBSD est très bien
|
||
documenté, malheureusement il est entièrement écrit en `C'.</emphasis>
|
||
</para>
|
||
</sect1>
|
||
|
||
<sect1>
|
||
<title>Types de pilotes de module de périphériques.</title>
|
||
|
||
<sect2>
|
||
<title>Caractère</title>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
|
||
<para>Structure <citerefentry><refentrytitle>cdevsw</refentrytitle></citerefentry></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>d_open()</function></title>
|
||
<para>
|
||
<function>d_open()</function> prend plusieurs arguments, la liste formelle ressemble à
|
||
quelque chose comme :
|
||
</para>
|
||
|
||
<programlisting>
|
||
int
|
||
d_open(dev_t dev, int flag, int mode, struct proc *p)
|
||
</programlisting>
|
||
|
||
<para><function>d_open()</function> est appelé à <emphasis>chaque</emphasis> ouverture du périphérique.</para>
|
||
|
||
<para>L'argument <citerefentry><refentrytitle>dev</refentrytitle></citerefentry> contient le nombre majeur et mineur du
|
||
périphérique ouvert. Ils sont disponibles par les macros
|
||
<citerefentry><refentrytitle><function>major()</function></refentrytitle></citerefentry> et <citerefentry><refentrytitle><function>minor()</function></refentrytitle></citerefentry>
|
||
</para>
|
||
|
||
<para>Les arguments <citerefentry><refentrytitle>flag</refentrytitle></citerefentry> et <citerefentry><refentrytitle>mode</refentrytitle></citerefentry> sont comme décrits sur
|
||
la page de manuel de
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?open(2)">open</ulink>.
|
||
Il est recommandé que vous examiniez
|
||
ces derniers pour vous assurer des droits d'accès dans <sys/fcntl.h>
|
||
et faire ce qui est exigé. Par exemple si <citerefentry><refentrytitle>flag </refentrytitle></citerefentry> est
|
||
(O_NONBLOCK | O_EXLOCK) l'ouverture échouerait si il bloquait ou
|
||
si l'accès exclusif ne pouvait pas être accordé.
|
||
</para>
|
||
|
||
<para>
|
||
L'argument <citerefentry><refentrytitle>p</refentrytitle></citerefentry> contient toutes les informations à propos du
|
||
processus actuel.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_close()</function></title>
|
||
<para> <function>d_close()</function> prend la même liste d'argument que <function>d_open()</function>:
|
||
</para>
|
||
|
||
<programlisting>
|
||
int
|
||
d_close(dev_t dev , int flag , int mode , struct proc *p)
|
||
</programlisting>
|
||
|
||
<para><function>d_close()</function> est seulement appelé à la dernière fermeture de votre
|
||
périphérique (par périphérique mineur). Par exemple dans le fragment
|
||
suivant de code, <function>d_open()</function> est appelé 3 fois, mais <function>d_close()</function>
|
||
seulement une fois.
|
||
</para>
|
||
|
||
<programlisting>
|
||
...
|
||
fd1=open("/dev/mydev", O_RDONLY);
|
||
fd2=open("/dev/mydev", O_RDONLY);
|
||
fd3=open("/dev/mydev", O_RDONLY);
|
||
...
|
||
<useful stuff with fd1, fd2, fd3 here>
|
||
...
|
||
close(fd1);
|
||
close(fd2);
|
||
close(fd3);
|
||
...
|
||
</programlisting>
|
||
|
||
<para>Les arguments sont semblables à ceux décrits ci-dessus pour
|
||
<function>d_open()</function>.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_read()</function> et <function>d_write()</function></title>
|
||
|
||
<para><function>d_read()</function> et d_write prennent les listes suivantes d'argument:
|
||
</para>
|
||
|
||
<programlisting>
|
||
int
|
||
d_read(dev_t dev, struct uio *uio, int flat)
|
||
int
|
||
d_write(dev_t dev, struct uio *uio, int flat)
|
||
</programlisting>
|
||
|
||
<para>
|
||
Les points d'entrée de <function>d_read()</function> et de <function>d_write()</function> sont appelés quand
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?read(2)">read</ulink> et
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?write(2)">write</ulink>
|
||
sont appelés sur votre périphérique depuis l'espace utilisateur. Le transfert
|
||
des données peut être manipulé par la routine du noyau <function>uiomove()</function>.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_ioctl()</function></title>
|
||
|
||
<para> Sa liste d'argument est comme suit:
|
||
</para>
|
||
<programlisting>
|
||
int
|
||
d_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *p)
|
||
</programlisting>
|
||
|
||
<para>
|
||
<function>d_ioctl()</function> est un fourre-tout pour les exécutions qui ne semblent
|
||
pas raisonnable dans un paradigme lecture/écriture. Le plus
|
||
célèbre de tout les ioctl est probablement celui sur des périphériques
|
||
tty, par le
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?stty(1)">stty</ulink>.
|
||
|
||
Le point d'entrée d'ioctl est appelé depuis l'<function>ioctl()</function> de
|
||
<filename>sys/kern/sys_generic.c</filename></para>
|
||
|
||
<para>
|
||
Il y a quatre types différents d'ioctl qui peuvent être implémentés.
|
||
|
||
<sys/ioccom.h> contient des macros pratiques de
|
||
pour définir ces ioctls.
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para><citerefentry><refentrytitle>_IO(g, n) </refentrytitle></citerefentry> pour les opérations de type contrôle.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>
|
||
<citerefentry><refentrytitle>_IOR(g, n, t) </refentrytitle></citerefentry> pour des opérations lisant des données d'un
|
||
périphérique.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>
|
||
<citerefentry><refentrytitle>_IOW(g, n, t) </refentrytitle></citerefentry> pour les opérations écrivant des données
|
||
sur un périphérique.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>
|
||
<citerefentry><refentrytitle>_IOWR(g,n,t)</refentrytitle></citerefentry> pour les opérations écrivant sur un périphérique
|
||
puis lisent les données.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
|
||
<para>
|
||
Ici <citerefentry><refentrytitle>g </refentrytitle></citerefentry> se rapporte à un <emphasis>groupe </emphasis>/. C'est une valeur
|
||
de 8 bits, en général indicative du périphérique ; par exemple, 't'
|
||
est utilisé dans des ioctls de tty. <citerefentry><refentrytitle>n</refentrytitle></citerefentry> se
|
||
rapporte au nombre de l'ioctl dans le groupe. Sur SCO, ce seul nombre
|
||
dénote l'ioctl. <citerefentry><refentrytitle>t</refentrytitle></citerefentry> est le type de données qui sera
|
||
passé au pilote de périphérique; ceci est alors remis à un opérateur
|
||
<function>sizeof()</function> du noyau. L'appel système <function>ioctl()</function> fera soit un <function>copyin()</function>
|
||
soit un <function>copyout()</function> ou les deux à votre pilote, puis vous
|
||
renverra un pointeur à la structure de données dans l'argument
|
||
<citerefentry><refentrytitle>arg</refentrytitle></citerefentry> de l'appel d'd_ioctl. Actuellement la taille de
|
||
données est limitée à une page (4k sur l'i386).
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_stop()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_reset()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_devtotty()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_poll()</function> (3.0 et plus) ou <function>d_select()</function> (2.2)</title>
|
||
|
||
<para>la liste d'argument de <function>d_poll()</function> est comme suit :
|
||
</para>
|
||
|
||
<programlisting>
|
||
void
|
||
d_poll(dev_t dev, int events, struct proc *p)
|
||
</programlisting>
|
||
|
||
<para> <function>d_poll()</function> est employé pour découvrir si un périphérique
|
||
est prêt pour les E/S. Par exemple, attendre que des données du réseau
|
||
soient disponibles, ou que l'utilisateur presse une touche.
|
||
Cela correspond à un appel de <function>poll()</function> dans l'espace utilisateur.
|
||
</para>
|
||
|
||
<para>L'appel à <function>d_poll()</function> devrait vérifier les événements
|
||
indiqués dans le masque d'évènement. Si aucun des événements demandés n'est
|
||
en activité, mais qu'elles pourraient devenir actif plus tard, il
|
||
devrait enregistrer ceci pour les actions futures du noyau.
|
||
<function>d_poll()</function> fait ceci en appelant <function>selrecord()</function> avec une structure
|
||
selinfo pour ce périphérique. La somme de toutes ces activités
|
||
ressemblent à quelque chose comme ceci:
|
||
</para>
|
||
|
||
<programlisting>
|
||
static struct my_softc {
|
||
struct queue rx_queue; /* As example only - not required */
|
||
struct queue tx_queue; /* As example only - not required */
|
||
struct selinfo selp; /* Required */
|
||
} my_softc[NMYDEV];
|
||
|
||
...
|
||
|
||
static int
|
||
mydevpoll(dev_t dev, int events, struct proc *p)
|
||
{
|
||
int revents = 0; /* Events we found */
|
||
int s;
|
||
struct my_softc *sc = &my_softc[dev];
|
||
|
||
/* We can only check for IN and OUT */
|
||
if ((events & (POLLIN|POLLOUT)) == 0)
|
||
return(POLLNVAL);
|
||
|
||
s = <function>splhigh()</function>;
|
||
/* Writes are if the transmit queue can take them */
|
||
if ((events & POLLOUT) &&
|
||
!IF_QFULL(sc->tx_queue))
|
||
revents |= POLLOUT;
|
||
/* ... while reads are OK if we have any data */
|
||
if ((events & POLLIN) &&
|
||
!IF_QEMPTY(sc->rx_queue))
|
||
revents |= POLLIN;
|
||
if (revents == 0)
|
||
selrecord(p, &sc->selp);
|
||
splx(s);
|
||
return revents;
|
||
}
|
||
</programlisting>
|
||
|
||
<para> <function>d_select()</function> est utilisé dans la version 2.2 et
|
||
précédentes de FreeBSD. Au lieu de 'events', il prend un simple
|
||
entier 'rw', qui peut être FREAD pour la lecture (comme dans
|
||
POLLIN ci-dessus), FWRITE pour l'écriture (comme dans POLLOUT ci-dessus),
|
||
et 0 pour 'exception' - lorsque quelque chose d'exceptionnel se produit,
|
||
comme une carte étant insérée ou retirée pour le pilote de
|
||
pccard.
|
||
</para>
|
||
<para>Pour 'select', le fragment correspondant à la description
|
||
ci-dessus ressembleraient à ceci:
|
||
</para>
|
||
<programlisting>
|
||
static int
|
||
mydevselect(dev_t dev, int rw, struct proc *p)
|
||
{
|
||
int ret = 0;
|
||
int s;
|
||
struct my_softc *sc = &my_softc[dev];
|
||
|
||
s = <function>splhigh()</function>;
|
||
switch (rw) {
|
||
case FWRITE:
|
||
/* Writes are if the transmit queue can take them */
|
||
if (!IF_QFULL(sc->tx_queue))
|
||
ret = 1;
|
||
break;
|
||
case FREAD:
|
||
/* ... while reads are OK if we have any data */
|
||
if (!IF_QEMPTY(sc->rx_queue))
|
||
ret = 1;
|
||
break;
|
||
case 0:
|
||
/* This driver never get any exceptions */
|
||
break;
|
||
}
|
||
if(ret == 0)
|
||
selrecord(p, &sc->selp);
|
||
splx(s);
|
||
return(revents);
|
||
}
|
||
</programlisting>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_mmap()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_strategy()</function></title>
|
||
|
||
<para>
|
||
La liste d'argument de <function>d_strategy()</function> est comme suit :
|
||
</para>
|
||
|
||
<programlisting>
|
||
void
|
||
d_strategy(struct buf *bp)
|
||
</programlisting>
|
||
|
||
<para><function>d_strategy()</function> est utilisé pour les périphériques utilisant
|
||
des E/S de type disperser-regrouper (<foreignphrase>scatter-gather</foreignphrase>).
|
||
C'est ce qu'il y a de plus courant dans un périphérique de bloc.
|
||
C'est sensiblement différent du modèle de système V, où seulement
|
||
le pilote de bloc fait une E/S de type disperser-regrouper.
|
||
Sous BSD, les périphériques de caractère sont parfois sommé d'exécuter
|
||
une E/S de type disperser-regrouper par l'intermédiaire des appels
|
||
systèmes <function>readv()</function> et <function>writev()</function>.
|
||
</para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Bloc</title>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
<para> Structure <citerefentry><refentrytitle>struct bdevsw</refentrytitle></citerefentry>
|
||
</para>
|
||
|
||
<para> Structure <citerefentry><refentrytitle>struct buf</refentrytitle></citerefentry>
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>d_open()</function></title>
|
||
<para> Décrit dans la section périphérique de caractère.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_close()</function></title>
|
||
<para>Décrit dans la section périphérique de caractère.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_strategy()</function></title>
|
||
<para>Décrit dans la section périphérique de caractère.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_ioctl()</function></title>
|
||
<para>Décrit dans la section périphérique de caractère.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_dump()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>d_psize()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Réseau</title>
|
||
<para>Structure <citerefentry><refentrytitle>struct ifnet</refentrytitle></citerefentry>
|
||
</para>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>if_init()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>if_output()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>if_start()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>if_done()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>if_ioctl()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>if_watchdog()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Protocole de communication</title>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
<para>Structure <citerefentry><refentrytitle>struct linesw</refentrytitle></citerefentry>
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>l_open()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_close()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_read()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_write()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_ioctl()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_rint()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_start()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>l_modem()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1>
|
||
<title>Bus Supportés</title>
|
||
|
||
<sect2>
|
||
<title>ISA -- Architecture Standard d'Industrie (<foreignphrase>Industry Standard
|
||
Architecture</foreignphrase></title>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
|
||
<sect4>
|
||
<title>Structure <citerefentry><refentrytitle>struct isa_device</refentrytitle></citerefentry></title>
|
||
|
||
<para>Cette structure est obligatoire, mais généralement elle est créée par
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?config(8)">config</ulink> à partir du fichier de configuration de noyau.
|
||
Elle est requise pour chaque périphérique, c'est à dire que si vous avez
|
||
un pilote de périphérique contrôlant deux "serial boards", vous
|
||
aurez deux structures isa_device. Si vous construisez un périphérique
|
||
comme un LKM, vous devrez créer votre propre structure isa_device afin
|
||
de refléter votre configuration (lignes 85 - 131 de pcaudio_lkm.c).
|
||
Il y a une équivalence directe entre le fichier de configuration et la
|
||
structureisa_device. La définition de
|
||
<filename>/usr/src/sys/i386/isa/isa_device.h</filename>
|
||
est :
|
||
</para>
|
||
|
||
<programlisting>
|
||
struct isa_device {
|
||
int id_id; /* device id */
|
||
struct isa_driver *id_driver;
|
||
int id_iobase; /* base i/o address */
|
||
u_short id_irq; /* interrupt request */
|
||
short id_drq; /* DMA request */
|
||
caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
|
||
int id_msize; /* size of i/o memory */
|
||
inthand2_t *id_intr; /* interrupt interface routine */
|
||
int id_unit; /* unit number */
|
||
int id_flags; /* flags */
|
||
int id_scsiid; /* scsi id if needed */
|
||
int id_alive; /* device is present */
|
||
#define RI_FAST 1 /* fast interrupt handler */
|
||
u_int id_ri_flags; /* flags for <function>register_intr()</function> */
|
||
int id_reconfig; /* hot eject device support (such as PCMCIA) */
|
||
int id_enabled; /* is device enabled */
|
||
int id_conflicts; /* we're allowed to conflict with things */
|
||
struct isa_device *id_next; /* used in isa_devlist in <function>userconfig()</function> */
|
||
};
|
||
</programlisting>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title>Structure <citerefentry><refentrytitle>struct isa_driver</refentrytitle></citerefentry></title>
|
||
|
||
<para>Cette structure est définie dans
|
||
<filename>/usr/src/sys/i386/isa/isa_device.h</filename>,
|
||
est est requise pour chaque pilote de périphérique. La définition
|
||
est :
|
||
</para>
|
||
|
||
<programlisting>
|
||
struct isa_driver {
|
||
int (*probe) __P((struct isa_device *idp));
|
||
/* test whether device is present */
|
||
int (*attach) __P((struct isa_device *idp));
|
||
/* setup driver for a device */
|
||
char *name; /* device name */
|
||
int sensitive_hw; /* true if other probes confuse us */
|
||
};
|
||
</programlisting>
|
||
|
||
<para>
|
||
C'est la structure employée par le code sondage/attachement
|
||
(<foreignphrase>probe/attach</foreignphrase>) pour
|
||
détecter et initialiser votre périphérique. Le membre <citerefentry><refentrytitle>probe</refentrytitle></citerefentry>
|
||
est un pointeur à votre fonction permettant de sonder les périphériques.
|
||
Le membre <citerefentry><refentrytitle>attach</refentrytitle></citerefentry> est un pointeur vers votre fonction d'attache.
|
||
Le membre <citerefentry><refentrytitle>name</refentrytitle></citerefentry> est un pointeur de caractère sur le nom de deux
|
||
ou trois lettres de votre pilote.
|
||
C'est le nom enregistré pendant le processus de
|
||
sondage/attachement (et probablement aussi dans
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?lsdev(8)">lsdev</ulink>).
|
||
Le membre <citerefentry><refentrytitle>sensitive_hw </refentrytitle></citerefentry> est un
|
||
indicateur qui aide le code de sondage à déterminer l'ordre du sondage.
|
||
</para>
|
||
|
||
<para>
|
||
Un instantiation typique est:
|
||
</para>
|
||
|
||
<programlisting>
|
||
struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" };
|
||
</programlisting>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>probe()</function></title>
|
||
<para><function>probe()</function> prend un pointeur sur une structure isa_device
|
||
comme argument et renvoie un int. La valeur de retour est ``zéro'' ou
|
||
``non-zéro '' quant à l'absence ou à la présence de votre périphérique.
|
||
Ce point d'entrée peut être déclaré comme
|
||
<citerefentry><refentrytitle>static</refentrytitle></citerefentry> parce qu'il
|
||
est accessible par l'intermédiaire du membre
|
||
<citerefentry><refentrytitle>probe</refentrytitle></citerefentry> de la structre
|
||
isa_driver. Cette fonction est destinée à
|
||
détecter la présence de votre périphérique seulement et ne devrait
|
||
faire aucune configuration du périphérique elle-même.
|
||
</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>attach()</function></title>
|
||
<para>
|
||
<function>attach()</function> prend également un pointeur sur une structure
|
||
isa_device comme argument et
|
||
renvoie un int. La valeur de retour est également ``zéro'' ou
|
||
``non-zéro'' indiquant si l'attache a réussie. Cette fonction
|
||
est destinée pour faire n'importe quelle initialisation spéciale du
|
||
périphérique aussi bien que pour confirmer que le périphérique est utilisable.
|
||
Il devrait aussi être déclaré <citerefentry><refentrytitle>static</refentrytitle></citerefentry> parce qu'il est accesible
|
||
par le membre <citerefentry><refentrytitle>attach</refentrytitle></citerefentry> de la structure <citerefentry><refentrytitle>isa_driver </refentrytitle></citerefentry>.
|
||
</para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>EISA -- Architecture <20>tendue de Standard industriel (<foreignphrase>Extended Industry Standard Architecture</foreignphrase>)</title>
|
||
<para></para>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
|
||
<para>Structure <citerefentry><refentrytitle>struct eisa_dev </refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct isa_driver</refentrytitle></citerefentry> </para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>probe()</function></title>
|
||
<para>Décrit dans la section de périphérique ISA.</para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>attach()</function></title>
|
||
<para>Décrit dans la section de périphérique ISA.</para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>PCI -- Bus d'interconnexion Périphérique (<foreignphrase>Peripheral Computer
|
||
Interconnect</foreignphrase>)</title>
|
||
|
||
<sect3>
|
||
<title>Structures de données</title>
|
||
|
||
<para> Structure <citerefentry><refentrytitle>struct pci_device</refentrytitle></citerefentry>
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>nom : Le nom abrégé du périphérique.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para> sonde: Contrôle si le pilote peut supporter un périphérique avec
|
||
ce type. L'étiquette peut être employée pour obtenir plus
|
||
d'information avec <function>pci_read_conf()</function>. Voir ci-dessous. Elle renvoie
|
||
une chaîne de caractères avec le nom du périphérique, ou un pointeur
|
||
NULL si le pilote ne peut pas supporter ce périphérique.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para> attache: Assigne une structure de contrôle et la prépare. Cette
|
||
fonction peut utiliser les fonctions de mapping PCI. Voir
|
||
ci-dessous. (identification de configuration) ou type.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para> compte: Un pointeur sur un compteur d'unité. Il est
|
||
employé par le configurateur de PCI pour assigner des numéros.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>probe()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>attach()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>shutdown()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>SCSI -- <foreignphrase>Small Computer Systems Interface</foreignphrase></title>
|
||
|
||
<sect3>
|
||
<title>Structure de données</title>
|
||
|
||
<para>Structure <citerefentry><refentrytitle>struct scsi_adapter</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct scsi_device</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct scsi_ctlr_config</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct scsi_device_config</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct scsi_link</refentrytitle></citerefentry> </para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>attach()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>init()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
|
||
<sect2>
|
||
<title>PCCARD (PCMCIA)</title>
|
||
|
||
<sect3>
|
||
<title>Structure de données</title>
|
||
|
||
<para>Structure <citerefentry><refentrytitle>struct slot_cont</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct pccard_drv</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct pccard_dev</refentrytitle></citerefentry> </para>
|
||
<para>Structure <citerefentry><refentrytitle>struct slot</refentrytitle></citerefentry> </para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Points d'entrée</title>
|
||
|
||
<sect4>
|
||
<title><function>handler()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>unload()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>suspend()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
|
||
<sect4>
|
||
<title><function>init()</function></title>
|
||
<para></para>
|
||
</sect4>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Fichiers d'en-tête</title>
|
||
|
||
<para><pccard/slot.h>
|
||
</para>
|
||
</sect3>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
|
||
<sect1>
|
||
<title>Incorporation dans le noyau</title>
|
||
|
||
<para>Dans FreeBSD, le support des bus d'ISA et EISA est spécifique à
|
||
i386. Tandis que FreeBSD lui-même est actuellement
|
||
disponible sur la plateforme i386, un certain effort a été fait pour
|
||
faire du code portable pour PCI, PCCARD, et SCSI. Le code
|
||
spécifique à ISA et EISA réside dans
|
||
<filename>/usr/src/sys/i386/isa</filename> et
|
||
<filename>/usr/src/sys/i386/eisa</filename> respectivement. Le code indépendant de la
|
||
machine de PCI, de PCCARD, et de SCSI réside dans
|
||
<filename>/usr/src/sys/{pci,pccard,scsi</filename>}. Le code spécifique i386 quand à lui
|
||
réside dans <filename>/usr/src/sys/i386/{pci, pccard, scsi}</filename>.
|
||
</para>
|
||
|
||
|
||
<para> Dans FreeBSD, un module de gestion de périphérique peut
|
||
être soit sous forme binaire soit sous forme de sources.
|
||
Il n'y a aucun endroit ``officiel'' pour mettre les binaires des
|
||
pilotes de périphériques. Les systèmes BSD utilisent quelque
|
||
chose comme sys/i386/OBJ. Puisque la plupart des pilotes sont
|
||
distribués dans les sources, la discussion suivante se rapporte à un
|
||
source pilote de périphérique.
|
||
Des binaires de pilotes de périphériques sont
|
||
parfois fournis par les constructeurs de matériel qui souhaitent
|
||
maintenir les sources de manière propriétaire.
|
||
</para>
|
||
|
||
<para> Un pilote typique a son code source sous forme de fichier C,
|
||
comme dev.c. Le pilote peut également inclure des
|
||
fichiers; devreg.h contient typiquement des déclarations publiques
|
||
de registre de périphérique, des macros, et d'autres
|
||
déclarations spécifique au pilote de périphérique.
|
||
Quelques pilotes appellent parfois ce fichier devvar.h.
|
||
Quelques pilotes, tels que
|
||
le dgb (pour le Digiboard PC/Xe), exigent que du microcode soit chargé
|
||
sur la carte. Pour le pilote de dgb le microcode est compilé
|
||
et reporté dans un fichier d'en-tête par
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?file2c(1)">file2c</ulink>.
|
||
</para>
|
||
|
||
<para> Si le pilote de périphérique a des structures de données et des
|
||
ioctl qui sont spécifiques au pilote de périphérique ou
|
||
périphérique, et
|
||
doivent être accessibles de l'espace-utilisateur, elles devraient
|
||
être mises dans un fichier d'en-tête séparé qui résidera dans
|
||
<filename>/usr/include/machine/</filename> (certaines de ces derniers résident dans
|
||
<filename>/usr/include/sys/</filename>). Ceux-ci est typiquement nommé quelque chose comme
|
||
ioctl_dev.h ou devio.h.
|
||
</para>
|
||
|
||
<para> Si un pilote écrit depuis l'espace
|
||
d'utilisateur est identique à un périphérique qui existe déjà, il faut
|
||
prendre garde à utiliser les mêmes
|
||
interfaces ioctl et structures de données. Par exemple, de l'espace
|
||
utilisateur, un lecteur de SCSI CDROM devrait être identique à un
|
||
lecteur de cdrom IDE; ou une ligne série sur une carte
|
||
intelligente multiport (Digiboard, Cyclades...) devrait être identique
|
||
à un périphérique sio. Ces périphériques ont une interface définie
|
||
relativement bonne et devraient être utilisées.
|
||
</para>
|
||
|
||
<para> Il y a deux méthodes pour lier un pilote dans le
|
||
noyau, statiquement et le modèle LKM. La première méthode
|
||
est assez standard à travers la famille *BSD. L'autre
|
||
méthode a été initialement développée par Sun (je crois), et a
|
||
été mis en application dans BSD en utilisant le modèle de Sun.
|
||
Je ne crois pas que l'implémentation actuelle utilise encore le moindre
|
||
code de Sun.
|
||
</para>
|
||
|
||
<sect2>
|
||
<title>Modèle Standard</title>
|
||
|
||
<para> Les étapes exigées pour ajouter votre pilote au
|
||
noyau standard de FreeBSD sont
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>Ajout à la liste des pilotes de périphérique
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Ajout d'une entrée au [bc]devsw
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Ajout d'une entrée du pilote de périphérique au fichier de
|
||
configuration du noyau
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><ulink
|
||
url="http://www.freebsd.org/cgi/man.cgi?config(8)">config</ulink>,
|
||
compilation et installation du noyau
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>créer les fichiers spéciaux requis
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>redémarrage
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<sect3>
|
||
<title>Ajout à la liste des pilotes de périphérique</title>
|
||
|
||
<para>Le modèle standard pour ajouter un module de gestion de périphérique
|
||
au noyau de Berkeley est d'ajouter votre pilote à la liste des
|
||
périphériques connus. Cette liste dépend de l'architecture du CPU.
|
||
Si le périphérique n'est pas spécifique i386
|
||
(PCCARD, PCI, SCSI), le fichier est dans
|
||
<filename>/usr/src/sys/conf/files</filename>.
|
||
Si le périphérique est spécifique i386, utilisez
|
||
<filename>/usr/src/sys/i386/conf/files.i386</filename>. Une ligne typique ressemblerait
|
||
à :
|
||
</para>
|
||
|
||
<programlisting>
|
||
i386/isa/joy.c optional joy device-driver
|
||
</programlisting>
|
||
|
||
<para>Le premier champ relatif est le chemin du module de pilote
|
||
par rapport à <filename>/usr/src/sys</filename>.
|
||
Pour le cas d'un pilote binaire, le chemin d'accès serait quelque
|
||
chose comme <filename>i386/OBJ/joy.o</filename>.
|
||
</para>
|
||
|
||
<para>Le deuxième champ indique à
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?config(8)">config(8)</ulink>
|
||
que c'est un pilote facultatif. Quelques
|
||
périphériques sont obligatoires pour que le noyau puisse être construit.
|
||
</para>
|
||
|
||
<para>
|
||
Le troisième champ est le nom du périphérique.
|
||
</para>
|
||
|
||
<para>Le quatrième champ indique à config que c'est un
|
||
pilote de périphérique (par opposition à juste facultatif). Ceci
|
||
dit à config de créer des entrées pour le périphérique dans dans
|
||
des structures de <filename>/usr/src/sys/compile/KERNEL/ioconf.c</filename>.
|
||
</para>
|
||
|
||
<para>Il est également possible de créer un fichier
|
||
<filename>/usr/src/sys/i386/conf/files.KERNEL</filename> dont le contenu ignorera le
|
||
fichier par défaut files.i386, mais seulement pour le noyau ``KERNEL''.
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Faire de la place dans conf.c</title>
|
||
|
||
<para>Maintenant vous devez éditer <filename>/usr/src/sys/i386/i386/conf.c</filename>
|
||
pour faire une entrée pour votre pilote. Quelque part au début,
|
||
vous devez déclarer vos points d'entrée. L'entrée pour
|
||
le pilote du joystick est: </para>
|
||
|
||
<programlisting>
|
||
#include "joy.h"
|
||
#if NJOY > 0
|
||
d_open_t joyopen;
|
||
d_close_t joyclose;
|
||
d_rdwr_t joyread;
|
||
d_ioctl_t joyioctl;
|
||
#else
|
||
#define joyopen nxopen
|
||
#define joyclose nxclose
|
||
#define joyread nxread
|
||
#define joyioctl nxioctl
|
||
#endif
|
||
</programlisting>
|
||
|
||
<para>
|
||
Cela définit vos points d'entrée, ou points d'entrée nuls qui
|
||
renverront ENXIO quand appelé (clause #else).
|
||
</para>
|
||
|
||
<para>
|
||
Le fichier d'en-tête ``joy.h'' est automatiquement produit par
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?config(8)">config</ulink>
|
||
quand l'arborescence de construction du noyau est
|
||
créé. Cela se réduit habituellement à une seule ligne comme :
|
||
</para>
|
||
|
||
<programlisting>
|
||
#define NJOY 1
|
||
</programlisting>
|
||
|
||
<para>
|
||
ou
|
||
</para>
|
||
<programlisting>
|
||
#define NJOY 0
|
||
</programlisting>
|
||
|
||
<para> ce qui définit le nombre de vos périphériques dans votre noyau.
|
||
</para>
|
||
|
||
<para>
|
||
Vous devez de plus ajouter un slot au cdevsw[&rsqb, ou
|
||
au bdevsw[&rsqb, selon que ce soit un périphérique caractère,
|
||
périphérique bloc, ou les deux si c'est un périphérique bloc
|
||
avec une interface brute. L'entrée pour le pilote du joystick
|
||
est:
|
||
</para>
|
||
|
||
<programlisting>
|
||
/* open, close, read, write, ioctl, stop, reset, ttys, select, mmap, strat */
|
||
struct cdevsw cdevsw[] =
|
||
{
|
||
...
|
||
{ joyopen, joyclose, joyread, nowrite, /*51*/
|
||
joyioctl, nostop, nullreset, nodevtotty,/*joystick */
|
||
seltrue, nommap, NULL},
|
||
...
|
||
}
|
||
</programlisting>
|
||
|
||
<para>
|
||
L'ordre est ce qui détermine le nombre majeur de votre
|
||
périphérique. C'est pourquoi il y aura toujours une entrée
|
||
pour votre pilote, que ce soit des points d'entrée nuls,
|
||
ou des points d'entrée actuels. Il est probablement intéressant de
|
||
noter que c'est
|
||
sensiblement différent de SCO et d'autres dérivés du système V, où
|
||
n'importe quel périphérique (dans la théorie) peut avoir n'importe
|
||
quel nombre majeur. C'est en grande partie un avantage sur FreeBSD,
|
||
sur la manière dont les fichiers spéciaux de périphérique sont créés.
|
||
Nous reviendrons en détail sur ceci plus tard.
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Ajout de votre périphérique dans le fichier de configuration.</title>
|
||
|
||
<para> Ceci ajoute simplement une ligne décrivant votre périphérique. La
|
||
ligne de description du joystick est :
|
||
<programlisting>
|
||
device joy0 at isa? port "IO_GAME"
|
||
</programlisting>
|
||
Ceci indique que nous avons un
|
||
périphérique appelé ``joy0'' sur le bus ISA en utilisant
|
||
le port E/S ``IO_GAME'' (IO_GAME est une macro définie dans
|
||
<filename>/usr/src/sys/i386/isa/isa.h</filename>).
|
||
</para>
|
||
|
||
<para>
|
||
Une entrée légèrement plus compliquée est pour le pilote ``ix'' :
|
||
|
||
<programlisting>
|
||
device ix0 at isa? port 0x300 net irq 10 iomem 0xd0000 iosiz 32768
|
||
vector ixintr
|
||
</programlisting>
|
||
|
||
Ceci indique que nous avons un périphérique appelé
|
||
`ix0 ' sur le bus ISA. Il utilise le port E/S 0x300. Son
|
||
interruption sera masqué par d'autres périphériques dans la classe
|
||
réseau. Il utilise l'interruption 10. Il utilise 32k de mémoire
|
||
partagée à l'adresse physique 0xd0000. Il le définit également
|
||
son pilote d'interruption comme étant ``<function>ixintr()</function>''
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title><ulink url="http://www.freebsd.org/cgi/man.cgi?config(8)">config</ulink>
|
||
du noyau.</title>
|
||
|
||
<para> Maintenant avec notre fichier de configuration en main,
|
||
nous pouvons créer un répertoire de compilation du noyau. Cela peut être
|
||
fait en tapant :
|
||
<programlisting>
|
||
# config KERNEL
|
||
</programlisting>
|
||
|
||
où KERNEL est le nom de votre fichier de configuration.
|
||
La configuration crée un arbre de compilation
|
||
pour votre noyau dans <filename>/usr/src/sys/compile/KERNEL</filename>. Elle crée le fichier
|
||
makefile, quelques fichiers C, et quelques fichiers H avec des
|
||
macros définissant le nombre de chaque périphérique à inclure dans votre
|
||
votre noyau.
|
||
</para>
|
||
|
||
<para>
|
||
Maintenant vous pouvez aller dans le répertoire de compilation et
|
||
construire votre noyau. <20> chaque fois que vous lancerez config, votre
|
||
arbre de construction précédent sera retiré, à moins que vous ne lancez
|
||
config avec un -n. Si vous avez configuré et compilé un noyau GENERIC,
|
||
vous pouvez faire un ``make links'' afin d'éviter de compiler certains
|
||
fichiers à chaque itération. Typiquement, je lance :
|
||
<programlisting>
|
||
# make depend links all
|
||
</programlisting>
|
||
suivi d'un ``make install'' quand le noyau me convient.
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Créer les fichiers spéciaux de périphériques</title>
|
||
|
||
<para> Sur FreeBSD, vous avez la responsabilité de faire vos propres fichiers
|
||
spéciaux
|
||
de périphérique. Le
|
||
nombre majeur de votre périphérique est déterminé par le nombre de
|
||
slots dans le commutateur de périphérique. Le nombre mineur est
|
||
dépendant du pilote, naturellement. Vous pouvez
|
||
soit exécuter mknod depuis la ligne de commande, soit laisser faire le
|
||
travail à <filename>/dev/MAKEDEV.local</filename>, ou même
|
||
<filename>/dev/MAKEDEV</filename>.
|
||
Je crée parfois un script MAKEDEV.dev qui peut être soit lancé
|
||
de manière autonome soit collé dans <filename>/dev/MAKEDEV.local</filename>.
|
||
</para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Redémarrage</title>
|
||
<para> C'est la partie facile. Il y a un
|
||
certain nombre de méthodes pour faire ceci, reboot, fastboot,
|
||
shutdown - r, couper le courant, etc. Au démarrage, vous
|
||
devriez voir votre XX<function>probe()</function> appelé, et si tout marche,
|
||
votre <function>attach()</function> aussi.
|
||
</para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Module du noyau à chargement dynamique (LKM)</title>
|
||
|
||
<para>Il n'y a vraiment aucune procédure définie pour écrire un pilote de
|
||
LKM. Ce qui suit est ma propre conception après expérimentation
|
||
avec l'interface de périphérique LKM et en regardant le modèle standard
|
||
de module de gestion de périphérique, c'est une manière d'ajouter une
|
||
interface LKM à un pilote existant sans toucher aux sources (ou binaire)
|
||
initiaux de pilote . On recommande cependant,
|
||
que si vous projetez de distribuer les sources de votre pilote,
|
||
que les parties spécifiques LKM devraient faire partie du pilote
|
||
lui-même, compilé de manière conditionnelle par la macro LKM
|
||
(c.-à-d. #ifdef LKM).
|
||
</para>
|
||
|
||
<para>
|
||
Cette section se concentrera sur la manière d'écrire la partie spécifique
|
||
LKM du pilote. Nous supposerons que nous avons écrit un
|
||
pilote qui atterrira dans le modèle standard de
|
||
gestion de périphérique, que nous voudrions maintenant mettre en
|
||
application comme étant LKM. Nous utiliserons le pilote de pcaudio
|
||
comme pilote d'exemple, et développerons une entrée LKM. La
|
||
source et le fichier makefile pour le LKM pcaudio , ``pcaudio_lkm.c''
|
||
et ``Makefile'', devraient être dans placé <filename>/usr/src/lkm/pcaudio</filename>.
|
||
Ce qui suit est le code commenté de pcaudio_lkm.c.
|
||
</para>
|
||
|
||
<para>
|
||
Lignes 17 - 26
|
||
</para>
|
||
|
||
<para>
|
||
Ceci inclut le fichier ``pca.h'' et fait une compilation conditionnelle
|
||
du reste de LKM suivant que vous avez défini ou non le pilote de
|
||
périphérique pcaudio.
|
||
Cela imite le comportement de config. Dans un pilote de
|
||
périphérique standard,
|
||
<ulink url="http://www.freebsd.org/cgi/man.cgi?config(8)">config</ulink>
|
||
produit le fichier pca.h depuis le nombre de périphériques pca
|
||
le fichier de config. </para>
|
||
|
||
<programlisting>
|
||
17 /*
|
||
18 * figure out how many devices we have..
|
||
19 */
|
||
20
|
||
21 #include "pca.h"
|
||
22
|
||
23 /*
|
||
24 * if we have at least one ...
|
||
25 */
|
||
26 #if NPCA > 0
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 27 - 37
|
||
</para>
|
||
|
||
<para>
|
||
Les fichiers d'en-tête requis depuis divers répertoire d'inclusion.
|
||
</para>
|
||
|
||
<programlisting>
|
||
27 #include <sys/param.h>
|
||
28 #include <sys/systm.h>
|
||
29 #include <sys/exec.h>
|
||
30 #include <sys/conf.h>
|
||
31 #include <sys/sysent.h>
|
||
32 #include <sys/lkm.h>
|
||
33 #include <sys/errno.h>
|
||
34 #include <i386/isa/isa_device.h>
|
||
35 #include <i386/isa/isa.h>
|
||
36
|
||
37
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 38 - 51
|
||
</para>
|
||
|
||
<para>déclarent vos points d'entrée comme externs .
|
||
</para>
|
||
|
||
<programlisting>
|
||
38 /*
|
||
39 * declare your entry points as externs
|
||
40 */
|
||
41
|
||
42 extern int pcaprobe(struct isa_device *);
|
||
43 extern int pcaattach(struct isa_device *);
|
||
44 extern int pcaopen(dev_t, int, int, struct proc *);
|
||
45 extern int pcaclose(dev_t, int, int, struct proc *);
|
||
46 extern int pcawrite(dev_t, struct uio *, int);
|
||
47 extern int pcaioctl(dev_t, int, caddr_t);
|
||
48 extern int pcaselect(dev_t, int, struct proc *);
|
||
49 extern void pcaintr(struct clockframe *);
|
||
50 extern struct isa_driver pcadriver;
|
||
51
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 52 - 70
|
||
</para>
|
||
|
||
<para>
|
||
Cela crée la table d'entrée de commutateur de périphérique pour
|
||
votre pilote. Cette table est en gros entièrement mise dans le
|
||
système de commutation de périphériques à l'emplacement indiqué par
|
||
votre nombre majeur. Dans le modèle standard, c'est dans
|
||
<filename>/usr/src/sys/i386/i386/conf.c</filename>.
|
||
NOTE: vous ne pouvez pas sélectionner
|
||
un nombre majeur de périphérique plus grand que ce qui existe dans
|
||
conf.c, par exemple
|
||
il y a 67 slots pour des périphériques caractère, vous ne pouvez pas
|
||
utiliser un périphérique (caractère) de numéro majeur 67 ou
|
||
plus, sans avoir d'abord réservé de l'espace dans conf.c.
|
||
</para>
|
||
|
||
<programlisting>
|
||
52 /*
|
||
53 * build your device switch entry table
|
||
54 */
|
||
55
|
||
56 static struct cdevsw pcacdevsw = {
|
||
57 (d_open_t *) pcaopen, /* open */
|
||
58 (d_close_t *) pcaclose, /* close */
|
||
59 (d_rdwr_t *) enodev, /* read */
|
||
60 (d_rdwr_t *) pcawrite, /* write */
|
||
61 (d_ioctl_t *) pcaioctl, /* ioctl */
|
||
62 (d_stop_t *) enodev, /* stop?? */
|
||
63 (d_reset_t *) enodev, /* reset */
|
||
64 (d_ttycv_t *) enodev, /* ttys */
|
||
65 (d_select_t *) pcaselect, /* select */
|
||
66 (d_mmap_t *) enodev, /* mmap */
|
||
67 (d_strategy_t *) enodev /* strategy */
|
||
68 };
|
||
69
|
||
70
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 71 - 131
|
||
</para>
|
||
<para>
|
||
cette section est analogue à la déclaration de fichier de configuration
|
||
de votre périphérique. Les membres de la structure isa_device sont
|
||
remplis grace à ce qu'il connaît de votre périphérique,
|
||
port E/S, segment partagé de mémoire, etc...
|
||
Nous n'aurons probablement jamais un besoin de deux périphériques
|
||
pcaudio dans le noyau, mais cet exemple montre comment
|
||
périphériques multiples peuvent être supportés.
|
||
</para>
|
||
|
||
<programlisting>
|
||
71 /*
|
||
72 * this lkm arbitrarily supports two
|
||
73 * instantiations of the pc-audio device.
|
||
74 *
|
||
75 * this is for illustration purposes
|
||
76 * only, it doesn't make much sense
|
||
77 * to have two of these beasts...
|
||
78 */
|
||
79
|
||
80
|
||
81 /*
|
||
82 * these have a direct correlation to the
|
||
83 * config file entries...
|
||
84 */
|
||
85 struct isa_device pcadev[NPCA] = {
|
||
86 {
|
||
87 11, /* device id */
|
||
88 &pcadriver, /* driver pointer */
|
||
89 IO_TIMER1, /* base io address */
|
||
90 -1, /* interrupt */
|
||
91 -1, /* dma channel */
|
||
92 (caddr_t)-1, /* physical io memory */
|
||
93 0, /* size of io memory */
|
||
94 pcaintr , /* interrupt interface */
|
||
95 0, /* unit number */
|
||
96 0, /* flags */
|
||
97 0, /* scsi id */
|
||
98 0, /* is alive */
|
||
99 0, /* flags for register_intr */
|
||
100 0, /* hot eject device support */
|
||
101 1 /* is device enabled */
|
||
102 },
|
||
103 #if NPCA >1
|
||
104 {
|
||
105
|
||
106 /*
|
||
107 * these are all zeros, because it doesn't make
|
||
108 * much sense to be here
|
||
109 * but it may make sense for your device
|
||
110 */
|
||
111
|
||
112 0, /* device id */
|
||
113 &pcadriver, /* driver pointer */
|
||
114 0, /* base io address */
|
||
115 -1, /* interrupt */
|
||
116 -1, /* dma channel */
|
||
117 -1, /* physical io memory */
|
||
118 0, /* size of io memory */
|
||
119 NULL, /* interrupt interface */
|
||
120 1, /* unit number */
|
||
121 0, /* flags */
|
||
122 0, /* scsi id */
|
||
123 0, /* is alive */
|
||
124 0, /* flags for register_intr */
|
||
125 0, /* hot eject device support */
|
||
126 1 /* is device enabled */
|
||
127 },
|
||
128 #endif
|
||
129
|
||
130 };
|
||
131
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 132 - 139
|
||
</para>
|
||
|
||
<para>
|
||
Ceci appelle la macro MOD_DEV du préprocesseur C, qui
|
||
installe un module de gestion de périphérique de LKM, par
|
||
opposition à un système de fichiers LKM, ou un appel système de LKM.
|
||
</para>
|
||
|
||
<programlisting>
|
||
132 /*
|
||
133 * this macro maps to a function which
|
||
134 * sets the LKM up for a driver
|
||
135 * as opposed to a filesystem, system call, or misc
|
||
136 * LKM.
|
||
137 */
|
||
138 MOD_DEV("pcaudio_mod", LM_DT_CHAR, 24, &pcacdevsw);
|
||
139
|
||
</programlisting>
|
||
|
||
<para>
|
||
Lignes 140 - 168
|
||
</para>
|
||
|
||
<para>
|
||
c'est la fonction qui sera appelée lorsque le pilote sera
|
||
chargé. Cette fonction essaye de fonctionner comme
|
||
<filename>/sys/i386/isa/isa.c</filename> qui fait les appels de probe/attach pour un
|
||
pilote au moment du redémarrage. La plus grande astuce ici est qu'il
|
||
met en correspondance l'adresse physique du segment partagé de mémoire, qui est
|
||
indiqué dans la structure isa_device à une adresse virtuelle du noyau.
|
||
Normalement, l'adresse physique est mise dans le fichier de configuration
|
||
qui construit la structure isa_device dans
|
||
<filename>/usr/src/sys/compile/KERNEL/ioconf.c</filename>. La séquence probe/attach de
|
||
<filename>/usr/src/sys/isa/isa.c</filename> traduit l'adresse physique en une virtuelle de
|
||
sorte que dans les sous-programmes de probe/attach vous puissiez
|
||
faire des choses comme
|
||
</para>
|
||
<programlisting>
|
||
(int *)id->id_maddr = something;
|
||
</programlisting>
|
||
<para> et se réfère juste au segment partagé de mémoire
|
||
par l'intermédiaire de pointeurs.
|
||
</para>
|
||
|
||
<programlisting>
|
||
140 /*
|
||
141 * this function is called when the module is
|
||
142 * loaded; it tries to mimic the behavior
|
||
143 * of the standard probe/attach stuff from
|
||
144 * isa.c
|
||
145 */
|
||
146 int
|
||
147 <function>pcaload()</function>{
|
||
148 int i;
|
||
149 uprintf("PC Audio Driver Loaded\n");
|
||
150 for (i=0; i<NPCA; i++){
|
||
151 /*
|
||
152 * this maps the shared memory address
|
||
153 * from physical to virtual, to be
|
||
154 * consistent with the way
|
||
155 * /usr/src/sys/i386/isa.c handles it.
|
||
156 */
|
||
157 pcadev[i].id_maddr -=0xa0000;
|
||
158 pcadev[i].id_maddr += atdevbase;
|
||
159 if ((*pcadriver.probe)(pcadev+i)) {
|
||
160 (*(pcadriver.attach))(pcadev+i);
|
||
161 } else {
|
||
162 uprintf("PC Audio Probe Failed\n");
|
||
163 return(1);
|
||
164 }
|
||
165 }
|
||
166 return 0;
|
||
167 }
|
||
168
|
||
</programlisting>
|
||
|
||
<para>Lignes 169 - 179
|
||
</para>
|
||
|
||
<para>c'est la fonction appelée quand votre pilote n'est pas
|
||
chargé; il affiche juste un message à cet effet.
|
||
</para>
|
||
|
||
<programlisting>
|
||
169 /*
|
||
170 * this function is called
|
||
171 * when the module is unloaded
|
||
172 */
|
||
173
|
||
174 int
|
||
175 <function>pcaunload()</function>{
|
||
176 uprintf("PC Audio Driver Unloaded\n");
|
||
177 return 0;
|
||
178 }
|
||
179
|
||
</programlisting>
|
||
|
||
<para>Lignes 180 - 190
|
||
</para>
|
||
|
||
<para>c'est le point d'entrée qui est indiqué sur la ligne de commande
|
||
de modload. Par convention il est nommé <dev>_mod. C'est
|
||
ainsi qu'il est défini dans bsd.lkm.mk, le makefile qui
|
||
construit le LKM. Si vous nommez votre module suivant cette
|
||
convention, vous pouvez faire ``make load'' et ``make unload''
|
||
de /usr/src/lkm/pcaudio.</para>
|
||
|
||
<para>Note : Il y a eu <emphasis>tellement</emphasis> de révisions entre la version 2.0 et
|
||
2.1. Il peut ou ne peut ne pas être possible d'écrire
|
||
un module qui est portable pour chacune des trois versions.
|
||
</para>
|
||
|
||
|
||
<programlisting>
|
||
180 /*
|
||
181 * this is the entry point specified
|
||
182 * on the modload command line
|
||
183 */
|
||
184
|
||
185 int
|
||
186 pcaudio_mod(struct lkm_table *lkmtp, int cmd, int ver)
|
||
187 {
|
||
188 DISPATCH(lkmtp, cmd, ver, pcaload, pcaunload, nosys);
|
||
189 }
|
||
190
|
||
191 #endif /* NICP > 0 */
|
||
</programlisting>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Idiosyncrasies du type périphérique</title>
|
||
|
||
<sect3>
|
||
<title>Caractère</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Bloc</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Réseau</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Line discipline</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Idiosyncrasies du type bus</title>
|
||
|
||
<sect3>
|
||
<title>ISA</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>EISA</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>PCI</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>SCSI</title>
|
||
<para></para>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>PCCARD</title>
|
||
<para></para>
|
||
</sect3>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
|
||
<sect1>
|
||
<title>Support du noyau</title>
|
||
|
||
<sect2>
|
||
<title>Structures de données</title>
|
||
|
||
<sect3>
|
||
<title>Structure <citerefentry><refentrytitle>struct kern_devconf</refentrytitle></citerefentry></title>
|
||
|
||
<para>Cette structure contient quelques informations sur l'état du
|
||
périphérique et de son pilote. Elle est définie dans
|
||
<filename>/usr/src/sys/sys/devconf.h</filename> comme ci-dessous :
|
||
</para>
|
||
|
||
<programlisting>
|
||
struct devconf {
|
||
char dc_name[MAXDEVNAME]; /* name */
|
||
char dc_descr[MAXDEVDESCR]; /* description */
|
||
int dc_unit; /* unit number */
|
||
int dc_number; /* unique id */
|
||
char dc_pname[MAXDEVNAME]; /* name of the parent device */
|
||
int dc_punit; /* unit number of the parent */
|
||
int dc_pnumber; /* unique id of the parent */
|
||
struct machdep_devconf dc_md; /* machine-dependent stuff */
|
||
enum dc_state dc_state; /* state of the device (see above) */
|
||
enum dc_class dc_class; /* type of device (see above) */
|
||
size_t dc_datalen; /* length of data */
|
||
char dc_data[1]; /* variable-length data */
|
||
};
|
||
</programlisting>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Structure <citerefentry><refentrytitle>struct proc</refentrytitle></citerefentry></title>
|
||
|
||
<para> Cette structure contient toutes les informations sur un processus.
|
||
Elle est dans définie <filename>/usr/src/sys/sys/proc.h</filename>:
|
||
</para>
|
||
|
||
<programlisting>
|
||
/*
|
||
* Description of a process.
|
||
*
|
||
* This structure contains the information needed to manage a thread of
|
||
* control, known in UN*X as a process; it has references to
|
||
substructures
|
||
* containing descriptions of things that the process uses, but may
|
||
share
|
||
* with related processes. The process structure and the substructures
|
||
* are always addressable except for those marked "(PROC ONLY)" below,
|
||
* which might be addressable only on a processor on which the process
|
||
* is running.
|
||
*/
|
||
struct proc {
|
||
struct proc *p_forw; /* Doubly-linked run/sleep queue. */
|
||
struct proc *p_back;
|
||
struct proc *p_next; /* Linked list of active procs */
|
||
struct proc **p_prev; /* and zombies. */
|
||
|
||
/* substructures: */
|
||
struct pcred *p_cred; /* Process owner's identity. */
|
||
struct filedesc *p_fd; /* Ptr to open files structure. */
|
||
struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */
|
||
struct plimit *p_limit; /* Process limits. */
|
||
struct vmspace *p_vmspace; /* Address space. */
|
||
struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */
|
||
|
||
#define p_ucred p_cred->pc_ucred
|
||
#define p_rlimit p_limit->pl_rlimit
|
||
|
||
int p_flag; /* P_* flags. */
|
||
char p_stat; /* S* process status. */
|
||
char p_pad1[3];
|
||
|
||
pid_t p_pid; /* Process identifier. */
|
||
struct proc *p_hash; /* Hashed based on p_pid for kill+exit+... */
|
||
struct proc *p_pgrpnxt; /* Pointer to next process in process group. */
|
||
struct proc *p_pptr; /* Pointer to process structure of parent. */
|
||
struct proc *p_osptr; /* Pointer to older sibling processes. */
|
||
|
||
/* The following fields are all zeroed upon creation in fork. */
|
||
#define p_startzero p_ysptr
|
||
struct proc *p_ysptr; /* Pointer to younger siblings. */
|
||
struct proc *p_cptr; /* Pointer to youngest living child. */
|
||
pid_t p_oppid; /* Save parent pid during ptrace. XXX */
|
||
int p_dupfd; /* Sideways return value from fdopen. XXX */
|
||
|
||
/* scheduling */
|
||
u_int p_estcpu; /* Time averaged value of p_cpticks. */
|
||
int p_cpticks; /* Ticks of cpu time. */
|
||
fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */
|
||
void *p_wchan; /* Sleep address. */
|
||
char *p_wmesg; /* Reason for sleep. */
|
||
u_int p_swtime; /* Time swapped in or out. */
|
||
u_int p_slptime; /* Time since last blocked. */
|
||
|
||
struct itimerval p_realtimer; /* Alarm timer. */
|
||
struct timeval p_rtime; /* Real time. */
|
||
u_quad_t p_uticks; /* Statclock hits in user mode. */
|
||
u_quad_t p_sticks; /* Statclock hits in system mode. */
|
||
u_quad_t p_iticks; /* Statclock hits processing intr. */
|
||
|
||
int p_traceflag; /* Kernel trace points. */
|
||
struct vnode *p_tracep; /* Trace to vnode. */
|
||
|
||
int p_siglist; /* Signals arrived but not delivered. */
|
||
|
||
struct vnode *p_textvp; /* Vnode of executable. */
|
||
|
||
char p_lock; /* Process lock (prevent swap) count. */
|
||
char p_pad2[3]; /* alignment */
|
||
|
||
/* End area that is zeroed on creation. */
|
||
#define p_endzero p_startcopy
|
||
|
||
/* The following fields are all copied upon creation in fork. */
|
||
#define p_startcopy p_sigmask
|
||
|
||
sigset_t p_sigmask; /* Current signal mask. */
|
||
sigset_t p_sigignore; /* Signals being ignored. */
|
||
sigset_t p_sigcatch; /* Signals being caught by user. */
|
||
|
||
u_char p_priority; /* Process priority. */
|
||
u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */
|
||
char p_nice; /* Process "nice" value. */
|
||
char p_comm[MAXCOMLEN+1];
|
||
|
||
struct pgrp *p_pgrp; /* Pointer to process group. */
|
||
|
||
struct sysentvec *p_sysent; /* System call dispatch information. */
|
||
|
||
struct rtprio p_rtprio; /* Realtime priority. */
|
||
/* End area that is copied on creation. */
|
||
#define p_endcopy p_addr
|
||
struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */
|
||
struct mdproc p_md; /* Any machine-dependent fields. */
|
||
|
||
u_short p_xstat; /* Exit status for wait; also stop signal. */
|
||
u_short p_acflag; /* Accounting flags. */
|
||
struct rusage *p_ru; /* Exit information. XXX */
|
||
};
|
||
</programlisting>
|
||
</sect3>
|
||
|
||
<sect3>
|
||
<title>Structure <citerefentry><refentrytitle>struct buf</refentrytitle></citerefentry></title>
|
||
<para>La structure <citerefentry><refentrytitle>struct buf</refentrytitle></citerefentry> est employée pour s'interfacer
|
||
avec le cache de la mémoire tampon. Elle est dans
|
||
définie <filename>/usr/src/sys/sys/buf.h</filename> :
|
||
</para>
|
||
|
||
<programlisting>
|
||
/*
|
||
* The buffer header describes an I/O operation in the kernel.
|
||
*/
|
||
struct buf {
|
||
LIST_ENTRY(buf) b_hash; /* Hash chain. */
|
||
LIST_ENTRY(buf) b_vnbufs; /* Buffer's associated vnode. */
|
||
TAILQ_ENTRY(buf) b_freelist; /* Free list position if not active. */
|
||
struct buf *b_actf, **b_actb; /* Device driver queue when active. */
|
||
struct proc *b_proc; /* Associated proc; NULL if kernel. */
|
||
volatile long b_flags; /* B_* flags. */
|
||
int b_qindex; /* buffer queue index */
|
||
int b_error; /* Errno value. */
|
||
long b_bufsize; /* Allocated buffer size. */
|
||
long b_bcount; /* Valid bytes in buffer. */
|
||
long b_resid; /* Remaining I/O. */
|
||
dev_t b_dev; /* Device associated with buffer. */
|
||
struct {
|
||
caddr_t b_addr; /* Memory, superblocks, indirect etc. */
|
||
} b_un;
|
||
void *b_saveaddr; /* Original b_addr for physio. */
|
||
daddr_t b_lblkno; /* Logical block number. */
|
||
daddr_t b_blkno; /* Underlying physical block number. */
|
||
/* Function to call upon completion. */
|
||
void (*b_iodone) __P((struct buf *));
|
||
/* For nested b_iodone's. */
|
||
struct iodone_chain *b_iodone_chain;
|
||
struct vnode *b_vp; /* Device vnode. */
|
||
int b_pfcent; /* Center page when swapping cluster. */
|
||
int b_dirtyoff; /* Offset in buffer of dirty region. */
|
||
int b_dirtyend; /* Offset of end of dirty region. */
|
||
struct ucred *b_rcred; /* Read credentials reference. */
|
||
struct ucred *b_wcred; /* Write credentials reference. */
|
||
int b_validoff; /* Offset in buffer of valid region. */
|
||
int b_validend; /* Offset of end of valid region. */
|
||
daddr_t b_pblkno; /* physical block number */
|
||
caddr_t b_savekva; /* saved kva for transfer while bouncing */
|
||
void *b_driver1; /* for private use by the driver */
|
||
void *b_driver2; /* for private use by the driver */
|
||
void *b_spc;
|
||
struct vm_page *b_pages[(MAXPHYS + PAGE_SIZE - 1)/PAGE_SIZE];
|
||
int b_npages;
|
||
};
|
||
</programlisting>
|
||
</sect3>
|
||
|
||
|
||
<sect3>
|
||
<title>Structure <citerefentry><refentrytitle>struct uio</refentrytitle></citerefentry></title>
|
||
|
||
<para>Cette structure est utilisée pour déplacer des données entre le noyau et
|
||
les espaces utilisateur par les appels système de <function>read()</function> et de <function>write()</function>.
|
||
Il est dans défini <filename>/usr/src/sys/sys/uio.h</filename> :
|
||
</para>
|
||
|
||
<programlisting>
|
||
struct uio {
|
||
struct iovec *uio_iov;
|
||
int uio_iovcnt;
|
||
off_t uio_offset;
|
||
int uio_resid;
|
||
enum uio_seg uio_segflg;
|
||
enum uio_rw uio_rw;
|
||
struct proc *uio_procp;
|
||
};
|
||
</programlisting>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
|
||
<sect2>
|
||
<title>Fonctions</title>
|
||
<para>plein</para>
|
||
</sect2>
|
||
|
||
<sect2>
|
||
<title>Références.</title>
|
||
|
||
<para> FreeBSD Kernel Sources http://www.freebsd.org
|
||
</para>
|
||
|
||
<para> NetBSD Kernel Sources http://www.netbsd.org
|
||
</para>
|
||
|
||
<para> Writing Device Drivers: Tutorial and Reference;
|
||
Tim Burke, Mark A. Parenti, Al, Wojtas;
|
||
Digital Press, ISBN 1-55558-141-2.
|
||
</para>
|
||
|
||
<para> Writing A Unix Device Driver;
|
||
Janet I. Egan, Thomas J. Teixeira;
|
||
John Wiley & Sons, ISBN 0-471-62859-X.
|
||
</para>
|
||
|
||
<para> Writing Device Drivers for SCO Unix;
|
||
Peter Kettle;
|
||
</para>
|
||
</sect2>
|
||
</sect1>
|
||
</article>
|