0から作るソフトウェア開発

日々勉強中。。。

0から作るOS開発

環境準備

環境設定

ブートローダ

カーネルローダ

GRUB

カーネル

ドライバーその他

0から作るOS開発 キーボードドライバその1

前回までの内容

これまでで、 ことがわかりました。それではカーネルを0から開発していきましょう!

今回はキーボードドライバについてです

キーボードの成り立ち

キーボードの歴史を振り返ると、タイプライタまで遡ります。世界初のタイプライタは

”タイポグラファ”としてウィリアム・オースチン・バートが1829年に考えだし、特許を取得しています

商業的に初めて販売されたタイプライタは、マリング=ハンセンのライティングボールと呼ばれるタイプライタです

デンマークのラスマス・マリング=ハンセンが発明し、1870年に商業生産され販売されました

マリング=ハンセンのライティングボール

商業的に初めて成功したタイプライタは、クリストファー・レイサム・ショールズ(とその他の方)が

1868年に発明し、1874年に改良したものがレミントン社によって販売されました

このタイプライタが”ショールズとグリデンのタイプ-ライタ”として知られるようになりました

現在の多くのキーボードの配列であるQERTY配列が採用されています

商業的に初めて成功したタイプライタ

現在のキーボードへ

タイプライタに電気回路が組み入れられて、主にテレタイプとキーパンチの入力デバイスとしての

コンピュータキーボードが使用されるようになります。1870年代の前半には、株のティックの表示器の

入力としてテレプリンタが使用され、1903年から1910年頃から現在の形になってきました

1930年頃には英数字を入力できるキーパンチが作られています。

コンピュータの入力としてのキーボードは、初期のコンピュータであるENIACのキーパンチとして備え付けられ、

BINACで、電気回路で制御できるタイプライタをデータ入力に使用していました



1940年代から1960年代ではタイプライタがコンピュータの主な入力装置となり、

1967年に、データポイント3300と呼ばれるコンピュータターミナルに組み込まれるようになりました。



その後、CRTが開発され、電気回路を持つタイプライタとCRTでビデオディスプレイターミナルが作られ、

1970年代から1980年代には、現在目にするようなキーボードとディスプレイがほとんどのコンピュータに

搭載されるようになりました。



今日でも、キーボードはコンピュータに欠かすことのできない周辺機器で、iPhoneやアンドロイド端末など

携帯端末においても、画面上でキーボード入力ができるように発達していっています

キーレイアウト

キーのレイアウトはクリストファー・レイサム・ショールズがタイプライタを広めたその後は、QERTY配列が

主に使用されています。QERTYはキーボードの左上のQから始まり、Yまでの5文字のレイアウトから

そう呼ばれるようになりました。QERTY配列は現在主流のキーレイアウトとなっています

キーボードの種類

コンピュータにキーボードが備え付けられてから、更にキーボードに改良が加えられてきています

現在流通しているキーボードでは

IBMがIBM XTにXTキーボードとして知られるキーボードを開発しました。そして、IBM ATキーボード、次にPS/2キーボードが

開発されます。PS/2キーボードはATキーボードと似たキーボードですが、PS/2キーボードはATキーボードよりも

小さいコネクタを採用しています。更に、ATキーボードとの互換性を持つように設計されているため、ソフトウェアも

ATキーボードの機能が利用できます(全機能に互換性があるわけではありません)

IBMが開発したキーボードとして3つのタイプのキーボードがあります

IBMキーボードのタイプ
キーボードのタイプ キー数 コネクタ 通信 使用するスキャンコード ホストからのコマンド
IBM PC/XTキーボード(1981年) 83 5ピンDINコネクタ 1方向シリアル通信 スキャンコードセット1 コマンドに対応していない
IBM ATキーボード(1984年)
(XTとの互換性はありません)
84(101キー) 5ピンDINコネクタ 双方向シリアル通信 スキャンコードセット2 8コマンドに対応
IBM PS/2キーボード(1987年)
(ATとの互換性があります)
84から101 6ピンミニDINコネクタ 双方向シリアル通信 スキャンコードセット2
(オプションでスキャンコードセット3も使用するものもあります)
17コマンドに対応
IBM PS/2キーボード(現在)
(ATとの互換性があります)
101以上(通常は101か104、日本では106か109) 5ピンまたは6ピンミニDINコネクタ 双方向シリアル通信 スキャンコードセット2
(オプションでスキャンコードセット3も使用するものもあります)
17コマンドに対応

キーボードの構成

キーボードは英字、数字、スペースなどのキーとキーが押されたかどうかを判定する

キーボードエンコーダがあります。キーボードエンコーダは押されたキーをスキャンコードとして

PS/2コネクタを通してキーボードコントローラに伝えます。キーボードコントローラはCPUと

FSBで接続されていて、IN/OUT命令で制御します

キーボードエンコーダとキーボードコントローラを介してCPUはキーボードを制御します

キーボードエンコーダ

キーボードエンコーダはキーが押されたか離されたかをスキャンコードにエンコードします

キーボードが押されたか離されたのかを次のような回路でエンコーダは読み取ります

キーマトリックスとキーエンコーダ

上図の回路はキーA、B、C、D、E、F、G、H、Iがあります。合計9個のキーを読み取りたいのですが

当然キーボードにはもっと沢山のキーがあります。しかし、IC(エンコーダ)には各キーが押された(Highを読み取る)か

離されたか(Lowを読み取る)を読み取るためのポートが少ししかありません(キーに対して読み取るポートが

少ない)。そこで、上図のような回路が必要となってきます。この回路では合計9個のキーに対して

入力ポートが3つ、出力ポートが3つの合計6個だけでキーの状態を検出できるようになっています

通常は、入力ポートは端子がHighであれば1が、Lowであれば0を読み取ります。また、出力ポートは

1に設定すれば端子にHighを出力し、0を設定すればLowを出力します。(ポートの制御はエンコーダの

ファームウェアがポート入出レジスタを制御して行なっています)。



キーの読み取り手順としては、
  1. 出力1にHighを、出力2と3はLowを出力します。その状態で入力1から3の状態を読み取ります
    これにより、キーA、B、Cが押されているのか離されているのかを検出します

  2. 出力2にHighを、出力1と3はLowを出力します。その状態で入力1から3の状態を読み取ります
    これにより、キーD、E、Fが押されているのか離されているのかを検出します

  3. 出力3にHighを、出力1と2はLowを出力します。その状態で入力1から3の状態を読み取ります
    これにより、キーG、H、Iが押されているのか離されているのかを検出します


上図では、3番目の例を描いています。出力3をHighにしたときに、入力1を読み取ると、キーGの状態が

読み取れます。キーGが押されていると入力1は1(High)、離されていると入力1は0(Low)が読み取れます

この手順を順番に行うことで、キーAからIまでの9個のキーの状態を読み取っています

キーボードコネクタ

キーボードエンコーダとキーボードコントローラとデータのやりとりを行うために、キーボードから出ているコネクタを

マザーボードに差しておきます。このときに差すコネクタとして、5ピンDINコネクタ、6ピンミニDINコネクタ、USBコネクタ、

SDLコネクタ、Bluetoothインターフェイスコネクタがあります。歴史的に見て、AT/XTキーボードでは5ピンDINコネクタが、

PS/2キーボードでは6ピンミニDINコネクタが使われていました。



5ピンDINコネクタは次のようなコネクタとなります

5ピンDINコネクタ

電源VccとGNDはマザーボードの電源とGNDにつながっています。クロックはエンコーダとキーボードコントローラがデータを

送受信するときの同期をとります。



6ピンミニDINコネクタは次のようなコネクタとなります

6ピンミニDINコネクタ

5ピンDINコネクタと形状は異なりますが、ピン自体の機能は同様です



その他にUSBコネクタがあります。USBコネクタは、ご存知の通り色々なデバイスが接続でき、キーボードももちろん接続できます

USBコネクタのピンとして1:Vcc(電源)5V、2:DATA-、3:DATA+、4:GNDがあります

USBコネクタにキーボードを接続すると、USBプロトコルでキーボードを制御できるようになります

USBプロトコルは非常に複雑ですので、別の回とさせていただきます



最近のパソコンではUSBレガシーサポート機能があります。USBレガシーサポート機能があるマザーボードにUSBキーボードや

USBマウスを接続すると、マザーボードがPS/2キーボードとマウスをエミュレートしてくれます。この機能があるおかげで

プログラムからUSBキーボードにPS/2キーボードとしてアクセスすることができますので、USBのキーボードしか持っていない方でも

PS/2キーボードとして扱えます。



キーボードコネクタを通して、キーボードエンコーダはキーボードコントローラにスキャンコードを送信します

スキャンコード

スキャンコードはキーが押された、離されたという状態を表したコード(16進数の数値)です。ですので、キーが押されたまたは

離されたときに、スキャンコードがキーボードコントローラに送信されます。スキャンコードには2種類のタイプがあります

この2つのコードをまとめてスキャンコードと呼ばれています。キーボードの各キーに個別のメイクコードとブレイクコードが

割り当てられています。送信されてきた、メイクコードとブレイクコードから判断してどのキーが押されたのか、離されたのかを判断します

どのキーにどのコードが割り当てられているのかを決めたものをスキャンコードセットと呼ばれています

スキャンコードセットは3種類あります

スキャンコード表はスキャンコード仕様を参照してください

現在のところUSBレガシーサポート機能はUSBキーコードはスキャンコードセット2のみ変換可能です) 例えば次のようにキーを押した場合を考えてみます

  1. シフトキーを押す

  2. Aを押す

  3. Aを離す

  4. シフトキーを離す
そうするとこの順番でスキャンコードがキーボードエンコーダから送信されます

  1. 0x12(シフトキーを押す)

  2. 0x1C(Aを押す)

  3. 0xF0 0x1C(Aを離す)

  4. 0xF0 0x12(シフトキーを離す)

キーを押したままにすると、ある一定の間隔でスキャンコードが送信されます

例えば、適当なテキストエディタを開いて適当にAを押し続けてみますと、一定の間隔でAが

入力されていることが分かると思います。これをタイプマティックモードといいます

キーを押し続けた後一定時間してからタイプマティックモードになります

この遅延をタイプマティックディレイ、また押し続けている間に一定の間隔で

スキャンコードが送信される間隔をタイプマティックレートといいます。



スキャンコードがキーボードコントローラに送信されると、キーボードコントローラのバッファ内に

格納されます。そして、キーボードコントローラはIR(割り込み要求)ラインをHighにして

PICに割り込みを要求します。 PICはキーボードコントローラから割り込み要求を受けるとCPUに通知し、

IRQ1が発生します。そして、IRQ1割り込みハンドラでキーボードコントローラのバッファから

スキャンコードを読み取り、キーが押されているか離されているかを判断していきます

キーボードコントローラ

大昔のキーボードコントローラには、Intelの8042というICが使用されていました。

現在では8042のICが使用されているのではなく、マザーボードに載っているスーパーI/Oコントローラの

一部になっています。(スーパーI/Oコントローラにはその他にもフロッピーディスクコントローラ、

パラレルポートコントローラ、シリアルポートコントローラ、マウスコントローラが入っています)。

スーパーI/Oコントローラは、昔はISAバスを使用していましたが、最近では

ローピンカウント(LPC:Low Pin Count)バスを使用するようになっています

また、ATキーボードとの互換性のため、キーボードコントローラには

AT互換モードPS/2互換モードがあります

PS/2互換モードではPS/2マウスもサポートしていますので、キーボードコントローラは

マウスコントローラとしても動作します。今回はキーボードコントローラを制御していきます

キーボードドライバ

ここまでで、キーボードについていろいろ書いておりますが、内容について詳しく知っておく必要はありません。。。

単純に、キーが押されるとキーボードコントローラにスキャンコードが送信されるので、それを読み取るだけとなります。。。



ソフトウェアで直接制御をするのはキーボードコントローラだけですが、キーボードコントローラを通してキーボードエンコーダも

制御することができます。コントローラの制御には今まで見てきましたようにIN命令OUT命令を使います



キーボードコントローラとして有名なものに8042キーボードマイクロコントローラがあります

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

8042 IC

こちらが8042で、キーボードエンコーダとスキャンコードやその他の制御コマンドのやりとりを行うICです

昔はこの画像のように独立したICでしたが、現在のパソコンではマザーボードが8042をエミュレートしています

8042のブロック図が下記となります

ハードウェアにあまり興味がなければ飛ばしてください。特に知らなくても問題はありません。。。

8042はNEC、Intelなどの各社から同機能のICが開発されてきました。下記ブロック図はIntelの

UPI-42AHを例としています

8042はファームウェアを書き込むことができるICですので、各社で実装が異なっています

8042 ICブロック図

このICの各ピンの機能は下記となります

8042のピンアサイン
シンボル ピン番号 名称 入出力 説明
TEST0, TEST1 1, 39 テストピン 入力 デバッグ用の入力として使用します。
TEST0:ROM/EPROM書き込み、ベリファイに使用します
TEST1:イベントタイマ入力として使用します
XTAL1, XTAL2 2, 3 外部クロック 入力 外部クロックを入力します
RESET 4 リセット 入力 Low入力でICをリセットします
SS 5 シングルステップ 入力 プログラムをシングルステップで動作します(デバッグ用)
SYNC出力と連動します(Lowアクティブ)
使用しない場合は+5Vにプルアップしておきます
CS 6 チップセレクト 入力 このICにアクセスするときにチップセレクト信号を入力します
(Lowアクティブ)
EA 7 外部アクセスピン 入力 エミュレータを使用するときや、ROM/EPROMのベリファイに使用します
使用しない場合はプルダウンしておきます
RD 8 リード 入力 パソコンのCPUが8042からデータを読み込むときにLowにします
(Lowアクティブ)
A0 9 コマンド/データセレクト 入力 パソコンのCPUが8042から読み込むデータがコマンドであるかデータであるかを
指定するピンとなります。LowならデータでHighならコマンドとなります
WR 10 ライト 入力 パソコンのCPUが8042にデータを書き込むときにLowにします
(Lowアクティブ)
SYNC 11 クロック出力 出力 8042が命令を1つ実行するサイクルでクロックが出力されます
D0-D7 12-19 データバス 入力/出力 パソコンのCPUが8042とデータを読み込んだり書き込んだりする
8ビットデータバスです。
P10-P17 27-34 ポート1 入力/出力 データの入出力に使用する汎用ポートです
このポートでキーマトリクスを読み込むときの出力を出します
特にP17はキーボードのインヒビットキーに接続されています
サーバなどにインヒビットキーがついていてインヒビットキーが押されると
キーが押されてもキーボードコントローラは反応しなくなり、ロック状態となります
セキュリティのために使用します
P20-P27 21-24, 35-38 ポート2 入力/出力 データの入出力に使用する汎用ポートですその2です
このポートでキーボード制御で使用しています
P27がキーボードエンコーダからのデータを読み取ったり書き込んだりするポートになります
P26がP27でデータをやり取りするときに同期するクロックをやり取りします
P24は8042のバッファがフルになったときにPICにIRQを要求します
また、P20-P23は主に8243I/O拡張IC(キーマトリクスの読み込み)の入力に使用します
PROG 25 プログラム 入力/出力 ファームウェアを書き込むときのパルスを入力したり、
8243とのデータ入出力に使用します。使用しない場合はプルアップします
VCC 40 電源   +5Vをこのピンに供給します
VDD 26 電源   通常動作時は+5Vを、ファームウェア書き込み時は
+12.5Vをこのピンに供給します。
VSS 20 グラウンド   グラウンドに接続します


このICに対してOUT命令IN命令でアクセスしていきます

キーボードコントローラのポートアドレス

OUT命令とIN命令でキーボードコントローラにアクセスするにはポートアドレスを指定します

また、キーボードエンコーダについてもキーボードコントローラを通してアクセスできます

各ポートアドレスは次のようになります

(その他のI/Oデバイスの大まかなポートアドレスマッピングは カーネルローダその3を参照してください)。

キーボードコントローラのポートアドレス
ポートアドレス IN/OUT 説明
0x64 IN ステータスレジスタ
0x64 OUT インプットバッファ(コマンドレジスタ)
キーボードコントローラ(キーボードエンコーダ)のポートアドレス
ポートアドレス IN/OUT 説明
0x60 IN アウトプットバッファ
0x60 OUT インプットバッファ(コマンドレジスタ)


キーボードコントローラにはポートアドレスとして0x60と0x64が割り当てられています

ポートアドレス0x64の方は実際にキーボードコントローラとのデータのやり取りに使用します

ポートアドレス0x60の方はキーボードコントローラのバッファに対して読み込みまたは書き込みを行いますが、

これまで見てきましたように、キーボードコントローラの先にキーボードエンコーダがつながっていまして、

キーボードエンコーダとデータのやり取りをするにはキーボードコントローラを経由する必要があります

そのため、キーボードエンコーダとデータのやり取りを行うときにはポートアドレス0x60のバッファに

アクセスすることでキーボードエンコーダからデータを読み込んだり、書き込んだりすることができます

キーボードのアドレスポートと8042のレジスタ

図のように0x60にアクセスするときと0x64にアクセスするときではA0を0(=High)、1(=Low)に

することで読み込むレジスタや書き込み先を判断しています。この関係を見てみますと

ということがわかります。

キーボードコントローラとエンコーダどちらの場合にせよ、書き込みの場合は8042のインプットバッファに

に書き込みます。インプットバッファに書き込む前にはバッファが空いているかどうかをステータスレジスタの

状態を見て、バッファが空いている場合に書き込むようにプログラムしていきます

まずは、ステータスレジスタについて見ていきましょう

キーボードコントローラのステータスレジスタ

ステータスレジスタについてはカーネルローダその3のA20を有効にするときに見ましたがもう一度見てみます

キーボードコントローラ8042のステータスレジスタ

キーボードコントローラ8042のステータスレジスタ
ビット シンボル 名前 説明
ビット0 OBF アウトプットバッファフル 0:キーボードコントローラのアウトプットバッファにデータが無いことを意味しています
1:アウトプットバッファにデータが存在していて、まだリードされていない状態です。リードバッファレジスタから値を読み込みとこのビットが0になります
ビット1 IBF インプットバッファフル 0:キーボードコントローラのインプットバッファ(0x060または0x064)が空の状態
1:キーボードコントローラのインプットバッファにデータが書き込まれた状態であるが、まだコントローラが値を読み取っていない状態。コントローラが書き込まれた値を読み取るとこのビットは0になります
ビット2 F0 システムフラグ 制御コマンドを書き込み、コマンドが成功すると、制御コマンドに応じて0または1にセットされます
例えばコントローラの中にはセルフテストが成功したときに1をセットします
また、パワーONリセットしたときにはこのビットが0にセットされます
ビット3 F1 コマンド/データフラグ 0:最後に書き込みしたのがデータ(0x060に書き込みをした)
1:最後に書き込みしたのがコマンド(0x064に書き込みをした)
このビットはA0の値がそのまま反映されます
ビット4 ST4 禁止(ロック)フラグ キーボードコントローラのデータアウトプットバッファにデータが書き込まれるたびに、このビットが更新されます
このフラグはキーボードのインヒビット(禁止)キーが押されている状態に1になります
インヒビットキーが押されている状態ではキーボードコントローラはキーが押されても何も反応しません
0:インヒビットキーが離されている状態です
1:インヒビットキーが押されている状態です
ビット5 ST5 送信(書き込み)タイムアウトフラグ <PS/2> ビット0の値が1であれば
0:ポートアドレス0x60から読み込むデータはキーボードエンコーダからのデータです
1:ポートアドレス0x60から読み込むデータはマウスからのデータです

<AT> 0:キーボードコントローラからの送信(書き込み)が完了した状態
1:キーボードコントローラからの送信(書き込み)が完了していない状態。または送信エラーが起こった状態。 ソフトウェアで一定時間タイムアウトを監視します
ビット6 ST6 受信(読み込み)タイムアウトフラグ 0:キーボードコントローラが受信(読み込み)を完了した状態
1:キーボードコントローラが受信(読み込み)を完了していない状態。または受信エラーが起こった状態。 ソフトウェアで一定時間タイムアウトを監視します
ビット7 ST7 パリティエラー 0:キーボードコントローラから受信(読み込み)した最後のバイトは奇数パリティ
1:キーボードコントローラから受信(読み込み)した最後のバイトは偶数パリティ
キーボードコントローラは通常奇数パリティで送信してきます


カーネルローダその3で見てきましたように、コマンドを書き込む前には必ずステータスレジスタの

IBF:インプットバッファフルビットが0になっているかどうか確認してからコマンドを書き込みます

では、ステータスレジスタを読み込むプログラムを実装していきます

キーボードコントローラのレジスタにアクセスする関数を作成する

まずはキーボードのポートアドレスとステータスレジスタのビットを定義していきます


/*********************************************************************************
    File:portAddress.h
    Description:Definition of port address

*********************************************************************************/
#ifndef __PORTADDRESS__H
#define __PORTADDRESS__H

/*
==================================================================================

    Description :Keyboard Encorder

==================================================================================
*/
#define	DEF_PORT_KBD_ENCODER        0x0060
#define DEF_PORT_KBD_ENC_BUFFER     DEF_PORT_KBD_ENCODER
#define DEF_PORT_KBD_ENC_COMMAND    DEF_PORT_KBD_ENCODER

/*
==================================================================================

    Description :Onboard Keyboard Controller

==================================================================================
*/
#define	DEF_PORT_KBD_CONTROLLER     0x0064
#define	DEF_PORT_KBD_CTRL_STATUS    DEF_PORT_KBD_CONTROLLER
#define DEF_PORT_KBD_CTRL_COMMAND   DEF_PORT_KBD_CONTROLLER

#endif /* __PORTADDRESS__H */



次にステータスレジスタのビットを定義します。


/*********************************************************************************
    File:keyboard.h
    Description:Definition for Keyboard Driver

*********************************************************************************/
#ifndef __KEYBOARD__H
#define __KEYBOARD__H

/*
==================================================================================

    Description :Keyboard controller register

    bit number  value    description
    0           0        Output buffer is empty
                1        Output buffer is full
    1           0        Input buffer is empty
                1        Input buffer is full
    2           0        Set after power on reset 
                1        Set after successfull completion of 
                         the keyboard controllers self-test 
    3           0        Last write to input buffer was data (via port 0x60) 
                1        Last write to input buffer was a command (via port 0x64)
    4           0        Inhibit key is released
                1        Inhibit key is pressed 
    5           0        Data has been written by keyboard controller
                1        Data hasn't been written
    6           0        Data has been read by keyboard controller 
                1        Data hasn't been read
    7           0        Last data read from keyaboard controller is odd parity 
                1        Last data read from keyaboard controller is even parity

==================================================================================
*/
#define DEF_KBD_STS_OBF    0x01
#define DEF_KBD_STS_IBF    0x02
#define DEF_KBD_STS_F0     0x04
#define DEF_KBD_STS_F1     0x08
#define DEF_KBD_STS_ST4    0x10
#define DEF_KBD_STS_ST5    0x20
#define DEF_KBD_STS_ST6    0x40
#define DEF_KBD_STS_ST7    0x80

#endif /* __KEYBOARD__H */



そしてステータスレジスタを読み込む関数を作ります。

キーボードコントローラのステータスレジスタを読み込む関数

ステータスレジスタはポートからIN命令で読み込みます

IN命令で読み込む関数は割り込みその2 PICとIRQ で作ったinPortByte関数を使用していきます


/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :readKbdCtrlStatus
    Input       :void
    Output      :void
    Return      :unsigned char
                 < value of status register >

    Description :read status register from  keyboard controller
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
unsigned char readKbdCtrlStatus( void )
{
    return( inPortByte( DEF_PORT_KBD_CTRL_STATUS ) );
}



キーボードコントローラのコマンドを書き込む関数

キーボードコントローラにコマンドを書き込むには OUT命令を使います

同様にOUT命令で書き込む関数は割り込みその2 PICとIRQ で作ったoutPortByte関数を

使用していきます。但し、コマンドを書き込む前にステータスレジスタを読み込んで

インプットバッファフルビットが0になっているかどうか確認します


#define DEF_KBD_OK         0
#define DEF_KBD_ERROR      (-1)
#define MAX_RETRY          0x01000000

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :writeKbdCtrlCommand
    Input       :unsigned char command
                 < command to keyboard controller >
    Output      :void
    Return      :STATUS

    Description :write a command to keyboard controller
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS writeKbdCtrlCommand( unsigned char command )
{
    int retry;

    /* ------------------------------------------------------------------------ */
    /*  retry reading status register                                           */
    /* ------------------------------------------------------------------------ */
    for( retry = 0 ; retry < MAX_RETRY ; retry++ )
    {
        if( ( readKbdCtrlStatus( ) & DEF_KBD_STS_IBF ) == 0 )
        {
            outPortByte( DEF_PORT_KBD_CTRL_COMMAND, command );
            return( DEF_KBD_OK );
        }
    }

    return( DEF_KBD_ERROR );
}



コマンドを書き込む前にステータスレジスタを読み込んでいますが、読み込み処理に

リトライ回数を設けています。while文でビットが0になるまで回してもよいかと思いますが

ここでは念のために、いつまでも読み込めないときはエラーを返すようにしています

(リトライ回数はすごく適当です。。。)



次にエンコーダからのデータ読み込み(スキャンコードを読み込みます)と

エンコーダへのコマンド書き込み関数を作ります

キーボードエンコーダからデータを読み込む関数

キーボードエンコーダからデータを読み込むにはポートアドレス0x60から読み込みます


/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :readKbdEncBuffer
    Input       :void
    Output      :void
    Return      :unsigned char
                 < data read from encoder >

    Description :read buffer from keyboard encoder
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
unsigned char readKbdEncBuffer( void )
{
    return( inPortByte( DEF_PORT_KBD_ENC_BUFFER ) );
}



同様にキーボードエンコーダにコマンドを書き込む関数を作ります

キーボードエンコーダにコマンドを書き込む関数

キーボードエンコーダにコマンドを書き込む場合にも、一旦キーボードコントローラを経由しますので

キーボードコントローラのステータスレジスタのインプットバッファフルビットを確認してから書き込みます

キーボードコントローラにコマンドを書き込む関数と違う箇所はポートアドレスだけとなります


/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :writeKbdEncCommand
    Input       :unsigned char command
                 < command to keyboard encoder >
    Output      :void
    Return      :STATUS

    Description :write a command to keyboard encoder
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS writeKbdEncCommand( unsigned char command )
{
    int retry;

    /* ------------------------------------------------------------------------ */
    /*  retry reading status register                                           */
    /* ------------------------------------------------------------------------ */
    for( retry = 0 ; retry < MAX_RETRY ; retry++ )
    {
        if( ( readKbdCtrlStatus( ) & DEF_KBD_STS_IBF ) == 0 )
        {
            outPortByte( DEF_PORT_KBD_ENC_COMMAND, command );
            return( DEF_KBD_OK );
        }
    }

    return( DEF_KBD_ERROR );
}



これでキーボードを制御するための下準備ができました!

それでは実際に制御するコマンドを次回見ていきます

inserted by FC2 system