现在的位置: 首页 > 综合 > 正文

linux 0.11 内核学习 — keyboard.s,键盘原来是这么干的。

2013年01月15日 ⁄ 综合 ⁄ 共 9269字 ⁄ 字号 评论关闭

/*

 *  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

抱歉!评论已关闭.