主板的鍵盤有一塊專用的接口芯片,一般是采用一塊單片微處理器8042(現在大多已集成在南橋或SIO里)。它控制整個鍵盤的工作,包括加電自檢、鍵盤掃描碼的緩沖以及與主板的通訊。
6 a% p0 [8 A0 q0 o9 B* x0 N
兩個重要的中斷:
計匠網論壇" L; }+ _. d1 y9 a" ?* o
INT 09H是H/W中斷,對應IRQ1,INT 16H是一個S/W中斷。當鍵盤的一個鍵被按下時,鍵盤接口芯片根據被按下的位置,INT 09H負責把鍵值轉換成INT16H認識的值,返回給INT 16H。INT 16H再把該值根據OS所選定的不同語系鍵盤而轉換成相應的二進制字符傳給OS或應用程序。當用戶敲擊鍵盤速度過快,使主CPU來不及處理時,則先將所鍵 入的內容送往住存儲器的鍵盤緩沖區,等CPU能處理時,便從緩沖區中取出,送入CPU進行分析和執行。一般在PC機的內存中安排了大約20個字符的鍵盤緩 沖區。
, O0 I. K3 n2 O4 i# a& z
主板的鍵盤有一塊專用的接口芯片,一般是采用一塊單片微處理器8042(現在大多已集成在南橋或SIO里)。它控制整個鍵盤的工作,包括加電自檢、鍵盤掃描碼的緩沖以及與主板的通訊。
?? D) f, C# Z% t# I
計匠網論壇, D2 M+ N0 c5 P?? N
(Award Code ,In file?? ATORGS.ASM, INT 09h( KBDINT_VECT?? JMP KBC_INT<at AKBRD.ASM> ) and INT 16h(KBD_VECT JMP keyboard) )
www.ufoit.com% J; F" ^& B2 f% L! ^2 y
對緩沖和命令的處理:
????? 8042分輸入緩沖和輸出緩沖,它的數據傳輸在I/O口60H和64H進行。基本上,I/O 64H是命令和狀態口,I/O 60H是數據口,它們同時可做讀寫動作,在讀和寫時有著不同的意義。I/O 64H的bit 0、1置位分別代表輸出/輸入緩沖滿。如果發現輸入緩沖滿(即判斷出I/O 64H[1]=1),要從I/O 60H將數據讀完。BIOS在自檢時如果確定輸入/輸出緩沖都沒有問題,會發“AAH”給I/O 64H,讓它自測試。等到輸入緩沖空(說明上一個命令已執行完),輸出緩沖滿(KB控制器對自測試命令有反應),再讀I/O 60H是否為“55H”(IBM PC/AT規范)。如果是,則表示KB沒有問題,若等不到輸出緩沖滿,說明有問題。
??? 在寫命令之前,必須對I/O 64H口送一個60H的值,并等到輸入緩沖空,再操作I/O 60H。同樣,在讀狀態之前,也必須對I/O 64H口送一個20H的值,并等到輸出緩沖滿(表示有狀態輸出),再操作I/O 60H。這時,我們可以把64H看作索引口,而60H看作數據口。
A20地址線的切換:
* o; I2 D- h3 u?? |
; t! ~0 E* l5 H2 N
鍵盤接口芯片除了接受來自鍵盤的信息外,還要負責A20地址線的切換,因為當CPU從實模式切換到保護模式時便是通過A20地址線的切換完成的。平常 A20為“0”時,CPU工作于DOS的實模式;當A20切換為“1”時,便可進入保護模式。但由于鍵盤接口芯片切換A20地址線的速度不夠快,目前多由 主板上的芯片組以模擬方式取代,這樣也就省去了一塊鍵盤接口芯片。
& Y+ W& S& T" g! ~
8042 端口的操作:
通過8042芯片,可以:
1. 向8042芯片發布命令(通過64h),并通過60h讀取命令的返回結果(如果有的話),或通過60h端口寫入命令所需的數據(如果需要的話)。
2.讀取Status Register的內容(通過64h);
3.向8048發布命令(通過60h);
4.讀取來自于Keyboard的數據(通過60h)。這些數據包括Scan Code(由按鍵和釋放鍵引起的),對8048發送的命令的確認字節(ACK)及回復數據。
& x5 ]?? z?? i. {- D$ P?? [
再次強調一遍,Command(命令)分為發送給8042芯片的命令和發送給8048的命令。它們是不相同的,并且使用的端口也是不相同的(分別為64h和60h)。
- l: [5 z
64h端口(讀操作)
?????? 對64h端口進行讀操作,會讀取Status Register的內容。
???? in al, 0x64
計匠網論壇" z( @" P/ A8 }?? A4 V) O! o+ o
?? 執行這個指令之后,AL寄存器中存放的就是Status Register的內容。
64h端口(寫操作)
; ?* {) h8 r& _9 N1 K
??? 向64h端口寫入的字節,被認為是對8042芯片發布的命令(Command): 寫入的字節將會被存放在Input Register中; 同時會引起Status Register的Bit-3自動被設置為1,表示現在放在Input Register中的數據是一個Command,而不是一個Data;
計匠網論壇8 G% Z, n% F. G* F
?? 在向64h端口寫某些命令之前必須確保鍵盤是被禁止的,因為這些被寫入的命令的返回結果將會放到Output Register中,而鍵盤如果不被禁止,則也會將數據放入到Output Register中,會引起相互之間的數據覆蓋;
9 J; |9 l0 @; H. S* g
?? 在向64h端口寫數據之前必須確保Input Register是空的(通過判斷Status Register的Bit-1是否為0)。
" {/ }9 l: p' t?? G2 _
計匠網論壇/ A% W- C?? a' `
60h端口(讀操作)
??????? 對60h端口進行讀操作,將會讀取Output Register的內容。Output Register的內容可能是: . 來自于8048的數據。這些數據包括Scan Code,對8048發送的命令的確認字節(ACK)及回復數據。 . 通過64h端口對8042發布的命令的返回結果。
www.ufoit.com: j: v: u1 c3 ]/ o
在向60h端口讀取數據之前必須確保Output Register中有數據(通過判斷Status Register的Bit-0是否為1)
60h端口(寫操作)
% b9 N5 /# B' I# s2 I7 L( s) ^- e
?? ??? 向60h端口寫入的字節,有兩種可能: 1.如果之前通過64h端口向8042芯片發布的命令需要進一步的數據,則此時寫入的字節就被認為是數據; 2.否則,此字節被認為是發送給8048的命令。 在向60h端口寫數據之前,必須確保Input Register是空的(通過判斷Status Register的Bit-1是否為0)。
R_ALT E0,38 E0,B8
UP ARROW E0,48 E0,C8
PG UP E0,49 E0,C9
R ARROW E0,4D E0,CD
D ARROW E0,50 E0,D0
PG DN E0,51 E0,D1
INSERT E0,52 E0,D2
DELETE E0,53 E0,D3
R GUI E0,5C E0,DC
APPS E0,5D E0,DD
PRNT SCRN E0,2A, E0,37 E0,B7, E0,AA
PAUSE E1,1D,45 E1,9D,C5 -NONE
這里說幾句對驅動沒有幫助的題外話,記不清是由于先有了關于 Scan Code 的值的猜測,才去按這個順序列 Scan Code ,還是先這樣列 Scan Code ,才有了關于 Scan Code 的值的猜測。總之,用這個 Make Code 的順序,和我們現在鍵盤上鍵的布局做對照,我們大致就能猜到為什么 A 鍵的 Make Code 值為 0x1e,為什么 H 鍵的 Make Code 值為 0x23。我們拿其中的一小段舉例子,A 1E,S 1F,D 20,F 21,G 22,H 23,看看鍵盤上 A,S,D,F,G,H 的位置吧。能感覺到些什么吧,感覺不到就算了,這個和驅動是無關的。從 Scan Code Set 1,可能還能推測出來最早的鍵盤的樣子。以及發生在鍵盤上的一些變化。我們注意到 F10 和 F11,F12 的 Make Code 不是連在一起的,估計比較早的鍵盤只有10個功能鍵,而不是現在的12個功能鍵。從鍵的 Make Code 來看,有可能曾經使用的一些鍵,現在已經不出現在鍵盤上了。
Status Register(狀態寄存器)
Bit6: RCV-TMOUT(R_T): 接收超時,置1
Bit5: TRANS_TMOUT(T_T): 發送超時,置1
Bit4: KYBD_INH(K_I): 為1,鍵盤沒有被禁止。為0,鍵盤被禁止。
Bit3: CMD_DATA(C_D): 為1,輸入緩沖器中的內容為命令,為0,輸入緩沖器中的內容為數據。
Bit2: SYS_FLAG(S_F): 系統標志,加電啟動置0,自檢通過后置1
Bit1: INPUT_BUF_FULL(I_B_F): 輸入緩沖器滿置1,i8042 取走后置0
BitO: OUT_BUF_FULL(O_B_F): 輸出緩沖器滿置1,CPU讀取后置0
Output Buffer(輸出緩沖器)
Input Buffer(輸入緩沖器)
Control Register(控制寄存器)
Bit6: 將第二套掃描碼翻譯為第一套
Bit5: 置1,禁止鼠標
Bit4: 置1,禁止鍵盤
Bit3: 置1,忽略狀態寄存器中的 Bit4
Bit2: 設置狀態寄存器中的 Bit2
Bit1: 置1,enable 鼠標中斷
BitO: 置1,enable 鍵盤中斷
驅動中把 0x64 叫命令端口
1.5.1 發給i8042的命令
準備讀取8042芯片的Command Byte;其行為是將當前8042 Command Byte的內容放置于Output Register中,下一個從60H端口的讀操作將會將其讀取出來。
準備寫入8042芯片的Command Byte;下一個通過60h寫入的字節將會被放入Command Byte。
測試一下鍵盤密碼是否被設置;測試結果放置在Output Register,然后可以通過60h讀取出來。測試結果可以有兩種值:FAh=密碼被設置;F1h=沒有密碼。
設置鍵盤密碼。其結果被按照順序通過60h端口一個一個被放置在Input Register中。密碼的最后是一個空字節(內容為0)。
讓密碼生效。在發布這個命令之前,必須首先使用A5h命令設置密碼。
自檢。診斷結果放置在Output Register中,可以通過60h讀取。55h=OK。
禁止鍵盤接口。Command Byte的bit-4被設置。當此命令被發布后,Keyboard將被禁止發送數據到Output Register。
打開鍵盤接口。Command Byte的bit-4被清除。當此命令被發布后,Keyboard將被允許發送數據到Output Register。
準備讀取Input Port。Input Port的內容被放置于Output Register中,隨后可以通過60h端口讀取。
準備讀取Outport端口。結果被放在Output Register中,隨后通過60h端口讀取出來。
準備寫Output端口。隨后通過60h端口寫入的字節,會被放置在Output Port中。
D2h
準備寫數據到Output Register中。隨后通過60h寫入到Input Register的字節會被放入到Output Register中,此功能被用來模擬來自于Keyboard發送的數據。如果中斷被允許,則會觸發一個中斷。
1.5.2 發給8048的命令
設置LED。Keyboard收到此命令后,一個LED設置會話開始。Keyboard首先回復一個ACK(FAh),然后等待從60h端口寫入的LED 設置字節,如果等到一個,則再次回復一個ACK,然后根據此字節設置LED。然后接著等待。。。直到等到一個非LED設置字節(高位被設置),此時LED 設置會話結束。
診斷Echo。此命令純粹為了檢測Keyboard是否正常,如果正常,當Keyboard收到此命令后,將會回復一個EEh字節。
選擇Scan code set。Keyboard系統共可能有3個Scan code set。當Keyboard收到此命令后,將回復一個ACK,然后等待一個來自于60h端口的Scan code set代碼。系統必須在此命令之后發送給Keyboard一個Scan code set代碼。當Keyboard收到此代碼后,將再次回復一個ACK,然后將Scan code set設置為收到的Scan code set代碼所要求的。
讀取Keyboard ID。由于8042芯片后不僅僅能夠接Keyboard。此命令是為了讀取8042后所接的設備ID。設備ID為2個字節,Keyboard ID為83ABh。當鍵盤收到此命令后,會首先回復一個ACK,然后,將2字節的Keyboard ID一個一個回復回去。
設置Typematic Rate/Delay。當Keyboard收到此命令后,將回復一個ACK。然后等待來自于60h的設置字節。一旦收到,將回復一個ACK,然后將Keyboard Rate/Delay設置為相應的值。
清理鍵盤的Output Buffer。一旦Keyboard收到此命令,將會將Output buffer清空,然后回復一個ACK。然后繼續接受Keyboard的擊鍵。
設置默認狀態(w/Disable)。一旦Keyboard收到此命令,將會將Keyboard完全初始化成默認狀態。之前所有對它的設置都將失效—— Output buffer被清空,Typematic Rate/Delay被設置成默認值。然后回復一個ACK,接著等待下一個命令。需要注意的是,這個命令被執行后,鍵盤的擊鍵接受是禁止的。如果想讓鍵盤 接受擊鍵輸入,必須Enable Keyboard。
設置默認狀態。和F5命令唯一不同的是,當此命令被執行之后,鍵盤的擊鍵接收是允許的。
Resend。如果Keyboard收到此命令,則必須將剛才發送到8042 Output Register中的數據重新發送一遍。當系統檢測到一個來自于Keyboard的錯誤之后,可以使用自命令讓Keyboard重新發送剛才發送的字節。
Reset Keyboard。如果Keyboard收到此命令,則首先回復一個ACK,然后啟動自身的Reset程序,并進行自身基本正確性檢測(BAT- Basic Assurance Test)。等這一切結束之后,將返回給系統一個單字節的結束碼(AAh=Success, FCh=Failed),并將鍵盤的Scan code set設置為2。
1.5.3 讀到的數據
00h/FFh
當擊鍵或釋放鍵時檢測到錯誤時,則在Output Bufer后放入此字節,如果Output Buffer已滿,則會將Output Buffer的最后一個字節替代為此字節。使用Scan code set 1時使用00h,Scan code 2和Scan Code 3使用FFh。
BAT完成代碼。如果鍵盤檢測成功,則會將此字節發送到8042 Output Register中。
Echo響應。Keyboard使用EEh響應從60h發來的Echo請求。
在Scan code set 2和Scan code set 3中,被用作Break Code的前綴。
ACK。當Keyboard任何時候收到一個來自于60h端口的合法命令或合法數據之后,都回復一個FAh。
BAT失敗代碼。如果鍵盤檢測失敗,則會將此字節發送到8042 Output Register中。
Resend。當Keyboard任何時候收到一個來自于60h端口的非法命令或非法數據之后,或者數據的奇偶交驗錯誤,都回復一個FEh,要求系統重新發送相關命令或數據。
當鍵盤收到一個來自于60h的F2h命令之后,會依次回復83h,ABh。83AB是鍵盤的ID。
除了上述那些特殊字節以外,剩下的都是Scan code。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
