CPU如何读取键盘传过来的数据--OS

键盘

键盘是如何与操作系统交互的?

在显示器那一节,我们说过,CPU使用外设就是向外设写入一条指令,然后中断处理,中断处理就在键盘这一篇里,我们每按下一次键盘,就相当与向CPU发起一次中断

我们从键盘中断开始,看一下键盘中断的初始化

void con_init(void)
{
    set_trap_gate(0x21, &keyboard_interrupt);
}
//在kernel/chr_drv/keyboard.s中
.global _keyboard_interrupt
_keyboard_interrupt:
    inb $0x60, %al  
    //从端口0x60读扫描码,inb表示读入一个字节,扫描码(每一个按键对应一个码)
    call key_table(,%eax,4) //调用keyboard+eax*4,根据不同的按键调用不同的函数
    ...
    push $0
    call _do_tty_interrupt 

处理扫描码key_table+eax*4

key_table是一个函数数组

在kernel/chr_drv/keyboard.s中
key_table:
    .long none,do_self,so_self,do_self  //扫描码00-03
    .long do_self,...,func,scroll,cursor 等

mode: .byte 0
do_self:
    lea alt_map, %ebx
    testb $0x20, mode //alt键是否同时按下   jne 1f
    lea shift_map, %ebx testb $0x03, mode  jne 1f
    lea key_map, %ebx
1:

从key_map中取出ASCLL码

#if defined(KBD_US)
key_mpa: .byte 0, 27 .ascll "1234567890-=" ...
shift_map: .byte 0, 27 .ascll "!@#$%^&*()_+" ...
#elif defined(KBD_GR) ...

回到do_self函数,从1f开始,ebx存放的是map的起始地址

1:  movb (%ebx,%eax), %al  //扫描码索引,ASCLL码->al
    orb %al, %al    je none //找不到对应的ASCLL码
    testb $0x4c, mode //看caps是否亮
    je 2f   capb $'a,%al    jb 2f
    cmpb $'}, %al   ja 2f   subb $32, %al //变大写
2:  testb %??, mode //处理其他模式,如ctr1同时按下
3:  andl $0xff, %eax call_put_queue
none:ret

do_self函数得到ASCLL码后就要把它放入缓冲队列中,等待CPU读取

put_queue:
    movl _table_list, %edx  //得到队列
    movl head(%edx), %ecx  //取出队列头部位置
1:  movb %al,buf(%edx,%ecx) //将键盘输入的ASCLL码放入队列的头部

struct tty_queue *table_list[]={
    &tty_table[0].read_q,
    &tty_table[0].write_q;
    ...
};

上面已经成功将ASCLL码放入队列中,接下只要等待CPU读取并处理就可以了,但是还还要实现回显

回显:将键盘输入的显示到屏幕上,其实就是上节的内容,只要将输入的字符放入write_q队列中,就可以了

void do_tty_interrupt(int tty)
{copy_to_cooked(tty_table+tty);}
void copy_to_cooked(struct tty_struct *tty)
{
    GETCH(tty->read_q,c);
    if(L_ECHO(tty))
    {
        PUTCH(c,tty->write_q);
        tty->write(tty);
    }
    PUTCH(c,tty->secondary);
    ...
    wake_up(&tty->secondary.proc_list);
}

我们重新回顾一下操作系统是如何让CPU使用外设的

CPU如何读取键盘传过来的数据--OS_第1张图片
可以看到,这实际上就是一个文件系统,用文件系统形成统一接口,让外设工作起来。

可以看一下配套的实验按下F12使输出全部变成*号

你可能感兴趣的:(操作系统)