シリアルポートを使うだけなら基礎を理解する必要はありませんが、基礎 を理解しておけば、問題が起きた際に原因を特定する役に立つかもしれません。 この章は新しい話題について述べるだけでなく、前の章( ハードウェアによるバイトデータの転送の仕方 の内容の一部も繰り返します。ただし、こちらの章ではずっと詳しい説明を行 います。
シリアルポートは I/O (入出力)デバイスです。
I/O デバイスはコンピュータにデータを出し入れするための方法です。I/O デ バイスにはシリアルポートやパラレルポート、ディスクドライブコントローラ、 イーサネットボード、汎用シリアルバス等のたくさんの種類があります。 ほとんどの PC はシリアルポートを 1 つあるいは 2 つ持っています。各ポー トはコンピュータの裏側に 9 ピン(25 ピンのこともあります)コネクタを持っ ています。コンピュータのプログラムは送信ピン(出力)にデータ(バイト列)を 送ることができますし、受信ピン(入力)からデータを受け取ることもできます。 他のピンはフロー制御と接地のために使います。
シリアルポートは単なるコネクタではありません。シリアルポートは並列のデー タを直列に変換し、データの電気的な表現を変えます。コンピュータ内部では、 データを表すビット群は並列に流れます(同時に複数の配線を用います)。デー タを直列に流すとは、1 本の配線(シリアルコネクタの送信ピンや受信ピン等) にビットのストリームを流すことです。シリアルポートでこのようにデータを 流すため、シリアルポートは送信ピン上でデータを並列(コンピュータ内部の 形式)から直列に変換できなければなりません(その逆の変換も必要です)。
シリアルポートの電子回路のほとんどは、UART と呼ばれるチップ(あるいはチッ プの一部)です。UART の詳細については、 UART って 何ですか? 性能にどんな影響を与えますか?の章を見てください。しかし、 まずはこの章から読むとよいでしょう。全体における UART の位置づけが分か るからです。
古い PC では 25 ピンのコネクタが使われていましたが、このうち実際に 使われていたのは 9 本のピンだけです。したがって、現在ではほとんどのコ ネクタは 9 ピンです。9 本のピンは普通、それぞれ配線に繋がっています。 データの送信と受信用に使われる 2 本の線の他に、信号の接地用に 1 本のピ ン(配線)が使われます。各配線の電圧は、この接地電圧に対して計測されます。 このように、双方向のデータの送信のために使う配線の最小数は 3 本です。 これを除くと、信号接地線がなくても動作することが知られていますが、この 場合には性能が落ちたり、エラーが起きたりします。
他にも配線がありますが、これらは制御用(シグナリング)に使われるだけであ り、データの送信には使われません。全種類の信号を同じ線で共有することも できますが、シリアルポートはそうなっておらず、信号の種類ごとに別々の専 用線が用意されています。これらの制御用配線の一部(あるいは全部)は 「モデム制御線(modem control line)」と呼ばれます。モデム制御線の状態は、 +12 ボルトの有効(on)状態か、-12 ボルトの無効(off)状態のどちらかです。 これらのモデム制御線の 1 つは、コンピュータにシリアルポートからのデー タ送信を止めさせる信号を送るためのものです。この反対に、シリアルポート に接続されたデバイスからコンピュータへのデータ送信を止めさせるための制 御線もあります。この他にも、接続されているデバイスがモデムの場合にモデ ムに電話を取るように指示したり、接続が確立していることや電話が鳴ってい る(誰かが電話をかけてきている)状態であることをコンピュータに教えるため の線もあります。詳しくは ピン配置と信号 の章 をご覧ください。
(USB ではない)シリアルポートの規格は普通 RS-232-C, EIA-232-D, EIA-232-E のいずれかです。これら 3 つはほとんど同じものです。元々の頭 に付いていた RS(Recommended Standard)が EIA (Electronics Industries Association)となり、EIA と TIA (Telecommunications Industries Association) が合併した後に EIA/TIA と なりました。EIA-232 の仕様には同期通信も書かれていましたが、ほとんどの 全て PC には同期通信をサポートするハードウェアは付いていませんでした。 RS の仕様自体は過去のものとなりましたが、今でも広く使われています。本 HOWTO 文書では EIA を使います。文書によっては完全な EIA/TIA 仕様を使っ ているものもあります。これ以外の(EIA-232 以外の)シリアルポートについては、 他のシリアルデバイス (非同期 EIA-232 でないもの) の章をご覧ください。
コンピュータはそれぞれのシリアルデバイスと通信する必要があるので、 OS はそれぞれのシリアルポートが存在することとそれらがある場所 (I/O アドレス)を知っていなければなりません。OS は、シリアルポートが CPU にサービスを要求する時にどの線(IRQ 番号)を使わなければならないかも 知っている必要があります。シリアルポートはこの線に割り込みを送ることに よってサービスを要求します。したがって、それぞれのシリアルポートデバイ スは I/O アドレスと IRQ (Interrupt ReQuest number)の両方を不揮発性メモリ に保存していなければなりません。 割り込み の節を参照してください。PCI バス の場合は、全くこのように動作するわけではありません。というのも、PCI に は独自の割り込みシステムがあるからです。しかし、PCI 対応の BIOS はチッ プの設定を行って PCI の割り込みを IRQ にマッピングするため、見かけ上は 先の説明の通りに動作します。ただし、割り込みの共有が許されている点は除 きます(2 つあるいはそれ以上のデバイスが同じ IRQ 番号を使うことができま す)。
I/O アドレスはメモリのアドレスとは異なります。I/O アドレスがコンピュー タのアドレスバスに設定されると、他の配線に信号が流れます。この信号は、 メインメモリにアドレスを無視させることと、I/O アドレスを持っている全て のデバイス(シリアルポート等)にそのアドレスを監視させ、それがデバイスの アドレスにマッチするかどうかを調べさせることを指示します。もしアドレス がマッチすれば、その I/O デバイスはデータバス上のデータを読み込みます。
シリアルポートには ttyS0, ttyS1 といった名前が付けられます(そしてこ れは普通 DOS や Windows における COM1, COM2 等に対応します)。/dev ディ レクトリには、それぞれのポートに関する特殊ファイルがあります。 "ls /dev/ttyS*" を実行してこれらのファイルを見てみましょう。ただし、 (例えば)ttyS3 ファイルがあるからといって、必ずしもそこに物理的なシリア ルポートが存在するわけではありません。
(ttyS0, ttyS1 等の)どの名前がどの物理シリアルポートを指すのかは、以下
のようにして決まります。シリアルドライバ(ソフトウェア)は、どの I/O ア
ドレスがどの ttyS に対応するのかを示す表を管理しています。このような名
前(ttyS1 等)から I/O アドレス(と IRQ)への対応は、設定も表示も "setserial"
コマンドで行うことができます。
setserial とは何か?の節をご覧ください。こ
のプログラムは、ハードウェアそのものの I/O アドレスや IRQ の設定は
行いません
(ハードウェアの設定はジャンパやプラグ&プレイの設定
プログラムで行います)。このように、どの物理ポートが ttyS1 などに対応す
るのかは、シリアルドライバの設定(setserial による)とハードウェアの設定
の両方に依存します。これに間違いがあると、物理ポートは(ttyS2 などの)ど
の名前にも対応せず、したがって使えないかもしれません。詳しくは
/dev/ttyS2 等のシリアルポートデバイスをご覧く
ださい。
シリアルポートは、ある数のバイトデータ(1, 4, 8, 14 のいずれかに設定さ れていると思います)のデータを FIFO バッファに受け取ると、通常はそのポー トだけが使う特定の配線上に割り込みとして知られる電気信号を流すことによ り、そのデータを取り込むように CPU に伝えます。このように FIFO は、あ る数のバイトデータを待って、それから割り込みを発行します。
しかし、この割り込みは、次のバイトデータが届くのを待っている間に、予期 しない遅延が生じた時にも送られます(タイムアウトといいます)。このように、 バイトデータがゆっくり受信されていると(端末のキーボードで入力している ように)、1 バイトを受け取るごとに割り込みが発行されるかもしれません。 一部の UART チップでは、以下のような規則になります: 4 バイトを連続し て受け取れるかもしれなかったのに、これらの 4 バイトのデータがいずれも 出てこなければ、シリアルポートは次のバイトデータを待つのをあきらめ、現 在 FIFO に入っているバイトデータを取得させるために割り込みを発行します。 もちろん、FIFO が空であれば割り込みは発行されません。
それぞれの割り込み線(コンピュータ内部)には番号(IRQ)が付いており、シリ アルポートは信号を送るためにどの線を使うのかを知っていなければなりませ ん。例えば ttyS0 は通常、IRQ 番号 4 を使います。これは IRQ4(または IRQ 4)と書かれます。IRQ 番号のリスト等は "man setserial" に書かれています( 「シリアルポートのコンフィギュレーション上の注意事項 (Configuring Serial Ports)」の章を見てください)。シリアルポートが CPU の注意を引く必要がある時には必ず割り込みが発行されます。 割り込みの発行を適切なタイミングで行うことは重要です。というのも、シリ アルポートのバッファは入ってくるデータを 16 バイト(古いシリアルポートでは 1 バ イト)しか保持できないからです。このような受信データをバッファからうま く取り出すことに CPU が失敗すると、これ以上のデータが入る場所がなくな り、小さなバッファがあふれて(オーバーラン)データが無くなってしまうかも しれません。 これを フロー制御で防ぐことはできません。
割り込みは、シリアルポートが 16 バイトのデータを小さい送信バッファから 外部ケーブルに全て送り出した直後にも発行されます。この送信バッファには、 送り出すデータ用の 16 バイトの空きができます。割り込みはこの事実を CPU に伝え、小さい送信バッファに送信すべき新しいデータを入れさせるために用 います。また、モデム制御ラインの状態が変化した時にも割り込みが発行され ます。
上の説明のバッファは全てハードウェアバッファのことです。シリアルポート もメインメモリ上に大きいバッファを持っています。これは後ほど説明します。
割り込みは多くの情報を伝えますが、これは間接的にしか行いません。 割り込みそのものは、特定のポートが注意を求めていることを割り込みコント ローラと呼ばれるチップに知らせるだけです。割り込みコントローラはこれを 受けて CPU に信号を送ります。CPU はシリアルポートにサービスを提供する 特殊なプログラムを実行します。このプログラムは割り込みサービスルーチン と呼ばれます(シリアルドライバのソフトウェアの一部です)。 割り込みサービスルーチンはシリアルポートで起きた出来事を調べ、その問題 (シリアルポートのハードウェアバッファのデータ入出力など)を処理します。 このルーチンはシリアルポートで起きたことを簡単に知ることができます。と いうのも、シリアルポートのレジスタはシリアルデバイスドライバが知ってい る I/O アドレスにあるからです。このレジスタは、シリアルポートの状態に 関する情報を保持しています。デバイスドライバはこのレジスタを読んでその 内容を調べることにより、シリアルポートで起きたことを知り、適切な動作を 行うことができます。
シリアルポートではデータ(文字、画像などを表すバイト列)の入出力が行 われます。データが流れる速度であるフローレート(56k (56000) ビット/秒な ど)は(不正確ですが)「速度」と呼ばれます。ですが大抵の人は 「フローレート」ではなく「速度」の方を使います。
平均速度は仕様で決められている速度よりも遅い場合が多いことを理解してお くことが大切です。待ち時間(あるいはアイドル時間)があると、平均速度は低 くなります。このような待ち時間には、 フロー制御による 1 秒程度もある長い待ち時間も含まれます。別の 極端な例としては、バイトデータを送る間の数ミリ秒という非常に短い待ち時 間があります。シリアルポートに接続したデバイス(モデムなど)がシリアルポー トの最高速度に付いていけない場合には、平均速度を低くしなければなりませ ん。
フロー制御とは、配線を流れるバイトデータを止める機能のことです。 これには、バイトデータを失うことなくデータを再び流し始める機能も含まれ ます。フロー制御は、モデムが瞬間のフローレートを非連続的に変えられるよ うにするために必要です。
例として、33.6k の外部モデムを短いケーブルを使ってシリアルポートに 接続する場合を考えましょう。このモデムは電話回線上で 33.6k bps (ビット毎秒)でデータを送受信します。データ圧縮やエラー訂正は全く行わな いものとします。シリアルポートの速度は 115.2k bps に設定してあり、デー タをコンピュータから電話回線に送ります。すると、コンピュータからモデム へは短いケーブルを通って 115.2k bps でデータが流れます。しかし、モデム から電話回線へは 33.6k bps でしかデータが流れません。データが出て行く よりも速くデータが入ってくるので、モデムは超過分のデータ (115.2k -33.6k = 81.6k bps)をバッファに保持しなければなりません。 115.2k bps のデータの流れが止まらない限り、結局はこのバッファは溢れて (空き容量がなくなって)しまいます。
ですが、ここでフロー制御が役立ちます。モデムのバッファが溢れそうになる と、モデムはシリアルポートに停止信号を送ります。シリアルポートはこの停 止信号をデバイスドライバに渡し、115.2k bps のデータの流れは停止します。 モデムは、今までバッファに蓄えたデータを取り出しながら、その まま 33.6k bps でデータを送り続けます。するとバッファには何も入ってこ ないため、バッファ内のデータ量は減り始めます。バッファ内のデータがほと んどなくなると、モデムは開始信号をシリアルポートに送り、コンピュータから モデムへ再び 115.2k bps でデータが流れ始めます。フロー制御により事実上、 短いケーブル上での平均的なフロー速度(この場合は 33.6k bps)は、データを 「流し続けた」場合の速度である 115.2k bps よりもずっと遅くなります。 これが「開始-停止」フロー制御です。
上記の簡単な例はコンピュータからモデムへの流れのフロー制御でしたが、反 対向きの流れ(モデムからコンピュータへの向き)に対して用いるフロー制御も あります。すなわちモデム(または他のデバイス)からコンピュータの向きです。 どちらの向きの流れにも 3 つのバッファ(1. モデム内のバッファ、 2. UART チップ(いわゆる FIFO)の内部、3. シリアルドライバが管理するメイ ンメモリ中のバッファ)があります。フロー制御は、特定のバッファが溢れない ように保護します。小さい UART FIFO バッファはこのような保護を受けてい ませんが、その代わりに、このバッファが発行する割り込みへの応答が高速で あることを期待して動作します。FIFO は「First In, First Out(先に入った データが先に出る)」という、バイトデータの扱い方を表しています。 3 つのバッファ全てが FIFO の規則で動作しますが、これを名前として持って いるのは 1 つだけです。これがフロー制御の本質ですが、説明することはもっ とたくさんあります。
フロー制御の理屈が分かっていると、実際に役立つこともあります。フロー 制御がない時に出る症状は、フロー制御の恩恵を受けずに送られたファイルか らデータの一部が消えてしまうことです。これはオーバーフローが起こるた めであり、普通はオーバーフローを起こして消えてしまうデータは数バイトで は済みません。何百、何千バイトもデータが消え、この際に全てのデータが一 続きであることもしばしば起こります。
可能であれば、できるだけ「ハードウェア」のフロー制御を使いましょう。 これは専用の「モデム制御線」を 2 本使い、「停止(stop)」と「開始(start)」 の信号を送るものです。
ソフトウェアによるフロー制御は、開始信号と停止信号 を送るためにメインの送信線と受信線を使います。ソフトウェアのフロー制御 は、この信号を送るために ASCII 制御文字の DC1(開始)と DC3(停止)を使い ます。この制御文字は単に、通常のデータストリーム内に挿入されます。ソフ トウェアのフロー制御は反応が遅いだけでなく、特別な対策を講じなければモ デムを使ってバイナリデータを送ることもできません。バイナリデータには大 抵、フロー制御用の制御文字 DC1, DC3 が入っているので、特殊な対策を立て て、フロー制御の停止信号である DC3 とバイナリコードの一部である DC3 を区別しなければなりません。DC1 についても同様です。
この話題については、フロー制御・(ハードウェアが持つ)16 バイトの FIFO バッファのペア・シリアルポートに接続されている大きいバッファの ペアを含めた大部分を既に説明しましたが、これ以外にもまだバッファの対があ ります。すなわちメインメモリ上に大きな(多分 8KB)バッファが存在し、 これもシリアルポートのバッファと呼ばれます。アプリケーションプログラム がデータをシリアルポートに送ると、このデータはまずメインメモリの方の 送信シリアルポートバッファに格納されます。バッファの対は、データの流れ の向きが反対である送信バッファと受信バッファの組み合せです。
シリアルポートのデバイスドライバは、例えば 16 バイトのデータを 1 バイ トずつ送信バッファから取り出し、これをシリアルポートのハードウェアが送 信用に持っている送信バッファに入れます。一度データが送信バッファに入る と、その送信を止める方法はありません。そしてこのデータは、シリアルポー トに接続されているデバイスに送られます。シリアルポートも適切な大きさ (例えば 1K バイト)のバッファを持っています。デバイスドライバが(フロー 制御による指示で)コンピュータから出ていくバイトデータの流れを止めた時 には、実際に止まるのはメインメモリ上にある大きな送信バッファから出てい くバイトデータの流れです。これが起こり、シリアルポー トに接続されているデバイスへのデータの流れが止まった後であっても、アプ リケーションプログラムは、8K バイトの送信バッファがいっぱいになるまでは、 ここにデータを送り続けることができます。
このバッファがいっぱいになると、アプリケーションプログラムはそれ以上の データを送る(C 言語では "write" 文を使います)ことができなくなり、アプ リケーションの実行を一時的に停止してバッファに 空きができるのを待ちます。このように、フロー制御の "stop" 信号は結局、 データを送るプログラムを止めることができます。このプログラムが止まって も、コンピュータは計算を止める必要はありません。フロー制御の stop 信号 を受けて待っている間は、別のプロセスに切替えればよいのです。以上の説明 は多少簡略化しすぎていますが、"write" 文を待っている間にこれはアプリケー ションプログラム自体に別処理をさせる方法がこれとは別にあるからです。
多くの場合、伝送経路が複数のリンクを持ち、そのそれぞれが独自のフロー 制御を行うことがあります。例えば、モデム経由で BBS にアクセスしている PC に接続しているテキスト端末上で文字をタイプしたとします。この場合、 使っているアプリケーションプログラム "minicom" はシリアルポートを 2 つ 扱うことになります。テキスト端末上で入力された文字は、まずシリアルポー トから minicom に送られ、次に minicom から次のシリアルポートを経由でモ デムに送り出されます。そして最後に、この文字は電話回線を通じて BBS に 送られます。テキスト端末が画面に文字を表示できる速度には限界があるので、 速度を落すためにフロー制御の "stop" 信号が時々発行されます。"stop" 信 号が発行されると一体何が起こるのでしょうか? "stop" 信号が BBS まで届き、 BBS ホスト上でデータを送り出しているプログラムを止めるまでに長い時間が かかる場合を考えてみましょう。
この "stop" 信号の流れを追跡してみましょう(リンクによって ソフトウェアで処理されたり、ハードウェアで処理されたりします)。まずは BBS から大きなファイルを「取得する」場合を考えます。この際には、テキス ト端末とハードディスク上のファイルの両方に同時にデータが送られます。 テキスト端末の表示速度よりも速くデータが送られてくるので、テキスト端末 は PC の 1 つ目のシリアルポートに "stop" 信号を送ります。デバイスドラ イバはこれを検出し、(メインメモリ上にある)8kB のシリアルバッファから端 末へのデータ送信を停止させます。この時点ではまだ、minicom は端末へ送る ためのデータを 8kB のバッファに送り続けています。
(1 つめのシリアルポートの)この 8kB の送信バッファがいっぱいになると、 minicom はここへの書き込みを止めなければなりません。minocom はデータを 送るのを止めて待ち状態に入ります。ですがこれによって同時に、モデムに接 続されている 2 番目のシリアルポートの 8kB の受信バッファからの読み込み も止まってしまいます。モデムからのデータは、8 KB のバッファがいっぱい になり、モデムに対する "stop" 信号が新しく送られるまで流れ続けます。 モデム(エラー訂正は有効であるものとします) "stop 信号" を BBS 側のモデ ムに送ります。このモデムはバッファからデータを送り出すのを止め、 このバッファがいっぱいになると、BBS ホストのシリアルポートに stop 信号 を送ります。BBS ホストでは、8kB(など)のバッファがいっぱいになり、BBS ホスト側のプログラムから書き込みできなくなると、このプログラムが一時的 に停止します。
このようにして、テキスト端末から送られた stop 信号が BBS ホスト上のプ ログラムを止めます。とっても面倒な仕組みですね! stop 信号はシリアルポー トを 4 つ通り、モデムを 2 つ通り、アプリケーションプログラムを 1 つ (minicom)を通過するのです。各シリアルポートは(一方向につき)バッファを 2 つ(8kB のバッファと、ハードウェアが持つ 16 バイトのバッファ)持ちます。 アプリケーションプログラムは C 言語のコード内部でもバッファを持ってい るでしょう。これも含めると、データは 11 個もの別々のバッファを通ります。 シリアルハードウェアの小さいバッファはフロー制御を直接は識別しない点に は注意してください。
BBS から端末へデータが流れる際に端末の速さの限界がボトルネックになって いる場合、フロー制御の "stop" 信号は実際には BBS からデータを送るプロ グラムを止めることになります。これは先程説明した通りです。 ですが「"stop" 信号がそんなに時間を食っていたら、11 個のバッファ(大き いバッファも一部あります)が全部溢れるのでは?」と思われるかもしれません。 テキスト端末が "stop" 信号を送った時に全てのバッファが容量いっぱいに近 かった場合には、実際にこのようになることもあります。
ですが実験を行ってみれば、これよりももっと説明が複雑になる ことがお分かりになると思います。ある瞬間にデータを流しているリンクもあ りますし、(フロー制御によって)止まっているリンクもあります。 端末からの "stop" 信号が、先に説明したようにうまく BBS ホストに伝わる ことは滅多にありません。BBS 側に "stop" 信号を 1 つ届けるには、端末か らは "stop" 信号をいくつか送らなければならないことがあります。実際の動 作を理解するには、机にコインを置いて行う簡単な実験をやってみるといいで しょう。バッファの数は 2, 3 個で、各バッファの容量もコイン 2, 3 個だけ にしてください。
読者の皆さんは、なぜこんなことをいちいち説明するのかと思われるかもしれ ません。ですが筆者は、BBS から取得したテキストがなくなる原因をこれで理 解したことがあるのです。その時の状況はちょうど前の例と同じですが、モデ ム対モデムのフロー制御が無効になっていました。ハードディスクにも保存さ れるはずの、取得したテキストデータが実際には保存されなかったのですが、 その原因は端末からのフロー制御の "stop" 信号のためにモデムのバッファが オーバーフローしていたことでした。ボトルネックがないデータの経路が BBS からハードディスクまであっても、端末が原因となるオーバーフローがこの経 路上で起きたため、テキストデータが無くなってハードディスクに保存できま せんでした。モデム経由でハードディスクにデータを渡すはずが、モデムでオー バーフローが起こっていたために、ハードディスクに送るべきデータが消えて いたのでした。
シリアルポート用のデバイスドライバは、シリアルポートを操作するソフ
トウェアです。現在はこれはシリアルモジュールとして用意されています。
このモジュールは普通、必要な時に自動的にロードされます。バージョン 2.2
以降のカーネルはこれを行います。これより古いカーネルでは、必要な時にモ
ジュールを自動ロードするためには kerneld
を実行する必要がありまし
た。これを行わない場合には、/etc/modules に明示的に列挙する必要があり
ました。モジュールが Linux で一般的になる前は、シリアルドライバはカー
ネルに組み込むのが普通でした。もし、シリアルドライバがまだカーネルに組
み込んであるのなら(カーネルのコンパイル時にそう選択したのかもしれませ
ん)、シリアルモジュールをロードしてはいけません。もしこれをロードして
シリアルドライバが 2 つになってしまうと、シリアルポートは使えなくなり
ます。この場合にシリアルポートをオープンしようとすると "I/O error" と
なります。
シリアルモジュールがロードされると、存在するシリアルポートに関するメッ
セージが画面に表示されます(よく間違った IRQ を表示します)。
しかし、一度 setserial
を使ってデバイスドライバに(たぶん)正しい
IRQ を教えれば、次の表示は最初の表示に似ていますが、IRQ 等が正しくなっ
ているはずです。setserial
の詳細については
setserial とは何か?をご覧ください。
カーネルのソースコードを編集してドライバを修正することができます。シリ アルドライバの大部分は serial.c ファイルにあります。シリアルポートを使 うプログラムの詳しい書き方については、Serial-Programming-HOWTO をご覧ください(現在 Vern Hoxie さんが改訂中です)。