【迅為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,也正確。
收尾
學到現在,感覺對於主次裝置號大致有點概念了。
主裝置號用於區分某一類的裝置
次裝置號用於區分這一類裝置裡的哪一個裝置。
有了主+次,就可以具體定位到某一裝置了。
以上就是我目前的見解。