<!-- <!DOCTYPE Article PUBLIC "-//Davenport//DTD DocBook V3.0//EN"> -->
<!DOCTYPE Article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">

<article>

<artheader>
<!--
<title>Linux I/O port programming mini-HOWTO</title>
-->
<title>Linux I/O ポートプログラミング mini-HOWTO</title>
<author>
<firstname>Riku</firstname>
<surname>Saikkonen</surname>
<affiliation>
 <address>Riku.Saikkonen@hut.fi</address>
</affiliation>
</author>
<othercredit role="translator" lang="ja">
<firstname>JF Project</firstname>
<surname></surname>
<contrib>日本語訳</contrib>
<affiliation>
 <address>JF@linux.or.jp</address>
</affiliation>
</othercredit>
<pubdate>v3.0, 2000-12-13</pubdate>

<abstract>
<para>
<!--
This HOWTO document describes programming hardware I/O ports and
waiting for small periods of time in user-mode Linux programs running
on the Intel x86 architecture.
-->
この ハウツーでは、インテルの x86 プロセッサ上で走るプログラム上の、
ハードウェア I/O ポートのプログラミングと、Linux のユーザモードで短い時間
待ちをおこなうプログラム、などについて述べます。
</para>
</abstract>

</artheader>

<sect1 id="intro">
<title>Introduction </title>

<para>
<!--
This HOWTO document describes programming hardware I/O ports and
waiting for small periods of time in user-mode Linux programs running
on the Intel x86 architecture. This document is a descendant of the
very small IO-Port mini-HOWTO by the same author.
-->
この ハウツーでは、インテルの x86 プロセッサ上で走るプログラム上の、
ハードウェア I/O ポートのプログラミングと、Linux のユーザモードで短い時間
待ちをおこなうプログラム、などについて述べます。
私は前にも同じような(とても小さな) IO-Port-mini-HOWTO を書きましたが、
この文書はその続編です。
</para>

<para>
<!--
This document is Copyright 1995-2000 Riku Saikkonen. See the <ULink
url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/COPYRIGHT"
>Linux HOWTO copyright</ULink
> for details.
-->
このドキュメントの著作権は 1995-2000 Riku Saikkonsen に属します。
詳細に関しては通常の <ulink 
url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/COPYRIGHT">
Linux の HOWTO COPYRIGHT </ulink>をご覧下さい。
</para>

<para>
<!--
If you have corrections or something to add, feel free to e-mail me
(<Literal remap="tt">Riku.Saikkonen@hut.fi</literal>)...
-->
もし、なにか間違いがあったり、付け加えることなどありましたらぜひ
私にメイルしてください。(<literal>Riku.Saikkonen@hut.fi</literal>)
</para>

<para>
日本語訳版についてのご指摘、ご意見などございましたら
JF Projectまでお願いします。&lt;JF@linux.or.jp&gt;
</para>
</sect1>

<sect1 id="using">
<!-- <title>Using I/O ports in C programs</title> -->
<title> C プログラムから I/O ポートを使う</title>

<sect2>
<!-- <title>The normal method</title> -->
<title>普通の方法</title>
<para>
<!--
Routines for accessing I/O ports are in <literal>/usr/include/asm/io.h
</literal> (or <literal>linux/include/asm-i386/io.h</literal> in the kernel 
source distribution). The routines there are inline macros, so it is enough
to <literal>&num;include &lt;asm/io.h&gt;</literal>; you do not need any 
additional libraries.
-->
I/O ポートをアクセスするためのルーチンは <filename>/usr/include/asm/io.h
</filename> (またはカーネルのソースパッケージの中の <filename>
linux/include/asm-i386/io.h</filename>) に定義されています。必要なルーチンは、
この中でインラインマクロとして定義されていま
すので、<filename>&num;include &lt;asm/io.h&gt;</filename> 
とするだけで十分でしょう。特別なライブラリなどは不要です。
</para>

<para>
<!--
Because of a limitation in gcc (present in all versions I know of,
including egcs), you <Emphasis>have to</Emphasis> compile any source code that 
uses these routines with optimisation turned on (<literal>gcc -O1</literal> or 
higher),or alternatively use <literal>&num;define extern static</literal> 
before you <literal>&num;include &lt;asm/io.h&gt;</literal> (remember to 
<literal>&num;undef extern</literal>afterwards).
-->
gcc (私の知る限り全てのバージョン、egcs も含む) からの制限のため、
これらのルーチンを使うソースをコンパイルするにあたり、最適化をオン
にする( <command>gcc <option>-O1</option></command> またはそれ以上)、あるい
は <literal>&num;include &lt;asm/io.h&gt;</literal> の前に 
<literal>&num;define extern static</literal> という宣言を
おこなっておく<emphasis>必要</emphasis>があります。
(あとで <literal>&num;undef extern</literal> しておくのを
忘れないように。)
</para>

<para>
<!--
For debugging, you can use <literal>gcc -g -O</literal> (at least with modern
versions of gcc), though optimisation can sometimes make the debugger
behave a bit strangely. If this bothers you, put the routines that use
I/O port access in a separate source file and compile only that with
optimisation turned on.
-->
デバッグのために、(少なくとも最近の gcc では) <command>
gcc <option>-g</option> <option>-O</option></command>を使うことができますが、
最適化されたコードではデ
バッガが変な挙動を示すこともあります。このような場合には、I/O ポート
アクセスを含んだコードを独立したファイルにしておいて、そのファイルの
コンパイルの時にだけ最適化をオンにするという方法を使うこともできます。
</para>

<sect3>
<!-- <title>Permissions</title> -->
<title>パーミッション</title>

<para>
<!--
Before you access any ports, you must give your program permission to
do so. This is done by calling the <literal>ioperm()</literal> function 
(declared in <literal>unistd.h</literal>, and defined in the kernel) somewhere 
near the start of your program (before any I/O port accesses). The syntax is
<literal>ioperm(from, num, turn&lowbar;on)</literal>, where <literal>from
</literal> is the first port number to give access to, and <literal>num
</literal> the number of consecutive ports to give access to. 
-->
ポートをアクセスする前に、そのポートをアクセスする許可をプログラムに与え
なければなりません。これには、<function>ioperm()</function> 関数
 (<filename class="headerfile">unistd.h</filename> で宣言され、カーネルの中で
定義されている)を呼び出します。この関数はプログラムの最初の方で( I/O ポート
アクセスをする前に)呼び出す必要があります。
この関数の書式は <function>ioperm(from, num, turn&lowbar;on)
</function>です。
<literal>from</literal>はアクセスを許すポートの最初のアドレス、
<literal>num</literal>は<literal>from</literal>から
いくつの連続アドレスのアクセスを許すか、を指定します。
<!--
For example, <literal>ioperm(0x300, 5, 1)</literal> would give
access to ports 0x300 through 0x304 (a total of 5 ports). The last
argument is a Boolean value specifying whether to give access to the
program to the ports (true (1)) or to remove access (false (0)). You
can call <literal>ioperm()</literal> multiple times to enable multiple
non-consecutive ports. See the <literal>ioperm(2)</literal> manual page for 
details on the syntax.
-->
例えば、<function>ioperm(0x300, 5, 1)</function> は、0x300 から
0x304 (合計で 5 つのポート)に対する許可を指定し、最後のパラメータでは、
そのポートに対するアクセス許可を与えるのか禁止するのかを論理値(true : 1 
= アクセスを許可する, false : 0 = アクセスを禁止する)で指定します。
連続していないポートの場合には、複数回<function>ioperm()</function>
を呼び出して、適切な許可を指定します。
文法の詳細に関しては <literal>ioperm(2)</literal> のマニュアル
ページを参照してください。
</para>

<para>
<!--
The <literal>ioperm()</literal> call requires your program to have root 
privileges;
thus you need to either run it as the root user, or make it setuid
root. You can drop the root privileges after you have called
<literal>ioperm()</literal> to enable the ports you want to use. You are not
required to explicitly drop your port access privileges with
<literal>ioperm(..., 0)</literal> at the end of your program; this is done
automatically as the process exits.
-->
<function>ioperm()</function> を呼び出すには、そのプログラムが 
root 特権で走っていることが必要です。
つまり、そのプログラムをルートユーザで実行するか、setuid root (訳注: 実
行ファイルのオーナーを root にしておき、chmod 4755 hogehoge というやつ
です。)しておく必要があります。
必要なポートに対する許可を <function>ioperm()</function> で与え
たあとに、root 特権を落すこともできます。
プログラムの最後で、明示的に <function>ioperm(..., 0)</function> 
を呼び出して許可を落す必要はありません。
これはプログラムの終了時に自動的に行なわれますから。
</para>

<para>
<!--
A <literal>setuid()</literal> to a non-root user does not disable the port 
access granted by <literal>ioperm()</literal>, but a <literal>fork()</literal> 
does (the child process does not get access, but the parent retains it).
-->
root 以外のユーザに <function>setuid()</function> することで 
<function>ioperm()</function> の与えたポートアクセス許可が
なくなることはありませんが、一方で <function>fork()</function> 
すると許可がなくなります。
(子プロセスはアクセス許可を持っていませんが、親プロセスは持っています。)
</para>

<para>
<!--
<literal>ioperm()</literal> can only give access to ports 0x000 through 0x3ff; 
for higher ports, you need to use <literal>iopl()</literal> (which gives you 
access to all ports at once). Use the level argument 3 (i.e., <literal>iopl(3)
</literal>) to give your program access to <Emphasis>all</Emphasis> I/O ports 
(so be careful &#045;&#045;&#045; accessing the wrong ports can do all sorts 
of nasty things to your computer). Again, you need root privileges to call 
<literal>iopl()</literal>. See the <literal>iopl(2)</literal> manual page for 
details.
-->
<function>ioperm()</function> では、0x000 から 0x3ff までの
ポートに対するアクセス許可しか与えることはできません。
これよりも上のポートに対しては、<function>iopl()</function> 
を使う必要があります。
(<function>iopl()</function> を使うと一度にすべてのポートに対
するアクセス許可を与えることになります。)
<emphasis>すべての</emphasis>ポートに対してアクセス許可を与えるには、
レベルパラメータとして「3」を使います。つまり、<function>
iopl(3)</function> という関数呼び出しをします。
(間違ったポートにアクセスするととんでもないことが起きるかも知れません
から、使うときには注意してください。)
もちろん、<function>iopl()</function> を呼び出す時には root 
特権が必要です。
詳細に関しては <literal>iopl(2)</literal> のマニュアルページを
参照してください。
</para>

</sect3>

<sect3>
<!-- <title>Accessing the ports</title> -->
<title>ポートのアクセス</title>

<para>
<!--
To input a byte (8 bits) from a port, call <literal>inb(port)</literal>, it 
returns the byte it got. To output a byte, call <literal>outb(value, port)
</literal> (please note the order of the parameters). To input a word (16 bits)
from ports <literal>x</literal> and <literal>x+1</literal> (one byte from each 
to form the word, using the assembler instruction <literal>inw</literal>), 
call <literal>inw(x)</literal>. To output a word to the two ports, use 
<literal>outw(value, x)</literal>. If you're unsure of which port instructions 
(byte or word) to use, you probably want <literal>inb()</literal> and <literal>
outb()</literal> &#045;&#045;&#045; most devices are designed for bytewise
port access. Note that all port access instructions take at least
about a microsecond to execute.
-->
ポートからバイトデータ(8bit)を入力する場合には <function>
inb(port)</function> を呼び出します。
この関数はバイトデータを返します。
ポートにバイトデータを出力するには、<function>outb(value, port)
</function> を呼び出します。
(パラメータの順番に注意して下さい。)
(訳注:アセンブラや、MS-DOS のコンパイラライブラリなどの場合とは逆です。) 
ポートアドレス <literal>x</literal> と <literal>x+1 
</literal>からワードデータを入力する場合には <function>inw(x)
</function> を呼び出します。(アセンブラの<function>inw</function>
とまったく同じようにそれぞれのポートから 1 バイトずつ読んできて、ワード
データを構成するわけですが。)
ふたつのポートにワード( 2 バイト)を出力するには <function>
outw(value, x)</function> を使います。
どちらの命令(バイトデータかワードデータか)を使えばいいのか分からないときは、
多分、<function>inb()</function> と <function>outb()
</function> を使えばいいでしょう。
大抵のデバイスはバイト単位のポートアクセスをするよう設計されています。
ポートアクセスの命令はすべて実行に少なくとも約 1 マイクロ秒かかるので
注意してください。
</para>

<para>
<!--
The <literal>inb&lowbar;p()</literal>, <literal>outb&lowbar;p()</literal>, 
<literal>inw&lowbar;p()</literal>, and <literal>outw&lowbar;p()</literal>
macros work otherwise identically to the ones above, but they do an
additional short (about one microsecond) delay after the port access;
you can make the delay about four microseconds with <literal>&num;define
REALLY&lowbar;SLOW&lowbar;IO</literal> before you <literal>&num;include &lt;
asm/io.h&gt;</literal>. These macros normally (unless you <literal>&num;define 
SLOW&lowbar;IO&lowbar;BY&lowbar;JUMPING</literal>, which
is probably less accurate) use a port output to port 0x80 for their
delay, so you need to give access to port 0x80 with <literal>ioperm()</literal>
first (outputs to port 0x80 should not affect any part of the
system). For more versatile methods of delaying, read on.
-->
<function>inb&lowbar;p()</function>, 
<function>outb&lowbar;p()</function>, 
<function>inw&lowbar;p()</function>, 
<function>outw&lowbar;p()</function> といったマクロは、上に述べたのと
同じ動作をしますが、ポートにアクセスした後に少しだけ(約 1 マイクロ秒)
ウエイトします。
<literal>&num;include &lt;asm/io.h&gt;</literal> の前に 
<literal>&num;define REALLY&lowbar;SLOW&lowbar;IO</literal> を
付け加えるとこのウエイト時間を 4 マイクロ秒に変えることができます。
これらのマクロは通常、0x80 番地の I/O ポートに出力することでウエイトを
実現しています。
(<literal>&num;define SLOW&lowbar;IO&lowbar;BY&lowbar;JUMPING
</literal> としている場合には別の方法が使われますが、これはあまり正確な遅延
をおこなうことができないはずです。)
このような理由から、0x80 番地のポートに対する <function>ioperm()
</function> を先に実行しておく必要が
あります。(0x80 番地のポートに対する出力はシステムに対してなんら影響を
与えることはないはずです。)
さらにさまざまな遅延を行なう方法については、以下を読み進めて下さい。
</para>

<para>
<!--
There are manual pages for <literal>ioperm(2)</literal>, <literal>iopl(2)
</literal>, and the above macros in reasonably recent releases of the Linux 
manual page collection.
-->
そこそこ最近のリリースの Linux マニュアルページには、
<literal>ioperm(2)</literal> や <literal>iopl(2)
</literal>、上述のマクロに関する説明があります。
</para>

</sect3>

</sect2>

<sect2>
<!-- <title>An alternate method: <literal>/dev/port</literal></title> -->
<title>I/O ポートアクセスをする別の方法：<literal>/dev/port</literal></title>

<para>
<!--
Another way to access I/O ports is to <literal>open()</literal> <literal>
/dev/port</literal> (a character device, major number 1, minor 4) for reading 
and/or writing (the stdio <literal>f*()</literal> functions have internal 
buffering, so avoid them). Then <literal>lseek()</literal> to the appropriate 
byte in the file (file position 0 = port 0x00, file position 1 = port 0x01, 
and so on), and <literal>read()</literal> or <literal>write()</literal> a byte 
or word from or to it.
-->
I/O ポートにアクセスするもう一つの方法は、<function>open()
</function> を使って <filename>/dev/port</filename> (キャラクタデ
バイス、メジャー番号 1、マイナー番号 4)をオープンして、read/write をお
こなうという方法です。
(stdio の <function>f*()</function> 関数(訳注: <function>
fwrite()</function> とか <function>fread()</function> とか...)は内
部でバッファリングをしているので、使えませんね。)
オープンした後に、入出力したいポートのアドレスまで <function>
lseek()</function> します。
(file position 0 が ポート 0x00 に、file position 1 が ポート 0x01 ... 
といった具合に相当します。)
その後に <function>read()</function>, <function>write()
</function> を使ってバイト/ワードを読み書きします。
</para>

<para>
<!--
Naturally, for this to work your program needs read/write access to
<literal>/dev/port</literal>. This method is probably slower than the normal
method above, but does not need compiler optimisation nor
<literal>ioperm()</literal>. It doesn't need root access either, if you give a
non-root user or group access to <literal>/dev/port</literal> 
&#045;&#045;&#045; but this is a
very bad thing to do in terms of system security, since it is possible
to hurt the system, perhaps even gain root access, by using
<literal>/dev/port</literal> to access hard disks, network cards, etc. 
directly.
-->
この方法を使うには、もちろん そのプログラムが <filename>/dev/port
</filename> に対する read/write 許可を持っていなければなりません。
この方法は上に述べた通常の方法よりもおそらく遅いでしょうが、コンパイル時の
最適化や <function>ioperm()</function> が不要であるという利点があり
ます。
<filename>/dev/port</filename> に対してルート以外のユーザやグループの
アクセス許可を与えれば root 特権も必要ありません。
でもこれはシステムセキュリティという意味ではとても良くないことです。
というのは、<filename>/dev/port</filename> を使ってハードディスク、
ネットワークカード、その他に直接アクセスすることで、システムに障害を与えたり、
さらには root 特権も与えてしまう可能性があるからです。
</para>

<para>
<!--
You cannot use <literal>select(2)</literal> or <literal>poll(2)</literal> to 
read /dev/port, because the hardware does not have a facility for notifying 
the CPU when a value in an input port changes.
-->
<filename>/dev/port</filename> からの読み込みにおいて 
<literal>select(2)</literal> や <literal>poll(2)</literal> 
を使うことはできません。
なぜなら入力ポートの値が変化したときに、ハードウェアにはそれをCPUに
伝える機能がないからです。
</para>

</sect2>

</sect1>

<sect1 id="irq">
<!-- <title>Interrupts (IRQs) and DMA access</title> -->
<title>割り込み (IRQ) と DMA アクセス</title>

<para>
<!--
You cannot use IRQs or DMA directly from a user-mode process. You need
to write a kernel driver; see <ulink
url="http://www.redhat.com:8080/HyperNews/get/khg.html"
>The Linux Kernel Hacker's Guide</ulink
> for details and the kernel source code
for examples.
-->
ユーザモードのプログラムから直接に割り込みや DMA を使うことはできません。
これには、カーネルドライバを作成する必要があります。その詳細については
<ulink url="http://www.redhat.com:8080/HyperNews/get/khg.html">
「Linux カーネルハッカーズ ガイド」</ulink>を、またその例としては、カーネルの
ソースコードを読んで下さい。
</para>

<para>
<!--
You can disable interrupts from within a user-mode program, though it can
be dangerous (even kernel drivers do it for as short a time as possible).
After calling <literal>iopl(3)</literal>, you can disable interrupts simply by 
calling <literal>asm("cli");</literal>, and re-enable them with <literal>asm
("sti");</literal>.
-->
ユーザモードのプログラムから割り込みを禁止することは、危険を伴いますが、
可能です。(カーネルドライバですらそれを実行するときはできる限り短い時間
でするものです。)
<function>iopl(3)</function> を呼び出したあと、<function>
asm("cli");</function> を呼び出すだけで割り込みを禁止することができます。
再び割り込み可能にするには <function>asm("sti")</function> を
呼びます。
</para>

</sect1>

<sect1 id="high-resolution">
<!-- <title>High-resolution timing</title> -->
<title>高い精度のタイミング制御</title>
<sect2>
<!-- <title>Delays</title> -->
<title>ディレイ</title>

<para>
<!--
First of all, I should say that you cannot guarantee user-mode
processes to have exact control of timing because of the multi-tasking
nature of Linux. Your process might be scheduled out at any time for
anything from about 10 milliseconds to a few seconds (on a system with
very high load). However, for most applications using I/O ports, this
does not really matter. To minimise this, you may want to nice your
process to a high-priority value (see the <literal>nice(2)</literal> manual 
page) or use real-time scheduling (see below).
-->
まず最初に断っておきますが、ユーザプログラムにおいて正確なタイミング保証
をすることはできません。これは、Linux がマルチタスク・プリエンプティブ
なシステムだからです。あなたのプロセスが、約 10 ミリ秒から数秒(非常に負荷の
高いシステムなどで)に渡ってなんらかの理由でスケジューリング対象から外され
ることは、いつでもあり得ます。
しかし、I/O ポートを使うほとんどのアプリケーションでは、これは実際には問題
にはならないでしょう。
この時間をできるだけ小さくするためには、nice (マニュアルページ nice(2)を
参照のこと) を使ってプロセスの優先順位を高くしたり、またはリアルタイムス
ケジュールのシステム(下記を参照のこと)を使うということもできます。
<!-- Commented out by coda.
(訳注: スラッシングがおきているような状況では nice の効果はほとんどない
と思いますが、ただ単に負荷が高いような場合
(つまり、CPU リソースだけが足りない、という状況)には効果があるのかな。)
-->
(訳注：nice を有効に使うことで、プロセスの持ち時間の再計算を頻繁に行い、
それによりある程度、優先的にスケジュールされるという効果があります。)
</para>

<para>
<!--
If you want more precise timing than normal user-mode processes give
you, there are some provisions for user-mode `real time' support.
Linux 2.x kernels have soft real time support; see the manual page for
<literal>sched&lowbar;setscheduler(2)</literal> for details. There is a 
special kernel that supports hard real time; see <ulink
url="http://luz.cs.nmt.edu/&#732;rtlinux/">&#65533;</ulink> for more 
information on this.
-->
通常のユーザモードプロセスで扱える範囲よりもっと精細なタイミング制御を
求めるのなら、ユーザモードで「リアルタイム」をサポートするための対策も
あります。
Linux 2.x カーネルはソフトリアルタイムをサポートしています。
詳細は <literal>sched&lowbar;setscheduler(2)</literal> の
マニュアルページを参照してください。
ハードリアルタイムをサポートする特別なカーネルもあります。
これについてのもっと詳しい情報は
<ulink url="http://luz.cs.nmt.edu/">http://luz.cs.nmt.edu/</ulink>
をご覧ください。
(訳注：上記以外にもハードリアルタイムをサポートする実装が存在します。
詳細は<ulink url="http://www.linux.or.jp/link/kernel.html&num;RT">
http://www.linux.or.jp/link/kernel.html&num;RT</ulink>を参照してください。)
</para>

<sect3>
<!-- <title>Sleeping: <literal>sleep()</literal> and <literal>usleep()
</literal></title> -->
<title>スリープ：<function>sleep()</function> と <function>usleep()</function>
</title>

<para>
<!--
Now, let me start with the easier timing calls. For delays of multiple
seconds, your best bet is probably to use <literal>sleep()</literal>. For 
delays of at least tens of milliseconds (about 10 ms seems to be the minimum
delay), <literal>usleep()</literal> should work. These functions give the CPU 
to other processes (``sleep''), so CPU time isn't wasted. See the manual
pages <literal>sleep(3)</literal> and <literal>usleep(3)</literal> for details.
-->
さて、もっと簡単なタイミングについてお話しましょう。数秒のディレイが
欲しい場合には、おそらく <function>sleep()</function> がいい
でしょう。
数十ミリ秒以上のディレイ(最小のディレイは約 10 ミリ秒のようです。)の
場合には <function>usleep()</function> がお薦めです。
これらの関数を呼び出すと、CPU は他のプロセスに割り当てられます(つまり
プロセスが「眠る」)ので、CPU タイムが無駄になることはありません。
詳細については <literal>sleep(3)</literal> 
と <literal>usleep(3)</literal> のマニュアルページをご覧くだ
さい。
</para>

<para>
<!--
For delays of under about 50 milliseconds (depending on the speed of
your processor and machine, and the system load), giving up the CPU
takes too much time, because the Linux scheduler (for the x86
architecture) usually takes at least about 10-30 milliseconds before
it returns control to your process. Due to this, in small delays,
<literal>usleep(3)</literal> usually delays somewhat more than the amount that 
you specify in the parameters, and at least about 10 ms.
-->
約 50 ミリ秒よりも小さいディレイに関しては(おそらくプロセッサやマシンの
速度、システムの負荷にも依存しますが)、上に述べたような CPU を放してしまう
というアプローチではうまくいきません。通常、Linux のスケジューラがあなたの
プロセスに対して制御を戻す前に(x86 アーキテクチャでは)少なくとも 10-30 ミ
リ秒はかかるからです。
そのようなわけで、<literal>usleep(3)</literal> に小さいディレイ
を指定すると通常は指定した値をちょっとだけ越えるディレイが発生します。
また最小の値は約 10 ミリ秒ということになります。
</para>

</sect3>

<sect3>
<title><function>nanosleep()</function></title>

<para>
<!--
In the 2.0.x series of Linux kernels, there is a new system call,
<literal>nanosleep()</literal> (see the <literal>nanosleep(2)</literal> manual 
page), that allows you to sleep or delay for short times (a few microseconds 
or more).
-->
2.0.x シリーズの Linux カーネルには <function>nanosleep()</function> 
という新たなシステムコールが付け加わりました。(詳細は <literal>
nanosleep(2)</literal> のマニュアルページを参照してください。)
このシステムコールを使えば(数マイクロ秒といった)短い時間のスリープまたは
ディレイが可能となります。
</para>

<para>
<!--
For delays &lt;= 2 ms, if (and only if) your process is set to soft
real time scheduling (using <literal>sched&lowbar;setscheduler()</literal>),
<literal>nanosleep()</literal> uses a busy loop; otherwise it sleeps, just like
<literal>usleep()</literal>.
-->
プロセスが (<function>sched&lowbar;setscheduler()</function>を
用いて)ソフトリアルタイムスケジューリングされている場合、2 ミリ秒以下の
ディレイに対しては、<function>nanosleep()</function> はビジール
ープを使います。
それ以上のディレイに対しては <function>usleep()</function> と同様
スリープします。
(訳注：ソフトリアルタイムでなければ、<function>usleep()</function> 
と同程度の時間分解能になるようです。)
</para>

<para>
<!--
The busy loop uses <literal>udelay()</literal> (an internal kernel function 
used by many kernel drivers), and the length of the loop is calculated using
the BogoMips value (the speed of this kind of busy loop is one of the
things that BogoMips measures accurately). See
<literal>/usr/include/asm/delay.h</literal>) for details on how it works.
-->
このビジーループは <function>udelay()</function> (多くのカーネル
ドライバが使うカーネルの内部ファンクション)を使っていて、ループの長さは
BogoMips 値を使って計算されます。
(この手のビジーループの速さなどは BogoMips 値が正確に反映されるものの例です。)
どのように動作するかについて詳細は <filename>
/usr/include/asm/delay.h</filename> を参照してください。
</para>

</sect3>

<sect3>
<!-- <title>Delaying with port I/O</title> -->
<title>ポートI/Oを使ったディレイ</title>

<para>
<!--
Another way of delaying small numbers of microseconds is port
I/O. Inputting or outputting any byte from/to port 0x80 (see above for
how to do it) should wait for almost exactly 1 microsecond independent
of your processor type and speed. You can do this multiple times to
wait a few microseconds. The port output should have no harmful side
effects on any standard machine (and some kernel drivers use it). This
is how <literal>&lcub;in&verbar;out&rcub;[bw]&lowbar;p()</literal> normally do 
the delay (see <literal>asm/io.h</literal>).
-->
ポート I/O を使えば数マイクロ秒のディレイがまた違った方法で作れます。
ポート 0x80 に何かバイトデータを出力または入力すると、プロセッサの種類や
速度に関係なく、ほぼ正確に 1 マイクロ秒待つことができます。
(入出力の方法については、前の方を読んで下さい。)
これを必要な回数繰り返すことで数マイクロ秒待つこともできます。
標準的なマシンでは、このポート出力によってなにか変な副作用があったりし
ないはずです。
(カーネルドライバでこれを使っているものもありますから。)
この方法は <function>&lcub;in&verbar;out&rcub;[bw]&lowbar;p()
</function> でもディレイするために通常に使われている方法です。
(<filename>asm/io.h</filename> を見て下さい。)
</para>

<para>
<!--
Actually, a port I/O instruction on most ports in the 0-0x3ff range
takes almost exactly 1 microsecond, so if you're, for example, using
the parallel port directly, just do additional <literal>inb()</literal>s from 
that port to delay.
-->
ポートアドレス 0-0x3ff の範囲にある大抵のポートへの I/O 命令は実際のところ
ほぼ正確に 1 マイクロ秒かかります。
だから例えばパラレルポートを直接扱っている場合なら、ディレイを作るためには
そのポートに対して <function>inb()</function> をいくつか追加するだけ
でいいわけです。
</para>

</sect3>

<sect3>
<!-- <title>Delaying with assembler instructions</title> -->
<title>アセンブラ命令によるディレイ</title>

<para>
<!--
If you know the processor type and clock speed of the machine the
program will be running on, you can hard-code shorter delays by
running certain assembler instructions (but remember, your process
might be scheduled out at any time, so the delays might well be longer
every now and then). For the table below, the internal processor speed
determines the number of clock cycles taken; e.g., for a 50 MHz
processor (e.g. 486DX-50 or 486DX2-50), one clock cycle takes
1/50000000 seconds (=200 nanoseconds).
-->
そのプログラムが走るマシンのプロセッサの種類とクロック速度がわかっている
場合には、特定のアセンブラ命令をハードコードすることで、もっと短いディレイ
を実現することもできます。
(しかし、プロセスがスケジューリングから外され、ディレイが長くなってしまう
ことがあり得ることを忘れないで下さい。)
以下の表では、それぞれの命令で何クロック(内部クロック)消費されるかを示して
います。
これによってどれくらいの時間を消費するかを知ることができます。
例えば 50MHz のプロセッサ (486DX-50 とか、486DX2-50) の場合には 1 クロックは
1/50000000 秒(＝ 200 ナノ秒)です。
</para>

<para>

<screen>
Instruction   i386 clock cycles   i486 clock cycles
xchg %bx,%bx          3                   3
nop                   3                   1
or %ax,%ax            2                   1
mov %ax,%ax           2                   1
add %ax,0             2                   1
</screen>

</para>

<para>
<!--
Clock cycles for Pentiums should be the same as for i486, except that
on Pentium Pro/II, <literal>add &percnt;ax, 0</literal> may take only 1/2 
clock cycles. It can sometimes be paired with another instruction (because of
out-of-order execution, this need not even be the very next
instruction in the instruction stream).
-->
Pentium のクロック数は i486 と同じになるはずです。
ただし Pentium Pro/II では違います。
また <function>add &percnt;ax, 0</function> は半クロックしか消費
しません。
この命令は時々他の命令とペアで実行されるからです。
(out-of-order 実行のため、相方は命令実行ストリームのすぐお隣の命令である
必要はないのです。)
</para>

<para>
<!--
The instructions <literal>nop</literal> and <literal>xchg</literal> in the 
table should have no side effects. The rest may modify the flags register, but 
this shouldn't matter since gcc should detect it. <literal>xchg &percnt;bx, 
&percnt;bx</literal> is a safe choice for a delay instruction.
-->
上の表で、<literal>nop</literal> と <literal>xchg
</literal> は何も副作用はないはずです。
その他の命令はフラグレジスタを変更する可能性があります。
でも、gcc はそれを検出してくれますから、問題にはならないはずです。
<literal>xchg &percnt;bx, &percnt;bx</literal> がディレイ用の
命令としては無難な選択と言えるでしょう。
</para>

<para>
<!--
To use these, call <literal>asm(&dquot;instruction&dquot;)</literal> in your
program. The syntax of the instructions is as in the table above; if
you want multiple instructions in a single <literal>asm()</literal> statement,
separate them with semicolons. For example,
<literal>asm(&dquot;nop ; nop ; nop ; nop&dquot;)</literal> executes four 
<literal>nop</literal> instructions, delaying for four clock cycles on i486 or 
Pentium processors (or 12 clock cycles on an i386).
-->
これらを使うには、プログラムの中で <function>asm(&quot;命令&quot;)
</function> という書式を使って、上の表の命令を埋め込みます。
ひとつの <function>asm()</function> 文で複数の命令を埋め込む
にはセミコロンで各命令をつなげます。
例えば <function>asm(&quot;nop ; nop ; nop ; nop&quot;)</function> 
は <function>nop</function> 命令を4回実行して、i486 または Pentium 
プロセッサでは 4 クロックのディレイ(i386 では 12 クロック)になります。
</para>

<para>
<!--
<literal>asm()</literal> is translated into inline assembler code by gcc, so 
there is no function call overhead.
-->
<function>asm()</function> 文は、gcc によって、インラインアセ
ンブラコードに変換されるので関数呼び出しのオーバーヘッドはありません。
</para>

<para>
<!--
Shorter delays than one clock cycle are impossible in the Intel x86
architecture.
-->
Intel x86 アーキテクチャでは 1 クロックより短いディレイを作ることは
不可能です。
</para>

</sect3>

<sect3>
<!-- <title><literal>rdtsc</literal> for Pentiums</title> -->
<title>Pentiumの<literal>rdtsc</literal>について</title>

<para>
<!--
For Pentiums, you can get the number of clock cycles elapsed since the
last reboot with the following C code (which executes the CPU
instrution named RDTSC):
-->
Pentium プロセッサでは、リブートから現在までの経過クロックサイクル数
を知ることができます。
以下のコードです(このコードは RDTSC という CPU 命令を実行しています。):
</para>

<para>

<programlisting>
   extern __inline__ unsigned long long int rdtsc()
   {
     unsigned long long int x;
     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
     return x;
   }
</programlisting>

</para>

<para>
<!--
You can poll this value in a busy loop to delay for as many clock
cycles as you want.
-->
この値がディレイとして必要な数だけ変化するのをビジーループ中で
監視すればよいでしょう。
</para>

</sect3>

</sect2>

<sect2>
<!-- <title>Measuring time</title> -->
<title>時間の測定</title>

<para>
<!--
For times accurate to one second, it is probably easiest to use
<literal>time()</literal>. For more accurate times, <literal>gettimeofday()
</literal> is accurate to about a microsecond (but see above about scheduling).
For Pentiums, the <literal>rdtsc</literal> code fragment above is accurate to 
one clock cycle.
-->
1 秒くらいの精度の時間ならば、<function>time()</function> 
を使うのが一番簡単でしょう。
もっと正確な時間が必要な場合には、<function>gettimeofday()
</function> を使うと大体、マイクロ秒の精度があります。
(でも、前の方で述べた、スケジューリングのことは忘れないでください。)
Pentium の場合には、上のコードを使うと 1 クロックサイクルの精度が出ます。
</para>

<para>
<!--
If you want your process to get a signal after some amount of time,
use <literal>setitimer()</literal> or <literal>alarm()</literal>. See the 
manual pages of the functions for details.
-->
プロセスが、ある時間経過した後にシグナルを受け取るようにしたい場合には、
<function>setitimer()</function> か <function>alarm()
</function> を使います。
この関数の詳細についてはマニュアルページをご覧ください。
</para>

</sect2>

</sect1>

<sect1 id="other-prog">
<!-- <title>Other programming languages</title> -->
<title>その他のプログラミング言語について</title>

<para>
<!--
The description above concentrates on the C programming language. It
should apply directly to C++ and Objective C. In assembler, you have
to call <literal>ioperm()</literal> or <literal>iopl()</literal> as in C, but 
after that you can use the I/O port read/write instructions directly.
-->
以上の説明では C 言語に特化して述べましたが、C++ や Objective C でも
同じようにできるはずです。
アセンブラの場合、C の場合と同様に <function>ioperm()</function> 
や <function>iopl()</function> を呼び出さなければなりませんが、
その後には直接 I/O ポートに対するリード/ライト命令(訳注: in, out 命令)
を使うことができます。
</para>

<para>
<!--
In other languages, unless you can insert inline assembler or C code
into the program or use the system calls mentioned above, it is
probably easiest to write a simple C source file with functions for
the I/O port accesses or delays that you need, and compile and link it
in with the rest of your program. Or use <literal>/dev/port</literal> as 
described above.
-->
その他の言語で、もしインラインアセンブラや C のコードを埋め込むことが
できない、または前に述べたシステムコールが使えない場合にもっとも簡単な
方法は、必要な I/O ポートアクセスのためのソースコードを C で記述してコ
ンパイルし、プログラムの他の部分とリンクしてしまうという方法でしょう。
あるいは前で触れた <filename>/dev/port</filename> を使うとよいで
しょう。
</para>

</sect1>

<sect1 id="useful-ports">
<!-- <title>Some useful ports</title> -->
<title>よく使われるポート</title>

<para>
<!--
Here is some programming information for common ports that can be directly
used for general-purpose TTL (or CMOS) logic I/O.
-->
以下は、よく使われる TTL (または CMOS)の汎用論理 I/O ポートについての
プログラミング情報です。
</para>

<para>
<!--
If you want to use these or other common ports for their intended
purpose (e.g., to control a normal printer or modem), you should most
likely use existing drivers (which are usually included in the kernel)
instead of programming the ports directly as this HOWTO describes.
This section is intended for those people who want to connect LCD
displays, stepper motors, or other custom electronics to a PC's
standard ports.
-->
もし以下に述べるポートやその他の標準的なポートで本来の使い方(例えば
普通のプリンタやモデムを制御するといったような)をしたいのなら、この
HOWTO で述べるようにポートを直接操作するよりも、既存のドライバ(大抵は
カーネルにくっついてきます。)を使った方がいいでしょう。
このセクションは PC の標準ポートにLCDディスプレイ(訳注：と言っても
近頃はやりの 14 インチとかのディスプレイのことじゃないですよ。)とか
ステッピングモーターとか特製の電子機器をつなぎたいという人を意図して
います。
</para>

<para>
<!--
If you want to control a mass-market device like a scanner (that has
been on the market for a while), look for an existing Linux driver for
it. The <ulink
url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Hardware-HOWTO"
>Hardware-HOWTO</ulink
> is a good place to start.
-->
もしスキャナとかいったお店に並べて売ってあるような機器(しかもお店に
出回り始めてからをちょっと経ったようなもの)を制御したいのなら、既に
ある Linux ドライバを探してみましょう。
<ulink url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Hardware-HOWTO">
Hardware-HOWTO</ulink>
(訳注：日本語訳は
<ulink url="http://www.linux.or.jp/JF/JFdocs/Hardware-HOWTO.html">
Hardware-HOWTO(日本語訳)</ulink>です。)
などが最初の手がかりとしてはいいと思います。
</para>

<para>
<!--
<ulink
url="http://www.hut.fi/Misc/Electronics/"
>&#65533;</ulink
> is a good source for
more information on connecting devices to computers (and on
electronics in general).
-->
コンピュータに接続する機器(とか、他にも一般の電子機器)についての
より詳しい情報は<ulink url="http://www.hut.fi/Misc/Electronics/">
http://www.hut.fi/Misc/Electronics/</ulink>がお薦めです。
</para>

<sect2>
<!-- <title>The parallel port</title> -->
<title>パラレルポート</title>

<para>
<!--
The parallel port's base address (called ``<literal>BASE</literal>'' below) is 
0x3bc for <literal>/dev/lp0</literal>, 0x378 for <literal>/dev/lp1</literal>, 
and 0x278 for <literal>/dev/lp2</literal>. If you only want to control 
something that acts like a normal printer, see the <ulink
url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Printing-HOWTO"
>Printing-HOWTO</ulink
>.
-->
パラレルポートのベースアドレス(以下では ``<literal>BASE</literal>''
と呼ぶことにします。)は <filename>/dev/lp0</filename> では 0x3bc、
<filename>/dev/lp1</filename> では 0x378、<filename>
/dev/lp2</filename> では 0x278 になります。
(訳注：Linux カーネル2.2.x以降の parport ドライバをサポートしたシステムでは
lp デバイスファイルとベースアドレスが必ずしも対応しているわけではありません。
詳しくはカーネル付属文書 parport.txt を参照してください。)
通常のプリンタポートとして動作させたいだけでしたら、
<ulink url="http://sunsite.unc.edu/pub/Linux/docs/HOWTO/Printing-HOWTO">
Printing-HOWTO</ulink>(訳注：日本語訳は
<ulink url="http://www.linux.or.jp/JF/JFdocs/Printing-HOWTO.html">
Printing-HOWTO(日本語訳)</ulink>です。)を
読むのがいいでしょう。
</para>

<para>
<!--
In addition to the standard output-only mode described below, there is
an `extended' bidirectional mode in most parallel ports. For
information on this and the newer ECP/EPP modes (and the IEEE 1284
standard in general), see <ulink
url="http://www.fapo.com/"
>&#65533;</ulink
> and <ulink
url="http://www.senet.com.au/&#732;cpeacock/parallel.htm"
>&#65533;</ulink
>. Remember
that since you cannot use IRQs or DMA in a user-mode program, you will
probably have to write a kernel driver to use ECP/EPP; I think someone
is writing such a driver, but I don't know the details.
-->
ほとんどのパラレルポートには以下に述べる標準的な出力専用モードに加えて、
「拡張」双方向モードがあります。これに関すること、また最近の ECP/EPP 
モード(さらには汎用の IEEE1284 規格)については、
<ulink url="http://www.fapo.com/">http://www.fapo.com/</ulink>や
<ulink url="http://www.senet.com.au/~cpeacock/parallel.htm">
http://www.senet.com.au/~cpeacock/parallel.html</ulink>を参照してください。
ユーザモードのプログラムでは IRQ や DMA が使えませんので、ECP/EPP を使う
ためにはおそらくカーネルドライバを書かなければならないでしょう。
誰かがそういったドライバを書いているだろうとは思いますが、私は詳しいこと
は知りません。
</para>

<para>
<!--
The port <literal>BASE+0</literal> (Data port) controls the data signals of 
the port (D0
to D7 for bits 0 to 7, respectively; states: 0 = low (0 V), 1 = high
(5 V)). A write to this port latches the data on the pins. A read
returns the data last written in standard or extended write mode, or
the data in the pins from another device in extended read mode.
-->
<literal>BASE+0</literal>のポート(データポート) は、ポートの
データ信号を制御します。
(D0 〜 D7 はビット 0 〜 7 に対応します。状態 : 0 = low (0V)、1 = high (5V))。
このポートに対するライトはデータをラッチして外部のピンに出力します。
標準または拡張ライトモードの場合には、リードすると、最後にライトされた
データが読み出されます。
拡張リードモードの場合には、外部デバイスからのデータが読み出されます。
</para>

<para>
<!--
The port <literal>BASE+1</literal> (Status port) is read-only, and returns the 
state of the following input signals:
-->
<literal>BASE+1</literal>のポート(ステータスポート) は
リードオンリーで、以下のような入力信号のステータスを返します:

<itemizedlist>
<listitem>

<para>
<!--
Bits 0 and 1 are reserved.
-->
Bit 0 と 1 は予約済
</para> 
</listitem>
<listitem>

<para>
<!--
Bit 2 IRQ status (not a pin, I don't know how this works)
-->
Bit 2 IRQ ステータス (外部ピンの値ではない。どういうふうに動作するか知らない)
</para>
</listitem>
<listitem>

<para>
Bit 3 ERROR (1=high)
</para>
</listitem>
<listitem>

<para>
Bit 4 SLCT (1=high)
</para>
</listitem>
<listitem>

<para>
Bit 5 PE (1=high)
</para>
</listitem>
<listitem>

<para>
Bit 6 ACK (1=high)
</para>
</listitem>
<listitem>

<para>
Bit 7 -BUSY (0=high)
</para>
</listitem>

</itemizedlist>

</para>

<para>
<!--
The port <literal>BASE+2</literal> (Control port) is write-only (a read 
returns the data last written), and controls the following status signals:
-->
<literal>BASE+2</literal>のポート(制御ポート)はライトオンリー
(リードした場合、最後にライトしたデータを返す。)で、
以下のステータス信号を制御します:

<itemizedlist>
<listitem>

<para>
Bit 0 -STROBE (0=high)
</para>
</listitem>
<listitem>

<para>
Bit 1 -AUTO&lowbar;FD&lowbar;XT (0=high)
</para>
</listitem>
<listitem>

<para>
Bit 2 INIT (1=high)
</para>
</listitem>
<listitem>

<para>
Bit 3 -SLCT&lowbar;IN (0=high)
</para>
</listitem>
<listitem>

<para>
<!--
Bit 4 enables the parallel port IRQ (which occurs on the
low-to-high transition of ACK) when set to 1.
-->
Bit 4 '1' にすると、パラレルポートの割り込みを許可する(ACK の low -&gt; high 
の遷移で割り込み発生。)
</para>
</listitem>
<listitem>

<para>
<!--
Bit 5 controls the extended mode direction (0 = write, 1 =
read), and is completely write-only (a read returns nothing
useful for this bit).
-->
Bit 5 拡張モードでの方向(0 = 出力, 1 = 入力) を制御する。このビットは
完全にライトオンリーで、リード時には不定の値が返る。
</para>
</listitem>
<listitem>

<para>
<!--
Bits 6 and 7 are reserved.
-->
Bit 6 と 7 は予約済
</para>
</listitem>

</itemizedlist>

</para>

<para>
<!--
Pinout (a 25-pin female D-shell connector on the port) (i=input, o=output):
-->
ピン接続 (25 ピンの D-sub メスコネクタ) (i=input, o=output):

<Screen>
1io -STROBE, 2io D0, 3io D1, 4io D2, 5io D3, 6io D4, 7io D5, 8io D6,
9io D7, 10i ACK, 11i -BUSY, 12i PE, 13i SLCT, 14o -AUTO_FD_XT,
15i ERROR, 16o INIT, 17o -SLCT_IN, 18-25 Ground
</Screen>

</para>

<para>
<!--
The IBM specifications say that pins 1, 14, 16, and 17 (the control
outputs) have open collector drivers pulled to 5 V through 4.7 kiloohm
resistors (sink 20 mA, source 0.55 mA, high-level output 5.0 V minus
pullup). The rest of the pins sink 24 mA, source 15 mA, and their
high-level output is min. 2.4 V. The low state for both is max. 0.5 V.
Non-IBM parallel ports probably deviate from this standard. For more
information on this, see <ulink
url="http://www.hut.fi/Misc/Electronics/circuits/lptpower.html"
>&#65533;</ulink
>.
-->
IBM の規格によれば、1, 14, 16, 17 番ピン(制御出力)は、4.7kオームで 5V に
プルアップされたオープンコレクタドライバ (シンク(吸い込み) 20mA, ソース
(吐き出し) 0.55mA, ただし、ハイレベルの出力は プルアップの 5V)
その他のピンについては、シンク(吸い込み) 24mA, ソース(吐き出し) 15mA,
ハイレベル出力は最小 2.4V, ローレベルの出力は最大 0.5V。
IBM 以外のパラレルポートではおそらくこの標準とは少々違う場合もあるでしょう。
これに関するもっと詳しい情報は
<ulink url="http://www.hut.fi/Misc/Electronics/circuits/lptpower.html">
http://www.hut.fi/Misc/Electronics/circuits/lptpower.html</ulink>
をご覧ください。
</para>

<para>
<!--
Finally, a warning: Be careful with grounding. I've broken several
parallel ports by connecting to them while the computer is turned
on. It might be a good thing to use a parallel port not integrated on
the motherboard for things like this. (You can usually get a second
parallel port for your machine with a cheap standard `multi-I/O' card;
just disable the ports that you don't need, and set the parallel port
I/O address on the card to a free address. You don't need to care
about the parallel port IRQ if you don't use it.)
-->
最後に注意: グランド(接地)には気をつけましょう。私はコンピュータが稼働中に
コネクタを接続したせいで、パラレルポートを何個も壊してしまった経験があります。
これを考えると、マザーボードに乗っているのではない(拡張カード上の)パラレル
ポートを使うのがいいかもしれませんね。
(標準的な安い「マルチI/O」カードを使えばあなたのコンピュータに二つめの
パラレルポートが作れます。
必要のない(パラレルポート以外の：訳注)ポートは disable してしまえばいいです。
拡張カードのパラレルポートのI/Oアドレスを空いているところに設定しましょう。
IRQ は使う予定がなければ気にする必要はありません。)
(訳注: 各機器のフレームグランドは、ちゃんととりましょうね。)
</para>

</sect2>

<sect2>
<!-- <title>The game (joystick) port</title> -->
<title>ゲーム(ジョイスティック)ポート</title>


<para>
<!--
The game port is located at port addresses 0x200-0x207. If you want to
control normal joysticks, you're probably better off using the drivers
distributed with the Linux kernel.
-->
ゲームポートはポートアドレス 0x200-0x207 です。
普通のジョイスティックを制御するなら、多分、Linux カーネルにくっついてくる
ドライバを使った方がいいですよ。
</para>

<para>
<!--
Pinout (a 15-pin female D-shell connector on the port):
-->
ピン接続 (15 ピンの D-sub メスコネクタ):

<itemizedlist>
<listitem>

<para>
1,8,9,15: +5 V (power)
</para>
</listitem>
<listitem>

<para>
4,5,12: Ground
</para>
</listitem>
<listitem>

<para>
<!--
2,7,10,14: Digital inputs BA1, BA2, BB1, and BB2, respectively
-->
2,7,10,14: デジタル入力 (順番に) BA1, BA2, BB1, BB2
</para>
</listitem>
<listitem>

<para>
<!--
3,6,11,13: ``Analog'' inputs AX, AY, BX, and BY, respectively
-->
3,6,11,13: アナログ入力 (順番に) AX,  AY,  BX,  BY
</para>
</listitem>

</itemizedlist>

</para>

<para>
<!--
The +5 V pins seem to often be connected directly to the power lines
in the motherboard, so they may be able to source quite a lot of
power, depending on the motherboard, power supply and game port.
-->
+5 V ピンはマザーボードの電源に直接接続されているようですので、
(マザーボードの作りや、電源、ゲームポートにもよりますが)非常に
大きな電力を供給することができるはずです。
</para>

<para>
<!--
The digital inputs are used for the buttons of the two joysticks
(joystick A and joystick B, with two buttons each) that you can
connect to the port. They should be normal TTL-level inputs, and you
can read their status directly from the status port (see below). A
real joystick returns a low (0 V) status when the button is pressed
and a high (the 5 V from the power pins through an 1 Kohm resistor)
status otherwise.
-->
このポートには二つのジョイスティックを接続できますが、デジタル入力は、
これらのボタンからの入力です。
(ジョイスティック A とジョイスティック B それぞれに二つずつボタンがあ
ります。)
これらは通常の TTL レベルの入力で、以下で述べるステータスポート(以下
に記述)から現在の状態を読み出すことができます。
実際のジョイスティックではボタンが押されていると low (0V) を、そうで
なければ high (1K オームの抵抗を通じて 5V 電源にプルアップ) が読み出
されます。
</para>

<para>
<!--
The so-called analog inputs actually measure resistance. The game port
has a quad one-shot multivibrator (a 558 chip) connected to the four
inputs. In each input, there is a 2.2 Kohm resistor between the input
pin and the multivibrator output, and a 0.01 uF timing capacitor
between the multivibrator output and the ground. A real joystick has a
potentiometer for each axis (X and Y), wired between +5 V and the
appropriate input pin (AX or AY for joystick A, or BX or BY for
joystick B).
-->
いわゆるアナログ入力というのは、実際には抵抗値を計っているのです。
以下でその仕組みを述べます。
ゲームポートには4本の入力それぞれにワンショットマルチバイブレータ
が接続されています。(全体(4本)で 558 チップ一つ)
それぞれの入力について、入力ピンとマルチバイブレータの出力の間に 
2.2K オームの抵抗が、マルチバイブレータの出力とグランドの間に 0.01uF
のタイミング用コンデンサが接続されています。
実際のジョイスティックには、X と Yの両方の軸にそれぞれポテンショメー
タがあり、+5V とそれぞれの入力ピンに接続されています。
(AX, AY がジョイスティック A に、BX, BY がジョイスティック B に対応し
ます。)

(訳注: 回路図はこんな感じかな:
<screen>
+5V
 |       ^
 |      /          2.2Kオーム
 +---/\/\/\--IN----/\/\/\------+
       /                       |
 ポテンショメータ              |
                  +---------+  |
                  | Multi   |  |
                  | vib.   Q|--+
                  |         |  |
                  |         |  |
                  |         |  |
                  |         | === 0.01uF
                  |         |  |
                  +---------+  |
                               |
                              GND
</screen>
)
</para>

<para>
<!--
The multivibrator, when activated, sets its output lines high (5 V)
and waits for each timing capacitor to reach 3.3 V before lowering the
respective output line. Thus the high period duration of the
multivibrator is proportional to the resistance of the potentiometer
in the joystick (i.e., the position of the joystick in the appropriate
axis), as follows:
<QUOTE
>R = (t - 24.2) / 0.011,</QUOTE
>
where R is the resistance (ohms) of the potentiometer and t the high
period duration (microseconds).
-->
マルチバイブレータが作動すると、その出力を high (5V) にドライブし、
それぞれに接続されているタイミングコンデンサの電位が 3.3V になるまで
待ち、その後に出力を low にします。
この結果、マルチバイブレータの出力が high の時間はジョイスティック中
のポテンショメータの抵抗値に比例します。
(つまり、それぞれの軸のジョイスティックの位置を表します。)
抵抗値は以下の式のとおりです:
</para>
<para>
<programlisting>
R = (t - 24.2) / 0.011,
</programlisting>
</para>
<para>
ここで、R は ポテンショメータの抵抗値(オーム)、t は high の時間(マイ
クロ秒)です。
</para>

<para>
<!--
Thus, to read the analog inputs, you first activate the multivibrator
(with a port write; see below), then poll the state of the four axes
(with repeated port reads) until they drop from high to low state,
measuring their high period duration. This polling uses quite a lot of
CPU time, and on a non-realtime multitasking system like (normal
user-mode) Linux, the result is not very accurate because you cannot
poll the port constantly (unless you use a kernel-level driver and
disable interrupts while polling, but this wastes even more CPU
time). If you know that the signal is going to take a long time (tens
of ms) to go down, you can call usleep() before polling to give CPU
time to other processes.
-->
とまあ、こういうわけですので、アナログ入力を読み出すためには、以下で
述べるようにまずポートにライトして、マルチバイブレータを作動させる必要が
あります。
その後に4つの軸の状態をポーリング(ポートを繰り返し読み出す)し、それぞれ
のポートが high から low になるまでの時間を測定します。
このポーリングには非常に CPU タイムを消費しますし、(通常のユーザモードの)
Linux のような非リアルタイム・マルチタスクシステムではその結果はあまり正
確ではありません。
ポートを絶え間なく読み出すことはできないからです。
(カーネルレベルのドライバを使うか、ポーリングの間、割り込みを禁止すれば
いいのですが、これは更に多くの CPU タイムを食います。)
信号が low になるまで長い時間(数十ミリ秒)かかるのが分かっているなら、ポー
リング前に CPU タイムを他のプロセスに明け渡すよう <function>
usleep()</function> を呼ぶこともできます。
</para>

<para>
<!--
The only I/O port you need to access is port 0x201 (the other ports
either behave identically or do nothing). Any write to this port (it
doesn't matter what you write) activates the multivibrator. A read
from this port returns the state of the input signals:
-->
さて、アクセスする必要のあるポートはただ一つ、0x201 (他のポートアドレスはこの
ポートと同じようにふるまうか、なにもしないか、のどちらか)です。
このポートに対するライト(書き込むデータはなんでも良いです。)によって
マルチバイブレータが作動します。リードすると入力信号の状態が返ります:

<itemizedlist>
<listitem>

<para>
<!--
Bit 0: AX (status (1=high) of the multivibrator output)
-->
Bit 0: AX (マルチバイブレータ出力の状態 (1=high))
</para>
</listitem>
<listitem>

<para>
<!--
Bit 1: AY (status (1=high) of the multivibrator output)
-->
Bit 1: AY (マルチバイブレータ出力の状態 (1=high))
</para>
</listitem>
<listitem>

<para>
<!--
Bit 2: BX (status (1=high) of the multivibrator output)
-->
Bit 2: BX (マルチバイブレータ出力の状態 (1=high))
</para>
</listitem>
<listitem>

<para>
<!--
Bit 3: BY (status (1=high) of the multivibrator output)
-->
Bit 3: BY (マルチバイブレータ出力の状態 (1=high))
</para>
</listitem>
<listitem>

<para>
<!--
Bit 4: BA1 (digital input, 1=high)
-->
Bit 4: BA1 (デジタル 入力, 1=high)
</para>
</listitem>
<listitem>

<para>
<!--
Bit 5: BA2 (digital input, 1=high)
-->
Bit 5: BA2 (デジタル 入力, 1=high)
</para>
</listitem>
<listitem>

<para>
<!--
Bit 6: BB1 (digital input, 1=high)
-->
Bit 6: BB1 (デジタル 入力, 1=high)
</para>
</listitem>
<listitem>

<para>
<!--
Bit 7: BB2 (digital input, 1=high)
-->
Bit 7: BB2 (デジタル 入力, 1=high)
</para>
</listitem>

</itemizedlist>

</para>

</sect2>

<sect2>
<!-- <title>The serial port</title> -->
<title>シリアルポート</title>

<para>
<!--
If the device you're talking to supports something resembling RS-232,
you should be able to use the serial port to talk to it. The Linux
serial driver should be enough for almost all applications (you
shouldn't have to program the serial port directly, and you'd probably
have to write a kernel driver to do it); it is quite versatile, so
using non-standard bps rates and so on shouldn't be a problem.
-->
コンピュータと接続させたい機器が RS-232 みたいな仕組みを持っているなら、
その機器との接続にシリアルポートを使うといいでしょう。
Linux のシリアルドライバはほとんどありとあらゆる応用が効きます。
(シリアルポートを直接操作するなんてしない方がいいです。そんなことするなら
多分カーネルドライバを書かなければならないハメになりますよ。)
このドライバとっても汎用性が高いので標準でない bps レートを使うといった
こととかも問題ではありません。
</para>

<para>
<!--
See the <literal>termios(3)</literal> manual page, the serial driver source 
code (<literal>linux/drivers/char/serial.c</literal>), and <ulink
url="http://www.easysw.com/&#732;mike/serial/">
&#65533;</ulink> for more
information on programming serial ports on Unix systems.
-->
Unix システムでシリアルポートを使うプログラムのより詳しい情報については 
<literal>termios(3)</literal> マニュアルページやシリアルドライバの
ソースコード(<filename>linux/drivers/char/serial.c</filename>)
、また<ulink url="http://www.easysw.com/~mike/serial/">
http://www.easysw.com/~mike/serial/</ulink>を参考にしてください。
</para>

</sect2>

</sect1>

<sect1 id="hints">
<title>Hints</title>

<para>
<!--
If you want good analog I/O, you can wire up ADC and/or DAC chips to
the parallel port (hint: for power, use the game port connector or a
spare disk drive power connector wired to outside the computer case,
unless you have a low-power device and can use the parallel port
itself for power, or use an external power supply), or buy an AD/DA
card (most of the older/slower ones are controlled by I/O ports). Or,
if you're satisfied with 1 or 2 channels, inaccuracy, and (probably)
bad zeroing, a cheap sound card supported by the Linux sound driver
should do (and it's quite fast).
-->
まともなアナログ I/O が必要な場合には、ADC (アナログ -&gt; デジタル
コンバータ)や DAC (デジタル -&gt; アナログコンバータ)チップをパラレ
ルポートに接続するという方法もあります。
(ヒント: 電源には気をつけて下さい。ゲームポートからの電源を使うか、
ディスクドライブ用の余っている電源コネクタをコンピュータケースから
引っ張り出すなどがいいでしょう。パラレルポートから電源をとるならば、
低消費電力のデバイスを使う必要があります。)
(訳注: いずれにせよ、これらはデジタル系の電源ですから、アナログ系に
使う場合にはなんらかの方法でデカップリングをお忘れなく。)
または、AD/DA カードを購入するという手もあります。
(昔のトロいものなら大抵 I/O ポートで制御できます。)
もし、1〜2 チャネルで十分であり、あまり正確でなくてもよく、(おそらく)
不正確な中点補正(zeroing)でもよければ、Linux のサウンドドライバでサ
ポートされている安いサウンドカードを買ってきて使う、という方法もあります。
(それに、結構高速ですよね。)
</para>

<para>
<!--
With accurate analog devices, improper grounding may generate errors
in the analog inputs or outputs. If you experience something like
this, you could try electrically isolating your device from the
computer with optocouplers (on <Emphasis>all</Emphasis> signals between the 
computer and your device). Try to get power for the optocouplers from the
computer (spare signals on the port may give enough power) to achieve
better isolation.
-->
精密なアナログ機器では不適当なグランド設定によりアナログ入出力の誤差が
生ずることになります。
何か変だなぁ、と思ったら、その機器をフォトカップラを用いてコンピュータから
電気的に(コンピュータと機器の間の<emphasis>すべての</emphasis>信号線を)
アイソレートしてみるといいでしょう。
より良いアイソレーションを得るためにフォトカップラの電源をコンピュータから
とるようにしてみましょう。
(ポートの予備の信号線から十分なくらいの電源がとれます。)
</para>

<para>
<!--
If you're looking for printed circuit board design software for Linux,
there is a free X11 application called Pcb that should do a nice job,
at least if you aren't doing anything very complex. It is included in
many Linux distributions, and available in <ulink
url="ftp://sunsite.unc.edu/pub/Linux/apps/circuits/"
>&#65533;</ulink
> (filename
<literal>pcb-*</literal>).
-->
Linux で使えるプリント基板設計のソフトウェアをお探しでしたら、
Pcb という名前のフリーな X11 アプリケーションがあります。
すごく難しいことをしようというのでない限り、これで十分役にたちます。
多くの Linux ディストリビューションに収録されていますが、
<ulink url="ftp://sunsite.unc.edu/pub/Linux/apps/circuits/">
ftp://sunsite.unc.edu/pub/Linux/apps/circuits/</ulink>
(ファイル名 <filename>pcb-*</filename> ) からも手にいれ
ることができます。
</para>

</sect1>

<sect1 id="troubleshooting">
<!-- <title>Troubleshooting</title> -->
<title>トラブルシュート</title>

<para>
<variablelist>

<varlistentry>
<term>Q1.</term>
<listitem>
<para>
<!--
I get segmentation faults when accessing ports.
-->
ポートをアクセスした時に segmentation faults が起きてしまいます。
</para></listitem>
</varlistentry>

<varlistentry>
<term>A1.</term>
<listitem>
<para>
<!--
Either your program does not have root privileges, or the
<literal>ioperm()</literal> call failed for some other reason. Check the return
value of <literal>ioperm()</literal>. Also, check that you're actually 
accessing the ports that you enabled with <literal>ioperm()</literal> (see Q3).
If you're using the delaying macros (<literal>inb&lowbar;p()</literal>, 
<literal>outb&lowbar;p()</literal>, and so on), remember
to call <literal>ioperm()</literal> to get access to port 0x80 too.
-->
プログラムが root 特権を持っていないか、なんらかの理由で 
<function>ioperm()</function> を呼び出した時に失敗しているので
しょう。
<function>ioperm()</function> の返り値を調べてみてください。
それと本当に <function>ioperm()</function> で許可を得たポートに
アクセスしているかどうかも調べてみてください。
(Q3も参考にしてください。)
ディレイ付きマクロ (<function>inb&lowbar;p()</function>, 
<function>outb&lowbar;p()</function> などなど)を使っているなら、
<function>ioperm()</function> でポート 0x80 のアクセス許可も忘れ
ずに取得してください。
</para></listitem>
</varlistentry>

<varlistentry>
<term>Q2.</term>
<listitem>
<para>
<!--
I can't find the <literal>in*()</literal>, <literal>out*()</literal> functions 
defined anywhere, and gcc complains about undefined references.
-->
<function>in*()</function> とか <function>out*()</function> 
とかの関数がどこにもみつかりません。gcc が undefined references とか文句
を言ってきます。
</para></listitem>
</varlistentry>
<varlistentry>
<term>A2.</term>
<listitem>
<para>
<!--
You did not compile with optimisation turned on (<literal>-O</literal>),
and thus gcc could not resolve the macros in <literal>asm/io.h</literal>. Or 
you did not <literal>&num;include &lt;asm/io.h&gt;</literal> at all.
-->
コンパイルの時に最適化をオン (<option>-O</option>)
にしなかったのでは? 
その結果、gcc は <filename>asm/io.h</filename> の中にあるマクロ
を解決することができなかったのです。
それとも、<literal>&num;include &lt;asm/io.h&gt;</literal> 
を忘れてませんか?
</para></listitem>
</varlistentry>

<varlistentry>
<term>Q3.</term>
<listitem>
<para>
<!--
<literal>out*()</literal> doesn't do anything, or does something weird.
-->
<function>out*()</function> を実行してもなにもおこらない、
またはなんか変なのですが。
</para></listitem>
</varlistentry>

<varlistentry>
<term>A3.</term>
<listitem>
<para>
<!--
Check the order of the parameters; it should be
<literal>outb(value, port)</literal>, not <literal>outportb(port, value)
</literal> as is common in MS-DOS.
-->
パラメータの順番をチェックして下さい。<function>outb(value, port)
</function> という順番です。
MS-DOS でおなじみの <function>outportb(port,value)</function> 
とは逆です。
</para></listitem>
</varlistentry>

<varlistentry>
<term>Q4.</term>
<listitem>
<para>
<!--
I want to control a standard RS-232 device/parallel
printer/joystick...
-->
標準の RS-232 機器、パラレルプリンター、ジョイスティック
といったものを制御したいのですが...
</para></listitem>
</varlistentry>

<varlistentry>
<term>A4.</term>
<listitem>
<para>
<!--
You're probably better off using existing drivers (in the
Linux kernel or an X server or somewhere else) to do it. The drivers
are usually quite versatile, so even slightly non-standard devices
usually work with them. See the information on standard ports above
for pointers to documentation for them.
-->
たぶん既にあるドライバ( Linux のカーネルとか X サーバとかそういったものに
くっついてくるやつのことです。)を使った方がいいです。
そういうドライバはすごく汎用性が高くて、ちょっと規格外の機器なんかも大
抵動きます。
そこらへんの文書へのポインターとして、上で書いた標準ポートの情報を参考
にしてください。
</para></listitem>
</varlistentry>
</variablelist>
</para>

</sect1>

<sect1 id="example-code">
<!-- <title>Example code</title> -->
<title>プログラムの例</title>

<para>
<!--
Here's a piece of simple example code for I/O port access:
-->
これは、I/O ポートアクセスの単純なコーディング例です:
</para>

<para>

<!--
<ProgramListing>
/*
 * example.c: very simple example of port I/O
 *
 * This code does nothing useful, just a port write, a pause,
 * and a port read. Compile with `gcc -O2 -o example example.c',
 * and run as root with `./example'.
 */

#include &#60;stdio.h&#62;
#include &#60;unistd.h&#62;
#include &#60;asm/io.h&#62;

#define BASEPORT 0x378 /* lp1 */

int main()
{
  /* Get access to the ports */
  if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);}
  
  /* Set the data signals (D0-7) of the port to all low (0) */
  outb(0, BASEPORT);
  
  /* Sleep for a while (100 ms) */
  usleep(100000);
  
  /* Read from the status port (BASE+1) and display the result */
  printf("status: %d\n", inb(BASEPORT + 1));

  /* We don't need the ports anymore */
  if (ioperm(BASEPORT, 3, 0)) {perror("ioperm"); exit(1);}

  exit(0);
}

/* end of example.c */
</ProgramListing>
-->
<programlisting>
/*
 * example.c: とっても簡単なポートI/Oの例
 *
 * なにも役にたつことはしていません。ポートに書き込み、一時停止して、
 * ポートから読み出すだけです。「gcc -O2 -o example example.c」で
 * コンパイルして、ルートユーザになって「./example」で実行してください。
 */

#include &#60;stdio.h&#62;
#include &#60;unistd.h&#62;
#include &#60;asm/io.h&#62;

#define BASEPORT 0x378 /* lp1 */

int main()
{
  /* ポートへのアクセス許可を得る */
  if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);}
  
  /* ポートのデータ (D0-D7)を全て low (0) にする */
  outb(0, BASEPORT);
  
  /* しばらくの間 (100 ms) スリープ */
  usleep(100000);
  
  /* ステータスポート (BASE+1) から読み出して、表示する */
  printf("status: %d\n", inb(BASEPORT + 1));

  /* もうポートを使わないので後始末 */
  if (ioperm(BASEPORT, 3, 0)) {perror("ioperm"); exit(1);}

  exit(0);
}

/* example.c おわり */
</programlisting>

</para>

</sect1>

<sect1 id="credits">
<!-- <title>Credits</title> -->
<title>謝辞</title>

<para>
<!--
Too many people have contributed for me to list, but thanks a lot,
everyone. I have not replied to all the contributions that I've
received; sorry for that, and thanks again for the help.
-->
とてもたくさんの方から助け (contribute) を受けましたので、ここには記しきれ
ません。皆さん、とてもありがとう。
すべての方にリプライすることはできませんでしたがそういう方々には
ごめんなさい、そしてもう一度、助けてくれてありがとう。
</para>

</sect1>

<sect1 id="jptrans">
<title>日本語訳について</title>
<para>
<literallayout>
訳者          : 川島 浩       &lt;kei@sm.sony.co.jp&gt;
訳の吟味/校正 : 山崎 康弘さん &lt;hiro@koneeko.linux.or.jp&gt;
(1996/12/26)
</literallayout>
</para>
<para>
更新：幸田あきひろ &lt;coda@post.kek.jp&gt; (2001/03/24)
</para>

</sect1>

</article>
