在Linux下,驅動設備有字符設備驅動、塊設備驅動和網絡設備驅動三種,之前學習了字符設備驅動,現在開始學習塊設備驅動。首先來比較看這兩種設備驅動有何不通,爲什麼要分割成不同類型的驅動。舉一個例子說明引入塊設備驅動的必要:
假如按照字符設備一樣的框架去構造驅動,如圖:
則需要頻繁地對存儲設備進行擦除,如果使用另一種框架構思(塊設備思想):
對比之下,對於這樣的存儲設備,則引入塊設備顯然使得操作的效果大爲提高。由此可知塊設備的特點就是:把請求放入隊列,優化後執行。
字符設備與塊設備I/O操作的區別:
a.塊設備只能按照塊爲單位進行輸入輸出,而字符設備則是以字節爲單位。大多數設備都是字符設備,因爲它們不需要緩衝而且不是以固定塊大小操作。
b.塊設備對應I/O請求有對應的緩衝區,因此它們可以以選擇任意順序來響應,字符設備無需緩衝區且可以直接讀寫。對於存儲設備而言,調整順序十分重要,因爲讀寫連續扇區比分離扇區快。
c.字符設備只能被順序讀寫,而塊設備可以隨機訪問。
類比於字符設備,在塊設備中,有一個類似於字符設備中file_operations的結構體:block_device_operations;在Linux內核中,使用一個gendisk結構體來表示一個獨立的磁盤設備或分區;在Linux內核中,使用一個queue隊列來管理這個設備的I/O請求。這就是塊設備的大體構架。
編寫塊設備驅動程序的框架主要爲:
1.用alloc_disk(int minors);來分配gendisk結構體
2.設置gendisk結構體
3.分配/設置queue隊列
4.設置gendisk的其他信息(如:容量)
5.註冊gendisk結構體:add_disk
相關操作函數:
struct gendisk *alloc_disk(int minors);//分配gendisk結構體
void add_disk(struct gendisk *disk);//註冊gendisk結構體
request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock);//分配隊列,rfn爲一個請求處理函數,lock是一個自旋鎖
int register_blkdev(unsigned int major, const char *name);////註冊塊設備,name在註冊驅動後,對應 cat /proc/devices裏的名字
例子:
以上就是塊設備驅動程序的框架。塊設備驅動程序相對於字符設備驅動程序要複雜,但對於像存儲設備這樣的塊設備,這樣的驅動構架可以提高效率。