加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 11.4  塊設備驅(qū)動編程
  • 相關推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式Linux設備驅(qū)動開發(fā)之:塊設備驅(qū)動編程

2013/09/13
閱讀需 14 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

?

11.4??塊設備驅(qū)動編程

塊設備通常指一些需要以塊(如512字節(jié))的方式寫入的設備,如IDE硬盤、SCSI硬盤、光驅(qū)等。它的驅(qū)動程序的編寫過程與字符型設備驅(qū)動程序的編寫有很大的區(qū)別。

塊設備驅(qū)動編程接口相對復雜,不如字符設備明晰易用。塊設備驅(qū)動程序?qū)φ麄€系統(tǒng)的性能影響較大,速度和效率是設計塊設備驅(qū)動程要重點考慮的問題。系統(tǒng)中使用緩沖區(qū)與訪問請求的優(yōu)化管理(合并與重新排序)來提高系統(tǒng)性能。

1.編程流程說明

塊設備驅(qū)動程序的編寫流程同字符設備驅(qū)動程序的編寫流程很類似,也包括了注冊和使用兩部分。但與字符驅(qū)動設備所不同的是,塊設備驅(qū)動程序包括一個request請求隊列。它是當內(nèi)核安排一次數(shù)據(jù)傳輸時在列表中的一個請求隊列,以最大化系統(tǒng)性能為原則進行排序。在后面的讀寫操作時會詳細講解這個函數(shù),圖11.5為塊設備驅(qū)動程序的流程圖,請讀者注意與字符設備驅(qū)動程序的區(qū)別。

圖11.5??塊設備驅(qū)動程序流程圖

2.重要數(shù)據(jù)結(jié)構(gòu)

每個塊設備物理實體由一個gendisk結(jié)構(gòu)體來表示(在</linux/genhd.h>中定義),每個gendisk可以支持多個分區(qū)。

每個gendisk中包含了本物理實體的全部信息以及操作函數(shù)接口。整個塊設備的注冊過程是圍繞gendisk來展開的。在驅(qū)動程序中需要初始化的gendisk的一些成員如下所示。

struct?gendisk?

{

????int?major;????????????/*?主設備號?*/

????int?first_minor;????/*?第一個次設備號?*/

????int?minors;??????????/*?次設備號個數(shù),一個塊設備至少需要使用一個次設備號,而且塊設

????????????????????????備的每個分區(qū)都需要一個次設備號,因此這個成員等于1,則表明該塊

????????????????????????設備是不可被分區(qū)的,否則可以包含minors?–?1????個分區(qū)。*/

????char?disk_name[32];????????/*?塊設備名稱,在/proc/partions中顯示?*/

????struct?hd_struct?**part;????/*?分區(qū)表?*/

????struct?block_device_operations?*fops;????????/*?塊設備操作接口,與字符設備的

???????????????????????????????????????????? ????file_operations結(jié)構(gòu)對應*/

????struct?request_queue?*queue;????/*?I/O請求隊列?*/

????void?*private_data;????????/*?指向驅(qū)動程序私有數(shù)據(jù)?*/

????sector_t?capacity;????/*?塊設備可包含的扇區(qū)數(shù)?*/

????……?/*?其他省略?*/

};

與字符設備驅(qū)動程序一樣,塊設備驅(qū)動程序也包含一個在<linux/fs.h>中定義的block_device_operations結(jié)構(gòu),其定義如下所示。

struct?block_device_operations?

{

????int?(*open)?(struct?inode?*,?struct?file?*);

????int?(*release)?(struct?inode?*,?struct?file?*);

????int?(*ioctl)?(struct?inode?*,?struct?file?*,?unsigned,?unsigned?long);

????long?(*unlocked_ioctl)?(struct?file?*,?unsigned,?unsigned?long);

????long?(*compat_ioctl)?(struct?file?*,?unsigned,?unsigned?long);

????int?(*direct_access)?(struct?block_device?*,?sector_t,?unsigned?long?*);

????int?(*media_changed)?(struct?gendisk?*);

????int?(*revalidate_disk)?(struct?gendisk?*);

????int?(*getgeo)(struct?block_device?*,?struct?hd_geometry?*);

????struct?module?*owner;

};

從該結(jié)構(gòu)的定義中,可以看出塊設備并不提供read()、write()等函數(shù)接口。對塊設備的讀寫請求都是以異步方式發(fā)送到設備相關的request?隊列之中。

?

3.塊設備注冊和初始化

塊設備的初始化過程要比字符設備復雜,它既需要像字符設備一樣在加載內(nèi)核時完成一定的工作,還需要在內(nèi)核編譯時增加一些內(nèi)容。塊設備驅(qū)動程序初始化時,由驅(qū)動程序的init()完成。

塊設備的初始化過程如圖11.6所示。

圖11.6??塊設備驅(qū)動程序初始化過程

(1)向內(nèi)核注冊。

使用register_blkdev()?函數(shù)對設備進行注冊。

int?register_blkdev(unsigned?int?major,?const?char?*name);

其中參數(shù)major為要注冊的塊設備的主設備號,如果其值等于0,則系統(tǒng)動態(tài)分配并返回主設備號。參數(shù)name為設備名,在/proc/devices中顯示。如果出錯,則該函數(shù)返回負值。

與其對應的塊設備的注銷函數(shù)為unregister_blkdev(),其格式如下所示。

int?unregister_blkdev(unsigned?int?major,?const?char?*name);

其參數(shù)必須與注冊函數(shù)中的參數(shù)相同。如果出錯則返回負值。

(2)申請并初始化請求隊列。

這一步要調(diào)用blk_init_queue()函數(shù)來申請并初始化請求隊列,其格式如下所示。

struct?request_queue?*blk_init_queue(request_fn_proc?*rfn,?spinlock_t?*lock)

其中參數(shù)rfn是請求隊列的處理函數(shù)指針,它負責執(zhí)行塊設備的讀、寫請求。參數(shù)lock為自旋鎖,用于控制對所分配的隊列的訪問。

(3)初始化并注冊gendisk結(jié)構(gòu)。

內(nèi)核提供的gendisk結(jié)構(gòu)相關函數(shù)如表11-16所示。

表11-16 gendisk結(jié)構(gòu)相關函數(shù)

函數(shù)格式

說明

struct?gendisk?*alloc_disk(int?minors)

動態(tài)分配gendisk結(jié)構(gòu),參數(shù)為次設備號的個數(shù)

void?add_disk(struct?gendisk?*disk)

向系統(tǒng)注冊gendisk結(jié)構(gòu)

void?del_gendisk(struct?gendisk?*disk)

從系統(tǒng)注銷gendisk結(jié)構(gòu)

首先使用alloc_disk()函數(shù)動態(tài)分配gendisk結(jié)構(gòu),接下來,對gendisk結(jié)構(gòu)的主設備號(major)、次設備號相關成員(first_minor和minors)、塊設備操作函數(shù)(fops)、請求隊列(queue)、可包含的扇區(qū)數(shù)(capacity)以及設備名稱(disk_name)等成員進行初始化。

在完成對gendisk的分配和初始化之后,調(diào)用add_disk()函數(shù)向系統(tǒng)注冊塊設備。在卸載gendisk結(jié)構(gòu)的時候,要調(diào)用del_gendisk()函數(shù)。

4.塊設備請求處理

塊設備驅(qū)動中一般要實現(xiàn)一個請求隊列處理函數(shù)來處理隊列中的請求。從塊設備的運行流程,可知請求處理是塊設備的基本處理單位,也是最核心的部分。對塊設備的讀寫操作被封裝到了每一個請求中。

已經(jīng)提過調(diào)用blk_init_queue()函數(shù)來申請并初始化請求隊列。表11-17列出了一些與請求處理相關的函數(shù)。

表11-17 請求處理相關函數(shù)

函數(shù)格式

說明

request_queue_t?*blk_alloc_queue(int?gfp_mask)

分配請求隊列

request_queue_t?*blk_init_queue
(request_fn_proc?*rfn,?spinlock_t?*lock)

分配并初始化請求隊列

struct?request?*blk_get_request
(request_queue_t?*q,?int?rw,?int?gfp_mask)

從隊列中獲取一個請求

void?blk_requeue_request(request_queue_t?*q,?struct?request?*rq)

將請求再次加入隊列

void?blk_queue_max_sectors
(request_queue_t?*q,?unsigned?short?max_sectors)

設置最大訪問扇區(qū)數(shù)

void?blk_queue_max_phys_segments
(request_queue_t?*q,?unsigned?short?max_segments)

設置最大物理段數(shù)

void?end_request(struct?request?*req,?int?uptodate)

結(jié)束本次請求處理

void?blk_queue_hardsect_size
(request_queue_t?*q,?unsigned?short?size)

設置物理扇區(qū)大小

以上簡單地介紹了塊設備驅(qū)動編程的最基本的概念和流程。更深入的內(nèi)容不是本書的重點,有興趣的讀者可以參考其他書籍。

相關推薦

電子產(chǎn)業(yè)圖譜

華清遠見(www.farsight.com.cn)是國內(nèi)領先嵌入師培訓機構(gòu),2004年注冊于中國北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營分公司。華清遠見除提供嵌入式相關的長期就業(yè)培訓、短期高端培訓、師資培訓及企業(yè)員工內(nèi)訓等業(yè)務外,其下屬研發(fā)中心還負責嵌入式、Android及物聯(lián)網(wǎng)方向的教學實驗平臺的研發(fā)及培訓教材的出版,截止目前為止已公開出版70余本嵌入式/移動開發(fā)/物聯(lián)網(wǎng)相關圖書。企業(yè)理念:專業(yè)始于專注 卓識源于遠見。企業(yè)價值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。