kernel源码(十七)字符设备-keyboard.S

0 键盘扫描码

当我们按下键盘的时候,键盘上的微控制器产生一个键盘扫描码传送给计算机,计算机把这个键盘扫描码传唤为ASCII字符。

下图为AT键盘的扫描码对照表

 键盘工作的大概过程:当用户在键盘上键入一个字符时,会引起键盘中断,此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后会将键盘扫描码翻译为对应的字符,放入tty读队列read_q中。然后调用中断处理的C函数do_tty_interrupt(),它又直接调用行规则函数copy_to_cooked()对该字符进行过滤处理,并放入tty辅助队列secondary中,同时把该字符放入tty写队列write_q中,并调用写控制台函数con_write()。如果设置了控制台回显属性,则该字符会显式到屏幕上。教材中代码介绍之前的原理描述部分讲解的不错,可以多看看。

这个文件代码比较多,但是相对来说代码没有那么复杂。我们阅读的时候,抓住一些关键代码就可以了,可以不必去深究每一行代码。比较重要的地方(后面随着理解的深入会慢慢补充):

  1. 键盘硬件中断过程涉及到三个队列:读缓冲队列read_q(键盘录入的内容)、辅助缓冲队列secondary(经过加工的内容)、写缓冲队列write_q
  2. 键盘处理程序的入口:_keyboard_interrupt
  3. 当键盘按下时,中断控制器8259A会向CPU的INTR引脚发送1号中断IRQ1,接着CPU做必要的现场保护,然后从0x60地址(0x60端口)处读取键盘扫描码
  4. 根据键盘扫描码的值,去key_table[]数组相应位置处执行相应按键处理子程序,对于常规按键,这个按键处理子程序就是_do_self
  5. _do_self中调用put_queue,把扫描码对应的字符放到读缓冲队列read_q中

00 tty tty0 tty1-6 console

在Linux 系统中,计算机显示器通常被称为控制台终端(Console)。它仿真了类型为Linux的一种终端(TERM=Linux),并且有一些设备特殊文件与之相关联:tty0、tty1、tty2 等。

当你在控制台上登录时,使用的是tty1,注意这里是控制台登陆,非远程ssh登陆,远程ssh登陆对应的终端设备名为/dev/pts/0

使用Alt+[F1—F6]组合键时,我们就可以切换到tty1-tty6上面去。tty1–tty6等称为虚拟终端。

而tty0则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上(这时也叫控制台终端)。也就是说当我们使用ALT+Fn切换到特定虚拟终端上面去后,当前在哪个tty(比如tty3)上,tty0就是tty3的别名。

当我们使用ALT+F3切换到tty3时,控制台终端就是tty3,系统信息会打印到tty3上(系统信息其实会打印到显示器上,而显示器其实就是控制台,也就是/dev/console,又因为tty0是当前虚拟终端的一个别名,因此这里/dev/tty0、/dev/tty3、/dev/console是一样的)

 1 keyboard.S

源码

/*
 *  linux/kernel/keyboard.S
 *
 *  (C) 1991  Linus Torvalds
 */

/*
 *    Thanks to Alfred Leung for US keyboard patches
 *        Wolfgang Thiel for German keyboard patches
 *        Marc Corsini for the French keyboard
 */

#include <linux/config.h>

.text
.globl _keyboard_interrupt

/*
 * these are for the keyboard read functions
 */
size    = 1024        /* must be a power of two ! And MUST be the same
               as in tty_io.c !!!! */
head = 4
tail = 8
proc_list = 12
buf = 16

mode:    .byte 0        /* caps, alt, ctrl and shift mode */
leds:    .byte 2        /* num-lock, caps, scroll-lock mode (nom-lock on) */
e0:    .byte 0

/*
 *  con_int is the real interrupt routine that reads the
 *  keyboard scan-code and converts it into the appropriate
 *  ascii character(s).
 */
_keyboard_interrupt:
    pushl %eax
    pushl %ebx
    pushl %ecx
    pushl %edx
    push %ds
    push %es
    movl $0x10,%eax
    mov %ax,%ds
    mov %ax,%es
    xorl %al,%al        /* %eax is scan code */
    inb $0x60,%al
    cmpb $0xe0,%al
    je set_e0
    cmpb $0xe1,%al
    je set_e1
    call key_table(,%eax,4)
    movb $0,e0
e0_e1:    inb $0x61,%al
    jmp 1f
1:    jmp 1f
1:    orb $0x80,%al
    jmp 1f
1:    jmp 1f
1:    outb %al,$0x61
    jmp 1f
1:    jmp 1f
1:    andb $0x7F,%al
    outb %al,$0x61
    movb $0x20,%al
    outb %al,$0x20
    pushl $0
    call _do_tty_interrupt
    addl $4,%esp
    pop %es
    pop %ds
    popl %edx
    popl %ecx
    popl %ebx
    popl %eax
    iret
set_e0:    movb $1,e0
    jmp e0_e1
set_e1:    movb $2,e0
    jmp e0_e1

/*
 * This routine fills the buffer with max 8 bytes, taken from
 * %ebx:%eax. (%edx is high). The bytes are written in the
 * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
 */
put_queue:
    pushl %ecx
    pushl %edx
    movl _table_list,%edx        # read-queue for console
    movl head(%edx),%ecx
1:    movb %al,buf(%edx,%ecx)
    incl %ecx
    andl $size-1,%ecx
    cmpl tail(%edx),%ecx        # buffer full - discard everything
    je 3f
    shrdl $8,%ebx,%eax
    je 2f
    shrl $8,%ebx
    jmp 1b
2:    movl %ecx,head(%edx)
    movl proc_list(%edx),%ecx
    testl %ecx,%ecx
    je 3f
    movl $0,(%ecx)
3:    popl %edx
    popl %ecx
    ret

ctrl:    movb $0x04,%al
    jmp 1f
alt:    movb $0x10,%al
1:    cmpb $0,e0
    je 2f
    addb %al,%al
2:    orb %al,mode
    ret
unctrl:    movb $0x04,%al
    jmp 1f
unalt:    movb $0x10,%al
1:    cmpb $0,e0
    je 2f
    addb %al,%al
2:    notb %al
    andb %al,mode
    ret

lshift:
    orb $0x01,mode
    ret
unlshift:
    andb $0xfe,mode
    ret
rshift:
    orb $0x02,mode
    ret
unrshift:
    andb $0xfd,mode
    ret

caps:    testb $0x80,mode
    jne 1f
    xorb $4,leds
    xorb $0x40,mode
    orb $0x80,mode
set_leds:
    call kb_wait
    movb $0xed,%al        /* set leds command */
    outb %al,$0x60
    call kb_wait
    movb leds,%al
    outb %al,$0x60
    ret
uncaps:    andb $0x7f,mode
    ret
scroll:
    xorb $1,leds
    jmp set_leds
num:    xorb $2,leds
    jmp set_leds

/*
 *  curosr-key/numeric keypad cursor keys are handled here.
 *  checking for numeric keypad etc.
 */
cursor:
    subb $0x47,%al
    jb 1f
    cmpb $12,%al
    ja 1f
    jne cur2        /* check for ctrl-alt-del */
    testb $0x0c,mode
    je cur2
    testb $0x30,mode
    jne reboot
cur2:    cmpb $0x01,e0        /* e0 forces cursor movement */
    je cur
    testb $0x02,leds    /* not num-lock forces cursor */
    je cur
    testb $0x03,mode    /* shift forces cursor */
    jne cur
    xorl %ebx,%ebx
    movb num_table(%eax),%al
    jmp put_queue
1:    ret

cur:    movb cur_table(%eax),%al
    cmpb $'9,%al
    ja ok_cur
    movb $'~,%ah
ok_cur:    shll $16,%eax
    movw $0x5b1b,%ax
    xorl %ebx,%ebx
    jmp put_queue

#if defined(KBD_FR)
num_table:
    .ascii "789 456 1230."
#else
num_table:
    .ascii "789 456 1230,"
#endif
cur_table:
    .ascii "HA5 DGC YB623"

/*
 * this routine handles function keys
 */
func:
    pushl %eax
    pushl %ecx
    pushl %edx
    call _show_stat
    popl %edx
    popl %ecx
    popl %eax
    subb $0x3B,%al
    jb end_func
    cmpb $9,%al
    jbe ok_func
    subb $18,%al
    cmpb $10,%al
    jb end_func
    cmpb $11,%al
    ja end_func
ok_func:
    cmpl $4,%ecx        /* check that there is enough room */
    jl end_func
    movl func_table(,%eax,4),%eax
    xorl %ebx,%ebx
    jmp put_queue
end_func:
    ret

/*
 * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
 */
func_table:
    .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
    .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
    .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b

#if    defined(KBD_FINNISH)
key_map:
    .byte 0,27
    .ascii "1234567890+'"
    .byte 127,9
    .ascii "qwertyuiop}"
    .byte 0,13,0
    .ascii "asdfghjkl|{"
    .byte 0,0
    .ascii "'zxcvbnm,.-"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0

shift_map:
    .byte 0,27
    .ascii "!\"#$%&/()=?`"
    .byte 127,9
    .ascii "QWERTYUIOP]^"
    .byte 13,0
    .ascii "ASDFGHJKL\\["
    .byte 0,0
    .ascii "*ZXCVBNM;:_"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

#elif defined(KBD_US)

key_map:
    .byte 0,27
    .ascii "1234567890-="
    .byte 127,9
    .ascii "qwertyuiop[]"
    .byte 13,0
    .ascii "asdfghjkl;'"
    .byte '`,0
    .ascii "\\zxcvbnm,./"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0


shift_map:
    .byte 0,27
    .ascii "!@#$%^&*()_+"
    .byte 127,9
    .ascii "QWERTYUIOP{}"
    .byte 13,0
    .ascii "ASDFGHJKL:\""
    .byte '~,0
    .ascii "|ZXCVBNM<>?"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

#elif defined(KBD_GR)

key_map:
    .byte 0,27
    .ascii "1234567890\\'"
    .byte 127,9
    .ascii "qwertzuiop@+"
    .byte 13,0
    .ascii "asdfghjkl[]^"
    .byte 0,'#
    .ascii "yxcvbnm,.-"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0


shift_map:
    .byte 0,27
    .ascii "!\"#$%&/()=?`"
    .byte 127,9
    .ascii "QWERTZUIOP\\*"
    .byte 13,0
    .ascii "ASDFGHJKL{}~"
    .byte 0,''
    .ascii "YXCVBNM;:_"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte '@,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0


#elif defined(KBD_FR)

key_map:
    .byte 0,27
    .ascii "&{\"'(-}_/@)="
    .byte 127,9
    .ascii "azertyuiop^$"
    .byte 13,0
    .ascii "qsdfghjklm|"
    .byte '`,0,42        /* coin sup gauche, don't know, [*|mu] */
    .ascii "wxcvbn,;:!"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0

shift_map:
    .byte 0,27
    .ascii "1234567890]+"
    .byte 127,9
    .ascii "AZERTYUIOP<>"
    .byte 13,0
    .ascii "QSDFGHJKLM%"
    .byte '~,0,'#
    .ascii "WXCVBN?./\\"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0~#{[|`\\^@]}"
    .byte 0,0
    .byte '@,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

#else
#error "KBD-type not defined"
#endif
/*
 * do_self handles "normal" keys, ie keys that don't change meaning
 * and which have just one character returns.
 */
do_self:
    lea alt_map,%ebx
    testb $0x20,mode        /* alt-gr */
    jne 1f
    lea shift_map,%ebx
    testb $0x03,mode
    jne 1f
    lea key_map,%ebx
1:    movb (%ebx,%eax),%al
    orb %al,%al
    je none
    testb $0x4c,mode        /* ctrl or caps */
    je 2f
    cmpb $'a,%al
    jb 2f
    cmpb $'},%al
    ja 2f
    subb $32,%al
2:    testb $0x0c,mode        /* ctrl */
    je 3f
    cmpb $64,%al
    jb 3f
    cmpb $64+32,%al
    jae 3f
    subb $64,%al
3:    testb $0x10,mode        /* left alt */
    je 4f
    orb $0x80,%al
4:    andl $0xff,%eax
    xorl %ebx,%ebx
    call put_queue
none:    ret

/*
 * minus has a routine of it's own, as a 'E0h' before
 * the scan code for minus means that the numeric keypad
 * slash was pushed.
 */
minus:    cmpb $1,e0
    jne do_self
    movl $'/,%eax
    xorl %ebx,%ebx
    jmp put_queue

/*
 * This table decides which routine to call when a scan-code has been
 * gotten. Most routines just call do_self, or none, depending if
 * they are make or break.
 */
key_table:
    .long none,do_self,do_self,do_self    /* 00-03 s0 esc 1 2 */
    .long do_self,do_self,do_self,do_self    /* 04-07 3 4 5 6 */
    .long do_self,do_self,do_self,do_self    /* 08-0B 7 8 9 0 */
    .long do_self,do_self,do_self,do_self    /* 0C-0F + ' bs tab */
    .long do_self,do_self,do_self,do_self    /* 10-13 q w e r */
    .long do_self,do_self,do_self,do_self    /* 14-17 t y u i */
    .long do_self,do_self,do_self,do_self    /* 18-1B o p } ^ */
    .long do_self,ctrl,do_self,do_self    /* 1C-1F enter ctrl a s */
    .long do_self,do_self,do_self,do_self    /* 20-23 d f g h */
    .long do_self,do_self,do_self,do_self    /* 24-27 j k l | */
    .long do_self,do_self,lshift,do_self    /* 28-2B { para lshift , */
    .long do_self,do_self,do_self,do_self    /* 2C-2F z x c v */
    .long do_self,do_self,do_self,do_self    /* 30-33 b n m , */
    .long do_self,minus,rshift,do_self    /* 34-37 . - rshift * */
    .long alt,do_self,caps,func        /* 38-3B alt sp caps f1 */
    .long func,func,func,func        /* 3C-3F f2 f3 f4 f5 */
    .long func,func,func,func        /* 40-43 f6 f7 f8 f9 */
    .long func,num,scroll,cursor        /* 44-47 f10 num scr home */
    .long cursor,cursor,do_self,cursor    /* 48-4B up pgup - left */
    .long cursor,cursor,do_self,cursor    /* 4C-4F n5 right + end */
    .long cursor,cursor,cursor,cursor    /* 50-53 dn pgdn ins del */
    .long none,none,do_self,func        /* 54-57 sysreq ? < f11 */
    .long func,none,none,none        /* 58-5B f12 ? ? ? */
    .long none,none,none,none        /* 5C-5F ? ? ? ? */
    .long none,none,none,none        /* 60-63 ? ? ? ? */
    .long none,none,none,none        /* 64-67 ? ? ? ? */
    .long none,none,none,none        /* 68-6B ? ? ? ? */
    .long none,none,none,none        /* 6C-6F ? ? ? ? */
    .long none,none,none,none        /* 70-73 ? ? ? ? */
    .long none,none,none,none        /* 74-77 ? ? ? ? */
    .long none,none,none,none        /* 78-7B ? ? ? ? */
    .long none,none,none,none        /* 7C-7F ? ? ? ? */
    .long none,none,none,none        /* 80-83 ? br br br */
    .long none,none,none,none        /* 84-87 br br br br */
    .long none,none,none,none        /* 88-8B br br br br */
    .long none,none,none,none        /* 8C-8F br br br br */
    .long none,none,none,none        /* 90-93 br br br br */
    .long none,none,none,none        /* 94-97 br br br br */
    .long none,none,none,none        /* 98-9B br br br br */
    .long none,unctrl,none,none        /* 9C-9F br unctrl br br */
    .long none,none,none,none        /* A0-A3 br br br br */
    .long none,none,none,none        /* A4-A7 br br br br */
    .long none,none,unlshift,none        /* A8-AB br br unlshift br */
    .long none,none,none,none        /* AC-AF br br br br */
    .long none,none,none,none        /* B0-B3 br br br br */
    .long none,none,unrshift,none        /* B4-B7 br br unrshift br */
    .long unalt,none,uncaps,none        /* B8-BB unalt br uncaps br */
    .long none,none,none,none        /* BC-BF br br br br */
    .long none,none,none,none        /* C0-C3 br br br br */
    .long none,none,none,none        /* C4-C7 br br br br */
    .long none,none,none,none        /* C8-CB br br br br */
    .long none,none,none,none        /* CC-CF br br br br */
    .long none,none,none,none        /* D0-D3 br br br br */
    .long none,none,none,none        /* D4-D7 br br br br */
    .long none,none,none,none        /* D8-DB br ? ? ? */
    .long none,none,none,none        /* DC-DF ? ? ? ? */
    .long none,none,none,none        /* E0-E3 e0 e1 ? ? */
    .long none,none,none,none        /* E4-E7 ? ? ? ? */
    .long none,none,none,none        /* E8-EB ? ? ? ? */
    .long none,none,none,none        /* EC-EF ? ? ? ? */
    .long none,none,none,none        /* F0-F3 ? ? ? ? */
    .long none,none,none,none        /* F4-F7 ? ? ? ? */
    .long none,none,none,none        /* F8-FB ? ? ? ? */
    .long none,none,none,none        /* FC-FF ? ? ? ? */

/*
 * kb_wait waits for the keyboard controller buffer to empty.
 * there is no timeout - if the buffer doesn't empty, we hang.
 */
kb_wait:
    pushl %eax
1:    inb $0x64,%al
    testb $0x02,%al
    jne 1b
    popl %eax
    ret
/*
 * This routine reboots the machine by asking the keyboard
 * controller to pulse the reset-line low.
 */
reboot:
    call kb_wait
    movw $0x1234,0x472    /* don't do memory check */
    movb $0xfc,%al        /* pulse reset and A20 low */
    outb %al,$0x64
die:    jmp die
View Code

 

size    = 1024 //键盘缓冲区大小       /* must be a power of two ! And MUST be the same
               as in tty_io.c !!!! */
head = 4 //下面4个是相对tty_queue的偏移量
tail = 8
proc_list = 12
buf = 16

其中,tty_queue是在include/linux/tty.h中定义的

struct tty_queue {
    unsigned long data;
    unsigned long head;
    unsigned long tail;
    struct task_struct * proc_list;
    char buf[TTY_BUF_SIZE];
};

 

mode:    .byte 0        //特殊按键是否按下 7-0位分别表示:[caps,caps的状态,右边alt,左边alt,右边ctrl,左边ctrl,右边shift,左边shift]
leds:    .byte 2        //指示灯的状态* num-lock, caps, scroll-lock mode (nom-lock on) */
e0:    .byte 0 //扫描码0xe0和0xe1的标志。通常,接收到0xe0表示后面还有一个字符,接收到0xe1表示后面还跟随两个字符

键盘中断处理程序的入口点

注意:IO端口0x60是和键盘控制器通信的端口。在内核中端口其实指的是内存中的某一个地址,0x60表示地址0x60位置,此位置存放从键盘控制器传输的键盘扫描码。

在asm.s中我们介绍了一些硬件中断的处理程序,这些硬件中断处理模式都是一样的,都是如下模式

_xxxx:
    pushl $_do_xxxx
    jmp no_error_code

都是先将xxxx中断处理程序do_xxxx压入堆栈,然后再跳转到no_error_code执行

但是在键盘中断入口程序处,则不是按照这个套路,阅读源码的时候可以注意一下这个地方。

_keyboard_interrupt:
    pushl %eax //下面6行是对寄存器入栈
    pushl %ebx
    pushl %ecx
    pushl %edx
    push %ds
    push %es
    movl $0x10,%eax //0x10=0001 0000,即RPL=0,TI=0,INDEX=2,即内核GDT表的第2项。是内核数据段的选择符
    mov %ax,%ds //数据段寄存器ds和附加段寄存器es设置为0x10.
    mov %ax,%es
    xorl %al,%al //异或指令。清空al,目的是为接收键盘扫描码做准备        /* %eax is scan code */
    inb $0x60,%al //从0x60读取扫描码到al当中
    cmpb $0xe0,%al //是否是0xe0。0xe0有特殊含义,见上面介绍
    je set_e0 //如果是,则跳转
    cmpb $0xe1,%al //是否是0xe1
    je set_e1 //如果是,则跳转
    call key_table(,%eax,4) //如果既不是0xe0也不是0xe1,则调用key_table,偏移量为eax*4的位置(long类型乘4)。其中key_table在本文件中定义
    movb $0,e0 //e0标志复位

//下面代码对
使用8255A芯片的标准键盘电路进行硬件的复位处理,先关闭键盘再开启键盘。注:8255A芯片可以百度一下。0x61是8255A输出端口B7-B0的地址
e0_e1:    inb $0x61,%al //从IO端口0x61读1个字节到al中
    jmp 1f //延迟两个指令周期
1:    jmp 1f
1:    orb $0x80,%al //al最高位置1,因为
    jmp 1f
1:    jmp 1f
1:    outb %al,$0x61 //向IO端口0x61写入a1(最高位已置位),禁止键盘工作
    jmp 1f //延迟两个指令周期
1:    jmp 1f
1:    andb $0x7F,%al //a1最高位又复位了
    outb %al,$0x61 //向IO端口0x61写入a1,重新开启键盘
    movb $0x20,%al 
    outb %al,$0x20 //向8259A芯片发送EOI信号(可先了解一下8259A工作机制)
    pushl $0 //这里的0是控制台的号tty0
    call _do_tty_interrupt //收到的数据转换为规范模式并且存放在规范字符的缓冲队列当中
    addl $4,%esp //因为调用_do_tty_interrupt之前往堆栈中压入了一个0,这里esp+4返回到原来esp的位置(堆栈是向下生长的)
    pop %es //弹出相应的寄存器
    pop %ds
    popl %edx
    popl %ecx
    popl %ebx
    popl %eax
    iret //iret为中断返回,为中断服务的最后一条指令
set_e0:    movb $1,e0 //e0第0位标志置位(e0是前面定义的)
    jmp e0_e1
set_e1:    movb $2,e0 //e0第1位标志置位
    jmp e0_e1

key_table的定义,是一个数组,数组中每一项是键盘扫描码的处理函数,比如说键盘扫描码为0x01,则处理函数是key_table[1]=do_self。do_self再将键盘扫描码转化为ASCII码放入字符缓存队列中。最终显示在屏幕上或流向其他tty中。

key_table:
    .long none,do_self,do_self,do_self    /* 00-03 s0 esc 1 2 */
    .long do_self,do_self,do_self,do_self    /* 04-07 3 4 5 6 */
    .long do_self,do_self,do_self,do_self    /* 08-0B 7 8 9 0 */
    .long do_self,do_self,do_self,do_self    /* 0C-0F + ' bs tab */
    .long do_self,do_self,do_self,do_self    /* 10-13 q w e r */
    .long do_self,do_self,do_self,do_self    /* 14-17 t y u i */
    .long do_self,do_self,do_self,do_self    /* 18-1B o p } ^ */
    .long do_self,ctrl,do_self,do_self    /* 1C-1F enter ctrl a s */
    .long do_self,do_self,do_self,do_self    /* 20-23 d f g h */
    .long do_self,do_self,do_self,do_self    /* 24-27 j k l | */
    .long do_self,do_self,lshift,do_self    /* 28-2B { para lshift , */
    .long do_self,do_self,do_self,do_self    /* 2C-2F z x c v */
    .long do_self,do_self,do_self,do_self    /* 30-33 b n m , */
    .long do_self,minus,rshift,do_self    /* 34-37 . - rshift * */
    .long alt,do_self,caps,func        /* 38-3B alt sp caps f1 */
    .long func,func,func,func        /* 3C-3F f2 f3 f4 f5 */
    .long func,func,func,func        /* 40-43 f6 f7 f8 f9 */
    .long func,num,scroll,cursor        /* 44-47 f10 num scr home */
    .long cursor,cursor,do_self,cursor    /* 48-4B up pgup - left */
    .long cursor,cursor,do_self,cursor    /* 4C-4F n5 right + end */
    .long cursor,cursor,cursor,cursor    /* 50-53 dn pgdn ins del */
    .long none,none,do_self,func        /* 54-57 sysreq ? < f11 */
    .long func,none,none,none        /* 58-5B f12 ? ? ? */
    .long none,none,none,none        /* 5C-5F ? ? ? ? */
    .long none,none,none,none        /* 60-63 ? ? ? ? */
    .long none,none,none,none        /* 64-67 ? ? ? ? */
    .long none,none,none,none        /* 68-6B ? ? ? ? */
    .long none,none,none,none        /* 6C-6F ? ? ? ? */
    .long none,none,none,none        /* 70-73 ? ? ? ? */
    .long none,none,none,none        /* 74-77 ? ? ? ? */
    .long none,none,none,none        /* 78-7B ? ? ? ? */
    .long none,none,none,none        /* 7C-7F ? ? ? ? */
    .long none,none,none,none        /* 80-83 ? br br br */
    .long none,none,none,none        /* 84-87 br br br br */
    .long none,none,none,none        /* 88-8B br br br br */
    .long none,none,none,none        /* 8C-8F br br br br */
    .long none,none,none,none        /* 90-93 br br br br */
    .long none,none,none,none        /* 94-97 br br br br */
    .long none,none,none,none        /* 98-9B br br br br */
    .long none,unctrl,none,none        /* 9C-9F br unctrl br br */
    .long none,none,none,none        /* A0-A3 br br br br */
    .long none,none,none,none        /* A4-A7 br br br br */
    .long none,none,unlshift,none        /* A8-AB br br unlshift br */
    .long none,none,none,none        /* AC-AF br br br br */
    .long none,none,none,none        /* B0-B3 br br br br */
    .long none,none,unrshift,none        /* B4-B7 br br unrshift br */
    .long unalt,none,uncaps,none        /* B8-BB unalt br uncaps br */
    .long none,none,none,none        /* BC-BF br br br br */
    .long none,none,none,none        /* C0-C3 br br br br */
    .long none,none,none,none        /* C4-C7 br br br br */
    .long none,none,none,none        /* C8-CB br br br br */
    .long none,none,none,none        /* CC-CF br br br br */
    .long none,none,none,none        /* D0-D3 br br br br */
    .long none,none,none,none        /* D4-D7 br br br br */
    .long none,none,none,none        /* D8-DB br ? ? ? */
    .long none,none,none,none        /* DC-DF ? ? ? ? */
    .long none,none,none,none        /* E0-E3 e0 e1 ? ? */
    .long none,none,none,none        /* E4-E7 ? ? ? ? */
    .long none,none,none,none        /* E8-EB ? ? ? ? */
    .long none,none,none,none        /* EC-EF ? ? ? ? */
    .long none,none,none,none        /* F0-F3 ? ? ? ? */
    .long none,none,none,none        /* F4-F7 ? ? ? ? */
    .long none,none,none,none        /* F8-FB ? ? ? ? */
    .long none,none,none,none        /* FC-FF ? ? ? ? */
View Code

 把字符放到缓冲队列当中

put_queue:
    pushl %ecx
    pushl %edx
    movl _table_list,%edx //从缓冲队列地址表_table_list取控制台的缓冲队列read_q的地址       # read-queue for console
    movl head(%edx),%ecx //head上面定义,为4。head+edx就是取队列read_q的头指针,放入ecx中
1:    movb %al,buf(%edx,%ecx) //把al当中的字符放入头指针的地方
    incl %ecx //头指针向前移动一个字节
    andl $size-1,%ecx //调整头指针
    cmpl tail(%edx),%ecx //缓冲区是否已经满了        # buffer full - discard everything
    je 3f //如果已经满了,则跳转到3处
    shrdl $8,%ebx,%eax //ebx当中的8个位右移到eax当中,ebx不变
    je 2f //如果没有数据了,则跳转到2处
    shrl $8,%ebx //否则,把ebx当中的值右移8位
    jmp 1b //跳转到1处循环执行,直到所有数据都读取完毕为止
2:    movl %ecx,head(%edx)
    movl proc_list(%edx),%ecx //队列的等待进程的指针放到ecx中
    testl %ecx,%ecx //检查是否有等待队列的进程
    je 3f //没有,跳转到3处
    movl $0,(%ecx) //如果有,则唤醒这个进程
3:    popl %edx
    popl %ecx
    ret

 根据ctrl、alt、shift、caps按键是否按下或松开来设置mode中各个比特位。以及设置指示灯

ctrl:    movb $0x04,%al //前面定义过mode,共8位,每位表示ctrl、alt等按键按下的标志。0x40=0000 0100表示左ctrl
    jmp 1f
alt:    movb $0x10,%al //0x10=0001 0000,表示左alt
1:    cmpb $0,e0 //检查e0有没有置位,也就是说按下的是否是右边的ctrl或者alt
    je 2f //如果不是,则跳转
    addb %al,%al //如果是,把相应的右键标志位置位。注:al中是左ctrl或者左alt,al+al等效于左移1位,正好对应mode中的右键标志位置位
2:    orb %al,mode //设置mode
    ret
unctrl:    movb $0x04,%al //处理ctrl松开时的扫描码。0x04=0000 0100表示左边ctrl
    jmp 1f 向前跳转到1处
unalt:    movb $0x10,%al //0x10=0001 0000表示左边alt
1:    cmpb $0,e0 //检查e0有没有置位
    je 2f //没有置位,则跳转到2处
    addb %al,%al //置位,则相应的右键标志位置位
2:    notb %al //al各位取反
    andb %al,mode //复位ctrl和alt标志位。
    ret

lshift:
    orb $0x01,mode //0x01=0000 0001,表示左shift按下时的扫描码。这里设置其对应的mode比特位
    ret
unlshift:
    andb $0xfe,mode //当shift松开时,复位mode对应的比特位
    ret
rshift:
    orb $0x02,mode //右shift对应比特位
    ret
unrshift:
    andb $0xfd,mode //复位mode中右shift对应的比特位
    ret

caps:    testb $0x80,mode //测试mode中的第7位是否被置位
    jne 1f //已经被置位则向前跳转到1位置处,1处是一个ret指令,直接返回了
    xorb $4,leds //否则,翻转leds中caps对应的位
    xorb $0x40,mode //设置mode中caps状态对应的比特位
    orb $0x80,mode //设置mode中caps对应的比特位
set_leds: //根据leds中的标志,开启或者关闭leds的指示灯
    call kb_wait //等待键盘缓冲器清空
    movb $0xed,%al //0xed=1110 1101       /* set leds command */
    outb %al,$0x60 把1110 1101 送到IO端口0x60中
    call kb_wait //再调用kb_wait
    movb leds,%al
    outb %al,$0x60 //把leds标志作为参数发送到IO端口0x60处
    ret
uncaps:    andb $0x7f,mode //caps键松开,复位mode中的相应位
    ret
scroll:
    xorb $1,leds //翻转leds中的第0位
    jmp set_leds //跳转到set_leds
num:    xorb $2,leds //翻转leds中第1位
    jmp set_leds //跳转到set_leds

判断小键盘是否按下(小键盘中的按键扫描码都是大于0x47的)设置mode中各个比特位。

cursor:
    subb $0x47,%al
    jb 1f //jb(jump below),如果al中的值小于0x47则跳转到1处,返回
    cmpb $12,%al //这里al是al-0x47的差值。如果大于12表示已经超出小键盘的扫描码的范围,直接返回
    ja 1f //超过则直接返回
    jne cur2 //下面5行判断是否按下ctrl+alt+delete。delete的键盘扫描码是0x53,0x53-0x47=12,如果正好是12说明按下delete按键。jne cur2意思是如果不是12则跳转       /* check for ctrl-alt-del */
    testb $0x0c,mode //是否是ctrl按键
    je cur2
    testb $0x30,mode //是否是alt按键
    jne reboot //如果ctrl+alt+delete按键,则跳转到reboot
cur2:    cmpb $0x01,e0 //比较e0第0位是否置位了       /* e0 forces cursor movement */
    je cur //如果置位了,则跳转到cur位置
    testb $0x02,leds //测试leds中nubLock标志是否置位了    /* not num-lock forces cursor */
    je cur //如果没有置位,则跳转到cur位置,处理光标移动
    testb $0x03,mode //测试mode当中的shift按键    /* shift forces cursor */
    jne cur //如果shift按键按下了,处理光标移动
    xorl %ebx,%ebx //异或清空ebx
    movb num_table(%eax),%al //查询小数字表取键的ASCII码,放入al中
    jmp put_queue //执行put_queue,把字符放到缓冲队列当中
1:    ret
//处理光标移动 
cur:    movb cur_table(%eax),%al //取光标字符表中eax处的字符放到al中。cur_table在下面定义
    cmpb $'9,%al //比较字符'9'和al,如果al<='9'说明是上一页或者下一页
    ja ok_cur //ja(jump above) 如果大于'9'则跳转到ok_cur
    movb $'~,%ah
ok_cur:    shll $16,%eax //ax左移16位。即之前ax放到eax的高16位上
    movw $0x5b1b,%ax //(0x5b1b对应的ascii码为'['和'ESC')。把0x5b1b放到eax低16位
    xorl %ebx,%ebx //ebx清零
    jmp put_queue //执行put_queue,把字符放到缓冲队列中

 

#if defined(KBD_FR)
num_table:
    .ascii "789 456 1230."
#else
num_table:
    .ascii "789 456 1230,"
#endif
cur_table:
    .ascii "HA5 DGC YB623"

把功能键的扫描码变换成转移字符序列,并且存放到读队列当中。

func:
    pushl %eax
    pushl %ecx
    pushl %edx
    call _show_stat //在schedule.c中定义的
    popl %edx
    popl %ecx
    popl %eax
    subb $0x3B,%al //扫描码0x3b对应的是F1,al当中是功能键的索引号。
    jb end_func //如果al小于F1则不处理了
    cmpb $9,%al //如果al-0x3b之后的值大于等于F1,则继续和9比较。这里的意思是判断按键是否是在F1-F10范围之内
    jbe ok_func //如果是在F1-F10之内,则跳转到ok_func
    subb $18,%al 否则,判断是否为F11
    cmpb $10,%al
    jb end_func //如果不是F11,则返回
    cmpb $11,%al //比较是否为F12
    ja end_func //如果不是则返回
ok_func: //执行到这说明是功能键F1-F12
    cmpl $4,%ecx  //检查空间是否够用      /* check that there is enough room */
    jl end_func //如果空间不够用则返回
    movl func_table(,%eax,4),%eax //取func_table的第eax项放到eax当中,func_table在下面定义
    xorl %ebx,%ebx //ebx清零
    jmp put_queue //把字符放到缓冲队列当中
end_func:
    ret

存放了F1-F12的键盘扫描码,共12个元素,分别表示F1-F12

比如:0x415b5b1b,1b对应的ascii码为ESC,5b对应的ascii码为[,41对应的ascii码为A。用他们的组合'esc [ [ A'表示功能键F1

/*
 * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
 */
func_table:
    .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
    .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
    .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b

芬兰语的键盘扫描码和ASCII码的映射表key_map

#if    defined(KBD_FINNISH) //芬兰语的键盘的扫描码映射表
key_map:
    .byte 0,27 //扫描码0x00对应ASCII码0,扫描码0x01对应ASCII码27
    .ascii "1234567890+'"//扫描码0x02-0x0D对应的ASCII码的字符为"1234567890+'"
    .byte 127,9 //扫描码0x0E对应ASCII码127,扫描码0x0F对应ASCII码为9
    .ascii "qwertyuiop}" //扫描码0x10-0x1A对应的ASCII码的字符
    .byte 0,13,0 //0x1B,0x1C,0x1D
    .ascii "asdfghjkl|{" //0x1E-0x28
    .byte 0,0 //0x29,0x2A
    .ascii "'zxcvbnm,.-" //0x2B-0x35
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0

shift_map: //按住shift后的映射表
    .byte 0,27
    .ascii "!\"#$%&/()=?`"
    .byte 127,9
    .ascii "QWERTYUIOP]^"
    .byte 13,0
    .ascii "ASDFGHJKL\\["
    .byte 0,0
    .ascii "*ZXCVBNM;:_"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map: //按住alt时的映射表
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

#elif defined(KBD_US)

美式键盘的键盘扫描码和ASCII码映射表

#elif defined(KBD_US)

key_map:
    .byte 0,27
    .ascii "1234567890-="
    .byte 127,9
    .ascii "qwertyuiop[]"
    .byte 13,0
    .ascii "asdfghjkl;'"
    .byte '`,0
    .ascii "\\zxcvbnm,./"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0


shift_map:
    .byte 0,27
    .ascii "!@#$%^&*()_+"
    .byte 127,9
    .ascii "QWERTYUIOP{}"
    .byte 13,0
    .ascii "ASDFGHJKL:\""
    .byte '~,0
    .ascii "|ZXCVBNM<>?"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

德国和法国键盘扫描码和ASCII码映射表

#elif defined(KBD_GR)

key_map:
    .byte 0,27
    .ascii "1234567890\\'"
    .byte 127,9
    .ascii "qwertzuiop@+"
    .byte 13,0
    .ascii "asdfghjkl[]^"
    .byte 0,'#
    .ascii "yxcvbnm,.-"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0


shift_map:
    .byte 0,27
    .ascii "!\"#$%&/()=?`"
    .byte 127,9
    .ascii "QWERTZUIOP\\*"
    .byte 13,0
    .ascii "ASDFGHJKL{}~"
    .byte 0,''
    .ascii "YXCVBNM;:_"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0@\0$\0\0{[]}\\\0"
    .byte 0,0
    .byte '@,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0


#elif defined(KBD_FR)

key_map:
    .byte 0,27
    .ascii "&{\"'(-}_/@)="
    .byte 127,9
    .ascii "azertyuiop^$"
    .byte 13,0
    .ascii "qsdfghjklm|"
    .byte '`,0,42        /* coin sup gauche, don't know, [*|mu] */
    .ascii "wxcvbn,;:!"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '<
    .fill 10,1,0

shift_map:
    .byte 0,27
    .ascii "1234567890]+"
    .byte 127,9
    .ascii "AZERTYUIOP<>"
    .byte 13,0
    .ascii "QSDFGHJKLM%"
    .byte '~,0,'#
    .ascii "WXCVBN?./\\"
    .byte 0,'*,0,32        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte '-,0,0,0,'+    /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '>
    .fill 10,1,0

alt_map:
    .byte 0,0
    .ascii "\0~#{[|`\\^@]}"
    .byte 0,0
    .byte '@,0,0,0,0,0,0,0,0,0,0
    .byte '~,13,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0
    .byte 0,0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0        /* 36-39 */
    .fill 16,1,0        /* 3A-49 */
    .byte 0,0,0,0,0        /* 4A-4E */
    .byte 0,0,0,0,0,0,0    /* 4F-55 */
    .byte '|
    .fill 10,1,0

#else
#error "KBD-type not defined"
#endif
View Code

do_self用于处理普通键

/*
 * do_self handles "normal" keys, ie keys that don't change meaning
 * and which have just one character returns.
 */
do_self:
    lea alt_map,%ebx //alt_map映射表首地址放到ebx中
    testb $0x20,mode //右边的alt是否被按下       /* alt-gr */
    jne 1f //如果是则跳转到1处
    lea shift_map,%ebx //shift_map映射表的首地址放到ebx中
    testb $0x03,mode //shift键是否被同时按下了
    jne 1f //如果是则跳转到1处
    lea key_map,%ebx //如果alt和shift都没有被按下,则加载普通的映射表key_map到ebx中
1:    movb (%ebx,%eax),%al //扫描码的索引值取对应的ascii码放入al中(ebx为key_map的基地址+eax为索引值,其ASCII码放到al中)
    orb %al,%al //检测是否有对应的ASCII码
    je none //如果对应的ASCII码是0,直接返回
    testb $0x4c,mode //caps键是否被按下       /* ctrl or caps */
    je 2f //如果没有按caps,则跳转到2处
    cmpb $'a,%al //如果caps被按下,则al中的字符和'a'进行比较
    jb 2f //如果al中的内容小于'a',则跳转
    cmpb $'},%al //al中的字符和'}'进行比较
    ja 2f //如果al中的内容大于'}',则跳转,上面这几行的意思是如果按下caps键,且为a-z,则转化为大写
    subb $32,%al //转换为大写字符(比如'a'和'A'之间差32:97-65=32)
2:    testb $0x0c,mode //ctrl键是否被按下        /* ctrl */
    je 3f //如果没有被按下,则跳转到编号3
    cmpb $64,%al //如果ctrl被按下,则比较al和64(ASCII字符@)
    jb 3f //如果al<'@',则跳转
    cmpb $64+32,%al //比较al和96
    jae 3f //如果al>'`',则跳转。上面几行代码判断al是否在'@'和'`'之间
    subb $64,%al //如果al在'@'和'`'之间,则al减去64转换为0x10-0x1F之间的控制字符。
3:    testb $0x10,mode //左边的alt是否被按下       /* left alt */
    je 4f //如果没有被按下,则跳转
    orb $0x80,%al //如果alt被按下,则把al最高位置位
4:    andl $0xff,%eax //清除eax的ah位
    xorl %ebx,%ebx //ebx清空
    call put_queue //把字符放到缓冲队列当中
none:    ret

minus处理减号

/*
 * minus has a routine of it's own, as a 'E0h' before
 * the scan code for minus means that the numeric keypad
 * slash was pushed.
 */
minus:    cmpb $1,e0 //e0标志是否置位
    jne do_self //如果没有,则跳转到do_self
    movl $'/,%eax //否则用'/'替换'-'放到eax当中
    xorl %ebx,%ebx
    jmp put_queue //把字符放到缓冲队列当中

等待键盘控制器的输入缓冲为空

/*
 * kb_wait waits for the keyboard controller buffer to empty.
 * there is no timeout - if the buffer doesn't empty, we hang.
 */
kb_wait:
    pushl %eax
1:    inb $0x64,%al //读取键盘控制器的状态
    testb $0x02,%al //测试是否为0000 0010 
    jne 1b //如果不空,则一直循环
    popl %eax //如果为空了,则返回
    ret

重启处理器

/*
 * This routine reboots the machine by asking the keyboard
 * controller to pulse the reset-line low.
 */
reboot:
    call kb_wait //等待键盘控制器输入缓冲为空
    movw $0x1234,0x472    /* don't do memory check */
    movb $0xfc,%al        /* pulse reset and A20 low */
    outb %al,$0x64
die:    jmp die

 

 
posted @ 2022-04-02 01:18  zhenjingcool  阅读(260)  评论(0编辑  收藏  举报