跟我一起写操作系统

    返回首页    发表留言
本文作者:李德强
          第二节 键盘中断
 
 

        键盘中断也是一个非常重要的硬中断。当键盘中的一个按钮被按下或抬起时,将通过8359A芯片向CPU发送一个键盘中断的消息,这时CPU将转入键盘中断处理程序。键盘上的每个按键都对应一个扫描码,当有键盘中断时,这个扫描码被送入0x60端口。CPU通过读取0x60端口中的扫描码就可以得知是键盘中的哪个键盘被按下或抬起了。按键盘的扫描码的大小顺序定义的按键如下:

#define KEY_ESC                        0X01        // ESC
#define KEY_1                          0X02        // 1
#define KEY_2                          0X03        // 2
#define KEY_3                          0X04        // 3
#define KEY_4                          0X05        // 4
#define KEY_5                          0X06        // 5
#define KEY_6                          0X07        // 6
#define KEY_7                          0X08        // 7
#define KEY_8                          0X09        // 8
#define KEY_9                          0X0A        // 9
#define KEY_0                          0X0B        // 0
#define KEY_DASH                       0X0C        // -
#define KEY_EQUAL                      0X0D        // =
#define KEY_BACKSPACE                  0X0E        // BACKSPACE
#define KEY_TAB                        0X0F        // TAB
#define KEY_Q                          0X10        // Q
#define KEY_W                          0X11        // W
#define KEY_E                          0X12        // E
#define KEY_R                          0X13        // R
#define KEY_T                          0X14        // T
#define KEY_Y                          0X15        // Y
#define KEY_U                          0X16        // U
#define KEY_I                          0X17        // I
#define KEY_O                          0X18        // O
#define KEY_P                          0X19        // P
#define KEY_LBRACKET                   0X1A        // [
#define KEY_RBRACKET                   0X1B        // ]
#define KEY_ENTER                      0X1C        // ENTER
#define KEY_CTRL                       0X1D        // CTRL
#define KEY_A                          0X1E        // A
#define KEY_S                          0X1F        // S
#define KEY_D                          0X20        // D
#define KEY_F                          0X21        // F
#define KEY_G                          0X22        // G
#define KEY_H                          0X23        // H
#define KEY_J                          0X24        // J
#define KEY_K                          0X25        // K
#define KEY_L                          0X26        // L
#define KEY_SEMICOLON                  0X27        // ;
#define KEY_RQUOTE                     0X28        // '
#define KEY_LQUOTE                     0X29        // `
#define KEY_LEFT_SHIFT                 0X2A        // LEFT SHIFT
#define KEY_BACKSLASH                  0X2B        // '\'
#define KEY_Z                          0X2C        // Z
#define KEY_X                          0X2D        // X
#define KEY_C                          0X2E        // C
#define KEY_V                          0X2F        // V
#define KEY_B                          0X30        // B
#define KEY_N                          0X31        // N
#define KEY_M                          0X32        // M
#define KEY_COMMA                      0X33        // ,
#define KEY_PERIOD                     0X34        // .
#define KEY_SLASH                      0X35        // /
#define KEY_RIGHT_SHIFT                0X36        // RIGHT SHIFT
#define KEY_PRTSC                      0X37        // PRINT SCREEN
#define KEY_ALT                        0X38        // ALT
#define KEY_SPACE                      0X39        // SPACE
#define KEY_CAPS_LOCK                  0X3A        // CAPS LOCK
#define KEY_F1                         0X3B        // F1
#define KEY_F2                         0X3C        // F2
#define KEY_F3                         0X3D        // F3
#define KEY_F4                         0X3E        // F4
#define KEY_F5                         0X3F        // F5
#define KEY_F6                         0X40        // F6
#define KEY_F7                         0X41        // F7
#define KEY_F8                         0X42        // F8
#define KEY_F9                         0X43        // F9
#define KEY_F10                        0X44        // F10
#define KEY_NUM_LOCK                   0X45        // NUM LOCK
#define KEY_SCROLL_LOCK                0X46        // SCROLL LOCK
#define KEY_HOME                       0X47        // HOME
#define KEY_UP                         0X48        // UP
#define KEY_PAGE_UP                    0X49        // PAGE UP
#define KEY_SUB                        0X4A        // SUB
#define KEY_LEFT                       0X4B        // LEFT
#define KEY_CENTER                     0X4C        // CENTER
#define KEY_RIGHT                      0X4D        // RIGHT
#define KEY_ADD                        0X4E        // ADD
#define KEY_END                        0X4F        // END
#define KEY_DOWN                       0X50        // DOWN
#define KEY_PAGE_DOWN                  0X51        // PAGE DOWN
#define KEY_INSERT                     0X52        // INSERT
#define KEY_DEL                        0X53        // DEL

      另外,当一个键被按下时,我们希望在显示器上显示出这个字符,所以还要定义可显字符与扫描码的对应关系。比如当CPU得到一个扫描码为0x1e的按键,可以通过这个对应关系找到这个按键为字符'a',于是调用putchar函数在显示器上显示'a'。这个对应关系被定义为一个二维的字符数组,这个字符数组的行下标为扫描码,列下标为当shift按键按下时的下标。如下:

u8 keys[0x53][2] =
{
        { 0x0, 0x0 },        // ESC
        { '1', '!' },        // 1
        { '2', '@' },        // 2
        { '3', '#' },        // 3
        { '4', '$' },        // 4
        { '5', '%' },        // 5
        { '6', '^' },        // 6
        { '7', '&' },        // 7
        { '8', '*' },        // 8
        { '9', '(' },        // 9
        { '0', ')' },        // 0
        { '-', '_' },        // -
        { '=', '+' },        // =
        { 0x0, 0x0 },        // BACKSPACE
        { 0x0, 0x0 },        // TAB
        { 'q', 'Q' },        // Q
        { 'w', 'W' },        // W
        { 'e', 'E' },        // E
        { 'r', 'R' },        // R
        { 't', 'T' },        // T
        { 'y', 'Y' },        // Y
        { 'u', 'U' },        // U
        { 'i', 'I' },        // I
        { 'o', 'O' },        // O
        { 'p', 'P' },        // P
        { '[', '{' },        // [
        { ']', '}' },        // ]
        { '\n', 0x0 },       // ENTER
        { 0x0, 0x0 },        // CTRL
        { 'a', 'A' },        // A
        { 's', 'S' },        // S
        { 'd', 'D' },        // D
        { 'f', 'F' },        // F
        { 'g', 'G' },        // G
        { 'h', 'H' },        // H
        { 'j', 'J' },        // J
        { 'k', 'K' },        // K
        { 'l', 'L' },        // L
        { ';', ':' },        // ;
        { '\'', '"' },       // '
        { '`', '~' },        // `
        { 0x0, 0x0 },        // LEFTSHIFT
        { '\\', '|' },       // '\'
        { 'a', 'Z' },        // Z
        { 'x', 'X' },        // X
        { 'c', 'C' },        // C
        { 'v', 'V' },        // V
        { 'b', 'B' },        // B
        { 'n', 'N' },        // N
        { 'm', 'M' },        // M
        { ',', '<' },        // ,
        { '.', '>' },        // .
        { '/', '?' },        // /
        { 0x0, 0x0 },        // RIGHTSHIFT
        { 0x0, 0x0 },        // PRINTSCREEN
        { 0x0, 0x0 },        // ALT
        { 0x0, 0x0 },        // SPACE
        { 0x0, 0x0 },        // CAPSLOCK
        { 0x0, 0x0 },        // F1
        { 0x0, 0x0 },        // F2
        { 0x0, 0x0 },        // F3
        { 0x0, 0x0 },        // F4
        { 0x0, 0x0 },        // F5
        { 0x0, 0x0 },        // F6
        { 0x0, 0x0 },        // F7
        { 0x0, 0x0 },        // F8
        { 0x0, 0x0 },        // F9
        { 0x0, 0x0 },        // F10
        { 0x0, 0x0 },        // NUMLOCK
        { 0x0, 0x0 },        // SCROLLLOCK
        { 0x0, 0x0 },        // HOME
        { 0x0, 0x0 },        // UP
        { 0x0, 0x0 },        // PAGEUP
        { 0x0, 0x0 },        // SUB
        { 0x0, 0x0 },        // LEFT
        { 0x0, 0x0 },        // CENTER
        { 0x0, 0x0 },        // RIGHT
        { 0x0, 0x0 },        // ADD
        { 0x0, 0x0 },        // END
        { 0x0, 0x0 },        // DOWN
        { 0x0, 0x0 },        // PAGEDOWN
        { 0x0, 0x0 },        // INSERT
        { 0x0, 0x0 }         // DEL
};

        可以看到可显字符只有0-9、a-z、A-Z以及一些符号,其中很多功能按键并不是可显字符,也就是说这些如Esc、Home、Left、ScrollLock、PrintScreen等这些按键并不是ascii中可显字符中的有效值。但是为了能够让可显字符的扫描码方便的作为keys行下标而使用,这里也保留了这些非可显字符的按键。接下来就可以使用这个扫描码了,通过打开8259A中断控制器的IRQ1脚来打开键盘中断:

//打开IRQ1的键盘中断
outb_p(inb_p(0x21) & 0xfd, 0x21);

        另外,键盘存放按键扫描码的端口为0x60,还有一个键盘按键控制端口0x61,向它写入相应的控制字节,此字节每一位格式如下:

  • 0:定时器扬声器
  • 1:扬声器数据
  • 2:奇偶校验
  • 3:通道检查
  • 4-6:保留
  • 7:IRQ复位

        对于0-6暂时不去管它们,只需要将IRQ复位即可。如果IRQ不复位,键盘中断只会被8259A响应一次,之后就不再触发键盘中断了。

//清除键盘状态可以接受新按键
outb_p(0x7f, 0x61);

        在int.S中处理键盘服务程序,调用int_keyborad函数来处理键盘按键:

//键盘中断
_int_0x21:
        cli
        pushal
        pushfl
        //调用键盘中断处理函数
        call int_keyboard
        popfl
        popal
        sti
        iret

        在int_keyborad函数中处理按下键盘的一个键时显示这个键所对应的字符:

/*
 * int_keyboard : 键盘中断
 * return : void
 */
void int_keyboard()
{
        //取得扫描码
        u8 scan_code = inb_p(0x60);
        //取得按下、抬起状态
        u8 status = scan_code >> 7;
        //扫描码的索引
        u8 key_ind = scan_code & 0x7f;
        //shift按下
        if ((key_ind == KEY_LEFT_SHIFT || key_ind == KEY_RIGHT_SHIFT) && status == 0)
        {
                kb_key_shift = 0x1;
        }
        //shift抬起
        else if ((key_ind == KEY_LEFT_SHIFT || key_ind == KEY_RIGHT_SHIFT) && status == 1)
        {
                kb_key_shift = 0x0;
        }
        else if (status == 0)
        {
                //显示字符
                putchar(keys[key_ind - 1][kb_key_shift]);
        }
        //清除键盘状态可以接受新按键
        outb_p(scan_code & 0x7f, 0x61);
        //通知PIC1可以接受新中断
        outb_p(0x20, 0x20);
}

         最后在start_kernel中加入安装键盘中断:

//安装键盘中断
install_kb();

        在Makefile中加入key.c的编译代码,编译并运行结果:



        运行结果中显示了一个叫作main的C语言主函数,千万不要被它吓到。这只是通过键盘输入在显示器上显示的一些字符罢了,并不是什么C的源代码和编译器。不过这已经说明我们的键盘中断已经可以正常工作了。

 

        源代码的下载地址为:

https           https://github.com/magicworldos/lidqos.git 
git             git@github.com:magicworldos/lidqos.git 
subverion       https://github.com/magicworldos/lidqos 
branch          v0.13

 

    返回首页    返回顶部
  看不清?点击刷新

 

  Copyright © 2015-2018 问渠网 辽ICP备15013245号