設備管理是操作系統五大管理中最復雜的部分。與Unix系統一樣,Linux系統采用設備文件統一管理硬件設備,從而將硬件設備的特性及管理細節對用戶隱藏起來,實現用戶程序與設備無關性。在Linux系統中,硬件設備分為兩種,即塊設備和字符設備。
1.特別文件
用戶是通過文件系統與設備接口的,所有設備都作為特別文件,從而在管理上就具有一些共性。 (1)每個設備都對應文件系統中的一個索引節點,都有一個文件名。設備的文件名一般由兩部分構成,第一部分是主設備號,第二部分是次設備號。
主設備號代表設備的類型,可以惟一地確定設備的驅動程序和界面,如hd表示IDE硬盤,sd表示SCSI硬盤,tty表示終端設備等;次設備號代表同類設備中的序號,如hda表示IDE主硬盤,hdb表示IDE從硬盤等。
(2)應用程序通常可以通過系統調用open( )打開設備文件,建立起與目標設備的連接。
(3)對設備的使用類似于對文件的存取。打開設備文件以后,就可以通過read( )、write( )、ioctl( )等文件操作對目標設備進行操作。
(4)
設備驅動程序都是系統內核的一部分,它們必須為系統內核或它們的子系統提供一個標準的接口。例如,一個終端驅動程序必須為Linux內核提供一個文件
I/O接口;一個SCSI設備驅動程序應該為SCSI子系統提供一個SCSI設備接口,同時SCSI子系統也應為內核提供文件I/O和緩沖區。
(5)設備驅動程序利用一些標準的內核服務,如內存分配等。另外,大多數Linux設備驅動程序都可以在需要時裝入內核,不需要時可以卸載下來。
圖6 設備驅動分層結構示意圖
圖6示出設備驅動的分層結構,從中可以看出,處于應用層的進程通過文件描述字fd與已打開文件的file結構相聯系。在文件系統層,按照文件系統的操作規則對該文件進行相應處理。
對于一般文件(即磁盤文件),要進行空間的映射—從普通文件的邏輯空間映射到設備的邏輯空間,然后在設備驅動層做進一步映射—從設備的邏輯空間映射到物理空間(即設備的物理地址空間),進而驅動底層物理設備工作。
對于設備文件,則文件的邏輯空間通常就等價于設備的邏輯空間,然后從設備的邏輯空間映射到設備的物理空間,再驅動底層的物理設備工作。
2.設備驅動程序和內核之間的接口
Linux系統和設備驅動程序之間使用標準的交互接口。無論是字符設備、塊設備還是網絡設備的驅動程序,當內核請求它們提供服務時,都使用同樣的接口。
Linux
提供了一種全新的機制,就是“可安裝模塊”。可安裝模塊是可以在系統運行時動態地安裝和拆卸的內核模塊。利用這個機制,可以根據需要在不必對內核重新編譯
連接的條件下,將可安裝模塊動態插入運行中的內核,成為其中一個有機組成部分,或者從內核卸載已安裝的模塊。設備驅動程序或與設備驅動緊密相關的部分(如
文件系統) 都是利用可安裝模塊實現的。
在應用程序界面上,利用內核提供的系統調用來實現可安裝模塊的動態安裝和拆卸。但通常情況下,用戶是利用系統提供的插入模塊工具和移走模塊工具來裝卸可安裝模塊。插入模塊的工作主要如下:
(1) 打開要安裝的模塊,把它讀到用戶空間。這種“模塊”就是經過編譯但尚未連接的.o文件。
(2) 必須把模塊內涉及對外訪問的符號(函數名或變量名)連接到內核,即把這些符號在內核映像中的地址填入該模塊需要訪問這些符號的指令及數據結構中。
(3) 在內核創建一個module數據結構,并申請所需的系統空間。
(4) 最后,把用戶空間中完成了連接的模塊映像裝入內核空間,并在內核中“登記”本模塊的有關數據結構(如file_operations結構),其中有指向執行相關操作函數的指針。
如前所述,Linux系統是一個動態的操作系統。用戶根據工作中的需要,會對系統中設備重新配置,如安裝新的打印機、卸載老式終端等。這樣,每當Linux系統內核初啟時,它都要對硬件配置進行檢測,很有可能會檢測到不同的物理設備,就需要不同的驅動程序。
在構建系統內核時,可以使用配置腳本將設備驅動程序包含在系統內核中。在系統啟動時對這些驅動程序初始化,它們可能未找到所控制的設備,而另外的設備驅動程序可以在需要時作為內核模塊裝入到系統內核中。
為了適應設備驅動程序動態連接的特性,設備驅動程序在其初始化時就在系統內核中進行登記。Linux系統利用設備驅動程序的登記表作為內核與驅動程序接口的一部分,這些表中包括指向有關處理程序的指針和其它信息。
3.字符設備
在Linux
系統中,打印機、終端等字符設備都作為字符特別文件出現在用戶面前。用戶對字符設備的使用就和存取普通文件一樣。在應用程序中,使用標準的系統調用來打
開、關閉、讀寫字符設備。當字符設備初始化時,其設備驅動程序被添加到由device_struct結構組成的chrdevs結構數組中。
device_struct
結構由兩項構成,一個是指向已登記的設備驅動程序名的指針,另一個是指向file_operations結構的指針。而file_operations結
構的成分幾乎全是函數指針,分別指向實現文件操作的入口函數。設備的主設備號用來對chrdevs數組進行索引,如圖7所示。
圖7 字符設備驅動程序示意圖前面講過,每個VFS索引節點都和一系列文件操作相聯系,并且這些文件操作隨索引節點所代表的文件類型不同而不同。每當一個VFS索引節點所代表的字符設備文件創建時,它的有關文件的操作就設置為默認的字符設備操作。
默認的文件操作只包含一個打開文件的操作。當打開一個代表字符設備的特別文件以后,就得到相應的VFS索引節點,其中包括該設備的主設備號和次設備號。
利用主設備號就可以檢索chrdevs數組,進而可以找到有關此設備的各種文件操作。這樣,應用程序中的文件操作就會映射到字符設備的文件操作調用中。
4.塊設備
對塊設備的存取和對文件的存取方式一樣,其實現機制也和字符設備使用的機制相同。Linux系統中有一個名為blkdevs的結構數組,它描述了一系列在系統中登記的塊設備。
數組blkdevs也使用設備的主設備號作為索引,其元素類型是device_struct結構。該結構中包括指向已登記的設備驅動程序名的指針和指向block_device_operations結構的指針。
在block_device_operations結構中包含指向有關操作的函數指針。所以,該結構就是連接抽象的塊設備操作與具體塊設備類型的操作之間的樞紐。
與字符設備不一樣,塊設備有幾種類型,例如SCSI設備和IDE設備。每類塊設備都在Linux系統內核中登記,并向內核提供自己的文件操作。
為了把各種塊設備的操作請求隊列有效地組織起來,內核中設置了一個結構數組blk_dev,該數組中的元素類型是blk_dev_struct結構。這個結構由三個成分組成,其主體是執行操作的請求隊列request_queue,還有一個函數指針queue。
當
這個指針不為0時,就調用這個函數來找到具體設備的請求隊列。這是考慮到多個設備可能具有同一主設備號,該指針在設備初始化時被設置好。通常當它不為0
時,還要使用該結構中的另一個指針data,用來提供輔助性信息,幫助該函數找到特定設備的請求隊列。每一個請求數據結構都代表一個來自緩沖區的請求。
每當緩沖區要和一個登記過的塊設備交換數據,它都會在blk_dev_struct中添加一個請求數據結構,如圖8所示。
圖8 塊設備驅動程序數據結構示意圖每
一個請求都有一個指針指向一個或多個buffer_head數
據結構,而該結構都是一個讀寫數據塊的請求。每一個請求結構都在一個靜態鏈表all_requests中。若干請求是添加到一個空的請求鏈表中,則調用設
備驅動程序的請求函數,開始處理該請求隊列。否則,設備驅動程序就簡單地處理請求隊列中的每一個請求。
當設備驅動程序完成了一個請求后,就把buffer_head結構從request結構中移走,并標記buffer_head結構已更新,同時解鎖,這樣,就可以喚醒相應的等待進程。