Sophie

Sophie

distrib > * > 2010.0 > * > by-pkgid > a412ceb851151854794ced2a242192bb > files > 1390

howto-html-fr-20080722-1mdv2010.0.noarch.rpm

<html><head><META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>2.&nbsp;Utilisation des ports d'entr&eacute;es / sorties en langage C</title><link href="style.css" rel="stylesheet" type="text/css"><meta content="DocBook XSL Stylesheets V1.69.1" name="generator"><link rel="start" href="index.html" title="
    
        Petit guide de programmation des ports 
        d'entr&eacute;es / sorties sous Linux
    
    "><link rel="up" href="index.html" title="
    
        Petit guide de programmation des ports 
        d'entr&eacute;es / sorties sous Linux
    
    "><link rel="prev" href="ar01s01.html" title="1.&nbsp;Introduction"><link rel="next" href="ar01s03.html" title="3.&nbsp;Interruptions (IRQ) et acc&egrave;s DMA"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table summary="Navigation header" width="100%"><tr><th align="center" colspan="3">2.&nbsp;Utilisation des ports d'entr&eacute;es / sorties en langage C</th></tr><tr><td align="left" width="20%"><a accesskey="p" href="ar01s01.html">Pr&eacute;c&eacute;dent</a>&nbsp;</td><th align="center" width="60%">&nbsp;</th><td align="right" width="20%">&nbsp;<a accesskey="n" href="ar01s03.html">Suivant</a></td></tr></table><hr></div><div class="sect1" lang="fr"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="N100A0"></a>2.&nbsp;Utilisation des ports d'entr&eacute;es / sorties en langage C</h2></div></div><div></div></div><div class="sect2" lang="fr"><div class="titlepage"><div><div><h3 class="title"><a name="N100A3"></a>2.1.&nbsp;La m&eacute;thode normale</h3></div></div><div></div></div><p>
	Les routines pour acc&eacute;der aux ports d'entr&eacute;es / sorties sont 
	situ&eacute;es dans le fichier d'en-t&ecirc;te 
	<code class="filename">/usr/include/asm/io.h</code> (ou 
	<code class="filename">linux/include/asm-i386/io.h</code> dans les 
	sources du noyau Linux). Ces routines sont des macros, il suffit
	donc de d&eacute;clarer <code class="literal">#include 
	&lt;asm/io.h&gt;</code>; dans votre code source sans avoir 
	besoin de biblioth&egrave;ques additionnelles.
      </p><p>
	&Agrave; cause d'une limitation de gcc (pr&eacute;sente dans toutes les 
	versions que je connais, egcs y compris) vous 
	<span class="emphasis"><em>devez</em></span> compiler le code source qui fait 
	appel &agrave; ces routines avec le drapeau d'optimisation 
	(<span><strong class="command">gcc -O1</strong></span> ou plus), ou alternativement en 
	d&eacute;clarant <code class="literal">#define extern static</code> avant la 
	ligne <code class="literal">#include &lt;asm/io.h&gt;</code> 
	(n'oubliez pas de rajouter ensuite <code class="literal">#undef 
	extern</code>).
      </p><p>
	Pour le d&eacute;bogage, vous pouvez compiler avec les drapeaux 
	suivants (tout du moins avec les versions les plus r&eacute;centes de 
	gcc)&nbsp;: <span><strong class="command">gcc -g -O</strong></span>. Il faut savoir que 
	l'optimisation engendre un comportement parfois bizarre de la 
	part du d&eacute;bogueur. Si cela vous pose un r&eacute;el probl&egrave;me, vous 
	pouvez toujours utiliser les routines d'acc&egrave;s aux ports 
	d'entr&eacute;es / sorties dans un fichier source s&eacute;par&eacute;, et ne 
	compiler que ce fichier avec le drapeau d'optimisation activ&eacute;.
      </p><div class="sect3" lang="fr"><div class="titlepage"><div><div><h4 class="title"><a name="N100D1"></a>2.1.1.&nbsp;Les permissions</h4></div></div><div></div></div><p>
	  Avant d'acc&eacute;der aux ports, vous devez donner &agrave; votre 
	  programme la permission de le faire. Pour cela, il vous faut 
	  faire appel &agrave; la fonction <code class="function">ioperm()</code> 
	  (d&eacute;clar&eacute;e dans <code class="filename">unistd.h</code> et d&eacute;finie dans le 
	  noyau) quelque part au d&eacute;but de votre programme (avant tout 
	  acc&egrave;s aux ports d'entr&eacute;es / sorties). La syntaxe est la 
	  suivante&nbsp;: 
	  <code class="function">ioperm(<em class="replaceable"><code>premier_port</code></em>, , 
	  <em class="replaceable"><code>nombre</code></em>, , 
	  <em class="replaceable"><code>activer</code></em>)</code>, o&ugrave;
	  <em class="replaceable"><code>premier_port</code></em> est le num&eacute;ro 
	  du premier port auquel on souhaite avoir acc&egrave;s et 
	  <em class="replaceable"><code>nombre</code></em> le nombre de ports 
	  cons&eacute;cutifs auxquels on veut avoir la permission d'acc&eacute;der.
	  Par exemple, <code class="function">ioperm(0x300, 5, 1)</code> donnerait 
	  acc&egrave;s aux ports <code class="literal">0x300</code> jusqu'&agrave; 
	  <code class="literal">0x304</code> (au total 5 ports). Le 
	  dernier argument est une valeur bool&eacute;enne sp&eacute;cifiant si on 
	  autorise l'acc&egrave;s aux ports (vrai [1]) ou si on le 
	  restreint (faux [0]). Pour activer l'acc&egrave;s &agrave; plusieurs 
	  ports non cons&eacute;cutifs, vous pouvez faire plusieurs appels &agrave; 
	  <code class="function">ioperm()</code>. Reportez vous &agrave; la page de manuel 
	  <span class="citerefentry"><span class="refentrytitle">ioperm</span>(2)</span> pour plus de d&eacute;tails sur la syntaxe.
	</p><p>
	  L'appel &agrave; <code class="function">ioperm()</code> dans votre 
	  programme n&eacute;cessite les privil&egrave;ges de
	  super utilisateur (root). Il faut donc que votre programme 
	  soit ex&eacute;cut&eacute; en tant qu'utilisateur root, ou qu'il soit rendu 
	  setuid root. Vous pouvez abandonner les privil&egrave;ges 
	  d'utilisateur root apr&egrave;s  l'appel &agrave; 
	  <code class="function">ioperm()</code>. Il n'est pas imp&eacute;ratif
	  d'abandonner de fa&ccedil;on explicite  les privil&egrave;ges d'acc&egrave;s aux 
	  ports en utilisant <code class="function">ioperm( ... , 0 )</code> 
	  &agrave; la fin de votre programme, ceci est fait automatiquement 
	  lorsque le processus se termine.
	</p><p>
	  L'utilisation de <code class="function">setuid()</code> par un 
	  utilisateur non privil&eacute;gi&eacute; ne supprime pas l'acc&egrave;s accord&eacute; aux 
	  ports par <code class="function">ioperm()</code>. En revanche, lors d'un 
	  <code class="function">fork()</code>, le processus fils n'h&eacute;rite pas des 
	  permissions de son p&egrave;re (qui lui les garde).
	</p><p>
	  La fonction <code class="function">ioperm()</code> permet de contr&ocirc;ler 
	  l'acc&egrave;s aux ports de <code class="literal">0x000</code> &agrave; 
	  <code class="literal">0x3ff</code> uniquement. Pour les ports 
	  sup&eacute;rieurs, vous devez utiliser <code class="function">iopl()</code> 
	  qui ouvre un acc&egrave;s &agrave; tous les ports d'un coup. Pour donner &agrave; 
	  votre programme l'acc&egrave;s &agrave; <span class="emphasis"><em>tous</em></span> les ports 
	  d'entr&eacute;es / sorties (soyez certains de ce que vous faites 
	  car l'acc&egrave;s &agrave; des ports inappropri&eacute;s peut avoir des 
	  cons&eacute;quences d&eacute;sastreuses pour votre syst&egrave;me), il suffit de 
	  passer &agrave; la fonction un argument de valeur 
	  <code class="literal">3</code> (<code class="function">iopl(3)</code>). 
	  Reportez-vous &agrave; la page de manuel 
	  <span class="citerefentry"><span class="refentrytitle">iopl</span>(2)</span>
	  pour plus de d&eacute;tails.
	</p></div><div class="sect3" lang="fr"><div class="titlepage"><div><div><h4 class="title"><a name="N10147"></a>2.1.2.&nbsp;L'acc&egrave;s aux ports</h4></div></div><div></div></div><p>
	  Pour lire un octet (8 bits) sur un port, un appel &agrave;
	  <code class="function">inb(<em class="replaceable"><code>port</code></em>)</code> 
	  retourne la valeur de l'octet lu. Pour l'&eacute;criture d'un octet, 
	  il suffit d'appeler la fonction 
	  <code class="function">outb(<em class="replaceable"><code>valeur</code></em>, , 
	  <em class="replaceable"><code>port</code></em>)</code> (attention &agrave; 
	  l'ordre des param&egrave;tres).
	  La lecture d'un mot (16 bits) sur les ports 
	  <code class="literal"><em class="replaceable"><code>x</code></em></code> et 
	  <code class="literal"><em class="replaceable"><code>x</code></em>+1</code> (un octet 
	  sur chaque port pour constituer un mot gr&acirc;ce &agrave; l'instruction 
	  assembleur <code class="function">inw</code>), faites appel &agrave; 
	  <code class="function">inw(<em class="replaceable"><code>x</code></em>)</code>. Enfin, 
	  pour l'&eacute;criture d'un mot sur les deux ports, utilisez 
	  <code class="function">outw(<em class="replaceable"><code>value</code></em>, , 
	  <em class="replaceable"><code>x</code></em>)</code>. 
	  Si vous n'&ecirc;tes pas certain quant &agrave; la fonction &agrave; utiliser 
	  (octet ou mot), il est sage de se cantonner &agrave; l'appel de 
	  <code class="function">inb()</code> et <code class="function">outb()</code>. La 
	  plupart des p&eacute;riph&eacute;riques sont con&ccedil;us pour des acc&egrave;s sur un 
	  octet. Notez que toutes les instructions d'acc&egrave;s aux ports 
	  n&eacute;cessitent un temps d'ex&eacute;cution d'au minimum une 
	  microseconde.
	</p><p>
	  Les macros <code class="function">inb_p()</code>, 
	  <code class="function">outb_p()</code>, 
	  <code class="function">inw_p()</code> et 
	  <code class="function">outw_p()</code> fonctionnent  de mani&egrave;re 
	  identique &agrave; celles &eacute;voqu&eacute;es pr&eacute;c&eacute;demment &agrave; l'exception du fait 
	  qu'elles effectuent un court temps de pause additionnel apr&egrave;s 
	  l'acc&egrave;s au port (environ une microseconde). Vous avez la 
	  possibilit&eacute; d'allonger ce temps de pause &agrave; quatre 
	  microsecondes avec la directive <code class="literal">#define 
	  REALLY_SLOW_IO</code> avant de d&eacute;clarer 
	  <code class="literal">#include &lt;asm/io.h&gt;</code>. Ces macros 
	  utilisent normalement une &eacute;criture sur le port 
	  <code class="literal">0x80</code> pour leur temps de pause (sauf en 
	  d&eacute;clarant un <code class="literal">#define 
	  SLOW_IO_BY_JUMPING</code>, qui est en 
	  revanche moins pr&eacute;cis). Vous devez donc au pr&eacute;alable autoriser 
	  l'acc&egrave;s au port <code class="literal">0x80</code> avec 
	  <code class="function">ioperm()</code> (l'&eacute;criture sur le port 
	  <code class="literal">0x80</code> ne devrait avoir aucun effet 
	  ind&eacute;sirable sur votre syst&egrave;me).
	</p><p>
	  Si vous &ecirc;tes &agrave; la recherche de m&eacute;thodes plus souples 
	  d'utilisation, lisez la suite&nbsp;&hellip;
	</p><p>
	  Des pages de manuel pour
	  <span class="citerefentry"><span class="refentrytitle">ioperm</span>(2)</span>,
	  <span class="citerefentry"><span class="refentrytitle">iopl</span>(2)</span> et les macros d&eacute;crites ci-dessus sont 
	  disponibles dans les collections assez r&eacute;centes des pages de 
	  manuel Linux.
	</p></div></div><div class="sect2" lang="fr"><div class="titlepage"><div><div><h3 class="title"><a name="N101C3"></a>2.2.&nbsp;Une m&eacute;thode alternative&nbsp;: <code class="filename">/dev/port</code></h3></div></div><div></div></div><p>
	Un autre moyen d'acc&eacute;der aux ports d'entr&eacute;es / sorties est 
	d'ouvrir en lecture ou en &eacute;criture le p&eacute;riph&eacute;rique <code class="filename">/dev/port</code> (un p&eacute;riph&eacute;rique en mode 
	caract&egrave;re, num&eacute;ro majeur <code class="literal">1</code>, mineur 
	<code class="literal">4</code>) au moyen de la fonction 
	<code class="function">open()</code>. Notons que les fonctions en 
	<code class="function">f*()</code> de la biblioth&egrave;que stdio font appel &agrave; 
	des tampons m&eacute;moires internes, il vaut donc mieux les &eacute;viter. Il 
	suffit ensuite, comme dans le cas d'un fichier, de se 
	positionner sur l'octet appropri&eacute; au moyen de la fonction 
	<code class="function">lseek()</code> (l'octet <code class="literal">0</code> du 
	fichier &eacute;quivaut au port <code class="literal">0x00</code>, l'octet 
	<code class="literal">1</code> au port <code class="literal">0x01</code>, et c&aelig;tera) 
	et d'en lire (<code class="function">read()</code>) ou &eacute;crire 
	(<code class="function">write()</code>) un octet ou un mot.
      </p><p>
	Il est &eacute;vident que l'application doit avoir la permission 
	d'acc&eacute;der au p&eacute;riph&eacute;rique <code class="filename">/dev/port</code> pour que cette m&eacute;thode 
	fonctionne. Cette fa&ccedil;on de faire reste certainement plus lente 
	que la premi&egrave;re, mais elle ne n&eacute;cessite ni optimisation lors de 
	la compilation ni appel &agrave; <code class="function">ioperm()</code>. L'acc&egrave;s 
	aux privil&egrave;ges de super-utilisateur n'est pas imp&eacute;ratif non 
	plus, si vous donnez les permissions ad&eacute;quates &agrave; un utilisateur 
	ou un groupe pour acc&eacute;der &agrave; <code class="filename">/dev/port</code> (cela reste tout de m&ecirc;me 
	une tr&egrave;s mauvaise id&eacute;e du point de vue de la s&eacute;curit&eacute; du 
	syst&egrave;me, puisqu'il devient possible de porter atteinte au 
	syst&egrave;me, peut-&ecirc;tre m&ecirc;me d'obtenir le statut de root en utilisant
	<code class="filename">/dev/port</code> pour acc&eacute;der 
	directement aux disques durs, cartes r&eacute;seaux, et c&aelig;tera).
      </p><p>
	Il n'est pas possible d'utiliser les fonctions
	<span class="citerefentry"><span class="refentrytitle">select</span>(2)</span> ou
	<span class="citerefentry"><span class="refentrytitle">poll</span>(2)</span>
	pour lire <code class="filename">/dev/port</code> puisque l'&eacute;lectronique du syst&egrave;me n'a pas la
	possibilit&eacute; d'avertir le microprocesseur qu'une valeur a chang&eacute; sur
	un port d'entr&eacute;e.
      </p></div></div><div class="navfooter"><hr><table summary="Navigation footer" width="100%"><tr><td align="left" width="40%"><a accesskey="p" href="ar01s01.html">Pr&eacute;c&eacute;dent</a>&nbsp;</td><td align="center" width="20%">&nbsp;</td><td align="right" width="40%">&nbsp;<a accesskey="n" href="ar01s03.html">Suivant</a></td></tr><tr><td valign="top" align="left" width="40%">1.&nbsp;Introduction&nbsp;</td><td align="center" width="20%"><a accesskey="h" href="index.html">Sommaire</a></td><td valign="top" align="right" width="40%">&nbsp;3.&nbsp;Interruptions (IRQ) et acc&egrave;s DMA</td></tr></table></div></body></html>