1. 程式人生 > >【迅為iTop4412學習筆記】17.靜態方式申請主次裝置號

【迅為iTop4412學習筆記】17.靜態方式申請主次裝置號

宣告

以下都是我剛開始看驅動視訊的個人強行解讀,如果有誤請指出,共同進步。

本節目標

靜態方式申請主次裝置號


申請主次裝置號的函式(本節講靜態,下節動態)

我們開啟 include/linux/fs.h 標頭檔案可以看到以下三個函式(具體引數含義後面再說)
當然,寫的時候要包含標頭檔案 linux/fs.h

// 動態申請主次裝置號(linux分配)
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
// 靜態申請主次裝置號(自己指定主次裝置號是多少)
extern int register_chrdev_region(dev_t, unsigned, const char *); // 已被上面倆取代,這個過時了... extern int __register_chrdev(太多懶得抄);

資料型別

就像檔案IO操作有個fd一樣,註冊裝置號也有一個類似的東西

申請主次裝置號,必須要用dev_t(其實就是int)來作為資料型別。
其標頭檔案為 linux/cdev.h

處理的巨集定義

主次裝置號一共32位,高12位用來表示主裝置號,低20位用來表示次裝置號。
當然,自己去移位也行,但是linux已經給我們封裝好了一個巨集定義叫MKDEV(ma,mi) ,引數1是主裝置號,引數2是次裝置號。
其標頭檔案為 linux/kdev_t.h

正文

我們本次編寫的模板參考上一節的模組傳參,這樣我們就可以直接把傳入的引數當作主、次裝置號。

如果我們insmod的時候,忘了傳入引數怎麼辦?所以我們在宣告主次裝置號的時候,賦一個初值,如果沒有傳入引數,就用初值好了。

那麼賦值多少好呢?

linux貼心的為我們提供了0,當傳入0的時候,表示不指定裝置號是多少,由linux去提供空閒的裝置號(從大到小找,主裝置號就255個,裝置號255->1)。

當然,只是為了保險起見,如果不是我們指定多少,那靜態還有啥意義,不如直接用動態申請的方式…

以下是模組傳參部分的程式碼

// 初始化主次裝置號
int device_major =
0; int device_minor = 0; // 模組傳參 module_param(device_major, int, S_IRUSR); module_param(device_minor, int, S_IRUSR);

我們在模組初始化的時候來申請主裝置號。
首先要定義一個主次裝置號,並把模組傳參主、次裝置號,合成後賦值給他

dev_t mryang_dev;
mryang_dev = MKDEV(device_major, device_minor);

有了主、次裝置號mryang_dev(高12位是主,低20位是次,用MKDEV巨集定義合成的)

我們就開始申請

先介紹一下申請函式的引數:

// 引數1:裝置號的編號
// 引數2:連續裝置編號個數
// 引數3:裝置的名字
// 返回:申請狀態
int register_chrdev_region(dev_t first,unsigned int count,char *name) 

裝置編號就傳入我們剛剛合成好的mryang_dev
連續裝置編號個數傳入2
裝置的名字我們就叫"mryang_cdev"
我們再宣告一個ret來檢視是否申請成功

當然,申請了,你退出模組的時候同樣要解除安裝釋放,其函式是:

// 引數內容類似申請的函式
void unregister_chrdev_region(dev_t first, unsigned int count);

全部程式碼:

#include <linux/init.h>
#include <linux/module.h>

#include <linux/moduleparam.h>

// 字元裝置申請函式
#include <linux/fs.h>
// 裝置號資料型別 dev_t
#include <linux/cdev.h>
// 處理巨集定義 MKDEV
#include <linux/kdev_t.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("MrYang");

// 初始化主次裝置號
int device_major = 0;
int device_minor = 0;
// 模組傳參
module_param(device_major, int, S_IRUSR);
module_param(device_minor, int, S_IRUSR);

static int mryang_init(void)
{
	int ret;
	dev_t mryang_dev;
	// 輸出
	printk(KERN_EMERG "HELLO MrYang\n");
	printk(KERN_EMERG "major: %d, minor: %d\n", device_major, device_minor);
	
	// 申請主裝置號
	mryang_dev = MKDEV(device_major, device_minor);
	ret = register_chrdev_region(mryang_dev, 2, "mryang_cdev");
	if(ret < 0)
		printk(KERN_EMERG "failed!\n");
	else
		printk(KERN_EMERG "success!\n");
	return 0;
}

static void mryang_exit(void)
{
	dev_t mryang_dev;
	// 輸出
	printk(KERN_EMERG "Bye MrYang\n");
	// 登出
	mryang_dev = MKDEV(device_major, device_minor);
	unregister_chrdev_region(mryang_dev, 2);
	printk(KERN_EMERG "over!\n");
}

module_init(mryang_init);
module_exit(mryang_exit);

編譯完成之後

我們先檢視一下linux已經分配的主裝置號

cat /proc/devices

我們隨便挑一個沒有的即可,比如主裝置號叫9,次裝置號本節不關心,所以設定為0讓他自動分配吧。

我們輸入:

insmod probe_linux_module.ko device_major=9 device_minor=0

返回:

[  176.009824] HELLO MrYang
[  176.010960] major: 9, minor: 0
[  176.013951] success!

檢視主裝置號發現編號是9,名字一致,全部正確。

我們還可以試一下不帶引數

insmod probe_linux_module.ko

返回:

[  900.409599] HELLO MrYang
[  900.410692] major: 0, minor: 0
[  900.413702] success!

主、次裝置號都是動態分配的號碼,然後靜態方式去申請它。
檢視裝置號發現被分配為248,也正確。

收尾

學到現在,感覺對於主次裝置號大致有點概念了。
主裝置號用於區分某一類的裝置
次裝置號用於區分這一類裝置裡的哪一個裝置。
有了主+次,就可以具體定位到某一裝置了。
以上就是我目前的見解。