linux 0.11 内核学习 -- 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,表示特殊键按下的状态

 * cap,alt,ctrl,shift

 */

mode: .byte 0 /* caps, alt, ctrl and shift mode */

/*

 * 数字锁定键,大小写转换键,滚动锁定键scroll-lock

 * 定义变量leds

 */

leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */

/*

 * 0xe0或者是0xe1指示气候跟随的是一个或者是两个字符扫描码

 */

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

//////////////////////////////////////////////

// ds,es设置为内核数据段

movl $0x10,%eax

mov %ax,%ds

mov %ax,%es

//////////////////////////////////////////////

xorl %al,%al /* %eax is scan code, al = 0 */

inb $0x60,%al // 现在al寄存器就是中断之后读取的键盘扫描码

/////////////////////////////////////////////

cmpb $0xe0,%al // 如果扫描码是0xe0

je set_e0 // 跳转到set_e0

/////////////////////////////////////////////

cmpb $0xe1,%al // 如果是0xe1

je set_e1

/////////////////////////////////////////////

call key_table(,%eax,4) // 调用键处理程序key_table + %eax * 4

movb $0,e0 // 复位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 // 将控制台号tty = 0压入栈

call _do_tty_interrupt // 调用_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.

 */

/* 下面的子程序将ebx:eax中最多8个字符添加入缓冲队列,知道eax = 0 */

/* ---------------------------------------------  */

/* ebx (4 char) | eax (4 char)  */

/* ---------------------------------------------  */

put_queue:

pushl %ecx

pushl %edx

movl _table_list,%edx # read-queue for console,得到_table_list地址

movl head(%edx),%ecx // ecx = 缓冲队列头指针

1: movb %al,buf(%edx,%ecx) // 将al中的字符放置在缓冲队列头指针位置

incl %ecx

andl $size-1,%ecx // ecx指向缓冲队列最后

cmpl tail(%edx),%ecx # buffer full - discard everything?

// 头指针 == 尾指针

je 3f // 到3处继续执行,将后面未放入的字符全部抛弃

shrdl $8,%ebx,%eax

je 2f // 还有剩余的字符吗?没有,跳转2f

shrl $8,%ebx // ebx右移

jmp 1b // 还有剩余字符,跳转到1标号

///////////////////////////////////////

// 所有字符放入了队列 //

2: movl %ecx,head(%edx) // 保存头指针

movl proc_list(%edx),%ecx // 是否存在等待进程?

testl %ecx,%ecx

je 3f // 没有等待任务,跳转

/* task_struct结构第一个字段就是state */

movl $0,(%ecx) // 有,则置进程为可运行就绪状态

//////////////////////////////////////

//////////////////////////////////////

// 中断返回 //

3: popl %edx

popl %ecx

ret

/////////////////////////////////////

/* 根据ctrl或者是alt的扫描码,设置全局变量mode */

ctrl: movb $0x04,%al

jmp 1f

alt: movb $0x10,%al

1: cmpb $0,e0

je 2f

addb %al,%al

2: orb %al,mode

ret

/* 下面的代码设置ctrl或者alt键松开时扫描码,设置mode */

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

/* 下面的代码根据扫描码,设置mode */

lshift: // 左shift按下

orb $0x01,mode

ret

unlshift: // 左shift松开

andb $0xfe,mode

ret

rshift: // 右shift按下

orb $0x02,mode

ret

unrshift: // 右shift松开

andb $0xfd,mode

ret

/* caps键标志 */

caps: testb $0x80,mode // 测试mode中的caps键是否按下?

jne 1f // 如果已经按下,中断返回

xorb $4,leds // 设置leds变量

xorb $0x40,mode // 设置mode中的位

orb $0x80,mode

/* 下面的代码是根据leds的表示,开启或者是关闭LED灯 */

set_leds:

call kb_wait // 等待键盘控制器输入缓冲空

movb $0xed,%al /* set leds command */

outb %al,$0x60

call kb_wait // 等待键盘控制器输入缓冲空

movb leds,%al // 取leds 标志,作为参数

outb %al,$0x60 // 发送

ret

/* caps键释放,设置mode值 */

uncaps: andb $0x7f,mode

ret

/* scroll键按下,设置leds值,并调用set_leds,重新显示led */

scroll:

xorb $1,leds

jmp set_leds

/* num-lock键 */

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 // 扫描码是小数字键盘上的键(其扫描码>=0x47)发出的?

jb 1f // 如果小于则不处理,返回

cmpb $12,%al // 如果扫描码 > 0x53

ja 1f // 不处理,返回

jne cur2 /* check for ctrl-alt-del */

testb $0x0c,mode // 有ctrl 键按下吗?

je cur2 // 无,则跳转

testb $0x30,mode // 有alt按下吗?

jne reboot // 无,则跳转reboot

cur2: cmpb $0x01,e0 /* e0 forces cursor movement */

/* e0 置位表示光标移动 */

je cur // 如果置位了,跳转到cur

testb $0x02,leds /* not num-lock forces cursor */

// 测试leds 中标志num-lock 键标志是否置位

je cur // 如果没有置位(num 的LED 不亮),则也进行光标移动处理

testb $0x03,mode /* shift forces cursor */

// 测试模式标志mode 中shift 按下标志

jne cur // 如果有shift 键按下,则也进行光标移动处理

// 取对应键的数字ASCII 码 -> al

xorl %ebx,%ebx

movb num_table(%eax),%al

jmp put_queue // 将该字符放入缓冲队列中

1: ret

/* 处理光标的移动 */

cur: movb cur_table(%eax),%al // 取光标字符表中相应键的代表字符 -> al

cmpb $'9,%al // 若该字符<='9',说明是上一页、下一页、插入或删除键

ja ok_cur // 功能字符序列中要添入字符'~'

movb $'~,%ah

ok_cur: shll $16,%eax // 将ax 中内容移到eax 高字中

movw $0x5b1b,%ax // 在ax中放入$0x5b1b,与eax 高字中字符组成移动序列

xorl %ebx,%ebx

jmp put_queue // 将该字符放入缓冲队列中

#if defined(KBD_FR)

num_table:

.ascii "789 456 1230." // 数字小键盘上键对应的数字ASCII 码表

#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 // kernl/sched.c

popl %edx

popl %ecx

popl %eax

/////////////////////////////////////

subb $0x3B,%al // 功能键'F1'的扫描码是0x3B

jb end_func // 如果扫描码小于0x3b,则不处理

cmpb $9,%al // 功能键是F1-F10?

jbe ok_func // 是,则跳转

subb $18,%al // 是功能键F11,F12 吗?

cmpb $10,%al // 是功能键F11?

jb end_func // 不是,则不处理

cmpb $11,%al // 是功能键F12?

ja end_func // 不是,则不处理

ok_func:

cmpl $4,%ecx /* check that there is enough room */

jl end_func // 需要放入4 个字符序列,如果放不下,则返回

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.

 */

/*

 * 功能键发送的扫描码,F1 键为:'esc [ [ A', F2 键为:'esc [ [ B'等

 */

func_table:

.long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b

.long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b

.long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b

/* 扫描码-ASCII 字符映射表 */

#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 键同时按下时的映射表

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 键同时按下时的映射表

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 handles "normal" keys

 */

do_self:

//////////////////////////////////////////////////////////////////

// 根据模式标志mode 选择alt_map、shift_map 或key_map 映射表之一 //

lea alt_map,%ebx // alt 键同时按下时的映射表基址alt_map􀃎-> ebx

testb $0x20,mode /* 右alt 键同时按下了? alt-gr */

jne 1f // 同时按下了,则向前跳转到标号1 处

lea shift_map,%ebx // shift 键同时按下时的映射表基址shift_map􀃎-> ebx

testb $0x03,mode // 有shift 键同时按下了吗?

jne 1f // 有,则向前跳转到标号1 处

lea key_map,%ebx // 否则使用普通映射表key_map

//////////////////////////////////////////////////////////////////

/* 取映射表中对应扫描码的ASCII 字符,若没有对应字符,则返回(转none) */

1: movb (%ebx,%eax),%al // 将扫描码作为索引值,取对应的ASCII 码 -> al

orb %al,%al // 检测看是否有对应的ASCII 码?

je none // 若没有(对应的ASCII 码=0),则返回

///////////////////////////////////////////////////////////////////

/* 若ctrl 键已按下或caps 键锁定,并且字符在'a'-'}'(0x61-0x7D)范围内,则将其转成大写字符 */

testb $0x4c,mode /* ctrl or caps */

je 2f

cmpb $'a,%al

jb 2f

cmpb $'},%al

ja 2f

subb $32,%al

///////////////////////////////////////////////////////////////////

/* 若ctrl 键已按下,并且字符在'`'--'_'(0x40-0x5F)之间(是大写字符),则将其转换为控制字符 */

2: testb $0x0c,mode /* ctrl */

je 3f

cmpb $64,%al

jb 3f

cmpb $64+32,%al

jae 3f

subb $64,%al

/* 若左alt 键同时按下,则将字符的位7 置位 */

3: testb $0x10,mode /* left alt */

je 4f

orb $0x80,%al

/* 将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 用于等待键盘控制器缓冲空

 */

kb_wait:

pushl %eax

1: inb $0x64,%al // 读键盘控制器状态

testb $0x02,%al // 测试输入缓冲器是否为空(等于0)?

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 // 向系统复位和A20 线输出负脉冲

die: jmp die // 死机

/*

 * 整个文件实现了键盘中断处理函数_keyboard_interrupt,通过查询

 * key_table来查找特定键的处理函数

 */

参考《linux内核完全注释》和网上相关知识

posted @   qiang.xu  阅读(2268)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示