Operating Systems Development Series
Keyboard
by Mike, 2008, 2009

はじめに

ようこそ!

この章では、もう少し複雑なキーボードを取り上げます。キーボードの歴史、キーボード内部、8042 と 8048 マイクロコントローラ、そしてキーボードドライバの開発について学びます。

また、このシリーズで最初にプログラミングするデバイスでもあります。楽しみですか?ハードウェアプログラミングの仕組みはすでに学び、経験も積んでいます。 次はそれを試す番です。準備はいいですか?これはまた、1つのコントローラだけでなく、2つのコントローラで作業する必要がある最初のデバイスです。 これらのコントローラは、互いに通信し、私たちのシステムも通信します。さらに複雑なのは、両方のコントローラがそれぞれ独自のコマンドを持っていて、それを使って動作させることができることです。このため、この章では、いくつかの箇所でかなり詳しく説明しています。

また、この章には最初の対話型デモも含まれています。基本的なコマンドラインパーサです。興奮しましたか?

この章はまた、デバイスドライバをより深く考察する最初の章でもあります。ハードウェアの抽象化とデバイスドライバの重要性。

以下はそのリストです。

  • キーボード-バックインタイムとキーボードレイアウト
  • キーボードの内部
  • キーボードのプロトコル
  • キーボード・エンコーダ
  • キーボード・コントローラ
  • スキャンコードセット
  • キーボードIRQ

さあ、始めよう

キーボード - 歴史

過去に戻る

キーボードは、私たちがコンピュータに入力するために使用する入力デバイスです。 キーボードが最初に導入されたときは、典型的なタイプライターをモデルにしていました。しかし、キーボードの作りは、それを直接モデル化したものではありません。

1877年にChristopher Latham Sholesによってタイプライターの特許が取得されると、いくつかのメーカーや人々がオリジナルのデザインをさらに発展させました。一連の発明を通じて進化したのが電信機です。同じ頃、1930年代には、IBMがキーパンチ(タイプライターと組み合わせたパンチカードマシン)を加算機で使っていた。初期のコンピュータのキーボードは、キーパンチと電信機の両方の設計を取り入れたものであった。

ENIAC(Electronic Numerical Integrator And Computer)は、最初の汎用コンピュータでした。ENIACは1946年にパンチカードリーダーを入力と出力の両方に使用しました。

1948年には、電気機械式タイプライターを入出力装置として使用した「BINAC(BINary Automatic Computer)」が登場した。

これらの発明から、キーボードはいつ進化したのだろうか。1964年、MIT(Fernando Corbató氏)、ベル研究所、ゼネラル・エレクトリック社が共同で、Multics(Multiplexed Information and Computing Service)マシンを開発した。 Multicsでは、新しいインターフェイスが登場したのだ。テレビと電動タイプライターに使われていたブラウン管(CRT)の技術を組み合わせて、ビデオ・ディスプレイ・ターミナル(VDT)を作ったのである。VDTは、ユーザーが入力した内容を見ることができるようにし、コンピュータをより使いやすくした。1970年代から1980年代にかけて、ほとんどのコンピューターにVDTと入力用の電子キーボードが搭載された。その後、VDTに代わってCRTやLCDのディスプレイが登場し、電子キーボードも汎用コンピュータの標準となりました。

現在、私たちはパソコンに向かうたびにキーボードを使用しています。キーボードのレイアウトのほとんどはまだタイプライターから残っており、使い方も同じです。しかし、新しい時代の電子機器のおかげで、キーボードは多くの異なる形で提供されるようになりました。一般的なプラスチック製のキーボードから、折りたたみ式やバックライト付きのキーボード、さらにはレーザーキーボードまで。

キーボードレイアウト

一般的なキーボードのレイアウトは、QWERTYという文字が最初の5文字であることから、QWERTYキーボードと呼ばれています。QWERTY配列は、タイプライター時代に、初期のタイプライターが元々持っていた機械的な限界から、タイピストの入力速度を遅くするために意図的に設計されたものである。これは主に、キーを押す間隔を短くし、プリントヘッドが詰まらないように十分な時間を確保するためでした。

QWERTY配列は、今日まですべてのキーボードで適応されています。

キーボード内部

キーボードのキーを押すと、実際に何が起こるのでしょうか?キーボードが押したキーをどうやってプログラムに伝えるのでしょうか?今読んでいるテキストは、キーボードで入力されたものです。キーボードにはどのような機能があるのでしょうか?ちょっと見てみましょう。

注:正確な情報はキーボードの種類とモデルによって異なります。ここでは、一般的な102キーボードのみを取り上げます。

ケースを開ける

キーボードが複雑なプリント基板から、マイクロプロセッサーを搭載した1枚の基板になったことに驚かれるかもしれません。キーボードを開けてみると、こんな感じです。

はい、これだけです。いかにシンプルか、おわかりいただけるでしょう。基板が1枚、グリッドが1枚です。上の写真では、グリッドが少し見えにくいかもしれません。しかし、よく見ると、グリッド内のポイントがキーボードのキー位置と一致していることに気づくでしょう。これが「キーマトリックス」です。ほとんどのキーボードでは、キーマトリックスを構成する回路は、グリッドの各ポイントの間で途切れています。キーがキーマトリックスのある点の上にあることを知り、キーを押せば、その点のスイッチが押され、水平回路が完成し、電流が流れるようになる。キーの機械的な動きによって生じる線の振動はバウンスと呼ばれ、キーボードのマイクロプロセッサー(別名キーボード・エンコーダー)によってフィルタリングされます。少し複雑に思われるかもしれませんが、ご安心ください。次のセクションで詳しく説明します。

キーボード・エンコーダ

キーボードに搭載されているマイクロプロセッサーは、Intel 8048の原型となるもので、偶然にもIntelの最初のマイクロコントローラーでもある。このコントローラは、キーボード・エンコーダと呼ばれています。使用するキーボード・エンコーダは、キーボードによって大きく異なります。キーボード・エンコーダは何百種類とありますが、基本的にはどれも同じことをします。

キーグリッド内の行と列は、キーボードエンコーダの8ビットI/Oポートに接続されています。キーが押されると、キーグリッド内のその位置にあるスイッチが閉じられ、電流が流れて回路が完成します。この電流は、キーボードエンコーダのピンが、キーの位置と一致する正しいポートに接続されることを可能にします。したがって、コントローラーがすべきことは、ポートをスキャンして、ポート線がアクティブかどうかをチェックすることで、キーがダウンしているかどうかを確認することです。

キーが押されていれば、キーボード・エンコーダはその位置をROM(Read Only Memory)文字マップ内で検索し、その文字のスキャン・コードを内部16バイト・メモリーに格納します。 キーボード・プロセッサには独自のタイマー、33の命令セット、さらに128Kの外部メモリーをアクセスすることが可能です。そのタイマーを使って、キーが押されているかどうかを、ユーザー入力かバウンスかで判断することができます。バウンドした場合は、通常、人間が入力できる速度よりはるかに速い。タイマーが0になったときにまだキーが押されていれば、リセットされ、その文字が内部の16バイトのバッファに挿入されます。

ここで重要なのは、私たちが通信できるキーボード・コントローラが2つあるということです。キーボードに内蔵されているキーボード・エンコーダと、マザーボードに内蔵されているキーボード・コントローラです。もう一方のコントローラについては、後で少し見ていきますので、心配しないでください;)今のところ、2つのコントローラがあり、キーボードエンコーダはそのうちの1つであることを覚えておいてください。

キーボード・エンコーダはキーボード・プロトコルで定義された方法でシステムと通信します。 見てみましょう。

キーボード・プロトコル

キーボードエンコーダは、データをバイトとしてマザーボードのオンボードキーボードコントローラに送信します。送信方法は、キーボードのインターフェイスで使用されるプロトコールに依存します。これは通常、5ピンDINコネクター、6ピンMini-DINコネクター、USBコネクター、SDLコネクター、または有線(IR)インターフェースを使用したワイヤレスである。

AT/XTキーボードに使用される5ピンのDINコネクターは、通常コンピューターの背面にあり、以下のような形状をしています。


1: Clock 2: Data 3: N/A 4: Ground 5: Vcc (+5V)

マザーボードは、電源ユニット(PSU)からVccとGroundピンを通じて電力を供給します。 clockピンは、キーボードのデータとシステムクロックの間の同期に使用されます。キーボードからのデータは、データピンを介してシリアルデータとして送信されます。

PS/2キーボードに使用される、より一般的な6ピンMini-DINコネクタは、非常によく似ています。


1: Data 2: N/A 3: Ground 4: Vcc (+5V) 5: Clock 6: N/A

特に新しいことはありません。DINは特に意味はなく、これを開発した規格団体(Deutsches Institut für Normung、英語ではGerman Institute for Standardization)のことである。

SDL(Shielded Data Link)コネクタとよく似ている。


A: N/A B: Data C: Ground D: Clock E: Vcc (+5V) F: N/A

ユニバーサル・シリアル・バス(USB)コネクタは、さまざまなデバイスで使用されている規格です。USBデバイスを直接操作するのは、かなり複雑なトピックです。USBは4つのピンで構成されています。1: Vcc (+5V), 2: Data-, 3: Data+, 4: Ground.

USBレガシーサポートは、USBポートを搭載した最新のコンピュータのほとんどで使用されています。このため、これらのコンピュータのマザーボードは、USBキーボードやマウスをPS/2キーボードやマウスとしてエミュレートすることができます。 このため。PS/2互換インターフェイスを使用したUSBキーボードやマウスとの通信は動作します。つまり、USBキーボードやマウスをお持ちの方でも、このチュートリアルのコードとデモは、マザーボードが提供するエミュレーションのおかげで、問題なく動作します。

このように、キーボードとコンピュータの間のインターフェースは、それほど複雑ではありません。キーボードコントローラとキーボードエンコーダの間でデータをビットとして送信する方法を提供するだけです。 データはマザーボード上のオンボードまたは統合キーボードコントローラに送られます。キーボードコントローラーが制御します。

キーボードコントローラー

システムケース内のキーボードコントローラは,通常,8042キーボードコントローラをそのまま使用しています。キーボード・コントローラは、キーボードのプロトコルを介してキーボード・エンコーダとインターフェイスし、そのインターフェイス方法を提供します。ほとんどの新しいシステムでは、キーボードコントローラは独立した集積回路(IC)ではなくフロッピーディスクコントローラ(FDC)パラレルポートインターフェースシリアルポートインターフェースマウスインターフェースも収容するマザーボードのスーパー入出力(IO)コントローラの一部になっています。ほとんどの新しいシステムのスーパーIOコントローラは、マザーボードのサウスブリッジの業界標準アーキテクチャ(ISA)ではなく低ピンカウント(LPC)バスを使用しています。

スキャンコード

スキャンコードとは、キーの状態を表すデータパケットです。キーが押されたり、離されたり、押さえられたりすると、スキャンコードがコンピュータに搭載されたキーボードコントローラに送信されます。スキャンコードには、2つのタイプがあります。メイクコードと ブレイクコードです。メイクコードは、キーが押されたり、押されたままになったときに送信され、ブレークコードは、キーが離されたときに送信されます。キーボードの各キーには、固有のメイクコードとブレイクコードがあります。すべてのスキャンコードを表す数字のセットが、キーボードのスキャンコードセットを構成しています。

キーボードが使用できるスキャンセットは、一般に3種類あります。しかし、スキャン値はランダムであるため、どのスキャンセットを使用しているかを簡単に判断する方法はありません。このため、ルックアップテーブルを使って、スキャンコードが表すキーを決定する必要があります。

それでは、スキャンコードのテーブルを見てみましょう。注意: これらのテーブルは重要です!キーボードでどのキーが押されたかを判断するために使用します。また、これらのテーブルのスキャンコードはすべて16進数です。

これらの表はかなり大きいので、別のリソースとして置くことにしました。リソースセクションにあるテーブルをご覧ください

例を見てみましょう。キーボードでshift+Aキーを押した場合、あなたのコンピュータに送信されるメイクコードは何でしょうか?まず、shiftキーが押され、次にAキーが押されます。次にAキーが離され、その後シフトキーが離されます。スキャンコードセットが最近のキーボードのデフォルトのスキャンコードセットであると仮定すると、左シフトキーのメイクコードは0x12、ブレークコードは0xF0と0x12になります。Aキーのメイクコードは0x1C、ブレークコードは0xF0, 0x1Cとなります。したがって、このイベントが発生すると、次のようなスキャンコードがコンピュータに送信されます。

Key events: shift down A down A released Shift released Scan codes: 0x12 0x1C 0xF0 0x1C 0xF0 0x12
上記を見ると、送信されるスキャンコードは0x12、0x1C、0xF0、0x1C、0xF0、および0x12であることがわかります。

キーを押したままにしておくと、そのキーはタイプミスになります。つまり、キーボードは、キーを離すか、別のキーを押すまで、キーのメイクコードを送り続けます。試してみましょう。お気に入りのテキストエディタを開き、あるキーを押したままにします。しばらくすると、同じ文字がもう一つ現れ、その後にその文字が長く続きます。タイプマティックディレイは、タイプマティックモードに入るまでの待ち時間を秒単位で、タイプマティックレートは、コンピュータに送信する1秒あたりのキャラクターメイクコードの量を決定するものです。タイペマティックモード中は、文字データのバッファリングは行われません。 複数のキーを押している場合は、最後に押したキーだけがタイペマティックモードになります。

スキャンコードはとても重要な機能です。スキャンコードがオンボードのキーボードコントローラーに送信されると、キーボードコントローラーはスキャンコードを内部メモリーに格納します。その後、キーボードコントローラは、その割り込み要求(IR)ラインをハイにトグルします。この割り込み線がプログラマブル割り込みコントローラ(PIC)によってマスクされていない場合、IRQ 1が発火します。IRQがマスクされていても、リードバッファはソフトウェアで読むことができるので、スキャンコードを読めば、今どのキーが離されたか、押されたかを判断することができる。

キーボードインタフェース。デバイスドライバの開発

この章では、すでに多くのことを取り上げてきました。インターフェイスデバイスとしてのキーボードの歴史、QWERTYキーボードレイアウト、キーボードの内部を見て、キーボードがどのように機能するか、それを機能させる主要な構成要素について見てきました。また、スキャンコードセットとキーボードのプロトコルについても説明しました。まだ、すべてを理解していなくても心配しないでください。これから数回に分けて、さらに詳しく見ていきます。また、キーボード用のデバイスドライバも開発する予定です。かっこいいでしょう?このセクションのすべてのコードは、最終的なデモにも含まれます。

キーボードインタフェース。ポーリング

キーボードには、キーボードエンコーダとマザーボード上のキーボードコントローラの2つのコントローラがあることを、前のセクションで説明しました。この章では、1つのハードウェアデバイスを制御するために、複数の異なるコントローラとインターフェイスする必要があります。その通りです。これらのコントローラの両方と通信することができます。まあ、そんなところです。キーボードエンコーダにコマンドを送るとき、オンボードのキーボードコントローラに送りますが、キーボードプロトコルでキーボードエンコーダに再ルーティングされます。

さて、これで両方のコントローラと通信できるようになりました。なんて楽しいんでしょう。両方のコントローラがお互いに動作していることを知ると、お互いに通信することもできます。キーボード・エンコーダは、オンボードのキーボード・コントローラにいろいろなコードを送って記憶させることができます。これらはスキャンコードであったり、エラーコードであったりします。これは私達がまたキーボード エンコーダーおよびオンボードのコントローラーの両方からの情報を受け取ることを可能にします。

これらの通信はすべて、IN命令とOUT命令を使用して、IOアドレス空間にマッピングされたコントローラポートに読み書きすることで行われます。これらのポートが何であるかを気にする必要はありませんが、コントローラで IO マッピングがどのように機能するかを理解することは、ここでより重要になります。

これは、キーボードとのインターフェイスの1つの方法です。コントローラと手動で通信して、キーが押されたか、上げられたか、などをチェックすることができます。これはキーボードのポーリングと呼ばれています。このように、キーボードから最後のスキャンコードを得るには、キーボードコントローラにポーリングする必要があります。

キーボードのインターフェイス割り込み要求(IRQ)

PICのチュートリアルで、キーボードコントローラは割り込みラインを使用するように設定できることを覚えましたか? キーが押されたり離されたりすると、キーボードコントローラはIRQ 1を発行するように設定できます。これはキーボードとのインターフェースとして最も一般的な方法です。

IRQ 1が発生したときはいつでも、スキャンコードが実際にキーボードコントローラに送信されたかどうかをテストする必要があります。これは、キーボードコントローラをポーリングして、最後のスキャンコードを取得することによって行われます。

詳細8042キーボードマイクロコントローラ


The original 8042 Microcontroller

これは、キーボード・エンコーダとインターフェースするマイクロコントローラです。キーボード・コントローラは、もともと8042マイクロコントローラで始まったマイクロコントローラ・ファミリーの一部です。最近のコンピューターでは、キーボード・コントローラーは独立した集積回路(IC)ではなく、その機能はマザーボード自体によってエミュレートされています。つまり、コントローラーの機能はマザーボードのチップセットに統合されているのです。

キーボード・コントローラーは、2つのモードで動作することができます。AT互換モードとPS/2互換モードがあり、どちらのモードで動作させるかによって、外部とのインタフェースが異なります。 まず、コントローラの外観を見てみましょう。

はい。それです。P10-P17ピンがコントローラーの入力ポートです。P20-P27はコントローラーの出力ポートです。これらのピンの正確な意味は、コントローラの動作モードによって異なります。

これらのポートについては、コマンドで操作できるため、後で詳しく説明します。

他のほとんどのピンは、私たちにとって重要ではありません。他のピンのほとんどは、私たちにとって重要ではありません。私は、完全性を期すために、ここにそれらを加えることにしました。

XTAL 1と XTAL 2は 水晶発振器入力端子です。XTAL 1は、CLKを外部で駆動する場合、グランドに接続することもできます。同様に、XTAL 2は、CLKが外部で駆動されている場合、CLKに接続することができます。

RESETは、Low(0)にするとコントローラがリセットされます。

SSは、マイコンのシングルステップ端子です。CSは、データレジスタポートインタフェースに使用されるチップセレクト端子です。EA(No, not the company ;)は、外部アクセス入力ピンです。OTP(One Time Programmable)ROMをディセーブルし、外部からコントローラへコマンドを送信することができます。

RD出力イネーブル入力です。 データレジスタポートインタフェースに使用します。A0はコマンド/データレジスタ選択入力です。 データレジスタポートインタフェースに使用します。WRはライトイネーブル入力ラインです。 データレジスタポートインタフェースに使用します。

SYNCはクロック出力信号です。D0~D7はデータレジスタポートインタフェースで使用します。GNDはグランドピン(Vss)です。Vddは+5V 入力端子です。PROGは、I/Oエクスパンダアクセス時の8243へのアドレス/データストローブとして使用されます。Vccは、もう 1 つの +5V 入力ピンです。

キーボードコントローラは、キーボードの動作を制御するためのインターフェイスを提供します。これは、ポートI/O空間にマッピングされたポートを介してキーボード・コントローラと通信することによって行われます。ご存知のように、キーボードコントローラと通信するためには、INとOUTの命令を使い、それがどのようにマッピングされているかを知る必要があるのです。それでは、見てみましょう。

ポートマッピング

i86アーキテクチャでは、キーボードと通信するために以下のポートが使用されます。

Keyboard Controller Ports
Port Read/Write Descripton
Keyboard Encoder
0x60 Read Read Input Buffer
0x60 Write Send Command
Onboard Keyboard Controller
0x64 Read Status Register
0x64 Write Send Command

この表は悪くないと思います;)基本的にはキーボード・エンコーダにコマンドを送るには、ポート0x60にコマンド・バイトを書き込む。ただし、その前にキーボード・コントローラのステータス・レジスタのビット0(出力バッファが一杯)が0であることを確認し、安全であることを確認する必要があります。もし、キーボードコントローラのステータスレジスタのビット1(入力バッファフル)が1であれば、データは入力バッファにあり、読み出し可能な状態になっています。ポート0x60から読み出すと、キーボード・エンコーダからこのデータを取得することができます。キーボード・エンコーダから読み出されるデータは、通常、キーボードから得られるものですが、特定の値を返すようにマイクロコントローラを再プログラムすることもできます。

ポート0x64に値を書き込むと、オンボードのキーボードコントローラにコマンドバイトを送信できます。 ポート0x64から読み出すと、キーボードコントローラのステータスバイトを取得できます。

これらすべてを知っていれば、これらのコントローラとの間でコマンドバイトやデータの読み書きを行うルーチンを簡単に提供することができます。ここでは、これらのコントローラで使用されるIOポートを抽象化しています。

enum KYBRD_ENCODER_IO { KYBRD_ENC_INPUT_BUF = 0x60, KYBRD_ENC_CMD_REG = 0x60 }; enum KYBRD_CTRL_IO { KYBRD_CTRL_STATS_REG = 0x64, KYBRD_CTRL_CMD_REG = 0x64 };

これらのコントローラと対話するために使用されるルーチンは、コントローラのコマンドに関するいくつかの知識が必要であるため、まだ説明しないことにします。

レジスタ

ステータスレジスタ

これは、20番目のアドレス・ラインを有効にすることを取り上げたときと同じように見えるかもしれません。ステータス・レジスタを読むには、単にI/Oポート0x64から読み込みます。返される値は、特定のフォーマットに従った8ビット値です。このフォーマットは、コントローラのモードによって少し異なります。

再度、紹介します。重要なものは太字にしました。

  • Bit 0: 出力バッファの状態
    • 0: 出力バッファは空です、まだ読まないでください
    • 1: 出力バッファ満杯、読んでください
  • Bit 1: 入力バッファーの状態
    • 0: 入力バッファは空、書き込み可能
    • 1: 入力バッファが一杯、書き込み不可
  • Bit 2: システム・フラグ
    • 0: パワーオンリセット後に設定
    • 1: キーボードコントローラーのセルフテスト(BAT)が正常に終了した後にセットされる。
  • Bit 3: コマンドデータ
    • 0: 入力バッファへの最後の書き込みがデータ(ポート 0x60 経由)
    • 1: 入力バッファへの最後の書き込みはコマンド(ポート0x64経由)
  • Bit 4: キーボードロック
    • 0: ロックされている
    • 1: ロックされていない
  • Bit 5: 補助出力バッファフル
    • PS/2 Systems:
      • 0: ポート0x60からの読み出しが有効かどうかを判断 有効な場合、0=キーボード・データ
      • 1: マウスデータ、ポート0x60からの読み込みが可能な場合のみ
    • AT Systems:
      • 0: OK flag
      • キーボードコントローラからキーボードへの送信でタイムアウト。これは、キーボードが存在しないことを示す場合がある
  • Bit 6: Timeout
    • 0: OK flag
    • 1: Timeout
    • PS/2:
      • 一般的なタイムアウト
    • AT:
      • キーボードからキーボードコントローラへの送信でタイムアウト。パリティエラーの可能性あり(この場合、ビット6と7の両方が設定される)
  • Bit 7: パリティエラー
    • 0: OKフラグ、エラーなし
    • 1: 最後のバイトでパリティエラー

キーボードの現在の状態を判断し、何ができて何ができないかを確認するために、ステータス・レジスタを読み込む必要があります。例えば、キーボードが接続されていない状態で、キーボードにコマンドを送ろうとは思いません。そこで、コマンドを送る前に現在の状態を読み込んでテストしたい。

また、プロセッサが命令を実行するスピードは、キーボードコントローラが応答できるスピードよりはるかに速いことも考慮する必要があります。このため、キーボードコントローラが次のコマンドに対応できるようになるのを待つ必要がある場合が多くあります。これを確認するには、ステータス・レジスタを読み込んでビット0(Output Buffer Full)をテストし、次のコマンドを送信してよいかどうかを確認する必要があります。これを行わないと、前のコマンドは破棄され、新しいコマンドが実行され始めますが、これは好ましくないかもしれません。

別のコマンドを送信したり、コントローラからデータを読み取る前に、コントローラの準備が整うのを待つことが重要です。

ステータス・レジスタの読み書きにビット・マスクを使用することができます。本章の最後のデモで使用されたものを示します。各ビットが上に示したリストの正しいビットとどのように共起しているかに注意してください。

enum KYBRD_CTRL_STATS_MASK { KYBRD_CTRL_STATS_MASK_OUT_BUF = 1, //00000001 KYBRD_CTRL_STATS_MASK_IN_BUF = 2, //00000010 KYBRD_CTRL_STATS_MASK_SYSTEM = 4, //00000100 KYBRD_CTRL_STATS_MASK_CMD_DATA = 8, //00001000 KYBRD_CTRL_STATS_MASK_LOCKED = 0x10, //00010000 KYBRD_CTRL_STATS_MASK_AUX_BUF = 0x20, //00100000 KYBRD_CTRL_STATS_MASK_TIMEOUT = 0x40, //01000000 KYBRD_CTRL_STATS_MASK_PARITY = 0x80 //10000000 };
素晴らしい!あとは、キーボードコントローラのステータスレジスタをポート0x64から読み出し、上記のビットマスクに基づいて、好きなビットをテストしてステータスをチェックするだけです。

つまり、キーボードコントローラのステータスレジスタから読み出すには、次のようにすればよいのです。

//! read status from keyboard controller uint8_t kybrd_ctrl_read_status () { return inportb (KYBRD_CTRL_STATS_REG); }

読み書きを行う。入力バッファ

コマンドを送信するには、まずキーボードコントローラの準備が整うのを待ちます。 これは、入力バッファが一杯になったかどうかを確認することで行われます。キーボードコントローラのステータスレジスタを読み、ビットをテストすることによって、これをテストします。もし0なら、バッファは空なので、コマンドバイトを送ります。(この情報はすべて、上に示したステータスレジスタのビットレイアウトの中にあることを思い出してください)。
//! send command byte to keyboard controller void kybrd_ctrl_send_cmd (uint8_t cmd) { //! wait for kkybrd controller input buffer to be clear while (1) if ( (kybrd_ctrl_read_status () & KYBRD_CTRL_STATS_MASK_IN_BUF) == 0) break; outportb (KYBRD_CTRL_CMD_REG, cmd); }
キーボードエンコーダは、下図に示すように非常によく似ています。キーボードエンコーダに送られるコマンドは、まずキーボードコントローラに送られることを覚えておいてください。このため、キーボード・コントローラがコマンドに対応できる状態であることを確認する必要があります。
//! read keyboard encoder buffer uint8_t kybrd_enc_read_buf () { return inportb (KYBRD_ENC_INPUT_BUF); } //! send command byte to keyboard encoder void kybrd_enc_send_cmd (uint8_t cmd) { //! wait for kkybrd controller input buffer to be clear while (1) if ( (kybrd_ctrl_read_status () & KYBRD_CTRL_STATS_MASK_IN_BUF) == 0) break; //! send command byte to kybrd encoder outportb (KYBRD_ENC_CMD_REG, cmd); }

キーボードエンコーダコマンド

ポート0x60にコマンドバイトを書き込むと、キーボードコントローラはその値を直接キーボードエンコーダーに送信します。以下にコマンド・バイトのリストを示します。

コマンド一覧
コマンド名 説明
0xED LEDの設定
0xEE エコーコマンド。診断テストとして0xEEをポート0x60に返す
0xF0 セットされた代替スキャンコード
0xF2 ポート0x60から読み込む次の2バイトとして、2バイトのキーボードIDコードを送信する
0xF3 オートリピートディレイとリピートレートの設定
0xF4 キーボードの有効化
0xF5 パワーオン状態へのリセットとイネーブルコマンドの待ち受け
0xF6 パワーオンリセット、キーボードスキャン開始
0xF7 すべてのキーをオートリピートに設定(PS/2のみ)
0xF8 すべてのキーでメイクコードとブレークコードを送信するように設定(PS/2のみ)
0xF9 すべてのキーをメイクコードのみ生成するように設定する
0xFA すべてのキーをオートリピートおよびメイク/ブレークコードの生成に設定する
0xFB キーを1つだけオートリピートさせる
0xFC 1つのキーをメイク/ブレークコード生成に設定
0xFD 1つのキーでブレークコードのみを生成するように設定
0xFE 最後の結果の再送
0xFF キーボードの電源をリセットし、セルフテストを開始する。

小さなコマンドはすべて上記の表に記載されていますが、より複雑なコマンドを詳しく見てみましょう。

コマンド0xED - 発光ダイオード(LED)の設定

このコマンドは、キーボードのLEDを設定するために使用されます。ポート 0x60 に書き込まれた次のバイトは、キーボードの LED を更新し、以下に示すフォーマットに従います。
  • ビット0:スクロールロックLED(0:オフ 1:オン)
  • 第1ビット:NumロックLED(0:消灯 1:点灯)
  • 第2ビット:キャップスロックLED(0:消灯 1:点灯)

他のビットはすべて0でなければなりません。

このコマンドは、ちょっと遊んでみるのも楽しいかもしれません;)以下は、デモがキーボードのライトを更新するために使用するルーチンの例です。パラメータがtrueかfalseかによってビットをセットしたりクリアしたりしていることに注目してください。また、最初にコマンドバイトをキーボードエンコーダーに書き、次にデータバイトを書き込んでいることにも注目してください。これらは両方ともキーボードエンコーダのコマンドレジスタに送られます。KYBRD_ENC_CMD_SET_LED は0xED(私たちが使っているコマンドバイト)用の定数です。魔法は使っていません :)

//! sets leds void kkybrd_set_leds (bool num, bool caps, bool scroll) { uint8_t data = 0; //! set or clear the bit data = (scroll) ? (data | 1) : (data & 1); data = (num) ? (num | 2) : (num & 2); data = (caps) ? (num | 4) : (num & 4); //! send the command -- update keyboard Light Emetting Diods (LEDs) kybrd_enc_send_cmd (KYBRD_ENC_CMD_SET_LED); kybrd_enc_send_cmd (data); }

コマンド 0xF0 - オルタネートスキャンコードセット(PS/2 のみ)

このコマンドは、使用するスキャン・コード・セットを設定します。ポート0x60に書き込まれる次のバイトは、次のフォーマットのバイトでなければなりません。
  • Bit 0: Returns current scan code set to port 0x60
  • Bit 1: Sets scan code set 1
  • Bit 2: Sets scan code set 2
  • Bit 3: Sets scan code set 3

コマンド 0xF3 - オートリピート・ディレイ・リピート・レート設定

このコマンドは、オートリピートディレイとリピートレートを設定します。ポート0x60に書き込まれる次のバイトは、以下のフォーマットである必要があります。
  • Bit 0-4: Repeat rate. 0: approx 30 chars/sec to 0x1F: approx 2 chars/sec
  • Bit 5-6: Repeat delay. 00: 1/4 sec, 01: 1/2 sec, 10: 3/4 sec, 11: 1 sec

他のビットは全て0を指定。

リターンコード

ご存知のように、キーボード・エンコーダは、システムのオンボード・キーボード・コントローラと通信しています。返される値のほとんどはスキャンコードですが、時にはエラーが返されることもあります。これらの値は、キーボードデコーダからポート0x60を通じてシステムに送信されます。

戻り値は、以下のいずれかとなります。

戻り値
説明
0x0 内部バッファオーバーラン
0x1-0x58, 0x81-0xD8 キープレススキャンコード
0x83AB F2 コマンドから返されたキーボード ID コード
0xAA リセット後のBAT(Basic Assurance Test)中に返されるコード。L.シフトキーメイクコードも
0xEE ECHO コマンドから返される
0xF0 特定のメイクコードのプレフィックス(PS/2には適用されません)
0xFA キーボード・コマンドに対するキーボード・アクノレッジ
0xFC 基本保証テスト(BAT)失敗(PS/2のみ)
0xFD ダイアゴスティックの失敗(PS/2 以外)
0xFE キーボードがシステムに対して最後のコマンドの再送を要求した
0xFF キーエラー(PS/2のみ)

オンボードキーボードコントローラコマンド

これらのコマンドのいくつかは、A20の章ですでに見ています。しかし、ここに挙げたコマンドの多くは新しいもので、中には非常に低レベルのものもあります。つまり、これらのコマンドのいくつかは、コントローラに接続された特定のラインを制御することができます。このため、コントローラのラインとキーボードデバイスとのインターフェイスを取り上げなければならなかったのです。その他のコマンドは、コントローラーの内部RAMの読み書きを行うものです。

コマンド一覧
コマンド名 説明
共通コマンド
0x20 コマンドバイトの読み出し
0x60 ライトコマンドバイト
0xAA セルフテスト
0xAB インターフェーステスト
0xAD キーボード無効化
0xAE キーボードの有効化
0xC0 入力ポートの読み出し
0xD0 出力ポートの読み出し
0xD1 ライト出力ポート
0xE0 テスト入力の読み出し
0xFE システム・リセット
0xA7 マウス・ポートの無効化
0xA8 マウスポートの有効化
0xA9 マウスポートのテスト
0xD4 マウスへの書き込み
非標準コマンド
0x00-0x1F コントローラRAMの読み出し
0x20-0x3F コントローラRAMの読み出し
0x40-0x5F ライトコントローラRAM
0x60-0x7F ライトコントローラRAM
0x90-0x93 シナプティックス・マルチプレクサ・プレフィックス
0x90-0x9F ライトポート13-ポート10
0xA0 読み取り著作権
0xA1 ファームウェアバージョンの読み出し
0xA2 速度変更
0xA3 速度変更
0xA4 パスワード設定確認
0xA5 パスワードの読み込み
0xA6 パスワードの確認
0xAC 診断ダンプ
0xAF キーボードバージョンの読み込み
0xB0-0xB5 コントローララインリセット
0xB8-0xBD コントローラライン設定
0xC1 連続入力ポート・ポール、Low
0xC2 連続入力ポートポール、High
0xC8 コントローララインP22とP23のブロック解除
0xC9 コントローララインP22とP23をブロック
0xCA コントローラモード読み出し
0xCB ライトコントローラモード
0xD2 ライト出力バッファ
0xD3 ライトマウス出力バッファ
0xDD A20アドレスライン無効化
0xDF A20アドレスラインの有効化
0xF0-0xFF パルス出力ビット

ずいぶんたくさんのコマンドがありますね。すべてのコマンドを網羅するには、かなりの時間がかかると思いませんか?A20のコマンドは、A20の章ですでに説明しました。このシリーズでは移植性を重視しているため、上記のような一般的なコマンドのみを取り上げますが、興味のある読者はここで取り上げていないコマンドの情報を探してみてください。

次のセクションまで、サンプルコードを取り上げるつもりはありません。ここでは、コマンドそのものを取り上げ、次のセクションから参照することにします。

コマンド0x20 - コマンドバイトの読み出しとコントローラRAMの読み出し

上の表を見てください。0x20〜0x3Fのコマンドは、コントローラのRAMを読み出すのに使われていることにお気づきでしょうか?それなのに、コマンド0x20は、コマンドバイトの読み出しにも使われています。どうなっているのでしょうか?

実は、この2つのコマンドは同じものを指しています。コマンド・バイトは、コントローラのRAMに格納されています。つまり、コマンドバイトを読むということは、コントローラの内部RAMから読むということです。どうです?

コントローラのRAMから読み出す場合、コマンドの最後の6ビットは、RAM内の読み出す場所を参照します。ある種の MCA システムでは、RAM 内の 32 のロケーションすべてにアクセスすることができます。他のシステムでは、0、0x13-0x17、0x1D、および 0x1F のバイトにのみアクセスできます。

これらの位置は次のとおりです。

  • Offset 0: Command Byte
  • Offset 0x13 (MCA): パスワードが有効な場合は非ゼロ
  • Offset 0x14 (MCA): パスワードが一致した場合、非ゼロ
  • Offsets 0x16-0x17 (MCA): パスワード照合時に破棄される2つのメークアップコードを与える
  • Offset 0x1D:
  • Offset 0x1F:

コマンドバイトは、より重要なバイトである。見た目ほど複雑ではないので、ご安心ください。

  • ビット0:キーボード割り込みイネーブル
    • 0: 割り込み禁止
    • 1: キーボード出力バッファが一杯になったらIRQ 1を送る
  • ビット1:マウス割り込みイネーブル
    • ISA:未使用
    • EISA / PS2
      • 0: マウス割り込みを無効にする
      • 1: マウス出力バッファが一杯になった時にIRQ 12を送信する
  • ビット2:システムフラグ(ステータスレジスタのビット2も同様)
    • 0: コールドリブート
    • 1: ウォームリブート(BATは既に終了)
  • 第3ビット: キーボードロック無視
    • PS/2:未使用
    • AT
      • 0:動作なし
      • 1: ステータスレジスタのビット4を強制的に1にする(ロックしない)
  • 第4ビット:キーボードイネーブル
    • 0: キーボードを使用可能にする
    • 1: クロックラインLow駆動によるキーボード無効化
  • 5ビット:マウスイネーブル
    • EISAまたはPS/2
      • 0: マウスを有効にする
      • 1: クロックラインLow駆動によるマウス無効化
    • ISA
      • 0: PCモードで、11ビットコードを使用し、パリティをチェックし、スキャン変換を行う。
      • 1: PCモードでは、8086コードを使用し、パリティをチェックせず、スキャンコンバージョンも行わない。
  • 第6ビット:トランスレーション
    • 0: 変換しない
    • 1: キースキャンコードを変換します。MCAタイプ2のコントローラはこのビットを設定できない。
  • ビット7:未使用、0にすべき

このコマンドは必要ないと思うので、ルーチンは書いていません。

コマンド 0x60 - ライトコマンドバイトとコントローラ RAM の書き込み

コマンドバイト 0x60 - 0x7F は、上記と非常によく似ており、上記と同じ RAM ロケーションに書き込むことができます。より重要なのは、コントローラ RAM のバイト 0(コマンドバイト、覚えていますか)を読むことで、これはコマンドバイト 0x60 を送信することで実行可能です。

上記のコマンドと同様に、エンドデモのためにこのコマンドのルーチンは書かれていません。

コマンド0xAA - セルフテスト

このコマンドにより、コントローラはセルフテストを実行します。このコマンドは、ポート 0x60 を通して読むことのできる出力バッファーに結果を返します。テストが成功した場合は0x55、失敗した場合は0xFCが返されます。

以下はルーチンの例です。最初にキーボード・コントローラにKYBRD_CTRL_CMD_SELF_TESTコマンド(コマンド0xAA)を送信していることに注意してください。その後、キーボード・コントローラの出力バッファがデータで満たされるのを待ちます。これにより、テストが完了したかどうかがわかります。テストが完了すると、出力バッファの結果が0x55であれば真(テスト成功)、そうでなければ偽(テスト失敗)を返します。

//! run self test bool kkybrd_self_test () { //! send command kybrd_ctrl_send_cmd (KYBRD_CTRL_CMD_SELF_TEST); //! wait for output buffer to be full while (1) if (kybrd_ctrl_read_status () & KYBRD_CTRL_STATS_MASK_OUT_BUF) break; //! if output buffer == 0x55, test passed return (kybrd_enc_read_buf () == 0x55) ? true : false; }

コマンド 0xAB - インタフェーステスト

このコマンドは、コントローラとキーボード間のシリアルインターフェイスをテストします。テストの結果は、ポート0x60で読み取ることができる出力バッファに格納されます。

結果は以下のいずれかになります。

  • 0: Success, no errors
  • 1: Keyboard clock line stuck low
  • 2: Keyboard clock line stuck high
  • 3: Keyboard data line stuck high
  • 0xFF: General error

ご覧のように、これらはすべてハードウェアのエラーです。エラーが発生した場合は、キーボードを無効にし、リセットすることをお勧めします。それでもダメな場合は、キーボードが故障している可能性があります。

コマンド 0xAD - キーボードを無効にする

このコマンドにより、コントローラはキーボードクロックラインを無効化し、コマンドバイトのビット4(キーボードイネーブル)を設定します。コマンド・バイトのフォーマットについては、コマンド・バイトの読み出しのセクションを参照してください。

つまり、このコマンドはキーボードを無効化するものです。

システムがキーボードの現在の状態を把握できるように、キーボードの現在の状態を保存しておくとよいでしょう。これはdemosのキーボードドライバで_kkybrd_disableを通して行われます。

//! disables the keyboard void kkybrd_disable () { kybrd_ctrl_send_cmd (KYBRD_CTRL_CMD_DISABLE); _kkybrd_disable = true; }

コマンド 0xAE - キーボードの有効化

このコマンドを使用すると、コントローラはキーボードクロックラインを有効にし、コマンドバイトのビット4(キーボードイネーブル)をクリアします。コマンド・バイトのフォーマットについては、「コマンド・バイトの読み出し」の項を参照してください。

つまり、このコマンドはキーボードを有効にするものです。

以下は、デモのルーチンの例です。このルーチンがいかに簡単であるかに注目してください :)

//! enables the keyboard void kkybrd_enable () { kybrd_ctrl_send_cmd (KYBRD_CTRL_CMD_ENABLE); _kkybrd_disable = false; }

コマンド 0xC0 - 入力ポートの読み込み

このコマンドは、入力ポート(コントローラ上のラインP10-P17)を読み取り、バイナリ値をポート0x64を通して読み取ることができる出力バッファにコピーします。このポートが持つラインはまだ見ていませんので、これから見ていきましょう。
  • Line P10 / Bit 0: Keyboard data in, Unused in ISA
  • Line P11 / Bit 1: Mouse data in, Unused in ISA
  • Line P12 / Bit 2: Unused in ISA, EISA, PS/2
  • Line P13 / Bit 3: Unused in ISA, EISA, PS/2
  • Line P14 / Bit 4: 0: 512 KB motherboard RAM, 1: 256K RAM
  • Line P15 / Bit 5: 0: Manufacturing jumper installed, 1: Not installed
  • Line P16 / Bit 6: 0: CGA display 1: MDA display
  • Line P17 / Bit 7: 0: Keyboard locked 1: Not locked
ジャンパーがアクティブの場合、BIOSは無限診断ループを実行することがあります。P13 と P14 ラインは、クロック切り替えのために設定されることがあります。

上記を見ると、最近のパソコンではこのコマンドはあまり役に立たないことがわかると思いますので、複雑に見えても気にしないでください。Bit 0, 1, 2, 3 はもう使われていない。ビット4は、最近のコンピュータは512KB以上のRAMを持っているので、ほとんど役に立ちません。Bit 5は、キーボードテストのためにジャンパがインストールされているかどうかをテストするために使用されます(ほとんどのユーザーはそんなことはしませんが)。ビット6はビデオアダプターから情報を得られるので不要です。ビット7はほとんどのユーザーがキーボードのロックを望んでいないので、ほとんど必要ありません。とても便利なコマンドでしょう?ほとんどのコンピュータで使えるわけではありません。

このコマンドは非常に便利なので(あるいはそうでなくても)、私はこのコマンドのルーチンを書かないことにしました。

コマンド0xD0 - 出力ポートの読み出し

このコマンドは、コントローラの出力ポート(P2)から読み出し、その結果をポート0x64の出力バッファーに格納するよう指示します。このコマンドを発行した後にポート0x64から読み出すことで、コントローラの出力ポートのビットをチェックすることができます。

コントローラの出力ポートは、コントローラのP20-P27ラインだけです(このことを前に覚えていますか?)。このコマンドが実行されると、これらのラインのバイナリ値が出力バッファに格納されます。

出力ポートのピンとその役割については、まだ説明していません。(A20の章で説明しましたが、詳細ではありません)そこで、ここで説明します。

  • Line P20 / Bit 0: 0: Reset CPU, 1: normal operation
  • Line P21 / Bit 1: 0: A20 line is forced, 1: enabled
  • Line P22 / Bit 2: Mouse data. Unused in ISA
  • Line P23 / Bit 3: Mouse clock. Unused in ISA
  • Line P24 / Bit 4: 0: IRQ 1 not active, 1: IRQ 1 active
  • Line P25 / Bit 5: 0: IRQ 12 not active, 1: IRQ 12 active
  • Line P26 / Bit 6: Keyboard Clock
  • Line P27 / Bit 7: Data to Keyboard
それがこちら。ビット2と3は、ISA(Industry Standard Architecture)コンピュータ(最近のほとんどのコンピュータ)では使われなくなりました。ビット4と5(ラインP24とP25)は、PICラインIR1とIR12でプログラマブル割り込みコントローラ(PIC)に接続されています。したがって、このラインがアクティブであれば、PICの割り込みラインもアクティブです(これは、割り込みが実行中または実行待ちであることも意味します)。6ビットと7ビットは、現在のキーボードクロックとデータ信号(ラインがアクティブかどうかにかかわらず)を含んでいるだけです。

ここまでのビットは、ほとんど意味がありませんね。これらのビットの多くは、現在のコントローラの動作に関する電子機器レベルのもので、私たちのニーズには無用のものです。最初の2行(ビット0と1)を除いては、システムをリセットするかどうか、あるいは20番目のアドレスラインを有効にするかどうかを制御します。ビット0を読んでも意味がありません。この行はアクティブ(1)でなければならず、通常動作していることを意味します。このビットがないと、システムは再起動します。したがって、ここで唯一の有用なビットはA20ラインです。これは、少なくとも読み出し動作には当てはまります。

このコマンドがポート0x64で発行されると、結果のバイトは出力バッファに置かれ、ポート0x60からバイトを読み出すことで読み出しが可能になります。

A20をすぐにでもディセーブルにしなければならない心配はない。また、キーボードからシステムをリセットする方法もあります。このため、このコマンドは私たちのニーズにはかなり有用であり、私はこのためのルーチンを書かないことにしました。

コマンド0xD1 - 出力ポートの書き込み

このコマンドは出力バッファ(ポート0x60)からバイトをコピーし、コントローラの出力ポート線にバイトを配置します。これらのラインの説明については、前のセクション(Read Output Port Command)を参照してください。

ほとんどの場合、起こりうる問題を防ぐために、変更したい特定のビットをビットごとにORし、他のすべてを変更しないようにしたいと思うことでしょう。

このコマンドはいくつかの点で有用である。コントローラによって使用されるIRQを有効または無効にしたり、A20ゲートを有効または無効にしたり、あるいはビット0を設定することによってシステムをリセットしたりすることができます。繰り返しになりますが、変更可能なビットのリストについては、前のセクションを参照してください。

コマンド 0xE0 - テスト入力の読み出し

このコマンドは、コントローラのテストポート線からバイナリ値を取り出し、出力バッファに配置し、ポート0x60を介して読み取ることができるようにコピーします。

テストポートは、マイクロコントローラのTEST 0と TEST 1のラインです(本章のコントローラピンアウト図を参照してください)。この章では、テストポートを説明しませんので、説明します。

  • Line TEST 0 / Bit 0: Keyboard Clock (input)
  • Line TEST 1 / Bit 1: AT - Keyboard data (input) PS/2 - Mouse clock (input)
その他のビットは未定義とみなし、読まないでください。

このコマンドはあまり役に立たないかもしれませんが、コントローラはテストポートがより有用であるかもしれない他のフィールドで使用されるかもしれないことを思い出してください。結局のところ、それはテスト目的のために存在するのです。

コマンド 0xFE - システム・リセット

コントローラ出力ポート(ピン P0)のビット 0 をパルスし、CPU をリセットします。 これは基本的に、ビット 0 をリセットするWrite Output Portコマンドを送信するのと同じことを行います。 素敵な方法でシステムをリセットしたい場合は、このコマンドを送信してください。
//! reset the system void kkybrd_reset_system () { //! writes 11111110 to the output port (sets reset system line low) kybrd_ctrl_send_cmd (KYBRD_CTRL_CMD_WRITE_OUT_PORT); kybrd_enc_send_cmd (0xfe); }

これはすべてのシステムで動作するとは限らないことを覚えておいてください。動作するかどうかを確認する簡単な方法は、上記のルーチンの後、プログラムがまだ実行されているかどうかを確認することです :)

キーボード。繋ぎ合わせる

我々は、すでにこのデモのキーボードドライバからルーチンのいくつかを見てきました。キーボード・エンコーダやコントローラとの通信、そして、有効化、無効化、テスト、LED更新、システムリセットなど、いくつかの重要な機能のルーチンを見てきました。これは素晴らしいことですが、すべてを結びつけるいくつかの重要な詳細が欠落しています。では、見ていきましょう。

キーボード現在の状態を保存する

ご存知のように、キーボードのどのキーもいつでも押すことができます。そのため、それぞれのキーが押されているかどうかをスキャンする方法が必要です。ここで良いことは、キーボード・エンコーダがすでにこれを実現していることです!もっと簡単に言うと、キーボードエンコーダはスキャンコードを直接オンボードのキーボードコントローラに送り、IRQ 1を起動します。

IRQ 1がマスクされていない限り、IRQ 1に独自の割り込みハンドラをインストールし、キーボードエンコーダからスキャンコードが送信されるたびに通知を受けることができます。これはどういうことでしょうか。キーボードコントローラにスキャンコードが送信されると、いつでも割り込みハンドラが起動されます。これはいつでも起こりうることです。

このため、ハンドラの内部でキーボードコントローラをポーリングしてスキャンコードが何であるかを何とか判断する必要があります。しかし、あるキー(caps lockキーやnum lockキーなど)が押されているときに、別の処理を行いたい場合がある。これらのキーは、押されたときにオンまたはオフになるはずだ。では、shiftなどのキーはどうでしょう?これらのキーは、押したままにしておき、キーを離したときに解放する必要があります。

このため、これらのキーの現在の状態と最後に読み取ったスキャンコードを保存しておき、IRQが復帰した後で再び読み取ることができる方法を考え出す必要があります。これは、いくつかのグローバル変数または構造体に現在の状態を格納し、単にそれらを使用することによって行うことができます。

キーボード割り込みハンドリング

これは重要です。キーストロークとキーリリースごとに、数バイト(スキャンコード)がキーボードコントローラに送信されることを覚えていますか?このとき、キーボードコントローラはプログラマブル割り込みコントローラ(PIC)に信号を送り、IRQ 1を発生させるのです。そうです、この信号によりPICはキーボード割り込みハンドラを実行するのです。

割り込みハンドラの目的は、ドライバの現在の状態を更新し、ドライバとシステムで使用できる形式に変換することによってスキャンコードを解読することです。そう、それがすべてです;)

割り込みハンドラは、すべてを結びつけるものです。少し大きいのでこの文章には書きませんが、ぜひ皆さんもご覧になって、どのように動作しているかを確認してください。

キーボード初期化

キーボードコントローラは、プログラマブル割り込みのIRQ 1ラインに間接的に接続されていることを思い出してください。PICでIRQを割り込みベクター32(IRQ 0)から始まるようにマッピングしたため、IRQ 1は割り込みベクター33にあります。このため、割り込みベクター33を使用するために、setvectルーチンを使用して割り込みハンドラをインストールする必要があります。

他のすべてはとてもシンプルです。現在のドライバの状態(グローバルとして保存されている)をクリアして、kkybrd_set_ledsルーチンを使ってLEDをクリアするだけです。

//! prepares driver for use void kkybrd_install (int irq) { //! Install our interrupt handler (irq 1 uses interrupt 33) setvect (irq, i86_kybrd_irq); //! assume Basic Assurance test (BAT) test is good _kkybrd_bat_res = true; _scancode = 0; //! set lock keys and led lights _numlock = _scrolllock = _capslock = false; kkybrd_set_leds (false, false, false); //! shift, ctrl, and alt keys _shift = _alt = _ctrl = false; }

まとめ

この章はこれで終わりです。このデモを発展させて、実際に使えるようにすることは可能です。 しかし、現在できることはかなり限られています。他のプログラムを動かして仕事をさせることができたら便利だと思いませんか?ファイルシステム全体の構造を抽象化することは非常に複雑なテーマですが、1つのディスクからファイルをロードすることに焦点を当てることは可能です。

しかし、問題が発生しました。最低限、ディスクからファイルをロードできるようにするためには、まずフロッピーディスクコントローラ(FDC)をプログラムしなければならないのです。これは次の章のトピックです。そこでお会いできるのを楽しみにしています。:)