inux字元裝置驅動之概述篇
一.概述:
1.在linux中有一句哲學「linux下皆檔案」。
裝置驅動程式為應用程式遮蔽了硬體的細節,這樣在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以像操作普通檔案一樣對硬體裝置進行操作。
但是裝置檔案和普通檔案還是又差別的。
那麼裝置和普通檔案之間又有什麼區分呢?
先看看兩個圖:
普通檔案:
-rwxr-xr-x 1 stella stella 8763 2011-05-08 11:27 tiger
-rw-r--r-- 1 stella stella 441 2011-05-08 11:27 tiger.c
裝置檔案:
crw------- 1 root root 252, 4 2011-05-11 16:42 usbmon4
crw------- 1 root root 252, 5 2011-05-11 16:42 usbmon5
crw-rw---- 1 root tty 7, 0 2011-05-11 16:42 vcs
crw-rw---- 1 root tty 7, 1 2011-05-11 16:42 vcs1
1>訪問許可權之前的字母是b或c,分別表示塊裝置和字元裝置。
2>裝置檔案沒有檔案長度,而增加了另外的兩個值,分別是主裝置號和從裝置號。二者共同形成乙個唯一的號碼,核心可由此查詢對應的裝置驅動程式。
3>之所以給裝置檔案分配名稱,是因為使用者更容易記憶符號名而不是數字,但名稱無法表示裝置檔案的實際功能,這主要是通過主從裝置號表示乙個裝置的,裝置檔案所處的目錄也與其功能不相干。
儘管如此,命名裝置檔案時仍然採用了一中標準方法:
mknod
用於建立裝置檔案。
2.核心採用主從裝置號來標識匹配的驅動程式
為什麼要採用兩個號碼來標識驅動程式呢?
1>首先,系統可能包含幾個同樣型別的裝置,由同乙個裝置驅動程式管理(將同樣的**多次載入到核心也沒有意義)
2>其次,可以將同類裝置合併起來,便於插入到核心的資料結構中進行管理
3.linux裝置驅動程式的分類:
1>linux裝置驅動程式分為字元裝置驅動(無緩衝且只能順序訪問),塊裝置驅動程式(有緩衝且可以隨機訪問)。每個字元裝置和塊裝置都必須有主次裝置號,主裝置號相同的裝置是同類裝置(使用同一驅動程式)
(1)塊裝置:系統中能夠隨機(不需要按順序)訪問固定大小資料片(chunk)的裝置被稱作塊裝置;他們都是以安裝檔案系統的方式使用的
(2)字元裝置:字元裝置按照字元流動的方式被有序訪問
2>這些裝置中,有些裝置是對實際物理硬體的抽象,而有些裝置則是核心自身提供的功能(不依賴於特定的物理硬體,又稱為「虛擬裝置」)
(1)每個裝置在/dev目錄下都有乙個對應的檔案(節點)
可以用下面的命令進行檢視
cd /dev
ls -al
日期的前兩列給出了對應裝置的主裝置號和次裝置號
(2)可以通過cat /proc/devices命令檢視當前已經載入的裝置驅動程式的主裝置號,第一列為主裝置號,第二列為裝置名
3>塊裝置和字元裝置的主裝置號可能是相同的。因此,除非同時指定裝置號和裝置型別(塊裝置/字元裝置),否則找到的驅動程式可能不是唯一的
4.主從裝置號
1>在核心中,dev_t型別用來儲存裝置編號(包括主裝置號和次裝置號),dev_t是乙個32位的數,12位表示主裝置號,20為表示次裝置號
(1)主裝置號 = major(dev_t dev)
(2)次裝置號 = minor(dev_t dev)
(3)裝置編號 = mkdev(int major,int minor)
2>主裝置號是與驅動對應的概念,同一類裝置一般使用相同的主裝置號,不同類的裝置一般使用不同的主裝置號。因為同一驅動可支援多個同類裝置,因此用次裝置號來描述使用該驅動的裝置的序號,序號一般從0開始
5.mkdev()巨集的實現
#define mkdev(ma,mi) (((ma) << minorbits)|(mi))
#define mkdev(ma,mi) ((ma)<<8 | (mi))
獲取裝置在裝置表中的位置
6.dev_t是無符號長整型號
1>typedef u_long dev_t;
2>typeddef unsigned long u_long;
7.分配和釋放裝置號:
(1)int register_chrdev_region(dev_t first,unsigned int count,char *name);
(2)int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
(3)void unregister_chrdev_region(dev_t first,unsigned int count);
1>register_chardev_region函式用於已知起始裝置號的情況;在靜態申請時,如果主裝置號沒有和系統中某個字元裝置的主裝置號 重複,則此函式肯定會成功返回;如果系統中某個已註冊的字元裝置的主裝置號與申請的主裝置號相同,則核心還需要檢查這兩個裝置的次裝置號範圍有沒有重合,若有重合部分,則register_chrdev_region
返回-ebusy,表示系統正忙,申請的裝置號已被占用;若無重合部分,則register_chrdev_region返回0,表示成功
2>alloc_chrdev_region()用於裝置號未知,向系統動態申請裝置號的情況。動態分配裝置號,是指在驅動程式中通過呼叫此函式,系統將為驅動程式動態分配乙個主裝置號,將分配到的主裝置號與引數baseminor組合成乙個裝置號,通過輸出引數dev返回給使用者
3>alloc_chrdev_region()比register_chrdev_region()對比的優點在於它會自動避開裝置號重複的衝突,但是當用alloc_chrdev_region動態申請裝置號時,在申請完後,要通過
major=mmor(dev)
獲取主裝置號;並且如果使用者使用靜態申請裝置號,只要使用者申請的主裝置號在0~2^12-1之間,次裝置號在0~2^20-1之間,並且裝置號不衝突,核心就會成功註冊該裝置號;而如果使用者使用了動態分配裝置號,核心為使用者分配的主裝置號只會在1~254之間,如果這254個裝置號全部被占用,則動態分配裝置號會失敗,但是常用的裝置只有三十多個,所以基本上不用擔心動態分配的時候核心會返回失敗
4>在呼叫cdev_del()函式從系統登出字元裝置之後,unregister_chrdev_region()應該被呼叫以釋放原先申請的裝置號
關於register_chrdev_region()函式系列的具體實現可以參看《linux字元裝置驅動之register_chrdev_region》
8. 註冊字元裝置
在獲得了裝置號範圍之後,需要將裝置新增到字元裝置資料庫中,以啟用裝置。這需要用cdev_init函式初始化乙個struct cdev的例項,然後呼叫cdev_add函式
(1)void cdev_init(struct cdev *cdev,struct file_operation *fops);
(2)int cdev_add(struct cdev *dev,dev_t num,unsigned int count)
(3)void cdev_del(stuct cdev *dev)
1> cdev_init()函式用於初始化cdev的成員,並建立cdev和file_operations之間的連線
2>cdev_add()函式和cdev_del()函式分別向系統新增和刪除乙個cdev,完成字元裝置的註冊和登出。對cdev_add()的呼叫通常發生在字元裝置驅動模組載入函式中,而對cdev_del()函式的呼叫則通常發生在字元裝置驅動模組解除安裝函式中。
3>先要申請裝置號,才能註冊字元裝置,順序不能亂
關於cdev_init ()函式系列的具體實現可以參看《linux字元裝置驅動之cdev_init ()》
9.在核心空間和使用者空間之間拷貝資料使用
(1)unsigned long copy_to_user(void _user* to,const void *from,unsigned long count);
(2)unsigned long copy_from_user(void *to,const void __user *from,unsigned long count);
由於核心空間與使用者空間的記憶體不能直接互訪問,因此借助函式copy_from_user()完成使用者空間到核心空間的複製。函式copy_to_user()完成核心空間到使用者空間的複製
驅動 linux裝置驅動 字元裝置驅動開發
preface 前面對linux裝置驅動的相應知識點進行了總結,現在進入實踐階段!linux 裝置驅動入門篇 linux 裝置驅動掃盲篇 fedora下的字元裝置驅動開發 開發乙個基本的字元裝置驅動 在linux核心驅動中,字元裝置是最基本的裝置驅動。字元裝置包括了裝置最基本的操作,如開啟裝置 關閉...
Linux裝置驅動之《字元裝置驅動》
linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...
Linux裝置驅動之字元裝置驅動
一 linux裝置的分類 linux系統將裝置分成三種基本型別,每個模組通常實現為其中某一類 字元模組 塊模組或網路模組。這三種型別有 字元裝置 字元裝置是個能夠像位元組流 類似檔案 一樣被訪問的裝置,由字元裝置驅動程式來實現這種特性。字元裝置可以通過檔案系統節點來訪問,比如 dev tty1等。這...