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

日々勉強中。。。

0から作るOS開発

環境準備

環境設定

ブートローダ

カーネルローダ

GRUB

カーネル

ドライバーその他

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

前回までの内容

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

今回はキーボードドライバの続きとなります

まずは、キーボードエンコーダの制御コマンドについて見ていきます

キーボードエンコーダの制御コマンド

キーボードエンコーダに制御コマンドを書き込むにはポートアドレス0x60にアクセスします

キーボードエンコーダの標準制御コマンド
コマンド 名称 説明
0xED LED設定 ポートアドレス0x60に0xEDを書き込んだ後に続けてLEDの設定値をポートアドレス0x60に書き込みます
LEDの設定値は次のフォーマットになります
キーボードコントローラ制御コマンド0xED LED設定
各ビットについては次のようになります。
制御コマンド0xED LED設定
ビット 名称 説明
ビット0 Scr Scroll LockのLEDを設定します。
0:スクロールロックのLEDをOFFします
1:スクロールロックのLEDをONします
ビット1 Num Num LockのLEDを設定します。
0:ナムロックのLEDをOFFします
1:ナムロックのLEDをONします
ビット2 Caps Caps LockのLEDを設定します。
0:キャプスロックのLEDをOFFします
1:キャプスロックのLEDをONします
ビット3-7 Reserved 予約。値は0固定です
0xEE エコー キーボードエンコーダに書き込んだ値0xEEをそのままポートアドレス0x60に返してきます。 キーボードエンコーダが正常に動作しているか確認することができます
0xF0 スキャンコード設定/取得 キーボードエンコーダから取得するスキャンコードセットを設定することができます。 設定するスキャンコードは下記フォーマットでコマンドに続けてポートアドレス0x60に書き込みます。 設定する値は次のようになります
制御コマンド0xF0 スキャンコード設定/取得
設定値 説明
0x00 続けてポートアドレス0x60を読み込むことで
現在キーボードに設定されているスキャンコードセットを取得します
取得した値は次のようになっています
0x43:スキャンコードセット1が設定されています
0x41:スキャンコードセット2が設定されています
0x3F:スキャンコードセット3が設定されています
0x01 キーボードにスキャンコードセット1を設定します
0x02 キーボードにスキャンコードセット2を設定します
0x03 キーボードにスキャンコードセット3を設定します
0xF2 キーボードID取得 2バイトのキーボードIDを取得します。 コマンド書き込み後ポートアドレス0x60を続けて読み込むことでキーボードIDを 取得できます。コマンド書き込み後は読み込み前に最低10ms待ちます。 キーボードIDの例は下記となります。キーボードごとにいろいろなIDがあります
制御コマンド0xF2 キーボードID取得
取得キーボードID 説明
0xAB 0x41(0xAB 0x83) MF2 ATキーボード
0xAB 0x54(0xAB 0x84) IBM Thinkpadのようなノートパソコンのキーボード
0xAB 0x86(0xAB 0x86) 122キーのキーボード
0xAB 0x85 パソコンに直接接続の122キーボード
0xBF 0xBF IBM 1390876キーボード
0xAB 0x85 NCD N-97キーボード
0x18 0xAB 105キーWindowsキーボード
0xF3 タイプマティックレート/ディレイ設定 タイプマティックレート(キーを押し続けている場合にスキャンコードが送信される間隔)と タイプマティックディレイ(タイプマティックモードになるまでの遅延時間)が設定できます このコマンド書き込み後続けてポートアドレス0x60に次のフォーマットで設定値を 書き込みます
キーボードコントローラ制御コマンド0xF3 タイプマティックレート/ディレイ設定
ビット0-4:タイプマティックレートを設定します。
設定値と対応するレートは下記表を参照してください

ビット5-6:タイプマティックディレイを設定します。
設定値と対応するディレイは下記表を参照してください

ビット7:予約。0固定となります。
タイプマティックディレイ設定値と対応するディレイ
設定値(ビット5-6)
0x0 250ms
0x1 500ms(デフォルト値)
0x2 750ms
0x3 1000ms

タイプマティックレート設定値と対応するレート
設定値(ビット0-4) 1秒間に送信される文字数
0x00 30.0文字
0x01 26.7文字
0x02 24.0文字
0x03 21.8文字
0x04 20.0文字
0x05 18.5文字
0x06 17.1文字
0x07 16.0文字
0x08 15.0文字
0x09 13.3文字
0x0A 12.0文字
0x0B 10.9文字(デフォルト値)
0x0C 10.0文字
0x0D 9.2文字
0x0E 8.6文字
0x0F 8.0文字
0x10 7.5文字
0x11 6.7文字
0x12 6.0文字
0x13 5.5文字
0x14 5.0文字
0x15 4.6文字
0x16 4.3文字
0x17 4.0文字
0x18 3.7文字
0x19 3.3文字
0x1A 3.0文字
0x1B 2.7文字
0x1C 2.5文字
0x1D 2.3文字
0x1E 2.1文字
0x1F 2.0文字

レートと設定値の関係は(2^ビット4-3)*(ビット2-0+8)/240秒となります
0xF4 キーボード有効 キーボードを有効にします。キーボードが有効の場合にコマンドを書き込むと 内部バッファがクリアされます。エラーコードが返ってきた場合はキーボードは 無効となります。
0xF5 キーボード無効 キーボードを無効にします。キーボードを無効にするとアウトプットバッファをクリア、 LEDをOFF、タイプマティックレート/ディレイをデフォルト値に設定、キーボードスキャンを 無効にします。
0xF6 デフォルト設定 アウトプットバッファをクリア、LEDをOFF、タイプマティックレート/ディレイをデフォルト値に設定します
0xF7 全キーのリピート設定 スキャンコードセット3でスキャンコードのリピートビットを常にセットするようになります。 スキャンコードセット3以外のスキャンコードセットには影響はありません。
0xF8 全キーのブレークコード設定 スキャンコードセット3でスキャンコードのブレークコード生成ビットを常にセットするようになります。 スキャンコードセット3以外の スキャンコードセットには影響はありません。
0xF9 全キーのブレークコード設定クリア スキャンコードセット3でスキャンコードのブレークコード生成ビットを常にクリアするようになります。 スキャンコードセット3以外の スキャンコードセットには影響はありません。
0xFA 全キーのリピート/ブレークコード設定 スキャンコードセット3でスキャンコードのリピートビットとブレークコード生成ビットを 常にセットするようになります。スキャンコードセット3以外のスキャンコードセットには 影響はありません。
0xFB キーのリピート設定 スキャンコードセット3で指定したキーのスキャンコードのリピートビットを常に セットするようになります。スキャンコードセット3以外のスキャンコードセットには 影響はありません。このコマンドを書き込み後続けいてポートアドレス0x60に リピート設定したいキーのスキャンコードセット3を書き込みます。設定したい キー分書き込んだ後終了コマンドとして"0xED 0xEE 0xF0 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF"を書き込みます。終了コマンドを書き込んだ後は0xF4キーボード有効コマンドを 書き込みキーボードを有効にしておきます
0xFC キーのブレークコード設定 スキャンコードセット3で指定したキーのスキャンコードのブレークコードビットを常に セットするようになります。スキャンコードセット3以外のスキャンコードセットには 影響はありません。このコマンドを書き込み後続けいてポートアドレス0x60に ブレークコード設定したいキーのスキャンコードセット3を書き込みます。設定したい キー分書き込んだ後終了コマンドとして"0xED 0xEE 0xF0 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF"を書き込みます。終了コマンドを書き込んだ後は0xF4キーボード有効コマンドを 書き込みキーボードを有効にしておきます
0xFD キーのブレークコード設定クリア スキャンコードセット3で指定したキーのスキャンコードのブレークコードビットを常に クリアするようになります。スキャンコードセット3以外のスキャンコードセットには 影響はありません。このコマンドを書き込み後続けいてポートアドレス0x60に ブレークコード設定クリアしたいキーのスキャンコードセット3を書き込みます。設定したい キー分書き込んだ後終了コマンドとして"0xED 0xEE 0xF0 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF"を書き込みます。終了コマンドを書き込んだ後は0xF4キーボード有効コマンドを 書き込みキーボードを有効にしておきます
0xFE 再送信要求 キーボードエンコーダにデータの再送信要求をします。 このコマンドはキーボードコントローラがキーボードエンコーダに対して 書き込むコマンドとなります
0xFF リセット/セルフテスト リセットしてからセルフテストを行います。セフルテスト完了ごポートアドレス0x60に 結果を格納します。0xAAであればテスト結果OK、0xFCであればテスト結果NGと なります。セフルテスト中はLEDを点灯/消灯します


標準以外の各社独自仕様コマンドとして下記コマンドがあります

キーボードエンコーダの各社独自制御コマンド
コマンド 名称 説明
0xE8 OmniKeyキーボードID取得 OmniKey101キーボードのIDを取得することができます。 IDは0xE0 0x4Cとなります
0xEA 拡張キー有効/無効 IBMキーボードの拡張キーを有効/無効にします
有効:0xEA 0x70
無効:0xEA 0x71
0xEB 拡張LED ON/OFF 拡張LEDをON/OFFします。 下記表のコマンド最後のバイトでLED ON/OFFを切り替えます。 該当ビットが1でLEDをON、ビットが0であればLEDをOFFにします
拡張LED ON/OFFコマンド
キーボード 対象LED コマンド
Chicony KBP-8993キーボード Moon LED 0xEB 0x00 0x01
zzZ LED 0xEB 0x00 0x02
IBM EZ Buttonキーボード Msg LED 0xEB 0x00 0x01
CD LED 0xEB 0x00 0x02
電源LED 0xEB 0x00 0x04
Talk LED 0xEB 0x00 0x10
メッセージウェイトLED 0xEB 0x00 0x20
IBM Rapid Accessキーボード サスペンドLED 0xEB 0x00 0x04
ミュートLED 0xEB 0x00 0x20
IBM Rapid Accessキーボード2 スタンバイLED ON 0xEB 0x71
スタンバイLED OFF 0xEB 0x70
Logitechインターネットキーボード アンバー色LED 0xEBを書き込むと1秒毎に点滅します。 OFFにするにはもう一度0xEBを書き込みます


キーボードエンコーダの制御

キーボードエンコーダの制御例としてLEDをON/OFFする関数について作成してみます

この実装例ででてくる関数writeKbdEncCommandは キーボードドライバその1で作ったものです


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

    Description :Commands of Keyboard Encoder

==================================================================================
*/
#define	DEF_KBD_ENC_COM_SETLED              0xED
#define	DEF_KBD_ENC_COM_ECHO                0xEE
#define	DEF_KBD_ENC_COM_GETSET_SCANCODE     0xF0
#define	DEF_KBD_ENC_COM_GET_KBD_ID          0xF2
#define	DEF_KBD_ENC_COM_SET_TYPEMATIC       0xF3
#define	DEF_KBD_ENC_COM_ENABLE_KBD          0xF4
#define	DEF_KBD_ENC_COM_DISABLE_KBD         0xF5
#define	DEF_KBD_ENC_COM_SET_DEFAULT         0xF6
#define	DEF_KBD_ENC_COM_SET_ALL_REPEAT      0xF7
#define	DEF_KBD_ENC_COM_SET_ALL_BREAK       0xF8
#define	DEF_KBD_ENC_COM_CLEAR_ALL_REP_BRK   0xF9
#define	DEF_KBD_ENC_COM_SET_ALL_REP_BRK     0xFA
#define	DEF_KBD_ENC_COM_SET_REPEAT          0xFB
#define	DEF_KBD_ENC_COM_SET_BREAK           0xFC
#define	DEF_KBD_ENC_COM_CLEAR_REP_BRK       0xFD
#define	DEF_KBD_ENC_COM_REQ_RESEND          0xFE
#define	DEF_KBD_ENC_COM_RESET_SELFTEST      0xFF

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

    Description :Keyboad LED

==================================================================================
*/
typedef enum
{
    E_KBD_NONE_LED          = 0x00000000,
    E_KBD_SCROLL_LOCK_LED   = 0x00000001,
    E_KBD_NUM_LOCK_LED      = 0x00000002,
    E_KBD_CAPS_LOCK_LED     = 0x00000004
} E_KBD_LED;

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :keyboardSetLED
    Input       :E_KBD_LED led
                 < designated led >
    Output      :void
    Return      :STATUS

    Description :set leds of keyboard
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS keyboardSetLED( E_KBD_LED led )
{
    unsigned char   wirte_data;
    STAUS           status;
	
    /*--------------------------------------------------------------------------*/
    /* if designated leds are unknow                                            */
    /*--------------------------------------------------------------------------*/
    if( ( E_KBD_SCROLL_LOCK_LED | E_KBD_NUM_LOCK_LED | E_KBD_CAPS_LOCK_LED ) < led)
    {
        return( DEF_KBD_ERROR );
    }

    status =  writeKbdEncCommand( DEF_KBD_ENC_COM_SETLED    );
    status |= writeKbdEncCommand( ( unsigned char )led      );

    return( status );
}



この関数は引数ledにEnum型で指定したLEDを点灯させ、それ以外は消灯する関数となります

Capsキーが押されたときにこのコマンドでCapsキーのLEDを点灯させます

キーボードエンコーダのリターンコード

キーボードエンコーダにコマンドを書き込んだ後にはポートアドレス0x60にリターンコードを返してきます

キーボードエンコーダのリターンコード
リターンコード 説明
0x00 エラーまたは内部バッファのオーバーランが発生しました。 スキャンコードセット2またはセット3の場合のみ書き込まれます
0x**、・・・ スキャンコードが書き込まれます。 (コマンド書き込み後以外)
0x**、0x** 0xF2キーボードID取得コマンド発行後のキーボードIDが書き込まれます
0xAA 0xFFリセット/セルフテストのセルフテスト(BAT:Basic Assurance Test) 実行中または成功後に書き込まれます。(スキャンコードのなかにも0xAAが含まれる コードがありますので注意します)。
0xEE 0xEEエコーコマンド書き込み後に書き込まれます
0xFA キーボードエンコーダのOK応答です。 キーボードコントローラに対して発行されます。キーボードエンコーダが正常動作しているか この応答で確認できます
0xFC 0xFFリセット/セルフテストのセルフテスト(BAT:Basic Assurance Test) が失敗した場合に書き込まれます。PS/2プロトコルのみ適用されます。
0xFD 0xEEエコーコマンドが失敗した場合に書き込まれます
0xFE 解釈できないコマンドやノイズなどでキーボードエンコーダが最後に受信した コマンドが正常に解釈できないときに書き込まれる、コマンドの再送信要求です


スキャンコードの読み取りとキーボードIDの読み取りが任意の値ですので、

このことに留意してプログラムします

キーボードに対する制御はキーボードエンコーダを制御することでできるようになりました

次にキーボードコントローラの制御コマンドについて見ていきます

キーボードコントローラの制御コマンド

キーボードコントローラの制御コマンドの何個かは カーネルローダその3で見てきました。

以前見たコマンドとあわせてその他のコマンドについても見ていきます

キーボードコントローラの制御コマンドで8042自体を制御していきます

コマンドはポートアドレス0x64に書き込みます。まずは、標準のコマンドについて見ていきます

キーボードコントローラの標準制御コマンド
コマンド 名称 説明
0x20 キーボードコントローラコマンド読み込み キーボードコントローラから制御コマンドを1バイト(CCB:Control Command Byte)を読み込みます。 制御コマンドバイトについては下のほうで詳細を見ていきます
0x60 キーボードコントローラコマンド書き込み キーボードコントローラから制御コマンドを1バイト(CCB:Control Command Byte)を書き込みます。 この0x60のコマンドをポートアドレス0x64に書き込み後、制御コマンドバイトをポートアドレス0x60に 書き込みます。 制御コマンドバイトについては下のほうで詳細を見ていきます
0xA7 マウスポート無効 MCAシステムでは、マウスとAUXデバイスのクロックをLowにして 制御コマンドバイトのビット5を1にします。その結果 ポートP23の出力が1になります。 ISA/EISAシステムのAMIBIOSではキャッシュバッドを書き込みます
0xA8 マウスポート有効 MCAシステムでは、マウスとAUXデバイスのクロックを有効にして 制御コマンドバイトのビット5を0にします。その結果 ポートP23の出力が0になります。 ISA/EISAシステムのAMIBIOSではキャッシュグッドを書き込みます
0xA9 マウスポートのテスト キーボードコントローラとマウス間のシリアル通信をテストします。 テスト結果はポートアドレス0x60に格納されます。 テスト結果は下記となります
0x00:テスト結果OK
0x01:マウスクロックラインがLowになったままです
0x02:マウスクロックラインがHighになったままです
0x03:マウスデータラインがLowになったままです
0x04:マウスデータラインがHighになったままです
0xFF:マウスは接続されていません
ISA/EISAシステムのAMIBIOSではキャッシュバッドもしくはキャッシュグッドを 読み込みます。結果は下記となります
0x00:キャッシュバッド
0x01:キャッシュグッド
0xAA セルフテスト セルフテストを行います。セルフテストの結果をポートアドレス0x64に返します。 セルフテストの結果は下記となります
0x55:テスト結果OK
0xFC:テスト結果NG
0xAB インターフェイステスト キーボードコントローラとキーボードエンコーダとのシリアル通信が正常に行えるかテストします。 テスト結果はポートアドレス0x60に返します。テスト結果は下記となります
0x00:テスト結果OK
0x01:キーボードクロックラインがLowになったままです
0x02:キーボードクロックラインがHighになったままです
0x03:キーボードデータラインがLowになったままです
0x04:キーボードデータラインがHighになったままです
0xFF:その他のエラーが発生しました
0xAD キーボード無効 キーボードエンコーダとのクロックラインを無効化し、制御コマンドバイトの4ビット目を1にします。 制御コマンドバイトについては下の方で詳細を見ていきます
0xAE キーボード有効 キーボードエンコーダとのクロックラインを有効化し、制御コマンドバイトの4ビット目を0にします。 制御コマンドバイトについては下の方で詳細を見ていきます
0xC0 インプットポート読み込み インプットポートを読み込んで、その結果をポートアドレス0x64に格納します。 インプットポートについては下の方で詳細を見ていきます
0xD0 アウトプットポート読み込み アウトプットポートを読み込んで、その結果をポートアドレス0x64(アウトプットバッファ)に 格納します。アウトプットポートについては下の方で詳細を見ていきます
0xD1 アウトプットポート書き込み アウトプットポートに書き込みします。アウトプットポートのビット0に0を書き込むと ハードウェアリセットします。アウトプットポートについては下の方で詳細を見ていきます
0xD4 マウスへの書き込み このコマンド書き込み後ポートアドレス0x60にマウスへ書き込むデータを 書き込みます。MCAシステムで使用します。
0xE0 テストポート読み込み テストポートを読み込み、結果をポートアドレス0x60に格納します。 アウトプットバッファが空の場合のみ使用できるコマンドです。 テストポートは下記となります
ビット0:キーボードクロック(入力)
ビット1:ATの場合はキーボードデータ(入力)、PS/2の場合はマウスクロック(入力)
0xFE システムリセット アウトプットポートのビット0を0にしてハードウェアリセットを行います


標準以外のキーボードコントローラのコマンドは下記となります

下記コマンドに対応していないキーボードもありますので注意します

(対応していないコマンドもありますので今回重要となる部分をボールドしています)

キーボードコントローラの標準以外の制御コマンド
コマンド 名称 説明
0x00-1F キーボードコントローラのRAM読み込み 0x20-0x3Fのエイリアスとなります
(AMIBIOSのみ)
0x20-3F キーボードコントローラのRAM読み込み キーボードコントローラは32バイトRAMを持っています。RAMのアドレスを0x00から0x3Fまでで 指定し、ポートアドレス0x64に書き込みます。RAMから読みだしたデータはポートアドレス0x60に 格納されます。MCA(Micro Channel Architecture)では、タイプ1コントローラが32バイト目の アドレスまでアクセスできます。タイプ2コントローラでは0x00、0x13-0x17、0x1D、0x1Fのみ アクセスできます。下記アドレスは特殊なデータを格納するアドレスとなります
アドレス0x00:制御コマンドバイトのデータが格納されています(下の方で詳細を見ていきます)
アドレス0x13:パスワードが有効に設定されている場合0以外が格納されます(MCAのみ)
アドレス0x14:パスワードが認証された場合0以外が格納されます(MCAのみ)
アドレス0x16,0x17:パスワード認証中にメイクコードが格納されます(MCAのみ)
0x40-5F キーボードコントローラのRAM書き込み 0x60-0x7Fのエイリアスとなります (AMIBIOSのみ)
0x60-7F キーボードコントローラのRAM書き込み キーボードコントローラのRAM上のアドレスを指定して、ポートアドレス0x64に書き込みます。 続けて書き込みたいデータをポートアドレス0x60に書き込みます
0x90-93 Synapticsルーティングプリフィクス PS/2プロトコルで接続されているAUXデバイスを選択するプリフィクスコマンドです。 Synaptics社 から PS/2マルチプレクシングの仕様 がダウンロードできますので、 気になる方は参照してください。 下記プリフィクスをポートアドレス0x64に書き込んでから、デバイスに書き込む データをポートアドレス0x60に書き込みます
0x90:AUXポートNo.1にコマンドを書き込みます
0x91:AUXポートNo.2にコマンドを書き込みます
0x92:AUXポートNo.3にコマンドを書き込みます
0x93:AUXポートNo.4にコマンドを書き込みます
VIAがこのコマンドを採用しています)
0x90-0x9F ポート13-ポート10書き込み このコマンドのローニブルがポート13-ポート10の出力になります。 各ポートに同時に出力するときはローニブルをORします
0x90:全ポートをLowにします
0x91:ポート13をHighにします
0x92:ポート12をHighにします
0x94:ポート11をHighにします
0x98:ポート10をHighにします
(VIA VT82C42で使用できます)
0xA0 コピーライト読み込み ポートアドレス0x64にこのコマンドを書き込むとポートアドレス0x60に コピーライトがアスキーコードで格納されます。(Nullだけの場合もあります)。 このコマンドに対応していないキーボードコントローラには無視されます
0xA1 ファームウェアバージョン読み込み ポートアドレス0x64にこのコマンドを書き込むとポートアドレス0x60に ファームウェアバージョンがアスキーコードで1バイト格納されます。 このコマンドに対応していないキーボードコントローラには無視されます
0xA2 スイッチスピードリセット キーボードコントローラのP22とP23をLowにします。P22とP23は スイッチスピード切り替えに使用されます。処理が完了すると キーボードコントローラからダミーデータが送信されます。 (ISA/EISAシステムのAMIBIOSで使用できます)
0xA3 スイッチスピード設定 キーボードコントローラのP22とP23をHighにします。 処理が完了するとキーボードコントローラからダミーデータが送信されます。 (ISA/EISAシステムのAMIBIOSで使用できます、COMPAQのBIOSでは システムスピード制御を有効にします)
0xA4 パスワード設定確認 ポートアドレス0x64にこのコマンドを書き込むと、パスワードが設定されて いるかどうかを確認し、その結果がポートアドレス0x60に格納されます。 格納されれる結果は次のようになります
0xF1:MCAシステムでパスワードが設定されていない
0xFA:MCAシステムでパスワード設定されている
0xF1:パスワード機能が無いその他のシステム

ISA/EISAシステムのAMIBIOSではクロックがLowになります
COMPAQのBIOSはシステムスピードが変更されます
0xA5 パスワード読み込み MCAシステムではNullで終わるパスワード文字列がポートアドレス0x60に 格納されます。格納されるデータはスキャンコードです。 ISA/EISAシステムのAMIBIOSではクロックをHighにします。 COMPAQのBIOSではポートアドレス0x60に次のデータが格納されます
ビット4が0:アウトプットバッファフル割り込みが無効
ビット4が1:アウトプットバッファフル割り込みが有効
ビット5が0:9ビットキーボードエンコーダ
ビット5が1:11ビットキーボドエンコーダ
0xA6 パスワードチェック MCAシステムでパスワードが設定されている場合、設定されているパスワードと このコマンドが書き込まれた以降に押されたキーが一致しているかチェックします。 一致していればキーボードが有効になります。 ISA/EISAシステムのAMIBIOSではクロックの状態を読み込みます
0:クロックはLowです
1:クロックはHighです
0xAC 診断データダンプ キーボードコントローラのRAMから16バイトのデータ、アウトプットポート、 インプットポート、キーボードコントローラのプログラムステータスを ポートアドレス0x60から読み込みます。
0xAF キーボードエンコーダバージョン読み込み Award BIOS、VIAで使用します。
キーボードエンコーダのバージョンを読み込みます
0xB0-0xB5 キーボードコントローララインのリセット <AMIBIOS>
ポートアドレス0x64に0xB0から0xB5を書き込むとキーボードコントローラの ポートをLowにします。ポートとコマンドの対応関係は下記となります。
0xB0:P10をLowにします(ISA/EISAシステムのみ)
0xB1:P11をLowにします(ISA/EISAシステムのみ)
0xB2:P12をLowにします
0xB3:P13をLowにします
0xB4:P22をLowにします(ISA/EISAシステムのみ)
0xB5:P23をLowにします(ISA/EISAシステムのみ)
コマンド書き込み後キーボードコントローラからダミーデータが送信されます

<VIA BIOS>
ポートアドレス0x64に0xB0から0xB7を書き込むとキーボードコントローラの ポートをLowにします。ポートとコマンドの対応関係は下記となります。
0xB0:P10をLowにします
0xB1:P11をLowにします
0xB2:P12をLowにします
0xB3:P13をLowにします
0xB4:P22をLowにします
0xB5:P23をLowにします
0xB6:P14をLowにします
0xB7:P15をLowにします
0xB8-0xBD キーボードコントローララインの設定 <AMIBIOS>
ポートアドレス0x64に0xB0から0xB5を書き込むとキーボードコントローラの ポートをHighにします。ポートとコマンドの対応関係は下記となります。
0xB0:P10をHighにします(ISA/EISAシステムのみ)
0xB1:P11をHighにします(ISA/EISAシステムのみ)
0xB2:P12をHighにします
0xB3:P13をHighにします
0xB4:P22をHighにします(ISA/EISAシステムのみ)
0xB5:P23をHighにします(ISA/EISAシステムのみ)
コマンド書き込み後キーボードコントローラからダミーデータが送信されます

<VIA BIOS>
ポートアドレス0x64に0xB0から0xB7を書き込むとキーボードコントローラの ポートをLowにします。ポートとコマンドの対応関係は下記となります。
0xB0:P10をHighにします
0xB1:P11をHighにします
0xB2:P12をHighにします
0xB3:P13をHighにします
0xB4:P22をHighにします
0xB5:P23をHighにします
0xB6:P14をHighにします
0xB7:P15をHighにします
0xC1 インプットポート連続ポーリング(ローニブル) MCAシステムのタイプ1コントローラのみ使用できます
このコマンド書き込み後インプットポートのビット3-0がポートアドレス0x64の ビット7-4に連続で書き込まれます。別のコマンドをキーボードコントローラに 書き込むと終了します。
0xC2 インプットポート連続ポーリング(ハイニブル) MCAシステムのタイプ1コントローラのみ使用できます
このコマンド書き込み後インプットポートのビット7-4がポートアドレス0x64の ビット7-4に連続で書き込まれます。別のコマンドをキーボードコントローラに 書き込むと終了します。
0xC8 ブロック解除(P22とP23) ISA/EISAシステムのAMIBIOSで使用できます
このコマンド送信後に、コマンド0xD1アウトプットポート書き込みで P22とP23をLow/Highにすることができます
0xC9 ブロック設定(P22とP23) ISA/EISAシステムのAMIBIOSで使用できます
このコマンド送信後に、コマンド0xD1アウトプットポート書き込みで P22とP23をLow/Highにすることができなくなります
0xCA キーボードコントローラモード読み込み AMIBIOS、VIA BIOSで使用できます
コマンド書き込み後ポートアドレス0x60のビット0にキーボードコントローラの モードを格納します。モードは下記となります
0:PS/2(MCA)インターフェイス
1:ISA(AT)インターフェイス
0xCB キーボードコントローラモード書き込み AMIBIOS、VIA BIOSで使用できます
コマンド書き込むとポートアドレス0x60のビット0がキーボードコントローラの モードに設定できます。モードは下記となります
0:PS/2(MCA)インターフェイス
1:ISA(AT)インターフェイス
このコマンドを書き込む前に、一度0xCAで1バイト読み込み、ビット0を変更してから モードを設定します
0xD2 キーボードコントローラアウトプットバッファ書き込み MCAシステムで使用します。
このコマンド書き込み後ポートアドレス0x60に書き込むデータを書き込みます (キーボードコントローラのアウトプットバッファにポートアドレス0x60のデータを 書き込みます)。特に注意すべき点は、このコマンドで書き込んだデータは キーボードエンコーダからキーボードコントローラに送信したように振る舞う ということです。ですので、割り込みの設定をしている場合IRQ1が発生します
0xD3 マウスアウトプットバッファ書き込み <MCAシステム>
このコマンド書き込み後ポートアドレス0x60に書き込むデータを書き込みます (キーボードコントローラのアウトプットバッファにポートアドレス0x60のデータを 書き込みます)。特に注意すべき点は、このコマンドで書き込んだデータは マウスからキーボードコントローラに送信したように振る舞う ということです。ですので、割り込みの設定をしている場合IRQ12が発生します

<Synaptics仕様のパソコン>
ノートパソコンなどはAUXデバイスが接続されているためAUXデバイスとの 通信プロトコルでこのコマンドを使用します。 Synaptics社 から PS/2マルチプレクシングの仕様 がダウンロードできますので、 気になる方は参照してください
0xDD A20アドレスライン無効 HP Vectraで使用できます。
A20アドレスラインを無効にします
0xDF A20アドレスライン有効 HP Vectraで使用できます。
A20アドレスラインを有効にします
0xF0-0xFF パルス出力 キーボードコントローラのアウトプットポートのビット3-0から約6秒間パルスを出します。 ローニブルのビット3-0がアウトプットポートのビット3-0に対応しています。 ビットが0であればパルスを出し、ビットが1であればパルスを出しません。
0xF7:アウトプットポートのビット3からパルスを出します
0xFB:アウトプットポートのビット2からパルスを出します
0xFD:アウトプットポートのビット1からパルスを出します
0xFE:アウトプットポートのビット0からパルスを出します
(0xFEはすなわちシステムのリセットコマンドとなります)
出力したいポートのビットを複数0にすることもできます


では、制御コマンドにでてきました制御コマンドバイト、インプットポート、アウトプットポートについて

見ていきます

制御コマンドバイト、インプットポート、アウトプットポート

制御コマンドバイト、インプットポート、アウトプットポートについて見ていきます。

制御コマンドバイト

キーボードコントローラのIC8042はRAMを持っています。RAMはメモリですので、当然アドレスを

指定してデータを書き込んだり、読み込んだりすることができます。キーボードコントローラのRAMは

合計32バイトの小さな領域でバイトサイズで読み書きします。32バイトのRAMの中で一番重要な

データが一番最初のアドレス0x00にある制御コマンドバイトと呼ばれるデータとなります。特別な

データですので、標準制御コマンドで特にアドレスをしていせずにデータの読み書きができます。



コマンド制御バイトはキーボードコントローラの制御コマンド0x20で読み込みができます。

また制御コマンド0x60で書き込むことができます。コマンド制御バイトのビットアサインは次のようになります

キーボードコントローラの制御コマンドバイト


キーボードコントローラの制御コマンドバイト
ビット ラベル 名称 説明
ビット0 KIE キーボード割り込み有効 このビットを操作することで、キーボード割り込みを有効にしたり無効にしたりすることができます
0:キーボード割り込みは無効です
1:キーボード割り込みは有効で、キーボードコントローラのアウトプットバッファがフルになるとIRQ1を発生させます
ビット1 KIE マウス割り込み有効 <ISAシステム>
使用しません

<PS/2またはEISAシステム>
このビットを操作することで、マウス割り込みを有効にしたり無効にしたりすることができます
0:キーボード割り込みは無効です
1:キーボード割り込みは有効で、マウスのアウトプットバッファがフルになるとIRQ12を発生させます
ビット2 SYSF システムフラグ 0:システムはコールドリブート(Cold Reboot)しました
1:システムはウォームリブート(Warm Reboot)しました。(ウォームリブートはBIOSがBAT処理を完了した状態となります)。
このフラグによりBIOSのPOST処理で行う検査・初期化処理が変わります。 このビットはキーボードドライバその1で 見てきましたステータスレジスタのビット2と同じ内容となります。
ビット3 IGNLK キーボードロック強制解除
(Ignore Keyboard Lock)
<PS/2システム>
使用しません

<ATシステム>
このビットを1にすることで強制的にキーボードロックを解除します
0:何もしません
1:キーボードドライバその1で 見てきましたステータスレジスタのビット4を強制的に1にします。
このビットは電源ON後にキーボードをテストするために使用します。
ビット4 KE キーボード有効 このビットを操作することで、キーボードを有効にしたり無効にしたりすることができます
0:キーボードを有効にします
1:キーボードを無効にします(クロックラインをLowに固定します)
ビット5 ME マウス有効 <PS/2またはEISAシステム>
このビットを操作することで、マウスを有効にしたり無効にしたりすることができます
0:マウスを有効にします
1:マウスを無効にします(クロックラインをLowに固定します)

<ISAシステムの”PCモード”>
0:11ビットコードの使用、パリティ検査、スキャンコード変換をします
1:8086コードの使用し、パリティ検査とスキャンコード変換はしません
ビット6 XLATE スキャンコード変換 このビットを操作することで、キーボードエンコーダから8042に送信されてくるキーデータをスキャンコードに変換するか どうかを設定することができます
0:スキャンコードに変換しません
1:スキャンコードに変換します
<MCAシステムのタイプ2コントローラ>
このビットを変更することはできません。キーボードエンコーダの制御コマンド0xF0を使用します
ビット7 0 予約ビット 0固定です


制御コマンドバイトで特に重要なのがビット1とビット2です。割り込みでキーボードとマウスを制御したい

という場合はこのビットを制御します

インプットポート

キーボードコントローラの制御コマンドの0xC0インプットポート読み込みコマンドで

キーボードコントローラのインプットポートを読み込むことができます。インプットポートは

8042のP10-P17となります。制御コマンド0xC0を書き込むことで、キーボードコントローラは

P10-P17の状態を読み取って値をアウトプットバッファ(ポートアドレス0x64)に格納します。

キーボードコントローラのインプットポート


キーボードコントローラのインプットポート
ビット 対応ポート ラベル 名称 説明
ビット0 P10 KBD <ISAシステム以外>
キーボードデータ入力ポートです

<ISAシステム>
使用しません
ビット1 P11 MOUSE <ISAシステム以外>
マウスデータ入力ポートです

<ISAシステム>
使用しません
ビット2 P12 CLK2 クロック2 <PS/2とMCAシステム以外>
クロックスイッチに使用します。

<PS2とMCAシステム>
0:キーボード電源は正常です
1:キーボード電源が入っていません
ビット3 P13 CLK1 クロック1 クロックスイッチに使用します。ISA、EISA、PS/2システムでは使用しません。
ビット4 P14 RAM RAM 0:マザーボード上のRAMは512KBです
1:マザーボード上のRAMは256KBです
現在使用されているキーボードのRAMは512KBです
ビット5 P15 JAMPER ジャンパ 0:ジャンパで端子が接続されています
1:ジャンパで端子が接続されていません
ジャンパで物理的に端子が接続されている場合にはBIOSは診断処理を無限ループします
ビット6 P16 DISP ディスプレイ 0:ディスプレイはCGAです
1:ディスプレイはMDAです
ビット7 P17 LOCK キーボードロック 0:キーボードはロック状態です
1:キーボードはロック解除状態です


IBM ATではビット7-ビット4を使用します。PS/2、MCAではビット2-ビット0のみ使用します

上記表を見ていただいて分かると思いますが、プログラム上あまり役に立ちそうな情報は

残念ながら得られません。(もしかしたら昔のドライバでは有用だったのかもしれませんが。。。)

アウトプットポート

キーボードコントローラの制御コマンドの0xD0アウトプットポート読み込みコマンドで

キーボードコントローラのアウトプットポートを読み込むことができます。また制御コマンド0xD1

アウトプットポート書き込みコマンドでアウトプットポートに書き込むことができます。アウトプットポートは

8042のP20-P27となります。

キーボードコントローラのアウトプットポート


キーボードコントローラのアウトプットポート
ビット 対応ポート ラベル 名称 説明
ビット0 P20 Reset リセット 0:システムをリセットします
1:システムは通常稼働します
ビット1 P21 A20 A20有効/無効 0:A20ラインをLowにして無効にします
1:A20ラインをHighにして有効にします
このビットの操作についてはカーネルローダその3で見てきました
ビット2 P22 MDATA マウスデータ <ISAシステム以外>
マウスデータ出力ポートです
<ISAシステム>
使用しません
ビット3 P23 MCLK マウスデータ <ISAシステム以外>
マウスクロックポートです
<ISAシステム> 使用しません
ビット4 P24 IRQ1 IRQ1ステータス 0:IRQ1の割り込みは発生していません
1:IRQ1の割り込みが発生しています
ビット5 P25 IRQ12 IRQ12ステータス 0:IRQ12の割り込みは発生していません
1:IRQ12の割り込みが発生しています
ビット6 P26 CLK キーボードクロック キーボードエンコーダとの通信クロックです
ビット7 P27 DATA キーボードデータ キーボードエンコーダとの通信データ出力です


このようなビットアサインとなっておりますが、ビット2とビット3は現在のパソコンでは使用していないようです

そして重要となるのがビット4とビット5です。このビットに対応する8042のポートはP24とP25でそれぞれ

PICにつながっています。(PICについては割り込みその2 を参照してください)。

PICにはIR1とIR12に接続されています。



興味深いポートですが、プログラム的にはあまり役に立つ情報は得られないかと思います

(リセットビットにアクセスしてシステムをリセットできますが、0xFEコマンドでもリセットできます。。。)

キーボードコントローラの制御

キーボードドライバの実装例を少し見ていきます

この実装例ででてくる関数readKbdCtrlStatus、writeKbdCtrlCommand、readKbdEncBuffer

writeKbdEncCommandやDEF_PORT_KBD_CONTROLLERは キーボードドライバその1で作っていますので、

適宜ご参照お願いいたします



まずは、キーボードコントローラの制御コマンドをある程度定義していきます


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

    Description :Commands of Keyboard Controller

==================================================================================
*/
/* Standard Commands      */
#define DEF_KBD_CTRL_COM_READ_CCB        0x20
#define DEF_KBD_CTRL_COM_WRITE_CCB       0x60
#define DEF_KBD_CTRL_COM_DISABLE_MOUSE   0xA7
#define DEF_KBD_CTRL_COM_ENABLE_MOUSE    0xA8
#define DEF_KBD_CTRL_COM_TEST_MOUSE      0xA9
#define DEF_KBD_CTRL_COM_SELF_TEST       0xAA
#define DEF_KBD_CTRL_COM_TEST_IF         0xAB
#define DEF_KBD_CTRL_COM_DISABLE_KBD     0xAD
#define DEF_KBD_CTRL_COM_ENABLE_KBD      0xAE
#define DEF_KBD_CTRL_COM_READ_IN_PORT    0xC0
#define DEF_KBD_CTRL_COM_READ_OUT_PORT   0xD0
#define DEF_KBD_CTRL_COM_WRITE_OUT_PORT  0xD1
#define DEF_KBD_CTRL_COM_WRITE_MOUSE     0xD4
#define DEF_KBD_CTRL_COM_READ_TEST_PORT  0xE0
#define DEF_KBD_CTRL_COM_SYSTEM_RESET    0xFE

/* Vendo-Specific Commands  */
#define DEF_KBD_CTRL_COM_READ_RAM_0x00   0x20
#define DEF_KBD_CTRL_COM_READ_RAM_0x01   0x21
              .
              .
              .
#define DEF_KBD_CTRL_COM_READ_RAM_0x3F   0x3F

#define DEF_KBD_CTRL_COM_WRITE_RAM_0x00  0x60
#define DEF_KBD_CTRL_COM_WRITE_RAM_0x01  0x61
              .
              .
              .
#define DEF_KBD_CTRL_COM_WRITE_RAM_0x7F  0x7F



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

ポートアドレス0x64に0xAAを書き込むとキーボードコントローラはセルフテストを開始します


/*
----------------------------------------------------------------------------------

    Description :Status of Self Test Command

----------------------------------------------------------------------------------
*/
#define DEF_KBD_CTRL_STS_SELF_TEST_OK    0x55
#define DEF_KBD_CTRL_STS_SELF_TEST_NG    0xFC

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :keyboardSelfTest
    Input       :void
    Output      :void
    Return      :STATUS

    Description :command keyboard to test itself
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS keyboardSelfTest( VOID )
{
    unsigned char enc_buffer;
    STATUS        status;
    

    /*--------------------------------------------------------------------------*/
    /* execute self test                                                        */
    /*--------------------------------------------------------------------------*/
    status = writeKbdCtrlCommand( DEF_KBD_CTRL_COM_SELF_TEST );

    if( DEF_KBD_OK != status )
    {
        return( status );
    }

    /*--------------------------------------------------------------------------*/
    /* wait                                                                     */
    /*--------------------------------------------------------------------------*/
    status = waitKbdOutputBufferFull( );

    if( DEF_KBD_OK != status )
    {
        return( status );
    }

    /*--------------------------------------------------------------------------*/
    /* test result of self test                                                 */
    /*--------------------------------------------------------------------------*/
    enc_buffer = readKbdEncBuffer( );

    if( enc_buffer == DEF_KBD_CTRL_STS_SELF_TEST_OK )
    {
        return( status );
    }

    return( DEF_KBD_ERROR );
}

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :waitKbdOutputBufferFull
    Input       :void
    Output      :void
    Return      :STATUS
                 < DEF_KBD_ERROR : timeout occurs >

    Description :wait untill output buffer of keyboard controller is full
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS waitKbdOutputBufferFull( VOID )
{
    unsigned char kbd_status;
    int           retry;

    for( retry = 0 ; retry < MAX_RETRY ; retry++ )
    {
        kbd_status = readKbdCtrlStatus( );

        if( ( kbd_status & DEF_KBD_STS_OBF ) == DEF_KBD_STS_OBF )
        {
            return( DEF_KBD_OK );
        }
    }

    return( DEF_KBD_ERROR );
}



この実装例ではwaitKbdOutputBufferFull関数でアウトプットバッファが空に

なるまでキーボードコントローラのステータスを読み込んで待つ処理を行なっています

アウトプットバッファが空になればコマンドの処理が完了したことになります

その後でポートアドレス0x60にコマンドの結果が格納されますので、その結果を読み込んで

処理します

キーボード無効 制御コマンド0xAD

制御コマンド0xADを書き込むことで制御コマンドバイトのビット4が1になって

キーボードが無効になります


PRIVATE BOOL keyboard_disable;

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :keyboardDisableKBD
    Input       :void
    Output      :void
    Return      :void

    Description :disable a keyboard
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS keyboardDisableKBD( VOID )
{
    /*--------------------------------------------------------------------------*/
    /* disable a keyboard                                                       */
    /*--------------------------------------------------------------------------*/
    status = writeKbdCtrlCommand( DEF_KBD_CTRL_COM_DISABLE_KBD );

    if( DEF_KBD_OK != status )
    {
        keyboard_disable = False;
    }
    else
    {
        keyboard_disable = True;
    }

    return( status );
}



この実装例では、キーボードの無効状態をkeyboard_disable変数で管理するように

しています

キーボード無効 制御コマンド0xAE

制御コマンド0xAEを書き込むことで制御コマンドバイトのビット4が0になって

キーボードが有効になります


/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :keyboardEnableKBD
    Input       :void
    Output      :void
    Return      :void

    Description :enable a keyboard
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS keyboardEnableKBD( VOID )
{
    /*--------------------------------------------------------------------------*/
    /* enable a keyboard                                                        */
    /*--------------------------------------------------------------------------*/
    status = writeKbdCtrlCommand( DEF_KBD_CTRL_COM_ENABLE_KBD );

    if( DEF_KBD_OK != status )
    {
        keyboard_disable = True;
    }
    else
    {
        keyboard_disable = False;
    }

    return( status );
}



少しの実装例でしたが、上記のような要領でキーボードコントローラに

コマンドを書き込むことで制御できます。



これで、キーボードの制御ができるようになりました!

と言いたいところですが、肝心のスキャンコードを読み取るところを少し見ていきたいと思います

スキャンコードの読み取り

スキャンコードはキーが押されたときにキーボードエンコーダからキーボードコントローラに

送信されてくるといことはわかりました。

では、いつスキャンコードを読み込んでいけばよいのでしょうか。



タイミング的には次の2通りあるかと思います

ポーリングする方法では、スキャンコードが送信されてくるタイミングに注意します。

通常、人間が入力できるキーの操作は、歴史上で記録されている最速は

高橋名人 の16連打かと思います(少なくとも日本では。。。)。ですので、1/16秒(=62.5ms)よりも

CPUの処理速度は段違いに速いので、速い間隔でポーリグしても無駄となります。

ウェイト処理か別の処理を並行して処理しておく必要があります。

(キーを押されている間にキーボードエンコーダがスキャンコードを送信してくる

間隔のタイプマティックを制御コマンド0xF3で最速の30文字/秒に設定していれば2倍速く

ポーリングします。)。ウェイト処理には 割り込みその3 で見てきましたPITを使用して

時間を計測する方法などもあります。

ポーリングについては比較的簡単に実装できるかと思います



ここでは、IBM互換機にはシステム上IRQ1の割り込みが発生するように設計されていますので、

割り込みについて見ていきたいと思います。

キーボードの初期化と割り込み

まずはキーボードの初期化を見ていきたいと思います

キーボードドライバの初期化


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

    Description :key state

===================================================================================
*/
typedef struct
{
    BOOL    caps_on;
    BOOL    alt_on;
    BOOL    shift_on;
    BOOL    ctrl_on;
    BOOL    numlock_on;
    BOOL    scrolllock_on;
    BOOL    insert_on;
} KEY_STATE;


PRIVATE KEY_STATE     key_state;
PRIVATE unsigned char scan_code;

/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :initKeyboard
    Input       :void
    Output      :void
    Return      :STATUS
                 < status of initialization >

    Description :initialize keyboard driver
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
STATUS initKeyboard( VOID )
{
    STATUS status;

    /*--------------------------------------------------------------------------*/
    /* initialize keyboard management information                               */
    /*--------------------------------------------------------------------------*/
    key_state.caps_on       = False;
    key_state.alt_on        = False;
    key_state.shift_on      = False;
    key_state.ctrl_on       = False;
    key_state.numlock_on    = False;
    key_state.scrolllock_on = False;
    key_state.insert_on     = False;

    scan_code               = 0x00;

    /*--------------------------------------------------------------------------*/
    /* set leds of keyboard off                                                 */
    /*--------------------------------------------------------------------------*/
    status = keyboardSetLED( E_KBD_NONE_LED );
    
    return( status );
}



この実装例では、キーボードエンコーダから取得するスキャンコードを解釈した

結果、CapsキーやNumLockキーであった場合にその状態を記憶しておく

key_state構造体を定義し、そこに各キーの状態を保存するようことを想定しています



そして電源ON直後にLEDを消灯するようにしています

キーボードの割り込み

キーボードの割り込みハンドラを見ていきます

下記実装例はスキャンコードの処理を省略しています

スキャンコードの処理は読み取ったメイクコードとブレイクコードを解析する

処理などを行うとよいかと思います。割り込みの処理時間が気になる場合などは

タスクで処理を行うなど別の方法で実装します

			
/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :keyboard_interrupt
    Input       :void
    Output      :void
    Return      :void

    Description :handling keyboard interrupt
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
void keyboard_interrupt( void )
{
    /* --------------------------------------------------------------------- */
    /*  entering interrupt                                                   */
    /* --------------------------------------------------------------------- */
    enter_interrupt( );

    /* --------------------------------------------------------------------- */
    /*  read scan code from keyboard encoder                                 */
    /* --------------------------------------------------------------------- */
    scan_code = readKbdEncBuffer( );

    /* --------------------------------------------------------------------- */
    /*  inform end of interrupt to pics                                      */
    /* --------------------------------------------------------------------- */
    interrupt_done( );

    /* --------------------------------------------------------------------- */
    /*  exit interrupt                                                       */
    /* --------------------------------------------------------------------- */
    exit_interrupt( );
}



その他にキーボードの割り込みは 割り込みその2割り込みその3

見てきましたように、PICの設定と、IDTの設定を行う必要があります

PICの設定

PICの設定は割り込みその3 で作りましたinitPIC関数にIRQ1のマスクを解除するように変更します


/*
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Funtion     :initPIC
    Input       :void
    Output      :void
    Return      :void

    Description :initialize pics
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
void initPIC( void )
{
    /* PIC 初期化関数続き	*/
    /* --------------------------------------------------------------------- */
    /* 	send IMR ot PIC                                                      */
    /* --------------------------------------------------------------------- */
    outPortByte( PORT_MASTER_PIC_IMR, ( ~PIC_IMR_MASK_IRQ0 )
                 & ( ~PIC_IMR_MASK_IRQ1 ) & ( ~PIC_IMR_MASK_IRQ2 ) );
    outPortByte( PORT_SLAVE_PIC_IMR, PIC_IMR_MASK_IRQ_ALL          );
}



キーボードのIDTを設定する

キーボードのIDTを設定し、割り込みベクタに登録します。

IDTの登録には割り込みその1 で作りましたsetupInterruptGate関数を使用します

また、割り込みその3の IRQの割り込みベクタ一覧を見てきましたようにIRQ1は

割り込みベクタ番号33でしたので



IDTの設定するソースで次の関数呼び出し処理を追加しておきます


#define DEF_IDT_INT_NUM_IRQ1 33

setupInterruptGate( DEF_IDT_INT_NUM_IRQ1, keyboard_interrupt );



これで、ユーザ入力ができるようになりました!

ここまでで、簡単な画面の表示とユーザ入力ができるようになりました

次はフロッピーディスクからファイルを読み込む処理を作っていきます

inserted by FC2 system