シリアルポートを使うだけなら基礎を理解する必要はありませんが、基礎 を理解しておけば、問題が起きた際に原因を特定する役に立つかもしれません。 この章は新しい話題について述べるだけでなく、前の章( ハードウェアによるバイトデータの転送の仕方 の内容の一部も繰り返します。ただし、こちらの章ではずっと詳しい説明を行 います。
シリアルポートは I/O (入出力)デバイスです。
I/O デバイスはコンピュータにデータを出し入れするための方法です。I/O デ バイスにはシリアルポートやパラレルポート、ディスクドライブコントローラ、 イーサネットボード、汎用シリアルバス等のたくさんの種類があります。 ほとんどの PC にはシリアルポートが 1 つか 2 つあります。 各ポートはコンピュータの裏側に 9 ピン(25 ピンのこともあります)の コネクタを持っ ています。コンピュータのプログラムは送信ピン(出力)にデータ(バイト列)を 送ることができますし、受信ピン(入力)からデータを受け取ることもできます。 他のピンはフロー制御と接地のために使います。
シリアルポートは単なるコネクタではありません。シリアルポートは 並列(パラレル)のデータを直列(シリアル)に変換し、 データの電気的な表現を変えます。コンピュータ内部では、 データを表すビット群は並列に流れます(同時に多数の配線を用います)。 データを直列に流すとは、1 本の配線(シリアルコネクタの送信ピンや 受信ピン等)にビットのストリームを流すことです。 シリアルポートではこのようにデータを流すため、シリアルポートは送信ピン 上でデータを並列(コンピュータ内部の 形式)から直列に変換できなければなりません(その逆の変換も必要です)。
シリアルポートの電子回路のほとんどは、UART と呼ばれるチップ(あるいはチッ プの一部)です。UART の詳細については、 UART って 何ですか? 性能にどんな影響を与えますか?の章を見てください。しかし、 まずはこの章から読むとよいでしょう。全体における UART の位置づけが分か るからです。
古い PC では 25 ピンのコネクタが使われていましたが、このうち実際に 使われていたのは 9 本のピンだけです。したがって、現在ではほとんどのコ ネクタは 9 ピンです。9 本のピンは普通、それぞれ配線に繋がっています。 データの送信と受信用に使われる 2 本の線の他に、信号の接地用に 1 本のピ ン(配線)が使われます。各配線の電圧は、この接地電圧に対して計測されます。 このように、双方向のデータの送信のために使う配線の最小数は 3 本です。 ただし、信号接地線がなくても動作することが知られてはいますが、この 場合には性能が落ちたり、エラーが起きたりします。
他にももっと配線がありますが、これらは制御のため(信号処理)に使われるだ けであり、データの送信には使われません。 全ての信号を 1 本の線で共有することも できますが、シリアルポートはそうなっておらず、信号の種類ごとに別々の専 用線が用意されています。これらの制御用配線の一部(あるいは全部)は 「モデム制御線(modem control line)」と呼ばれます。モデム制御線の状態は、 +12 V の有効(on)状態か、-12 V の無効(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 アドレス)を知っていなければなりません。また、シリアルポートが CPU にサービスを要求する時にどの線(IRQ 番号)を使わなければならないかも OS は知っている必要があります。 シリアルポートはこの線に割り込みを送ることに よってサービスを要求します。したがって、それぞれのシリアルポートデバイ スは I/O アドレスと IRQ (Interrupt ReQuest number)の両方を不揮発性メモリ に保存していなければなりません。 詳しくは 割り込みの節を参照してください。 PCI バスの場合は、必ずしもこのように動作するわけではありません。 というのも、PCI に は独自の割り込みシステムがあるからです。しかし、PCI 対応の BIOS は PCI の割り込みを IRQ にマッピングするようにチップを設定するため、 見かけ上は先の説明の通りに動作します。ただし、割り込みの共有が許されて いる点は除きます(複数のデバイスが同じ 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 バイ トずつ送信バッファから取り出し、これをシリアルポートのハードウェアが送 信用に持っている 16 バイトの送信バッファに入れます。一度データが送信バッファに入る と、その送信を止める方法はありません。そしてこのデータは、シリアルポー トに接続されているデバイスに送られます。シリアルポートも適切な大きさ (例えば 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 さんが改訂中です)。