Linux字元裝置驅動之概述篇

來源:互聯網
上載者:User

一.概述:

1.在Linux中有一句哲學“Linux下皆檔案”。

裝置驅動程式為應用程式屏蔽了硬體的細節,這樣在應用程式看來,硬體裝置只是一個裝置檔案,應用程式可以像操作普通檔案一樣對硬體裝置進行操作。

但是裝置檔案和普通檔案還是又差別的。

那麼裝置和普通檔案之間又有什麼區分呢?

先看看兩個圖:

普通檔案:

-rw-r--r--  1 stella stella   3699 2011-05-10 16:02 my_USBTMCAPP.c

-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()完成核心空間到使用者空間的複製

轉載自:http://blog.csdn.net/tigerjb/article/details/6412438

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.