osdev-jpでは、OS開発に有用な情報を収集し公開しています

View My GitHub Profile

Receive data

このページでは USB キーボードからキー入力を受け取る方法を説明する.

Receive a key code

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 にある.

Convert a key code to ASCII code

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 キーボードから入力する手順の説明は完了. サンプルのソースコードは疑似コードであり,しかもほとんど構造化されていないので,そのあたりの改良は読者の課題とする.