<li id="qo4jt"></li>
  • <ruby id="qo4jt"><optgroup id="qo4jt"><td id="qo4jt"></td></optgroup></ruby>
  • <rp id="qo4jt"></rp>
      • 正文
        • 11.4  塊設(shè)備驅(qū)動(dòng)編程
      • 相關(guān)推薦
      申請(qǐng)入駐 產(chǎn)業(yè)圖譜

      嵌入式Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)之:塊設(shè)備驅(qū)動(dòng)編程

      2013/09/13
      加入交流群
      掃碼加入
      獲取工程師必備禮包
      參與熱點(diǎn)資訊討論

      ?

      11.4??塊設(shè)備驅(qū)動(dòng)編程

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

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

      1.編程流程說(shuō)明

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

      圖11.5??塊設(shè)備驅(qū)動(dòng)程序流程圖

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

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

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

      struct?gendisk?

      {

      ????int?major;????????????/*?主設(shè)備號(hào)?*/

      ????int?first_minor;????/*?第一個(gè)次設(shè)備號(hào)?*/

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

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

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

      ????char?disk_name[32];????????/*?塊設(shè)備名稱(chēng),在/proc/partions中顯示?*/

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

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

      ???????????????????????????????????????????? ????file_operations結(jié)構(gòu)對(duì)應(yīng)*/

      ????struct?request_queue?*queue;????/*?I/O請(qǐng)求隊(duì)列?*/

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

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

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

      };

      與字符設(shè)備驅(qū)動(dòng)程序一樣,塊設(shè)備驅(qū)動(dòng)程序也包含一個(gè)在<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)的定義中,可以看出塊設(shè)備并不提供read()、write()等函數(shù)接口。對(duì)塊設(shè)備的讀寫(xiě)請(qǐng)求都是以異步方式發(fā)送到設(shè)備相關(guān)的request?隊(duì)列之中。

      ?

      3.塊設(shè)備注冊(cè)和初始化

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

      塊設(shè)備的初始化過(guò)程如圖11.6所示。

      圖11.6??塊設(shè)備驅(qū)動(dòng)程序初始化過(guò)程

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

      使用register_blkdev()?函數(shù)對(duì)設(shè)備進(jìn)行注冊(cè)。

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

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

      與其對(duì)應(yīng)的塊設(shè)備的注銷(xiāo)函數(shù)為unregister_blkdev(),其格式如下所示。

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

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

      (2)申請(qǐng)并初始化請(qǐng)求隊(duì)列。

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

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

      其中參數(shù)rfn是請(qǐng)求隊(duì)列的處理函數(shù)指針,它負(fù)責(zé)執(zhí)行塊設(shè)備的讀、寫(xiě)請(qǐng)求。參數(shù)lock為自旋鎖,用于控制對(duì)所分配的隊(duì)列的訪(fǎng)問(wèn)。

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

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

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

      函數(shù)格式

      說(shuō)明

      struct?gendisk?*alloc_disk(int?minors)

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

      void?add_disk(struct?gendisk?*disk)

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

      void?del_gendisk(struct?gendisk?*disk)

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

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

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

      4.塊設(shè)備請(qǐng)求處理

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

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

      表11-17 請(qǐng)求處理相關(guān)函數(shù)

      函數(shù)格式

      說(shuō)明

      request_queue_t?*blk_alloc_queue(int?gfp_mask)

      分配請(qǐng)求隊(duì)列

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

      分配并初始化請(qǐng)求隊(duì)列

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

      從隊(duì)列中獲取一個(gè)請(qǐng)求

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

      將請(qǐng)求再次加入隊(duì)列

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

      設(shè)置最大訪(fǎng)問(wèn)扇區(qū)數(shù)

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

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

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

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

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

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

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

      相關(guān)推薦

      登錄即可解鎖
      • 海量技術(shù)文章
      • 設(shè)計(jì)資源下載
      • 產(chǎn)業(yè)鏈客戶(hù)資源
      • 寫(xiě)文章/發(fā)需求
      立即登錄

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