11.设备驱动程序
? ? ? ? 經過對高級中斷處理單元的學習。本章實現鍵盤,鼠標及IDE硬盤的設備驅動程序。如此,不但可以驗證APIC設備的功能設置和高級中斷管理單元的運行邏輯,還可使操作系統具備更加完善的輸入輸出及存儲能力。
? ? ? ? 本章將涉及鍵盤,鼠標控制器的配置,鍵盤掃描碼的解析,鼠標數據包格式的解析,硬盤控制器協議的使用等知識點。
11.1.鍵盤和鼠標驅動程序
? ? ? ? 第4章就初步實現了鍵盤驅動程序,但尚未對鍵盤控制器的功能或原理進行過多描述,僅提及Intel 8042鍵盤控制器的讀寫方式和鍵盤掃描碼等知識。
? ? ? ? 對鍵盤控制器而言,它不僅可控制鍵盤設備,同時還有諸多富余引腳可控制其他設備或功能,鼠標控制器就是依附于鍵盤控制器的子設備。
? ? ? ? 本節會對鍵盤及鼠標控制器進行講解,并實現鍵盤和鼠標設備驅動程序,鍵盤掃描碼解析功能和鼠標協議解析功能。
11.1.1.鍵盤和鼠標控制器
? ? ? ? 鍵盤和鼠標作為電腦的基礎輸入設備。由于鍵盤的按鍵數量龐大,從而無法像單片機的按鍵那樣通過微動開關和去抖動電路,直接將其連接到處理器(或中斷控制器)的中斷請求引腳。同理,鼠標設備也不能使用這種方式向處理器發送數據,它們都必須借助控制器才能向處理器發送中斷請求和數據。
? ? ? ? 對于現代電腦,其主板中都集成有Intel 8042鍵盤控制器或兼容芯片,該芯片不光用于控制鍵盤設備,還控制著A20地址線的開啟,系統重啟及操作鼠標控制器等功能。
? ? ? ? 上圖涵蓋了Intel 8042鍵盤控制器支持的常用功能,大體上可分為8042控制器,鍵盤控制器(PS/2接口),鼠標控制器(PS/2接口)三部分。下面將對它們逐一講解。
? ? ? ? 1.Intel 8042鍵盤控制器
? ? ? ? Intel 8042鍵盤控制器除了可與鍵盤鼠標外設進行交互外,還擁有幾組用于控制諸如A20地址線,系統重啟,屏幕顏色,擴展內存等功能的引腳,通過I/O端口0x60和0x64可訪問8042鍵盤控制器,進而管理這些功能。
? ? ? ? 1.1.Intel 8042鍵盤控制器的操作端口
? ? ? ? 端口0x60和0x64都是1B的雙向讀寫I/O端口地址,它們不光可向Intel 8042鍵盤控制器發送數據,還可向鍵盤發送數據。由于I/O端口的數據位寬有限,因此,不管是控制Intel 8042鍵盤控制器,還是控制鍵盤鼠標,都需采用命令加參數的通信方式。
| 端口 | 讀寫 | 名稱 | 功能描述 |
| 0x60 | 讀 | 輸出緩沖區 | 返回鍵盤掃描碼或8042鍵盤控制器發來的數據 |
| 0x60 | 寫 | 輸入緩沖區 | 可向鍵盤發送命令(如命令帶參數,隨后再向該端口發送參數),或向8042鍵盤控制器發送命令參數 |
| 0x64 | 讀 | 控制器狀態 | 返回8042鍵盤控制器的狀態,其各位功能描述如下: bit 7=1:說明與鍵盤通信時發生奇偶校驗錯誤 bit 6=1:說明接收鍵盤數據超時 bit 5=1:說明鼠標輸出緩沖區已滿 bit 4=0:禁止鍵盤 bit 3:記錄上次操作的端口號(鍵盤控制器內部使用),1為0x64端口,0為0x60端口。 bit 2=1:說明控制器已完成自檢 bit 1=1:說明鍵盤輸入緩沖區已滿 bit 0=1:說明鍵盤輸出緩沖區已滿 |
| 0x64 | 寫 | 控制器命令 | 向8042鍵盤控制器發送控制命令 |
? ? ? ? 1.2.Intel 8042鍵盤控制器的控制命令
? ? ? ? 系統可通過向I/O端口0x64發送1B的控制命令操作8042鍵盤控制器,如該命令需附加參數,則再向I/O端口0x60發送命令數值。對某些返回應答數據的控制命令,其應答數據將發往端口0x60。
? ? ? ? 下表已列舉出常用的控制命令,其中就包括用于控制鼠標的D4h命令,控制外圍端口的輸入輸出命令及測試端口命令。
| 命令 | 參數 | 返回值 | 功能描述 |
| 20h | 無 | 有 | 讀取鍵盤的配置值 |
| 60h | 有 | 無 | 向鍵盤發送配置命令,配置值(參數)各位的功能如下。 bit 7=0:0 bit 6=1:在掃描碼存入輸入緩存區前,將其轉換為第一套掃描碼。 bit 5=0:使能鼠標設備 bit 4=0:使能鍵盤設備 bit 3=0:0 bit 2=1:通知系統已完成熱啟動測試及初始化 bit 1=1:使能鼠標中斷IRQ12(MIBF) bit 0=1:使能鍵盤中斷IRQ1(IBF) |
| A7h | 無 | 無 | 禁止鼠標端口 |
| A8h | 無 | 無 | 開啟鼠標端口 |
| A9h | 無 | 有 | 鼠標端口自檢測試,返回值00h表示正常 |
| AAh | 無 | 有 | 控制器自檢測試,返回值55h表示正常 |
| ABh | 無 | 有 | 鍵盤端口自檢測試,返回值00h表示正常 |
| ADh | 無 | 無 | 禁止鍵盤通信,自動復位控制器狀態的第4位 |
| AEh | 無 | 無 | 開啟鍵盤通信,自動置位控制器狀態的第4位 |
| C0h | 無 | 有 | 讀輸入端口P1 |
| D0h | 無 | 有 | 讀輸出端口P2 |
| D1h | 有 | 無 | 寫輸出端口P2 |
| D2h | 有 | 無 | 把參數寫入到鍵盤緩沖區,就如同從鍵盤收到數據一樣 |
| D3h | 有 | 無 | 把參數寫入到鼠標緩沖區,就如同從鼠標收到數據一樣 |
| D4h | 有 | 無 | 向鼠標設備發送數據 |
| E0h | 無 | 無 | 讀測試端口P3 |
| FEh | 無 | 無 | 系統重啟 |
? ? ? ? 在這些常用命令中,20h和60h命令是控制鍵盤鼠標必備的命令,而命令C0h,D0h,D1h,E0h則用于控制輸入,輸出及測試端口各引腳的狀態值。這些引腳的功能各不相同。
| 輸入端口P1(Port1) | 輸出端口P2(Port2) | 測試端口P3(Port3) | |||
| 引腳 | 功能描述 | 引腳 | 功能描述 | 引腳 | 功能描述 |
| 0 | 鍵盤數據 | 0 | 系統重啟 | 0 | 鍵盤時鐘 |
| 1 | 鼠標數據 | 1 | A20地址線 | 1 | 鍵盤數據 |
| 2 | 2 | 鼠標數據 | 2 | ||
| 3 | 3 | 鼠標時鐘 | 3 | ||
| 4 | 4 | 鍵盤IBF中斷 | 4 | ||
| 5 | 5 | 鼠標IBF中斷 | 5 | ||
| 6 | 6 | 鍵盤時鐘 | 6 | ||
| 7 | 7 | 鍵盤數據 | 7 | ||
? ? ? ? 在這些端口引腳中,本系統可能會用到Port2端口的Pin0和Pin1引腳,剩余引腳使用頻率非常低。這兩個引腳分別控制著系統重啟功能和A20地址線。
? ? ? ? 1.3.A20地址線功能
? ? ? ? 第4章就已經對A20地址線的作用和開啟方法進行了講解,并用代碼實現了一種快速開啟A20地址線的方式。此處通過拉高Port2端口Pin1引腳的電平來開啟A20地址線的方式,在執行速度方面相對較慢,這種開啟方式僅供讀者參數。
? ? ? ? 1.4.系統重啟方式
? ? ? ? 通過拉低Port2端口的Pin0引腳可使系統重啟,或向I/O端口0x64發送控制命令FEh來重啟系統。
? ? ? ? 2.鍵盤控制器
? ? ? ? 鍵盤是計算機的一種重要輸入設備,它的工作原理是通過類8048鍵盤編碼器芯片不停地掃描鍵盤上的每一個按鍵,一旦發現有按鍵被按下或抬起,8048鍵盤編碼器芯片便立即將按鍵對應的鍵盤掃描碼發送至類8042鍵盤控制器。而類8042鍵盤控制器會將數據解析后保存到輸入緩沖區中,并觸發鍵盤按鍵中斷請求。
? ? ? ? 8048鍵盤編碼器芯片共定義三套不同格式的鍵盤掃描碼,現代鍵盤默認采用第二套鍵盤掃描碼,但為了兼容以前的XT鍵盤,8042鍵盤控制器在接收到鍵盤掃描碼后,都默認將其轉換為第一套鍵盤掃描碼。通過向I/O端口0x60發送鍵盤命令可修改默認的鍵盤掃描碼。
? ? ? ? 2.1.鍵盤命令
? ? ? ? Intel 8042鍵盤控制器為我們準備了豐富的鍵盤控制命令,這些命令依然通過I/O端口0x60發往鍵盤控制器。如命令需攜帶參數,則緊隨命令之后參數再寫入到0x60端口,一些鍵盤命令會在執行后回送應答數據(0xFA)。
| 命令 | 參數 | 返回值 | 功能描述 |
| FFh | 無 | 有 | 重啟鍵盤 |
| FEh | 無 | 無 | 重新發送上一字節 |
| F6h | 無 | 無 | 使用默認按鍵速率 |
| F5h | 無 | 無 | 停止鍵盤掃描 |
| F4h | 無 | 無 | 開啟鍵盤掃描 |
| F3h | 有 | 無 | 設置按鍵速率 |
| F2h | 無 | 有 | 獲取鍵盤的設備ID號(2B) |
| F0h | 有 | 無 | 設置鍵盤使用的掃描碼集,可用參數值如下: 0x0:取得當前掃描碼(有返回值) 0x1:代表第一套掃描碼 0x2:代表第二套掃描碼 0x3:代表第三套掃描碼 |
| EEh | 無 | 有 | 鍵盤回復EEh |
| EDh | 有 | 無 | 控制LED燈亮滅,參數各位功能說明如下: 位2:Caps Lock燈1(亮)、0(滅) 位1:Num Lock燈1(亮)、0(滅) 位0:Scroll Lock燈1(亮)、0(滅) |
? ? ? ? 2.2.鍵盤掃描碼
? ? ? ? XT型鍵盤使用的鍵盤掃描碼稱為第一套鍵盤掃描碼,它僅使用1B數據就描述了絕大部分按鍵的按下與抬起狀態。相比下,第二套和第三套鍵盤掃描碼需更多數據來描述按鍵狀態。鑒于第一套鍵盤掃描碼數據量小,便于解析,且鍵盤控制器在默認下仍將接收到的數據轉換為第一套鍵盤掃描碼,所以本系統也采用第一套鍵盤掃描碼來描述按鍵狀態。
? ? ? ? 3.鼠標控制器
? ? ? ? 鼠標和鍵盤都被接入到鍵盤控制器的PS/2接口上,由此可見,鼠標設備的控制方法與鍵盤設備類似。在之前表列出的鍵盤控制器命令中,已經提供了向鼠標設備發送數據的控制命令D4h,通過向I/O端口0x64發送控制命令D4h,8042鍵盤控制器就可將I/O端口0x60保存的鼠標控制命令發送至鼠標設備。
? ? ? ? 3.1.鼠標控制命令
? ? ? ? Intel 8042鍵盤控制器同樣為我們準備了豐富的鼠標控制命令。大部分鼠標控制命令在執行結束后都會向8042鍵盤控制器發送應答數據(0xFA)。
| KEY | MAKE | BREAK | KEY | MAKE | BREAK | KEY | MAKE | BREAK |
| A | 1E | 9E | 9 | 0A | 8A | [ | 1A | 9A |
| B | 30 | B0 | ' | 29 | A9 | INSERT | E0,52 | E0,D2 |
| C | 2E | AE | - | 0C | 8C | HOME | E0,47 | E0,C7 |
| D | 20 | A0 | = | 0D | 8D | PG UP | E0,49 | E0,C9 |
| E | 12 | 92 | \ | 2B | AB | DELETE | E0,53 | E0,D3 |
| F | 21 | A1 | BKSP | 0E | 8E | END | E0,4F | E0,CF |
| G | 22 | A2 | SPACE | 39 | B9 | PG DN | E0,51 | E0,D1 |
| H | 23 | A3 | TAB | 0F | 8F | U ARROW | E0,48 | E0,C8 |
| I | 17 | 97 | CAPS | 3A | BA | L ARROW | E0,4B | E0,CB |
| J | 24 | A4 | L SHFT | 2A | AA | D ARROW | E0,50 | E0,D0 |
| K | 25 | A5 | L CTRL | 1D | 9D | R ARROW | E0,4D | E0,CD |
| L | 26 | A6 | L GUI | E0,5B | E0,DB | NUM | 45 | C5 |
| M | 32 | B2 | L ALT | 38 | B8 | KP/ | E0,35 | E0,B5 |
| N | 31 | B1 | R SHFT | 36 | B6 | KP* | 37 | B7 |
| O | 18 | 98 | R CTRL | E0,1D | E0,9D | KP- | 4A | CA |
| P | 19 | 99 | R GUI | E0,5C | E0,DC | KP+ | 4E | CE |
| Q | 10 | 90 | R ALT | E0,38 | E0,B8 | KP EN | E0,1C | E0,9C |
| R | 13 | 93 | APPS | E0,5D | E0,DD | KP. | 53 | D3 |
| S | 1F | 9F | ENTER | 1C | 9C | KP 0 | 52 | D2 |
| T | 14 | 94 | ESC | 01 | 81 | KP 1 | 4F | CF |
| U | 16 | 96 | F1 | 3B | BB | KP 2? | 3F | CF |
| V | 2F | AF | F2 | 3C | BC | KP 3 | 51 | D1 |
| W | 11 | 91 | F3 | 3D | BD | KP 4 | 4B | CB |
| X | 2D | AD | F4 | 3E | BE | KP 5 | 4C | CC |
| Y | 15 | 95 | F5 | 3F | BF | KP 6 | 4D | CD |
| Z | 2C | AC | F6 | 40 | C0 | KP 7 | 47 | C7 |
| 0 | 0B | 8B | F7 | 41 | C1 | KP 8 | 48 | C8 |
| 1 | 02 | 82 | F8 | 42 | C2 | KP 9 | 49 | C9 |
| 2 | 03 | 83 | F9 | 43 | C3 | ] | 1B | 9B |
| 3 | 04 | 84 | F10 | 44 | C4 | ; | 27 | A7 |
| 4 | 05 | 85 | F11 | 57 | D7 | ' | 28 | A8 |
| 5 | 06 | 86 | F12 | 58 | D8 | . | 33 | B3 |
| 6 | 07 | 87 | PRNT SCRN | E0,2A E0,37 | E0,B7 E0,AA | . | 34 | B4 |
| 7 | 08 | 88 | SCROLL | 46 | C6 | / | 35 | B5 |
| 8 | 09 | 89 | PAUSE | E1,1D,45 E1,9D,C5 | - | - | - | - |
| 命令 | 功能描述 |
| FFh | 重啟鼠標 |
| FEh | 重新發送上一條數據包 |
| F6h | 使用默認采樣率100hZ,分辨率4 pixel/mm |
| F5h | 禁止鼠標設備發送數據包 |
| F4h | 允許鼠標設備發送數據包 |
| F3h | 設置鼠標采樣率 |
| F2h | 獲得鼠標設備的ID號 |
? ? ? ? 3.2.鼠標數據包格式
? ? ? ? 與鍵盤設備不同,鼠標設備上報的數據并非鍵盤掃描碼,而是一個數據包。數據包記錄著鼠標移動軌跡和當前按鍵狀態, 數據包根據鼠標設備的ID號可進一步分為3B和4B兩種數據包。當鼠標設備的ID號為3或4時,鼠標設備才會發送第4字節數據,但大部分鼠標設備的ID號為0。
Byte1: Y溢出 X溢出 Y符號位 X符號位 1 鼠標中鍵 鼠標右鍵 鼠標左鍵
Byte2: X移動值
Byte3: Y移動值
Byte4: Z移動值? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ID值為3
Byte5: 0 0 鼠標第5鍵 鼠標第4鍵 Z3 Z2 Z1 Z0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ID值為4
? ? ? ? 從上表可知,4B數據包還可根據鼠標設備ID號詳細分為兩種格式。當鼠標設備的ID號為3時,數據包的第4字節記錄著鼠標垂直滾輪的移動值(Z移動值);當鼠標設備的ID號為4時,數據包的第4字節記錄著鼠標擴展按鍵狀態(第4/5按鍵)和滾輪移動值(Z0~3)。
| 名稱 | 功能描述 |
| X/Y溢出 | 表示X或Y方向數值溢出,并丟棄整個數據包 |
| X/Y符號位 | 表示鼠標在平面直角坐標系內的移動方向 |
| X/Y/Z移動值 | 記錄X,Y或Z方向的移動值 |
| 左/中/右/第4/第5按鍵 | 記錄鼠標按鍵狀態 |
| Z0~3 | 記錄鼠標滾輪滾動方向 |
? ? ? ? 上表的X/Y表示鼠標相對上一個采集點的移動方向和距離,它們皆是由符號位和移動值組成的9位二進制補碼,符號位代表移動方向。而Z表示鼠標滾輪的滾動方向和距離,其表示方法與X/Y相同,下表描述了水平滾輪和垂直滾輪的4個滾動方向。
| Z0~3 | 功能描述 |
| 0 | 無滾動 |
| 1 | 垂直向上滾動 |
| F | 垂直向下滾動 |
| 2 | 水平向右滾動 |
| E | 水平向左滾動 |
? ? ? ? 鼠標雙擊不是硬件邏輯,而是借助軟件邏輯實現的。
11.1.2.完善鍵盤驅動
? ? ? ? 雖然章節4已經粗略實現了一個獲得鍵盤掃碼碼的中斷處理函數,但尚未達到一個鍵盤設備驅動程序的級別。本節就將這個鍵盤中斷處理函數升級為鍵盤驅動程序。
? ? ? ? 1.鍵盤初始化函數
? ? ? ? 編寫設備驅動程序前,通常會為設備驅動定義一系列結構體來描述設備的獨有特性,鍵盤驅動程序也不例外。首先為鍵盤設備定義結構體來描述它的獨有特性,并定義一些宏常量使操作寄存器的過程更易于理解。
? ? ? ? struct keyboard_inputbuffer便是此次用于描述鍵盤設備的結構體。
? ? ? ? 這個結構體為鍵盤設備定義了一個100B的循環隊列緩沖區,緩沖區首尾指針及緩沖數據計數器。代碼還為鍵盤驅動程序準備了一些便于理解的宏常量,以提升驅動程序的可讀性。
? ? ? ? 代碼定義了鍵盤控制器的I/O端口,命令,及初始數值等相關宏常量。
| 宏常量名 | 數值 | 功能描述 |
| PORT_KB_DATA | 0x60 | I/O端口0x60 |
| PORT_KB_STATUS | 0x64 | I/O端口0x64 |
| PORT_KB_CMD | 0x64 | I/O端口0x64 |
| KBCMD_WRITE_CMD | 0x60 | 向鍵盤發送配置命令,KB_INIT_MODE是命令參數 |
| KBCMD_READ_CMD | 0x20 | 讀取鍵盤的配置值 |
| KB_INIT_MODE | 0x47 | 發往鍵盤的配置值,其各位的設置狀態如下: bit 7=0:0 bit 6=1: 在掃描碼存入輸入緩存區前,將其轉換為第一套掃描碼 bit 5=0: 使能鼠標 bit 4=0: 使能鍵盤 bit 3=0: 0 bit 2=1: 通知系統已完成熱啟動測試及初始化 bit 1=1: 使能鼠標中斷IRQ12(M!BF) bit 0=1: 使能鍵盤中斷IRQ1(IBF) |
? ? ? ? 除此之外,還定義了一對宏函數來檢測輸入/輸出緩沖區是否已滿,檢測方法是讀取I/O端口0x64的控制器狀態位。
? ? ? ? 此番準備后,就實現鍵盤的初始化(掛載)函數keyboard_init。鍵盤的初始化過程不光需要對鍵盤控制器進行配置,還需對I/O APIC的I/O中斷定向投遞寄存器(RTE表項)進行配置。
? ? ? ? 程序起始處,定義了一些全局變量。用于記錄功能鍵的按鍵狀態,這些全局變量會在keyboard_init函數中被初始化。函數keyboard_init的首要任務是動態創建struct keyboard_inputbuffer結構體的存儲空間,并對其進行初始化賦值。
? ? ? ? 隨后,再對I/O APIC的RTE1表項進行配置,進而將鍵盤設備的中斷請求投遞至Local APIC ID為0的處理器核心(BSP處理器)中。
? ? ? ? 緊接著,通過向鍵盤控制器發送控制命令使能鍵盤設備和IRQ1中斷請求。此處,還使能了鼠標設備及IRQ12中斷請求。由于現在鼠標設備對應的RTE表項寄存器仍處于屏蔽狀態,因此不會響應鼠標發出的中斷請求。接下來的一百萬次無操作(nop宏函數封裝著匯編指令NOP,即無操作指令)循環只是為了拖延時間,使低速的鍵盤控制器把控制命令執行完。最后,調register_irq函數向系統注冊鍵盤設備的中斷處理程序。
? ? ? ? 雖然本系統目前無法實現驅動程序的動態掛載與卸載,但驅動卸載函數作為驅動程序的一部分是必不可少的。
? ? ? ? 卸載過程非常簡單,只需調中斷注銷函數,再釋放struct keyboard_inputbuffer。
? ? ? ? 關于注冊鍵盤中斷處理程序時使用的中斷處理接口keyboard_int_controller,它是采用此前已編寫好的操作接口封裝而成的。
·????????2.鍵盤中斷處理函數
? ? ? ? ?在鍵盤驅動初始化函數中,還有一個函數未介紹。那就是鍵盤中斷處理函數(中斷上半部處理函數)。鍵盤中斷處理函數的主要任務是從I/O端口0x60讀取鍵盤掃描碼,并將其存入struct keyboard_inputbuffer結構體內的循環隊列緩沖區,再調整循環隊列緩沖區首尾指針及緩沖區計數器。
? ? ? ? 至此,鍵盤驅動程序已基本實現。下面對do_IRQ進行調整。
? ? ? ? 3.鍵盤掃描碼解析函數
? ? ? ? 如此刻測試鍵盤驅動程序,內核只能打印出鍵盤掃描碼。根據前文,我們只有解析了鍵盤掃描碼后,才能分辨出按鍵字符。現在去實現鍵盤掃描碼解析函數。
? ? ? ? 為了讓鍵盤掃描碼解析函數可快速檢索出掃描碼的按鍵,特將鍵盤掃描碼歸納為三類,第一類是以0xE1開頭的PauseBreak鍵,第二類是以0xE0開頭的功能鍵,第三類是1B普通按鍵。
? ? ? ? 再實現鍵盤掃描碼解析函數前,依然要定義一些宏常量。
? ? ? ? 在這些宏常量中,NR_SCAN_CODES*MAP_COLS描述了一個由第三類鍵盤掃描碼組成的一維數組的長度,共128個按鍵,每個按鍵包含普通按鍵和Shift加普通按鍵兩種狀態;宏常量PAUSEBREAK,PRINTSCREEN和OTHERKEY表示第一類和第二類特殊按鍵。
? ? ? ? 一維數組keycode_map_normal里的按鍵字符是根據鍵盤掃描碼值升序排列到數組中,而數組pausebreak_scode值保存著PauseBreak鍵的掃描碼值。
? ? ? ? 此刻,解析鍵盤掃描碼的絕大部分準備工作已經就緒,馬上進入鍵盤掃描碼解析函數analysis_keycode的實現。
? ? ? ? 鍵盤掃描碼解析函數入口部分,它先為幾個局部變量開辟了棧存儲空間,再通過get_scancode從鍵盤循環隊列緩沖區中讀取1B數據到局部變量x中,并對局部變量x的數值進行判斷。
? ? ? ? 當局部變量x的數值為0xE1時,則繼續從鍵盤循環隊列緩沖區中讀取數據,并與第一類鍵盤掃描碼數組中的元素進行逐個比對,如數值完全相同,就認為PauseBreak鍵被按下。如局部變量x的數值不為0xE1,則繼續檢索其他兩類鍵盤掃描碼。
? ? ? ? 代碼中的get_scancode函數通過讀取鍵盤驅動程序的循環隊列緩沖區,將中斷處理函數捕獲的鍵盤掃描碼傳遞給鍵盤掃描碼解析函數。
? ? ? ? 如循環隊列緩沖區為空,則等待鍵盤發送數據。否則從循環隊列緩沖區中讀取1B數據返回給函數調用者,并在函數返回前調整緩沖區首尾指針及緩沖區計數器。
? ? ? ? 既然按鍵不屬于第一類鍵盤掃描碼,則通過代碼檢測按鍵是否屬于第二類鍵盤掃描碼,其檢測過程依然采用逐個字節匹配法。
? ? ? ? 代碼只對Print Screen,Right Ctrl,Right Alt三個第二類鍵盤掃描碼進行檢測,其他按鍵暫時忽略。如檢測出相匹配的鍵盤掃描碼,則用key, ctrl_r或alt_r變量進行記錄。如局部變量x的數值也不屬于第二類鍵盤掃描碼,則繼續檢索第三類鍵盤掃描碼。
? ? ? ? 代碼先判斷局部變量key的數值,以確定其是否與第一類或第二類鍵盤掃描碼匹配成功,如未匹配成功,則通過本段程序與第三類鍵盤掃描碼匹配。
? ? ? ? 匹配過程的第一步是通過代碼make=(x&FLAG_BREAK?0:1);判斷鍵盤掃描碼描述的是按下狀態還是抬起狀態;接著,再使用keyrow=&keycode_map_normal[(x&0x7F)*MAP_COLS];計算出鍵盤掃描碼在數組中的位置;然后,根據左右Shift鍵的狀態來確定局部變量key應該保存Shift位置的字符,還是unShift位置的字符。
? ? ? ? 如當前按下的是功能鍵,則執行相應的操作,否則將變量key保存的字符打印出來。?
? ? ? ? 至此,鍵盤掃描碼解析函數實現完畢,下面進入驅動程序測試階段。操作系統已將鍵盤初始化函數keyboard_init加入到內核主程序中,并循環調analysis_keycode獲取按鍵字符。
? ? ? ? 將編譯鏈接后的內核程序置于物理平臺運行,敲擊鍵盤按鍵,系統就會打印出鍵盤掃描碼值及其對應的字符。
11.1.3.實現鼠標驅動
? ? ? ? 盡管在鍵盤驅動程序中鼠標設備和IRQ12中斷請求已經使能,但滑動鼠標或滑鼠卻無法使系統作為任何反應。
? ? ? ? 現在實現鼠標驅動程序。
? ? ? ? 1.鼠標初始化函數
? ? ? ? 在編寫驅動程序前,需為鼠標驅動設計結構體來描述它的獨有特性。雖然PS/2接口的鼠標外設附屬于鍵盤控制器,但鼠標傳輸的數據信息卻與鍵盤截然不同。
? ? ? ? 代碼共為鼠標驅動定義了三個宏常量,分別代表發往鼠標的控制命令,發往鍵盤控制器的命令。
| 宏常量名 | 數值 | 功能描述 |
| KBCMD_SENDTO_MOUSE | 0xd4 | 向鼠標設備發送數據 |
| MOUSE_ENABLE | 0xf4 | 允許鼠標發送數據包 |
| KBCMD_EN_MOUSE_INTFACE | 0xa8 | 開啟鼠標端口 |
? ? ? ? 由于ThinkPad X220T的滑鼠采用3B數據包,故此采用struct mouse_packet結構體來描述鼠標的數據包。
? ? ? ? 接著實現鼠標的初始化函數mouse_init。
? ? ? ? 按設備驅動程序的初始化慣例,mouse_init將先為鼠標設備動態申請并初始化結構體存儲空間,結構體struct keyboard_inputbuffer不但可用來保存鍵盤掃描碼,還可用來保存鼠標數據包。隨后是對RTE12表項(I/O APIC的I/O中斷定向投遞寄存器)的配置過程。
? ? ? ? 接著,通過register_irq函數向系統注冊鼠標設備的中斷處理程序,并使用I/O端口操作函數設置鍵盤控制器和鼠標設備,進而完成鼠標設備的初始化工作。
? ? ? ? 至于鼠標中斷處理接口mouse_int_controller和卸載函數mouse_exit,它們與鍵盤驅動的代碼實現相似。鼠標中斷上半部處理函數mouse_handler亦如此。不過其中顯示的不再是鍵盤掃描碼而是鼠標數據包。
? ? ? ? 2.鼠標數據包解析函數
? ? ? ? 程序通過get_mousecode從鼠標循環隊列緩沖區讀取1B數據,再根據全局變量mouse_count的計數值將這1B數據填入struct mouse_packet結構體的成員變量中,并調整mouse_count的計數值。
? ? ? ? 當mouse_count值為3時,說明鼠標驅動此時已接收完整的一包數據,就將這3B數據打印出來。雖說X/Y是9位的二進制補碼,但其在本系統物理平臺的移動量幾乎不超過70,而且此處只為驗證運行效果,使用8位的char類型表示足以。
? ? ? ? 初始化鼠標設備時,鼠標驅動曾向鼠標設備發送過控制命令,為跳過控制命令返回的應答數據0xFA,特將全局變量mouse_count的初始值設為0,并把鼠標中斷處理程序的注冊過程置于發送控制命令前。
11.2.硬盤驅動程序
? ? ? ? 雖然硬盤驅動程序的軟件結構較鼠標,鍵盤驅動程序復雜很多,但功能和操作方式與軟盤,U盤類似。
? ? ? ? 硬盤設備與軟盤設備在機械結構,操作方式上十分相似,第三章已對軟盤設備有所涉及,但當時的軟盤扇區讀取操作完全依賴于BIOS中斷服務程序。
? ? ? ? 此刻,處理器已運行在IA-32e模式,驅動程序不能也不應該借助BIOS。為加深對驅動程序的理解,也為了給學習文件系統打下基礎,現在是探索硬盤設備的時候了。
11.2.1.硬盤設備初探
? ? ? ? 鑒于硬盤設備的數據傳輸過程是異步操作,其驅動程序的邏輯結構比較復雜。
? ? ? ? 為快速掌握硬盤設備操作方法,本節以基礎概念和操作方法的講解為主,至于硬盤驅動程序的邏輯結構將在后續章節予以講解。
? ? ? ? 1.硬盤設備概述
? ? ? ? 不論是硬盤設備,軟盤設備還是U盤設備,它們與鍵盤,鼠標等設備的最大區別在于它們以數據塊(扇區)作為傳輸單位,而非字節,這類設備統稱為塊設備。與塊設備相對的是字符設備(或稱字節流設備),諸如鼠標,鍵盤,串口等。
? ? ? ? 作為同屬塊設備的硬盤和軟盤,它們將整張磁盤片分為磁頭,磁道,扇區三部分。多張這樣的磁盤片便組成了一塊機械硬盤。
? ? ? ? 上圖,主軸由電機制動,其上固定著多張磁盤片,使得磁盤片向固定方向勻速旋轉。磁頭臂通過往復移動,從而將磁頭移至目標磁道上去讀取目標扇區內的數據。通常下,機械硬盤的平均尋道時間是一個非常重要的性能指標。目前,大多數機械硬盤的平均尋道時間為十幾毫秒,因此合理的排列扇區讀寫順序可有效降低尋道浪費的時間。
? ? ? ? 對于軟盤,硬盤及光盤等存儲介質,處理器無法像訪問內存地址一樣直接訪問磁盤扇區中的數據,需借助磁盤控制器才能對磁盤進行操作。磁盤控制器往往掛載于PCI總線或LPC總線下,下圖描繪了磁盤控制器在總線中的掛載位置。
? ? ? ? 之前圖的軟盤部分僅供讀者了解,這里重點介紹硬盤。
? ? ? ? SATA控制器用于操作硬盤或光驅等存儲設備,它通過向存儲設備發送ATA/ATAPI規范命令來操作存儲設備。為了兼容IDE接口的硬盤設備,SATA控制器通常會支持IDE操作模式和AHCI操作模式,通過BIOS的配置選項可在這兩種模式間自由切換。
? ? ? ? 下面將對描述中提及的名詞,硬盤操作模式的切換方法,ATA/ATAPI規范命令及本系統選用的硬盤操作模式予以講解。
? ? ? ? 1.名詞解釋
? ? ? ? 1.1.IDE。
? ? ? ? IDE代表了一種硬盤傳輸接口,這種接口連接著一個集硬盤控制器和磁盤片于一身的硬盤驅動器。更高級的EIDE傳輸接口可達到100MB/s的傳輸速度。
? ? ? ? 1.2.ATA
? ? ? ? IDE接口描述的是標準連接方式,ATA接口才是這類硬盤真正的名字。IDE只是通俗稱呼。經過多年發展,ATA規范擴展了多個版本。
| 版本 | 特點描述 |
| ATA-1 | 支持主,從兩個設備,支持PIO和DMA傳輸模式,傳輸速率只有3.3MS/s |
| ATA-2 | ATA-2是對ATA-1的擴展,也就是EIDE;支持CHS和LBA尋址模式,最高傳輸速率提高到16.6MB/s |
| ATA-3 | 引入S.M.A.R技術 |
| ATA-4 | 正是支持Ultra DMA數據傳輸模式,并引入冗余校驗技術,傳輸速度提升至33MB/s |
| ATA-5 | ATA-5也叫做Ultra DMA66或ATA66,傳輸速度提升至66MB/s |
| ATA-6 | ATA-6也稱為ATA100,在ATA33和ATA66的基礎上將傳輸速度提升至100MB/s |
| ATA-7 | ATA-7也稱為ATA133,傳輸速度進一步提升至133MB/s,由于硬件瓶頸,導致生產商轉而研發新型硬盤接口標準 |
| ATA-8 | ATA8標準包括AST,APT,ACS,AAM四卷,其中新增NCQ指令,亂序執行 |
? ? ? ? 目前,ATA規范描述的硬盤接口可分為PATA和SATA兩種。
? ? ? ? 1.2.1.PATA
? ? ? ? 并行ATA硬盤接口。已經退出舞臺。
? ? ? ? 1.2.2.SATA
? ? ? ? 1.3.ATAPI
? ? ? ? ATAPI接口是CD/DVD或其他驅動器的ATA接口
? ? ? ? 1.4.SAS
? ? ? ? SAS串行接口是繼SCSI并行接口后開發的新一代磁盤接口,它與SATA接口在物理層和協議層完全兼容。從接口標準而言,SATA是SAS子標準,故,SAS控制器可直接操作SATA接口的硬盤。
? ? ? ? 2.硬盤操作模式的選擇
? ? ? ? AHCI操作模式是SATA控制器的標準硬盤操作模式,但SATA控制器為兼容ATA接口的硬盤,特意在BIOS控制器中提供了配置選項供用戶在兩種操作模式間切換。
? ? ? ? SATA Controller Mode Option選項用于選擇硬盤操作模式,AHCI選項為SATA控制器的標準硬盤操作模式,而Compatibility選項為兼容ATA接口的硬盤操作模式。
? ? ? ? 3.ATA控制命令
? ? ? ? ATA8是ATA規范的最先版本,這些命令不僅包括磁盤扇區的讀寫操作,還包括讀/寫/刷新緩存操作,安全設置操作,磁盤機能配置操作,硬盤新型檢測操作等。
| 命令 | 功能描述 |
| ECh | 硬件設備識別信息 |
| 20h | 讀扇區(28位LBA尋址模式) |
| 24h | 擴展讀扇區(48位LBA尋址模式) |
| 30h | 寫扇區(28位LBA尋址模式) |
| 34h | 擴展寫扇區(48位LBA尋址模式) |
? ? ? ? 4.PIO模式
? ? ? ? 由于SATA控制器和PCI總線控制器的結構和協議比較復雜,同時為快速學習并簡化硬盤設備操作過程,本系統將選用基于IDE接口的PIO模式去訪問硬盤設備,即通過I/O端口對硬盤進行訪問。
? ? ? ? 對表提及的錯誤狀態端口,此處必須進行補充說明,
? ? ? ? 錯誤狀態端口,可描述命令錯誤狀態和診斷錯誤狀態。其中,診斷錯誤狀態是在控制器自檢時返回的狀態信息,而命令錯誤狀態則是在控制器執行命令期間產生的錯誤狀態。
? ? ? ? 4.1.診斷錯誤狀態
? ? ? ? 系統上電或重啟后,硬盤驅動器會自動進入自檢測狀態,此時從錯誤端口讀出的狀態信息描述了硬盤的診斷結果。
? ? ? ? 表描述了驅動器0/1的診斷錯誤狀態,I/O端口1F1h/171h每次只能描述一個驅動器的診斷狀態,處理器通過配置I/O端口的1F6h/176h的第4位可在兩個驅動器間切換。
? ? ? ? 4.2.命令錯誤狀態
? ? ? ? 硬盤完成初始化并進入運行狀態后,通過I.O端口1F1h可取得命令執行的錯誤狀態。
????????
? ? ? ? 2.獲取硬盤設備識別信息的測試程序
? ? ? ? 本節將通過ATA控制命令ECH來獲取硬盤設備識別信息。硬盤設備識別信息是一個由512B組成的數據塊。完整的硬盤設備識別信息需參照ATA規范文檔。
? ? ? ? 3.訪問硬盤扇區數據的測試程序
? ? ? ? 經過硬盤設備識別信息測試程序的演練,現在進一步實現硬盤扇區的訪問測試程序。
? ? ? ? 3.1.讀取扇區數據測試程序
? ? ? ? 讀取扇區數據測試程序的實現方法,依然是向表中的從控制器命令端口發送配置信息和扇區讀取命令,并在數據發送過程中,檢測每個階段的執行狀態。
? ? ? ? 代碼在使能了從控制器的中斷請求后,會對從硬盤的狀態進行檢測,只有在從硬盤空閑時才能向其發送配置信息。此處的配置信息將對從硬盤進行操作,把它的磁頭移動至LBA0扇區,操作扇區數1。隨后,待到驅動器準備好,向從硬盤發送ATA控制命令20h讀取目標扇區內的數據。
? ? ? ? 當磁頭將目標扇區內的數據讀取到硬盤緩存區后,從硬盤便向中斷控制器發送中斷請求,此時處理器將執行從硬盤的中斷處理函數,從I.O端口讀取硬盤緩存中的數據。
? ? ? ? 代碼較為直觀,先借助port_insw函數從I/O端口讀取256個字,然后顯示控制器狀態端口信息及讀取出來的扇區數據。
? ? ? ? 使用DiskGenius顯示出的LBA 0扇區數據。
? ? ? ? 3.2.寫入扇區數據測試程序
? ? ? ? 寫扇區操作過程與讀扇區操作過程相似,區別在于操作數據I/O端口的時機。為加深對寫扇區操作過程理解,現選用48位LBA尋址模式的ATA控制命令34h向扇區寫入數據。
? ? ? ? 為達到預期效果,目標扇區的LBA地址需突破28位(硬盤容量在138GB之上),還好主硬盤(SSD固態硬盤)的容量可滿足要求,它的LBA可尋址扇區總數為0x12A1,9EB0,本次測試選擇向LBA地址為1234,5678h的扇區寫入數據。
? ? ? ? 由于I/O端口寄存器單次只能支持28位的LBA地址,對于采用48位LBA尋址的ATA命令而言,48位的LBA地址需拆分為兩個24位的地址段,再逐段發送至命令端口。
? ? ? ? 為了向LBA 1234,5678h扇區寫入數據,特將硬盤驅動程序修改為操作主硬盤,并結合表的描述向主硬盤發送ATA控制命令及待寫入扇區的數據。
? ? ? ? 這段程序已改為主硬盤驅動的初始化函數,其中斷向量號為0x2e。在主硬盤初始化結束并處于空閑狀態時,通過命令端口向硬盤發送扇區寫命令0x34,并等待數據緩存區準備就緒。一旦數據緩存區準備就緒,立即調port_outsw向數據端口發送256個數值為0xA5A5的字。此處的函數port_outsw內封裝著匯編指令OUTSW,它與port_insw函數功能相反。
? ? ? ? 當數據全部寫入目標扇區后,硬盤會向處理器發送中斷請求,處理器隨即調用中斷處理函數disk_handler處理中斷請求。
? ? ? ? 寫扇區操作的中斷處理函數非常簡單,只打印出控制器狀態端口信息以表示寫扇區操作完成。
? ? ? ? 很難確定數據是否真的寫入到目標扇區。為驗證此事,使用DiskGenius查看目標扇區中的數據更直觀。
? ? ? ? 在操作目標扇區前請確保扇區內的數據是無用的,以免造成不必要損失。
11.2.2.完善硬盤驅動程序
? ? ? ? 下面就以linux的塊設備驅動結構模型為藍圖,來設計并實現本系統的硬盤設備驅動程序。
? ? ? ? 1.Linux的塊設備結構概述
? ? ? ? 機械硬盤作為低速的大容量存儲設備,它的磁頭尋道時間很可能比扇區的讀寫時間還要長,使得磁頭尋道時間不容忽視。且,寫扇區操作往往比讀扇區操作更耗時。則,縮短磁頭移動距離可有效節省磁頭尋道時間,提高硬盤的數據吞吐量,調整扇區讀寫順序則可提高任務的實時性。
? ? ? ? Linux采用一套復雜的驅動結構模型來實現塊設備的操作,這套模型以縮短磁頭尋道時間為宗旨,從多個方面優化了扇區操作過程。
? ? ? ? 塊設備驅動由諸多子模塊組成,其中的I/O調度器負責優化硬盤扇區操作過程。
| 模塊名 | 功能描述 |
| 應用程序 | 應用程序可訪問硬盤內的文件,或直接訪問硬盤扇區 |
| 文件系統 | 文件系統用于管理硬盤內的文件,應用只有穿過虛擬文件系統和文件系統才能訪問到文件 |
| 塊設備驅動 | 應用程序和文件系統通過硬盤設備的設備號調用塊設備驅動程序,進而將扇區操作請求發送至硬盤 |
| 請求包 | 塊設備驅動將扇區操作請求封裝成請求包,每個請求包可能含有多個操作請求,每個操作請求皆可追溯到對應得內存頁面 |
| I/O調度器 | I/O調度器根據請求包記錄得扇區位置和讀寫方向,將其插入到請求隊列得合適位置,或將其與請求隊列得某個請求包合并 |
| 發送操作命令 | 硬盤驅動程序從請求隊列中取出請求包,并按照請求包得描述向硬盤發送操作命令及數據 |
| 中斷處理函數 | 硬盤驅動程序根據操作命令,選擇執行不同得中斷處理程序分支 |
| 等待隊列 | 訪問硬盤屬于異步操作,在向硬盤發送操作命令時,硬盤驅動會掛起應用程序,并在中斷處理函數內將其喚醒 |
? ? ? ? 塊設備驅動得I/O調度器可由若干種調度算法組成。
? ? ? ? 2.重構硬盤驅動程序
? ? ? ? 本系統硬盤驅動程序將在PIO操作模式的基礎上,通過ATA控制命令操作硬盤,目前暫且支持讀扇區,寫扇區,獲取硬盤設備識別信息等功能。
? ? ? ? 編寫硬盤驅動程序開始階段,將根據硬盤的異步性操作,訪問速度快慢等特點,為硬盤驅動程序抽象出一系列結構體和宏常量。
? ? ? ? 代碼為硬盤驅動程序抽象出了一個用于保存硬盤操作請求的請求隊列結構體struct request_queue,其中記錄著硬盤操作請求隊列鏈表,剩余請求數,及正在處理的硬盤操作請求。
? ? ? ? 且硬盤操作請求隊列中的每個操作請求項也被抽象成了結構體,它保存著此次操作請求的全部信息及操作請求執行結束后的處理方法。
? ? ? ? 為方便文件系統和應用程序操作硬盤驅動程序,本系統為硬盤訪問者提供了統一的硬盤操作抽象接口。
? ? ? ? 盡管本系統物理平臺搭載的是SATA接口的機械硬盤,但其驅動程序卻采用IDE設備接口的PIO操作模式。因此驅動程序將硬盤操作抽象接口命名為IDE_device_operation。
? ? ? ? 這4個操作方法中,open和close接口用于打開和關閉驅動程序,目前尚未實現功能性代碼。ioctl接口則用于向硬盤發送控制命令,目前僅支持獲得硬盤設備識別信息功能。
? ? ? ? 此處重點介紹transfer接口。transfer接口主要負責處理硬盤的訪問操作。
? ? ? ? 函數IDE_transfer只能處理ATA_READ_CMD和ATA_WRITE_CMD兩個操作命令。而IDE_ioctl函數只能處理GET_INDENTIFY_DISK_CMD控制命令。上述三個命令的執行過程是一致的,即先通過make_request創建硬盤操作請求項,再使用submit將硬盤操作請求項插入到硬盤操作請求隊列中,隨后調wait_for_finish等待硬盤操作結束。?
? ? ? ? 一旦wait_for_finish返回,就意味著此次硬盤已將操作結果或數據返回給調用者。
? ? ? ? 按函數的執行順序,先看硬盤操作請求項的創建函數make_request,主要負責為操作請求項開辟存儲空間并對其成員變量進行賦值。
? ? ? ? 函數make_request會根據命令的特點為其指派不同的回調處理函數。當操作請求項賦值結束,便將其返回給調用者。
? ? ? ? 函數IDE_transfer會相繼調submit和wait_for_finish。其中的submit負責將操作請求項加入到硬盤操作請求隊列中,如硬盤目前處于空閑,則立即向硬盤控制器發送命令。隨著submit執行結束,處理器將通過wait_for_finish函數進入忙等階段,直至全局變量disk_flags被中斷處理程序賦值為0,完整程序實現見代碼。
? ? ? ? 在submit函數中,結構體變量disk_request的成員in_using保存著硬盤驅動程序正在處理的操作請求項,如其值為NULL,則說明驅動程序處于空閑,就執行cmd_out向硬盤控制器發送操作命令。
? ? ? ? 程序先從硬盤操作請求隊列中取出一個操作請求項,此請求項將作為硬盤驅動程序正在處理的操作請求項保存在in_using成員變量中,然后等硬盤進入空閑狀態。
? ? ? ? 當硬盤處于空閑狀態時,驅動程序將依據請求項記錄的信息執行不同的代碼分支,從而將ATA控制命令及數據發往硬盤控制器。設當前的請求項記錄著寫扇區操作請求,則驅動程序會將48位的LBA地址發送到硬盤控制器的命令端口。此處的扇區寫入代碼借鑒于寫入扇區數據測試程序。
? ? ? ? 將讀取扇區數據測試程序與扇區寫入代碼分支融合起來,便可實現48位的LBA地址的扇區讀取代碼分支。
? ? ? ? 如操作請求項用于獲取硬盤設備識別信息,則執行硬盤設備識別信息獲取分支。
? ? ? ? 函數disk_handler是硬盤中斷處理程序的主程序,在其執行過程會進一步調用操作請求項內預設的回調處理函數。?
? ? ? ? 這里的回調處理方法end_handler是在創建操作請求項時根據命令預設的處理函數。目前共實現read_handler,write_handler,other_hanlder三類回調函數。分別對應讀取,寫入,硬盤設備識別信息三個命令。
? ? ? ? 由于扇區的寫入操作會先發送數據,因此其回調處理函數僅需檢測硬盤狀態端口值即可。扇區的讀取操作會在檢測硬盤狀態端口值的同時,從I/O端口讀取硬盤緩存區中的數據。所有的回調處理函數終將以調用end_request宣告操作請求執行結束。
? ? ? ? 函數end_request主要任務是回收硬盤驅動程序正在處理的操作請求項,并使忙等待函數wait_for_finish返回。如此時的硬盤操作請求隊列中仍有操作請求項,則調cmd_out函數繼續向硬盤控制器發送命令和數據。
? ? ? ? 現在,硬盤設備(塊設備)驅動模型已經基本實現。在使用硬盤驅動程序前,不要忘記向驅動初始化程序加入硬盤操作請求隊列的初始化代碼,并更改硬盤中斷處理函數的參數。
? ? ? ? 程序在注冊硬盤中斷處理函數時,將硬盤操作請求隊列disk_request作為中斷處理函數的參數注冊到中斷處理單元中,并初始化硬盤操作請求隊列及相關全局變量。
? ? ? ? 至此,硬盤驅動程序已實現,下面就驗證它的執行效果。如依然選用LBA 1234,5678h作為測試扇區,測試程序會先向目標扇區寫入測試數據,再讀取目標扇區中的數據以驗證硬盤驅動程序的執行效果。
? ? ? ? 程序借助硬盤操作抽象接口transfer向硬盤發送操作命令ATA_WRITE_CMD和ATA_READ_CMD。當測試程序執行結束后,LBA 1234,5678h扇區中的數據已全部變為0x44。
? ? ? ? 如讀者希望在硬盤驅動程序中加入I/O調度器來優化磁頭尋道路徑,可考慮把I/O調度器插入到add_request函數或submit函數中。由于內核的基礎功能尚未完全實現,本章的硬盤驅動程序也只是一個基礎框架,它將伴隨內核基礎功能的逐步實現而進行升級和完善。
? ? ? ? 今后的系統程序將在不斷補充和完善中逐步趨于成熟。這個過程將會過往代碼進行修改和調整。
? ? ? ??
總結
- 上一篇: AltiumDesigner 的 Pcb
- 下一篇: anaconda3.6.5安装pyhiv