記憶體模擬裝置進行驅動程式設計

2021-06-19 17:39:16 字數 3003 閱讀 7449

裝置驅動

在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 ...