Kernel 的工作
Device Driver 扮演的角色
Device Driver 授權形式會受連結方式所影響
以 kernel module 形式提供的 device driver,開發者可透過 MODULE_LICENSE
這個巨集,將授權方式設定為以下七種之一:
GPL, GPL v2, GPL and additional rights, Dual BSD/GPL, Dual MIT/GPL, Dual MPL/GPL, Proprietary
Linux device driver 可分成 3 種類型
驅動程式本身可分成 2 個層面來討論
System call 是 user application 與 Linux device driver 的溝通介面
User application 透過呼叫 system call 來「叫起」driver 的 task,user application 要呼叫 system call 必須呼叫 GNU C 所提供的「wrapper function」,每個 system call 都會對應到 driver 內的一個 task,此 task 即是 file_operation 函數指標所指的函數
Linux 驅動程式與 user application 間的溝通方式是透過 system call,實際上 user application 是以 device file 與裝置驅動程式溝通。要達成此目的,驅動程式必須建構在此「file」之上,因此 Linux 驅動程式必須透過 VFS(virtual file system)層來實作 system call
/dev 目錄下的檔案稱為 device file,是 user application 用來與硬體裝置溝通的介面
我們把外部的周邊裝置均視為一個檔案,並透過此檔案與實體硬體溝通,這樣的檔案就叫做 device files 或 special files
檔案屬性的第一個位元如果顯示為 “c” 表示這是一個字元型裝置的 device file,若為 “b” 表示這是一個區塊型裝置的 device file
Device file 的 major number 代表一個特定的裝置,例如 major number 為 1 是 null 虛擬裝置,major number 定義於 kernel 文件目錄 Documentation/devices.txt
Minor number 代表裝置上的子裝置,例如,同一個硬碟上的分割區就用不同的 minor number 來代表,但其 major number 相同
我們在設計 device driver 時,會先透過一個 註冊 (register) 的動作將自己註冊到 kernel 裡,註冊時,我們會指定一個 major number 參數,以指定此驅動程式所要實作的週邊裝置。當 user 開啟 device file 時,kernel 便會根據 device file 的 major number 找到對應的驅動程式來回應使用者。Minor number 則是 device driver 內部所使用,kernel 並不會處理不同的 minor number
設計 device driver 的第一個步驟就是要定義 driver 所要提供的功能(capabilities),當 user application 呼叫 open() system call 時,kernel 就會連繫相對應的 driver 來回應使用者
file_operations 是學習 device driver 最重要的一個資料結構,file_operations 內的成員為函數指標,指向 system call 的實作函數,file_operations 即是圖中的 VFS 層
換句話說,Linux 驅動程式是透過 file_operations 來建構 VFS 層的支援。而 file_operation 裡的函數指標,即是指向每一個 system call 的實作函數
Virtual device driver 往上是為了連結 Linux kernel 的 VFS 層,physical device drvier 往下是為了存取實體硬體
Virtual device driver 的目的在於設計一個「機制」良好的 kernel mode 驅動程式,virtual device driver 也必須考慮與 user application 的互動。實作上,則是需要善用 kernel 所提供的介面(interface),即 kernel APIs
fops 是指向 file_operations 結構的指標,驅動程式呼叫 register_chrdev()
將 fops 註冊到 kernel 裡後,fops 便成為該 device driver 所實作的 system call 進入點。實作 system call 的函數便是透過 file_operations 結構來定義,我們稱實作 system call 的函數為 driver method。
kernel 會在需要時 callback 我們所註冊的 driver method,因此,當 driver 裡的 method 被呼叫時,kernel 便將傳遞 argument 給 driver method,driver method 可由 kernel 所傳遞進來的 argument 取得驅動程式資訊
註冊 driver 的動作呼叫 register_chrdev()函數完成,此函數接受 3 個參數如下
「註冊」這個動作觀念上是將 fops 加到 kernel 的 VFS 層,因此 user application 必須透過「device file」才能呼叫到 driver method。註冊這個動作的另一層涵意則是將 driver method 與不同的 system call 做「正確的對應」,當 user application 呼叫 system call 時,才能執行正確的 driver method
將 driver 自己「註冊」到 kernel 的 VFS 層,註冊時所要呼叫的函數根據裝置類型的不同而不同
將驅動程式「註冊」(registration)至 kernel 的動作必須在 init_module()函數裡實作,根據裝置類型的不同,所呼叫的函數也不同,以下是幾個基本的置註冊函數
注意 major : 為 device file 的 major number該 device file,應在 Linux 系統底下以 root 身份手動建立
註冊的動作是寫在 init_module()
裡,因此當使用者執行 insmod
載入驅動程式時,register_chrdev()
便會執行。由此可知,註冊驅動程式的時機為 insmod
時。相對的,在 rmmod
時,必須執行解除註冊的動作,此動作必須實作在 cleanup_module()
函數裡
Linux 驅動程式的「註冊」是一個非常重要的動作,這個動作代表 Linux 驅動程式是一個嚴謹的分層式架構,換句話說,Linux 驅動程式的分層 (layered) 關係可透過「註冊」的程序來分析