嵌入式Linux字元裝置驅動模型詳解

2021-07-25 10:42:48 字數 3089 閱讀 9532

在linux系統中,裝置的型別非常多。比如:字元裝置,塊裝置,網路裝置介面裝置,pci裝置,usb裝置,平台裝置,混雜裝置。裝置型別不同,對應的驅動模型也不同。linux下開發裝置驅動程式要遵循核心模組的編寫規範,在編寫字元裝置驅動程式時,有乙個統一的框架,也就是字元裝置驅動模型。下面我們來看下整個字元裝置驅動模型是怎樣的。

從思維導圖中我們可以看到整個裝置驅動模型分為了三個部分,分別是驅動初始化,實現裝置操作,還有驅動登出。下面重點分別介紹每個部分的具體實現。

分配裝置描述結構

初始化裝置描述結構

註冊裝置描述結構

硬體初始化

在任何一種驅動模型中,裝置都會通過核心的一種結構來描述,通過source in sight閱讀核心原始碼我們可以看到這個字元描述裝置結構體的定義如下

struct cdev ;
我們重點關注其中的三個變數。

1.第乙個是count,這個變數代表了有多少個相同的裝置,比如開發板上可能對應有多個串列埠,這個count值就代表了串列埠的數量。

2.第二個是dev,這個變數代表了這個裝置的裝置號,通過dev_t來定義,dev_t實際上是unsigned int無符號的32位整形核心規定,每個裝置都要對應乙個裝置號,裝置號又分為主裝置號和次裝置號。不同裝置對應的主裝置號是不相同的,多個同種裝置是通過次裝置號來區分開的。也就是說我們定義的這樣乙個cdev,是可以同時支援多個同種裝置的,我們通過設定不同次裝置號來將它們區分開。在linux終端下輸入ls -l /dev 來檢視當前接入系統的裝置。裝置在linux檔案系統中都是以裝置檔案來表示的。乙個裝置檔案即代表了乙個裝置。

矩形框裡的數值代表主裝置號,橢圓內的數值代表次裝置號。我們可以看到這是幾個同型別的裝置,所以它們的主裝置號都是1,而次裝置號是不同的。字元裝置檔案和字元裝置驅動程式是通過主裝置號來建立起聯絡的。乙個裝置號由高12位的主裝置號和低20位的次裝置號組成。核心中通過幾個巨集拓展的實現來完成裝置號的分解和合成,**寫的非常有意思,我們可以來看一下。

#define minorbits   20

#define minormask ((1u << minorbits) - 1)

#define major(dev) ((unsigned int) ((dev) >> minorbits))

#define minor(dev) ((unsigned int) ((dev) & minormask))

#define mkdev(ma,mi) (((ma) << minorbits) | (mi))

通過mkdev將主裝置號和次裝置號合成為裝置號,其實就是將主裝置號左移20位後位或低20位的次裝置號。

dev_t dev=mkdev(主裝置號,次裝置號)

major用來提取裝置號中的主裝置號,巨集定義中我們可以看到就是將主裝置號右移了20位,剔除了次裝置號,同時將主裝置號右對齊。

minor用來提取裝置號中的次裝置號,巨集定義中我們可以看到次裝置號是通過主裝置號位與乙個次裝置號掩碼來獲得,這個次裝置號寫的很有意思,將1左移20位後再減去1,從而得到乙個低20位都為1的掩碼。從而次裝置號得到提取。

那麼如何為乙個裝置分配乙個裝置號呢?linux核心提供了兩種分配裝置號的方法。第一種是靜態分配,第二種是動態分配。

cdev裝置描述結構也可以有兩種分配方式

- 靜態分配:struct cdev mdev;

- 動態分配:struct cdev *pdev=cdev_alloc();

通過cdev_init()函式來初始化裝置描述結構

void cdev_init(struct cdev *cdev, const

struct file_operations *fops)

/*cdev:待初始化的裝置描述結構 fops:裝置對應的操作函式集*/

字元裝置描述結構的註冊通過cdev_add()函式來完成

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

/*p待新增到核心的裝置描述結構 dev裝置號 count同型別裝置的數量*/

核心定義了乙個file_operations結構體來實現對裝置的各種操作,下面著重分析幾個常用的函式。我們可以看到,file_operations裡定義了非常多的函式指標,我們在編寫操作函式的時候,要對應這些函式指標規定的引數和返回值。這也是裝置驅動模型規範化的體現。

struct file_operations ;
在linux系統中,每乙個開啟的檔案,在核心中都會關聯乙個struct file結構體,這個結構體有幾個重要成員需要關注。

loff_t f_pos;/*檔案讀寫指標*/

const

struct file_operations *f_op;/*該檔案對應的操作*/

在linux系統中,每乙個存在於檔案系統裡的檔案都會關聯乙個struct inode結構體,該結構主要用來記錄檔案一些物理上的資訊。注意和上面的struct file區分開,struct file結構體只有當檔案開啟時才會被關聯,乙個檔案沒有被開啟時是不會關聯struct file的。重要的成員為

dev_t i_rdev;/*裝置號*/
open裝置方法主要用來為以後的操作完成初始化準備工作的。在大部分的驅動程式中,open完成如下操作:

release裝置方法和open正好相反。這個裝置方法有時也稱為close。

- 關閉裝置

read裝置方法通常完成兩件事情:

無論使用何種方式分配裝置號,都要在裝置掛起驅動退出時登出裝置號。我們使用核心提供的unregister_chrdev_region()函式來釋放這些裝置號。

}void cdev_del(struct cdev *p)

嵌入式linux字元裝置驅動

arm linux 驅動 抵岸科技 1.我們需要先呼叫register chrdev region 或 alloc chrdev region 來向系統申請裝置號 int register chrdev region dev t first,unsigned int count,char name ...

嵌入式linux字元裝置驅動

1.我們需要先呼叫register chrdev region 或 alloc chrdev region 來向系統申請裝置號 int register chrdev region dev t first,unsigned int count,char name 函式通過已知的裝置號first來註冊...

嵌入式linux字元裝置註冊裝置驅動

包含初始化巨集定義的標頭檔案,中的module init和module exit在此檔案中 include 包含初始化載入模組的標頭檔案,中的module license在此標頭檔案中 include 定義module param module param array的標頭檔案 include 定義...