diff options
author | Sebastien Gioria <gioria@FreeBSD.org> | 2000-06-01 19:14:23 +0000 |
---|---|---|
committer | Sebastien Gioria <gioria@FreeBSD.org> | 2000-06-01 19:14:23 +0000 |
commit | 354d5398632ac67498ed7dd3a25e99d4730eac2b (patch) | |
tree | 7aa7e44b29e83b1e15c878bf96baf9b285b1089c /fr_FR.ISO8859-1/articles | |
parent | 5313148f94c744b2b773951dcc3f06cdfe24ee11 (diff) | |
download | doc-354d5398632ac67498ed7dd3a25e99d4730eac2b.tar.gz doc-354d5398632ac67498ed7dd3a25e99d4730eac2b.zip |
Adding the device driver guide
Notes
Notes:
svn path=/head/; revision=7275
Diffstat (limited to 'fr_FR.ISO8859-1/articles')
-rw-r--r-- | fr_FR.ISO8859-1/articles/ddwg/Makefile | 20 | ||||
-rw-r--r-- | fr_FR.ISO8859-1/articles/ddwg/article.sgml | 1861 |
2 files changed, 1881 insertions, 0 deletions
diff --git a/fr_FR.ISO8859-1/articles/ddwg/Makefile b/fr_FR.ISO8859-1/articles/ddwg/Makefile new file mode 100644 index 0000000000..68714b471c --- /dev/null +++ b/fr_FR.ISO8859-1/articles/ddwg/Makefile @@ -0,0 +1,20 @@ +# +# The FreeBSD Documentation Project +# The FreeBSD French Documentation Project +# +# $Id: Makefile,v 1.1 2000-06-01 19:14:23 gioria Exp $ +# Original revision: 1.4 +# + +DOC?= article + +FORMATS?= html + +INSTALL_COMPRESSED?=gz +INSTALL_ONLY_COMPRESSED?= + +SRCS= article.sgml + +DOC_PREFIX?= ${.CURDIR}/../../.. + +.include "${DOC_PREFIX}/share/mk/doc.project.mk" diff --git a/fr_FR.ISO8859-1/articles/ddwg/article.sgml b/fr_FR.ISO8859-1/articles/ddwg/article.sgml new file mode 100644 index 0000000000..012e35654a --- /dev/null +++ b/fr_FR.ISO8859-1/articles/ddwg/article.sgml @@ -0,0 +1,1861 @@ +<!-- + The FreeBSD Documentation Project + The FreeBSD French Documentation Project + + $Id: article.sgml,v 1.1 2000-06-01 19:14:23 gioria Exp $ + Original revision: n.nn +--> + +<!DOCTYPE ARTICLE PUBLIC "-//FreeBSD//DTD DocBook V3.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 SYSTEM "../../../en_US.ISO_8859-1/books/handbook/authors.ent"> %authors; +<!ENTITY % mailing-lists SYSTEM "../../books/handbook/mailing-lists.ent"> %mailing-lists; + <!ENTITY rel.current CDATA "3.2"> +]> + + +<article lang="fr"> + <artheader> + <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> + </artheader> + + +<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 dispnibles, 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 un équivalence directe ebtre 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 É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 utilise 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 additionnellement 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. À 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 liasser 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 popuvez 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 connait 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> |