第三章:字元裝置驅動程式
1
,(裝置編號的內部表示)在核心中, dev_t 型別(在
中定義)用來持有裝置編號 -- 主次
部分都包括. 對於 2.6.0 核心, dev_t 是 32 位的量, 前12 位用作主編號,後 20 位
用作次編號. 當然, 對於裝置編號的內部組織從不做任何假設; 相反, 應當利用在中的一套巨集定義. 為獲得乙個 dev_t 的主或者次編號, 使用
major(dev_t dev);
minor(dev_t dev);
mkdev(int major, intminor);
2
,(分配和釋放裝置編號)靜態分配:int register_chrdev_region (dev_t first, unsigned int count, char*name); first是要分配的裝置編號範圍的起始位址。first的次裝置號通常被設定為0,但對該函式來講並不是必需的。count是要請求的連續裝置編號的個數。注意,如果count非常大,則所請求的範圍可能和下乙個主裝置號重疊,但只要我們所請求的編號範圍是可用的。則不會帶來任何問題,最後,name是和該編號範圍關聯的裝置名稱,它將出現在/proc/devices和sysfs中。
和大部分核心函式一樣,register_chrdev_region的返回值在分配成功時是0.在錯誤情況下,將返回乙個負的錯誤碼,並且不能使用所請求的編號區域。
動態分配:intalloc_chrdev_region(dev_t *dev, unsigned intfirstminor,unsigned int count, char *name);
在上面這個函式中,dev是僅用於輸出的引數,在成功完成呼叫後將儲存已分配範圍的第乙個編號。firstminor應該是要使用的被請求的第乙個次裝置號,它通常是0.count和name引數與register_chrdev_region函式是一樣的。
釋放函式:voidunregister_chrdev_region(dev_t first, unsigned int count);
first為開始第乙個被釋放的裝置號,count是釋放的數量。
通常我們在模組清除函式中呼叫unregister_chrdev_region函式。
3
,(三個重要的資料結構)(1)struct file_operations是用來建立裝置編號和驅動程式操作的這種連線的。其中包含了一組函式指標。每個開啟的檔案(在內部由乙個file結構表示)和一組函式關聯(通過包含指向乙個file_operations結構的f_ops字段)。這些操作主要是用來實現系統呼叫,命名為open,read等。
在通讀file_operations方法的清單時,我們會注意到許多引數包含有__user字串,它其實是一種形式的文件而已,表面指標是乙個使用者空間的位址,因此不能被直接引用。對通常的編譯來講,__user沒有任何效果,但是可由外部檢查軟體使用,用來尋找對使用者空間位址的錯誤使用。(2)struct file是裝置驅動程式所使用的第二個最重要的資料結構。注意,file結構與使用者空間程式中的file沒有任何的關聯。file在c庫中定義且不會出現在核心**中;而struct file是乙個核心結構,它不會出現在使用者程式中。
file結構代表乙個開啟的檔案,它不僅僅限定於裝置驅動程式,系統中每個開啟的檔案在核心空間都有乙個對應的file結構。它由核心在open時建立,並傳遞給在該檔案上進行操作的所有函式,直到最後的close函式。在檔案的所有例項都被關閉之後,核心會釋放這個資料結構。(3)struct inode在內部表示檔案,因此它和file結構不同,後者表示開啟的檔案描述符。對單個檔案可能會有許多個表示開啟的檔案描述符的file結構,但它們都指向單個inode結構。
4
,(字元裝置的註冊)核心內部使用struct cdev結構來表示字元裝置。在核心呼叫裝置的操作之前,必須分配並註冊乙個或者多個上述結構。為此我們的**應該包含,其中定義了這個結構以及與其相關的一些輔助函式。註冊乙個字元裝置一般分三步:(1)分配乙個cdev結構,struct cdev *my_cdev =cdev_alloc(); my_cdev->ops = &my_fops;(2)初始化cdev,void cdev_init(struct cdev *cdev,struct file_operations *fops);另外還有乙個struct cdev的字段需要初始化。和file_operations結構類似struct cdev也有乙個所有者字段,應該被設定為this_module。(3)新增cdev,使用int cdev_add(struct cdev*dev,dev_t num, unsigned int count);
dev是cdev結構,num是該裝置對應的第乙個裝置編號,count是應該和該裝置關聯的裝置編號的數量。count經常取1,但在某些情形下,會有多個裝置編號對應乙個特定的裝置。
在使用cdev_add是有幾個重要事情要記住. 第乙個是這個呼叫可能失敗. 如果它返回乙個負的錯誤碼 , 你的裝置沒有增加到系 統中. 但是,它幾乎會一直成 功, 並且帶起了其他的點:cdev_add回, 你的裝置就是"活的"並且核心可以呼叫它的操作. 除非你的驅動完全準備好處理裝置上的操作,否則, 你不應當呼叫cdev_add.
5
,(移除字元裝置)要從系統中移除乙個字元裝置,做如下呼叫:
void cdev_del(structcdev *dev);
要清除的是,在將cdev結構傳遞到cdev_del函式後,就不應該在訪問cdev結構了。
6
,(copy_to_user和copy_from_user)核心**不能直接引用使用者空間的內容,使用者空間也不能引用核心空間的**。如果你不打算因為自己的驅動程式而危及使用者系統的安全性,則永遠不應直接引用使用者空間的指標。應該使用unsigned longcopy_to_user(void __user *to, const void *from, unsigned long count);和unsigned longcopy_from_user(void *to, const void *from,unsigned long count);這兩個函式的作用並不限於在核心空間和使用者空間之間拷貝資料,它們還檢查使用者空間的指標是否有效。如果指標無效就不進行拷貝;另一方面,如果在拷貝過程中遇到無效的位址,則僅僅會複製部分資料。
Linux裝置驅動程式(第三版) 忙等待
include include include include include include include include include include jiffies include include u64 include file operations,file include inclu...
Linux裝置驅動程式 第三版 的學習 一
為自己編寫的模組配置並構造好核心樹 1.應用程式和核心模組的區別 應用程式 1 應用程式從頭到尾執行單個任務 2 應用程式在退出時,可以不管資源的釋放或者其他的清除工作 3 應用程式可以呼叫它並未定義的函式,這是因為在鏈結過程能夠解析外部引用從而使用適當的函式庫.4 應用程式開發過程中的段錯誤是無害...
編譯apue 第三版
想要直接使用作者提供的源 就需要編譯下,這個檔名是src.3e.tar.gz 很簡單的幾步就搞定了.解壓src.3e.tar.gz 進入apue.3e make 進入apue.3e lib目錄,複製libapue.a到 usr local lib目錄 進入 apue.3e include目錄,複製 ...