?? keyboard.s
字號:
/* passed* linux/kernel/keyboard.S** (C) 1991 Linus Torvalds*/.586p.model flat
/** Thanks to Alfred Leung for US keyboard patches* Wolfgang Thiel for German keyboard patches* Marc Corsini for the French keyboard*//** 感謝Alfred Leung 添加了US 鍵盤補丁程序;* Wolfgang Thiel 添加了德語鍵盤補丁程序;* Marc Corsini 添加了法文鍵盤補丁程序。*/#include <linux/config.h> // 內核配置頭文件。定義鍵盤語言和硬盤類型(HD_TYPE)可選項。extern _do_tty_interrupt:proc, _show_stat:proc
extern _table_list:dwordpublic _keyboard_interrupt //int 21h 在console.c內的conn_init函數內設置
/** these are for the keyboard read functions*//** 以下這些是用于鍵盤讀操作。*/// bsize 是鍵盤緩沖區的長度(字節數)。bsize = 1024 /* must be a power of two ! And MUST be the same as in tty_io.c !!!! */ /* 數值必須是2 的次方!并且與tty_io.c 中的值匹配!!!! */ // 以下這些是緩沖隊列結構中的偏移量 */head = 4 // 緩沖區中頭指針字段偏移。tail = 8 // 緩沖區中尾指針字段偏移。proc_list = 12 // 等待該緩沖隊列的進程字段偏移。buf = 16 // 緩沖區字段偏移。
.code
mode db 0 /* caps, alt, ctrl and shift mode */
// mode 是鍵盤特殊鍵的按下狀態標志。// 表示大小寫轉換鍵(caps)、交換鍵(alt)、控制鍵(ctrl)和換檔鍵(shift)的狀態。// 位7 caps 鍵按下;// 位6 caps 鍵的狀態(應該與leds 中的對應標志位一樣);// 位5 右alt 鍵按下;// 位4 左alt 鍵按下;// 位3 右ctrl 鍵按下;// 位2 左ctrl 鍵按下;// 位1 右shift 鍵按下;// 位0 左shift 鍵按下。
leds db 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
// 數字鎖定鍵(num-lock)、大小寫轉換鍵(caps-lock)和滾動鎖定鍵(scroll-lock)的LED 發光管狀態。// 位7-3 全0 不用;// 位2 caps-lock;// 位1 num-lock(初始置1,也即設置數字鎖定鍵(num-lock)發光管為亮);// 位0 scroll-lock。e0 db 0
// 當掃描碼是0xe0 或0xe1 時,置該標志。表示其后還跟隨著1 個或2 個字符掃描碼,參見列表后說明。// 位1 =1 收到0xe1 標志;// 位0 =1 收到0xe0 標志。/** con_int is the real interrupt routine that reads the* keyboard scan-code and converts it into the appropriate* ascii character(s).*//** con_int 是實際的中斷處理子程序,用于讀鍵盤掃描碼并將其轉換* 成相應的ascii 字符。*///// 鍵盤中斷int 21h處理程序入口點。
_keyboard_interrupt: push eax push ebx push ecx push edx push ds push es mov eax,10h // 將ds、es 段寄存器置為內核數據段。 mov ds,ax mov es,ax xor al,al /* %eax is scan code */ /* eax 中是掃描碼 */ in al,60h // 讀取掃描碼->al。 cmp al,0e0h // 該掃描碼是0xe0 嗎?如果是則跳轉到設置e0 標志代碼處。 je set_e0 cmp al,0e1h // 掃描碼是0xe1 嗎?如果是則跳轉到設置e1 標志代碼處。 je set_e1 call key_table[eax*4] // 調用鍵處理程序ker_table + eax * 4(參見下面502 行)。 mov e0,0 // 復位e0 標志。// 下面這段代碼(55-65 行)是針對使用8255A 的PC 標準鍵盤電路進行硬件復位處理。端口0x61 是// 8255A 輸出口B 的地址,該輸出端口的第7 位(PB7)用于禁止和允許對鍵盤數據的處理。// 這段程序用于對收到的掃描碼做出應答。方法是首先禁止鍵盤,然后立刻重新允許鍵盤工作。e0_e1:
in al,61h // 取PPI 端口B 狀態,其位7 用于允許/禁止(0/1)鍵盤。 jmp l1 // 延遲一會。l1: jmp l2l2: or al,80h // al 位7 置位(禁止鍵盤工作)。 jmp l3 // 再延遲一會。l3: jmp l4l4: out 61h,al // 使PPI PB7 位置位。 jmp l5 // 延遲一會。l5: jmp l6l6: and al,7Fh // al 位7 復位。 out 61h,al // 使PPI PB7 位復位(允許鍵盤工作)。 mov al,20h // 向8259 中斷芯片發送EOI(中斷結束)信號。 out 20h,al push 0 // 控制臺tty 號=0,作為參數入棧。 call _do_tty_interrupt // 將收到的數據復制成規范模式數據并存放在規范字符緩沖隊列中。 add esp,4 // 丟棄入棧的參數,彈出保留的寄存器,并中斷返回。 pop es pop ds pop edx pop ecx pop ebx pop eax iretdset_e0:
mov e0,1 // 收到掃描前導碼0xe0 時,設置e0 標志(位0)。 jmp e0_e1set_e1:
mov e0,2 // 收到掃描前導碼0xe1 時,設置e1 標志(位1)。 jmp e0_e1/** 下面該子程序把ebx:eax 中的最多8 個字符添入緩沖隊列中。(edx 是* 所寫入字符的順序是al,ah,eal,eah,bl,bh...直到eax 等于0。*/put_queue: push ecx // 保存ecx,edx 內容。 push edx // 取控制臺tty 結構中讀緩沖隊列指針。 mov edx,_table_list // read-queue for console mov ecx,head[edx] // 取緩沖隊列中頭指針->ecx。l7: mov buf[edx+ecx],al // 將al 中的字符放入緩沖隊列頭指針位置處。 inc ecx // 頭指針前移1 字節。 and ecx,bsize-1 // 以緩沖區大小調整頭指針(若超出則返回緩沖區開始)。 cmp ecx,tail[edx] // buffer full - discard everything// 頭指針==尾指針嗎(緩沖隊列滿)? je l9 // 如果已滿,則后面未放入的字符全拋棄。 shrd eax,ebx,8 // 將ebx 中8 位比特位右移8 位到eax 中,但ebx 不變。 je l8 // 還有字符嗎?若沒有(等于0)則跳轉。 shr ebx,8 // 將ebx 中比特位右移8 位,并跳轉到標號l7 繼續操作。 jmp l7l8: mov head[edx],ecx // 若已將所有字符都放入了隊列,則保存頭指針。 mov ecx,proc_list[edx] // 該隊列的等待進程指針? test ecx,ecx // 檢測任務結構指針是否為空(有等待該隊列的進程嗎?)。 je l9 // 無,則跳轉; mov dword ptr [ecx],0 // 有,則置該進程為可運行就緒狀態(喚醒該進程)。l9: pop edx // 彈出保留的寄存器并返回。 pop ecx ret// 下面這段代碼根據ctrl 或alt 的掃描碼,分別設置模式標志中相應位。如果該掃描碼之前收到過// 0xe0 掃描碼(e0 標志置位),則說明按下的是鍵盤右邊的ctrl 或alt 鍵,則對應設置ctrl 或alt// 在模式標志mode 中的比特位。ctrl:
mov al,04h // 0x4 是模式標志mode 中左ctrl 鍵對應的比特位(位2)。 jmp l10alt:
mov al,10h // 0x10 是模式標志mode 中左alt 鍵對應的比特位(位4)。l10:
cmp e0,0 // e0 標志置位了嗎(按下的是右邊的ctrl 或alt 鍵嗎)? je l11 // 不是則轉。 add al,al // 是,則改成置相應右鍵的標志位(位3 或位5)。l11:
or mode,al // 設置模式標志mode 中對應的比特位。 ret// 這段代碼處理ctrl 或alt 鍵松開的掃描碼,對應復位模式標志mode 中的比特位。在處理時要根據// e0 標志是否置位來判斷是否是鍵盤右邊的ctrl 或alt 鍵。unctrl:
mov al,04h // 模式標志mode 中左ctrl 鍵對應的比特位(位2)。 jmp l12unalt:
mov al,10h // 0x10 是模式標志mode 中左alt 鍵對應的比特位(位4)。l12:
cmp e0,0 // e0 標志置位了嗎(釋放的是右邊的ctrl 或alt 鍵嗎)? je l13 // 不是,則轉。 add al,al // 是,則該成復位相應右鍵的標志位(位3 或位5)。l13:
not al // 復位模式標志mode 中對應的比特位。 and mode,al retlshift: or mode,01h // 是左shift 鍵按下,設置mode 中對應的標志位(位0)。 retunlshift: and mode,0feh // 是左shift 鍵松開,復位mode 中對應的標志位(位0)。 retrshift: or mode,02h // 是右shift 鍵按下,設置mode 中對應的標志位(位1)。 retunrshift: and mode,0fdh // 是右shift 鍵松開,復位mode 中對應的標志位(位1)。 retcaps:
test mode,80h // 測試模式標志mode 中位7 是否已經置位(按下狀態)。 jne l14 // 如果已處于按下狀態,則返回(ret)。 xor leds,4 // 翻轉leds 標志中caps-lock 比特位(位2)。 xor mode,40h // 翻轉mode 標志中caps 鍵按下的比特位(位6)。 or mode,80h // 設置mode 標志中caps 鍵已按下標志位(位7)。// 這段代碼根據leds 標志,開啟或關閉LED 指示器。set_leds: call kb_wait // 等待鍵盤控制器輸入緩沖空。 mov al,0edh /* set leds command */ /* 設置LED 的命令 */ out 60h,al // 發送鍵盤命令0xed 到0x60 端口。 call kb_wait // 等待鍵盤控制器輸入緩沖空。 mov al,leds // 取leds 標志,作為參數。 out 60h,al // 發送該參數。 retuncaps:
and mode,7fh // caps 鍵松開,則復位模式標志mode 中的對應位(位7)。 retscroll: xor leds,1 // scroll 鍵按下,則翻轉leds 標志中的對應位(位0)。 jmp set_leds // 根據leds 標志重新開啟或關閉LED 指示器。num:
xor leds,2 // num 鍵按下,則翻轉leds 標志中的對應位(位1)。 jmp set_leds // 根據leds 標志重新開啟或關閉LED 指示器。/** curosr-key/numeric keypad cursor keys are handled here.* checking for numeric keypad etc.*//** 這里處理方向鍵/數字小鍵盤方向鍵,檢測數字小鍵盤等。*/cursor: sub al,47h // 掃描碼是小數字鍵盤上的鍵(其掃描碼>=0x47)發出的? jb l14 // 如果小于則不處理,返回。 cmp al,12 // 如果掃描碼 > 0x53(0x53 - 0x47= 12),則 ja l14 // 掃描碼值超過83(0x53),不處理,返回。 jne cur2 /* check for ctrl-alt-del */ /* 檢查是否ctrl-alt-del */// 如果等于12,則說明del 鍵已被按下,則繼續判斷ctrl// 和alt 是否也同時按下。 test mode,0ch // 有ctrl 鍵按下嗎? je cur2 // 無,則跳轉。 test mode,30h // 有alt 鍵按下嗎? jne reboot // 有,則跳轉到重啟動處理。cur2:
cmp e0,01h /* e0 forces cursor movement */ /* e0 置位表示光標移動 */// e0 標志置位了嗎? je cur // 置位了,則跳轉光標移動處理處cur。 test leds,02h /* not num-lock forces cursor */ /* num-lock 鍵則不許 */// 測試leds 中標志num-lock 鍵標志是否置位。 je cur // 如果沒有置位(num 的LED 不亮),則也進行光標移動處理。 test mode,03h /* shift forces cursor */ /* shift 鍵也使光標移動 */// 測試模式標志mode 中shift 按下標志。 jne cur // 如果有shift 鍵按下,則也進行光標移動處理。 xor ebx,ebx // 否則查詢掃數字表(199 行),取對應鍵的數字ASCII 碼。 mov al,num_table[eax] // 以eax 作為索引值,取對應數字字符->al。 jmp put_queue // 將該字符放入緩沖隊列中。l14:
ret// 這段代碼處理光標的移動。cur:
mov al,cur_table[eax] // 取光標字符表中相應鍵的代表字符??al。 cmp al,'9' // 若該字符<='9',說明是上一頁、下一頁、插入或刪除鍵, ja ok_cur // 則功能字符序列中要添入字符'~'。 mov ah,'~'ok_cur:
shl eax,16 // 將ax 中內容移到eax 高字中。 mov ax,5b1bh // 在ax 中放入'esc ['字符,與eax 高字中字符組成移動序列。 xor ebx,ebx jmp put_queue // 將該字符放入緩沖隊列中。#if defined(KBD_FR)num_table db "789 456 1230." // 數字小鍵盤上鍵對應的數字ASCII 碼表。#elsenum_table db "789 456 1230,"#endifcur_table db "HA5 DGC YB623" // 數字小鍵盤上方向鍵或插入刪除鍵對應的移動表示字符表。/** this routine handles function keys*/// 下面子程序處理功能鍵。func: push eax push ecx push edx call _show_stat // 調用顯示各任務狀態函數(kernl/sched.c, 37)。 pop edx pop ecx pop eax sub al,3Bh // 功能鍵'F1'的掃描碼是0x3B,因此此時al 中是功能鍵索引號。 jb end_func // 如果掃描碼小于0x3b,則不處理,返回。 cmp al,9 // 功能鍵是F1-F10? jbe ok_func // 是,則跳轉。 sub al,18 // 是功能鍵F11,F12 嗎? cmp al,10 // 是功能鍵F11? jb end_func // 不是,則不處理,返回。 cmp al,11 // 是功能鍵F12? ja end_func // 不是,則不處理,返回。ok_func: cmp ecx,4 /* check that there is enough room */ /* 檢查是否有足夠空間*/ jl end_func // 需要放入4 個字符序列,如果放不下,則返回。 mov eax,func_table[eax*4] // 取功能鍵對應字符序列。 xor ebx,ebx jmp put_queue // 放入緩沖隊列中。end_func: ret/** 功能鍵發送的掃描碼,F1 鍵為:'esc [ [ A', F2 鍵為:'esc [ [ B'等。*/func_table: DD 415b5b1bh,425b5b1bh,435b5b1bh,445b5b1bh DD 455b5b1bh,465b5b1bh,475b5b1bh,485b5b1bh DD 495b5b1bh,4a5b5b1bh,4b5b5b1bh,4c5b5b1bh
// ps:只有KBD_US檢測通過// 掃描碼-ASCII 字符映射表。// 根據在config.h 中定義的鍵盤類型(FINNISH,US,GERMEN,FRANCH),將相應鍵的掃描碼映射// 到ASCII 字符。#if defined(KBD_FINNISH)// 以下是芬蘭語鍵盤的掃描碼映射表。key_map: db 0,27 // 掃描碼0x00,0x01 對應的ASCII 碼; db "1234567890+'" // 掃描碼0x02,...0x0c,0x0d 對應的ASCII 碼,以下類似。 db 127,9 db "qwertyuiop}" db 0,13,0 db "asdfghjkl|{" db 0,0 db "'zxcvbnm,.-" db 0,'*',0,32 /* 36-39 */ /* 掃描碼0x36-0x39 對應的ASCII 碼 */ db 16 dup(0) /* 3A-49 */ /* 掃描碼0x3A-0x49 對應的ASCII 碼 */ db '-',0,0,0,'+' /* 4A-4E */ /* 掃描碼0x4A-0x4E 對應的ASCII 碼 */ db 0,0,0,0,0,0,0 /* 4F-55 */ /* 掃描碼0x4F-0x55 對應的ASCII 碼 */ db '<' db 10 dup(0)// shift 鍵同時按下時的映射表。shift_map: db 0,27 db '!','"',"#$%&/()=?`" db 127,9 db "QWERTYUIOP]^" db 13,0 db "ASDFGHJKL\[" db 0,0 db "*ZXCVBNM:_" db 0,'*',0,32 /* 36-39 */ db 16 dup(0) /* 3A-49 */ /* 掃描碼0x3A-0x49 對應的ASCII 碼 */
db '-',0,0,0,'+' /* 4A-4E */ db 0,0,0,0,0,0,0 /* 4F-55 */ db '>' db 10 dup(0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -