- 30天自制操作系統
- (日)川合秀實
- 1478字
- 2020-03-11 14:01:53
6 總算講到鼠標了(harib04f)
現在到了讓大家期待已久的講解鼠標的時間了。首先說一說,為什么雖然我們的電腦連著有鼠標,卻一直不能用的原因。
從計算機不算短暫的歷史來看,鼠標這種裝置屬于新興一族。早期的計算機一般都不配置鼠標。一個很明顯的證據就是,現在我們要講的分配給鼠標的中斷號碼,是IRQ12,這已經是一個很大的數字了。與鍵盤的IRQ1比起來,那可差了好多代了。
所以,當鼠標剛剛作為計算機的一個外部設備開始使用的時候,幾乎所有的操作系統都不支持它。在這種情況下,如果只是稍微動一動鼠標就產生中斷的話,那在使用那些操作系統的時候,就只好先把鼠標拔掉了。IBM的大叔們認為,這對于使用計算機的人來說是很不方便的。所以,雖然在主板上做了鼠標用的電路,但只要不執行激活鼠標的指令,就不產生鼠標的中斷信號(1)。
所謂不產生中斷信號,也就是說,即使從鼠標傳來了數據,CPU也不會接收。這樣的話,鼠標也就沒必要送數據了,否則倒會引起電路的混亂。所以,處于初期狀態的鼠標,不管是滑動操作也好,點擊操作也好,都沒有反應(2)。

總而言之,我們必須發行指令,讓下面兩個裝置有效,一個是鼠標控制電路,一個是鼠標本身。通過上面的說明,大家應該已經明白了,要先讓鼠標控制電路有效。如果先讓鼠標有效了,那時控制電路還沒準備好數據就來了,可就麻煩了,因為控制電路還處理不了。
■■■■■
現在來說說控制電路的設定。事實上,鼠標控制電路包含在鍵盤控制電路里,如果鍵盤控制電路的初始化正常完成,鼠標電路控制器的激活也就完成了。
bootpack.c節選
#define PORT_KEYDAT 0x0060 #define PORT_KEYSTA 0x0064 #define PORT_KEYCMD 0x0064 #define KEYSTA_SEND_NOTREADY 0x02 #define KEYCMD_WRITE_MODE 0x60 #define KBC_MODE 0x47 void wait_KBC_sendready(void) { /* 等待鍵盤控制電路準備完畢 */ for (; ; ) { if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { break; } } return; } void init_keyboard(void) { /* 初始化鍵盤控制電路 */ wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); wait_KBC_sendready(); io_out8(PORT_KEYDAT, KBC_MODE); return; }
首先我們來看函數wait_KBC_sendready。它的作用是,讓鍵盤控制電路(keyboard controller, KBC)做好準備動作,等待控制指令的到來。為什么要做這個工作呢?是因為雖然CPU的電路很快,但鍵盤控制電路卻沒有那么快。如果CPU不顧設備接收數據的能力,只是一個勁兒地發指令的話,有些指令會得不到執行,從而導致錯誤的結果。如果鍵盤控制電路可以接受CPU指令了,CPU從設備號碼0x0064處所讀取的數據的倒數第二位(從低位開始數的第二位)應該是0。在確認到這一位是0之前,程序一直通過for語句循環查詢。
break語句是從for循環中強制退出的語句。退出以后,只有return語句在那里等待執行,所以,把這里的break語句換寫成return語句,結果一樣。
下面看函數init_keyboard。它所要完成的工作很簡單,也就是一邊確認可否往鍵盤控制電路傳送信息,一邊發送模式設定指令,指令中包含著要設定為何種模式。模式設定的指令是0x60,利用鼠標模式的模式號碼是0x47,當然這些數值必須通過調查才能知道。我們可以從老地方得到這些數據。
這樣,如果在HariMain函數調用init_keyboard函數,鼠標控制電路的準備就完成了。
■■■■■
現在,我們開始發送激活鼠標的指令。所謂發送鼠標激活指令,歸根到底還是要向鍵盤控制器發送指令。
bootpack.c節選
#define KEYCMD_SENDTO_MOUSE 0xd4 #define MOUSECMD_ENABLE 0xf4 void enable_mouse(void) { /* 激活鼠標 */ wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); wait_KBC_sendready(); io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); return; /* 順利的話,鍵盤控制其會返送回ACK(0xfa)*/ }
這個函數與init_keyboard函數非常相似。不同點僅在于寫入的數據不同。如果往鍵盤控制電路發送指令0xd4,下一個數據就會自動發送給鼠標。我們根據這一特性來發送激活鼠標的指令。
另一方面,一直等著機會露臉的鼠標先生,收到激活指令以后,馬上就給CPU發送答復信息:“OK,從現在開始就要不停地發送鼠標信息了,拜托了。”這個答復信息就是0xfa。
因為這個數據馬上就跟著來了,即使我們保持鼠標完全不動,也一定會產生一個鼠標中斷。
■■■■■
所以,我們將enable_mouse也做成了從HariMain中調用的形式。好,我們馬上測試一下。運行“make run”。

鼠標中斷終于出來了。這可是很了不起的進步喲。
- 構建高可用Linux服務器(第4版)
- Kubernetes網絡權威指南:基礎、原理與實踐
- STM32庫開發實戰指南:基于STM32F4
- 注冊表應用完全DIY
- Troubleshooting Docker
- Windows 7使用詳解(修訂版)
- Linux系統安全:縱深防御、安全掃描與入侵檢測
- 操作系統之哲學原理第2版
- 15分鐘!畫出我的漫畫角色:賣萌篇
- Unity AR/VR開發:實戰高手訓練營
- UNIX傳奇:歷史與回憶
- Microsoft DirectAccess Best Practices and Troubleshooting
- SQL Server on Azure Virtual Machines
- VMware ESXi Cookbook
- Oracle Goldengate 11g Complete Cookbook