裝置驅動
在linux的裝置驅動程式設計中,都需要遵從一種核心程式設計的模式,這也可以理解為一種設計模式(design pattern),這種模式讓硬體programmer脫離硬體平台,開始和作業系統打交道,就像業務和邏輯分離一樣,提高了**的可復用性。
但是這樣依然沒有說清楚到底linux使用者是如何使用驅動程式的,linux系統上有三類裝置:
字元驅動裝置(character device)
塊裝置(block device)
網路裝置(network device)
它們(網路裝置除外)的訪問都是使用者通過裝置檔案(或者叫裝置節點)來進行訪問而使用的。
記憶體如何模擬裝置
下面來分析乙個簡單的字元裝置驅動,實現在一段記憶體中模擬字元裝置的讀和寫操作
首先定義乙個結構體來描述一段記憶體的具體資訊。因為外設的訪問是作業系統通過實體地址進行訪問的,因而我們可以把這段記憶體看作是乙個字元裝置。
view sourceprint?1 struct mem_dev
2 ;
data是指向記憶體起始位址的指標,size是記憶體的大小。因此把這樣乙個封裝可以看作乙個裝置。
字元裝置的統一描述
在linux2.6的核心中,字元裝置使用結構體struct cdev進行描述。它定義在/include/linux/cdev.h中:
在這個結構體中會發現另外乙個巢狀的結構體struct file_operations,它是字元裝置把驅動的操作和裝置聯絡在一起的紐帶。是乙個函式指標的集合,每個被開啟的檔案都對應於一系列的操作。它定義在/include/linux/fs.h中:
分配cdev
初始化cdev
新增cdev
裝置可以通過靜態和動態分配兩種方式進行分配。下面是實現**:
view sourceprint?1 dev_t devno = mkdev(mem_major, 0);//mkdev是將主裝置號和次裝置號轉換為dev_t型別資料
2 /* 靜態申請裝置號*/
3 if (mem_major)
4 result = register_chrdev_region(devno, 2, "memdev");//devno為主裝置號,共申請兩個連續的裝置
5 else /* 動態分配裝置號 */
6 mem_major是在巨集定義中自己選的乙個裝置號,定為254,所以下一步else不會執行。但當自己選定的裝置號已經被使用時就會產生衝突。這時就可以使用動態分配的方式獲得裝置號。
裝置號分配之後就是對cdev進行初始化:
view sourceprint?1 cdev_init(&cdev, &mem_fops);
2 cdev.owner = this_module;//驅動引用計數,作用是這個驅動正在使用的時候,你再次用inmod命令時,出現警告提示
3 cdev.ops = &mem_fops;
cdev_init(&cdev, &mem_fops)是初始化cdev結構,將結構體cdev和mem_fops繫結起來。cdev.ops = &mem_fops是對cdev結構體成員進行賦值。其中mem_fops是用file_operations定義描述的檔案操作結構體:
view sourceprint?1 static const struct file_operations mem_fops =
2 ;
最後是註冊字元裝置:
view sourceprint?1 cdev_add(&cdev, mkdev(mem_major, 0), memdev_nr_devs);//memdev_nr_devs=2,分配2個裝置
這樣三步就完成了字元裝置的註冊。
再看一下mem_read和mem_write的實現過程:
view sourceprint?01 /*讀函式*/
02 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)//buf快取區
03
18 else
19
24 return ret;//返回實際讀取位元組數,判斷讀取是否成功
25 }
26
27
28 /*寫函式*/
29 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)//write和read類似,直接參考read
30
49 return ret;
50 }
下面是字元裝置的測試程式:
view sourceprint?01 #include
02 int main()
03
17
18 /*寫入裝置:使用者空間——>字元裝置(即那一段記憶體中)*/
19 fwrite(buf, sizeof(buf), 1, fp0);//這個fwrite和.read = mem_read的關係?
20
21 /*重新定位檔案位置(思考沒有該指令,會有何後果) */
22 fseek(fp0,0,seek_set);//呼叫mem_llseek()定位
23
24 /*清除buf*/
25 strcpy(buf,"buf is null!");
26 printf("buf: %s\n",buf);
27
28 /*讀出裝置字元裝置(即那一段記憶體中)——>使用者空間*/
29 fread(buf, sizeof(buf), 1, fp0);
30 /*檢測結果*/
31 printf("buf: %s\n",buf);
32 return 0;
塊裝置驅動(記憶體模擬硬碟)
搜尋 blk init queut 參考 drivers block xd.c 和 drivers block z2ram.c 兩個檔案。看乙個驅動程式從 入口函式 開始看。處理函式 放到佇列 放到gendisk 其他屬性 gengdisk 最終效果,檔案系統通過處理函式來實現相應的功能.塊裝置驅動...
塊裝置驅動之記憶體模擬硬碟
一.塊裝置驅動框架 與字元裝置相比什麼差別 1.塊裝置僅僅能以塊為單位接受輸入和返回輸出。而字元裝置則以位元組為單位。大多數裝置是字元裝置,由於它們不須要緩衝並且不以固定塊大小進行操作。2.塊裝置對於i o請求有相應的緩衝區。因此它們能夠選擇以什麼順序進行響應,字元裝置無需緩衝且被直接讀寫。對於儲存...
Linux塊裝置驅動之記憶體模擬塊裝置
用記憶體代替塊裝置的總結,相對來簡單得多,對記憶體操作想必大家都很熟悉,直接分配一塊記憶體就可以直接讀寫操作了 參考 drivers block xd.c drivers block z2ram.c define ramblock size 1024 1024 乙個扇區是512位元組 static ...