osdev-jpでは、OS開発に有用な情報を収集し公開しています
このページでは USB キーボードからキー入力を受け取る方法を説明する.
USB キーボードが Configured 状態になれば,いよいよキー入力を行うことができる. そのためには Interrupt In な Endpoint に対して Normal TRB を発行するだけだ.
struct NormalTRB normal;
normal.data_buffer_pointer = (uint64_t)buf;
normal.trb_transfer_length = 8;
normal.interrupt_on_completion = 1;
ring_push(&tr_ep_key_in, &normal);
DOORBELL[assigned_slot_id] = ep_key_in_dci;
while (er_front(0)->cycle_bit != er_cycle_bit);
while (er_front(0)->cycle_bit == er_cycle_bit) er_pop(0);
for (size_t i = 2; i < 8; ++i)
{
if (buf[i] == 0) continue;
char ascii = keycode_map[buf[i]];
if (ascii)
{
putchar(ascii);
}
}
Normal TRB で Interrupt On Completion を 1 にしておくと,TRB Transfer Length に設定したバイト数以上のデータを受信した際にイベントが通知される. 設定値より少ないバイト数しか受信できなかった場合は Short Packet という扱いになり,Interrupt On Completion イベントは発生しない.
HID Spec B.1 Protocol 1 (Keyboard) によれば,USB キーボード(Boot Interface のもの)から受信したデータの構造は次の通り.
オフセット | 内容 |
---|---|
0 | モディファイアキー |
1 | Reserved |
2 | キーコード 1 |
7 | キーコード 6 |
上記のサンプルプログラムでは,とりあえずモディファイアキーを無視して文字を表示するようにした. モディファイアキーのビットマップは HID Spec 8.3 Report Format for Array Items にある.
keycode_map
はキーコードから ASCII コードへの変換辞書である.
定義は HID Usage Tables 10 Keyboard/Keypad Page (0x07) に載っている.
const char keycode_map[256] = {
0, 0, 0, 0, 'a', 'b', 'c', 'd', // 0
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', // 8
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', // 16
'u', 'v', 'w', 'x', 'y', 'z', '1', '2', // 24
'3', '4', '5', '6', '7', '8', '9', '0', // 32
'\n', '\b', 0x08, '\t', ' ', '-', '=', '[', // 40
']', '\\', '#', ';', '\'', '`', ',', '.', // 48
'/', 0, 0, 0, 0, 0, 0, 0, // 56
0, 0, 0, 0, 0, 0, 0, 0, // 64
0, 0, 0, 0, 0, 0, 0, 0, // 72
0, 0, 0, 0, '/', '*', '-', '+', // 80
'\n', '1', '2', '3', '4', '5', '6', '7', // 88
'8', '9', '0', '.', '\\', 0, 0, '=', // 96
};
以上で USB キーボードから入力する手順の説明は完了. サンプルのソースコードは疑似コードであり,しかもほとんど構造化されていないので,そのあたりの改良は読者の課題とする.