嵌入式之Linux驅(qū)動(dòng)(八)

姓名:鄭煜爍? 學(xué)號(hào):19029100010? ?學(xué)院:電子工程學(xué)院

轉(zhuǎn)自:https://blog.csdn.net/u012142460/article/details/78988741

【嵌牛導(dǎo)讀】介紹linux系統(tǒng)中如何動(dòng)態(tài)建立設(shè)備號(hào)和設(shè)備節(jié)點(diǎn)

【嵌牛鼻子】動(dòng)態(tài)建立設(shè)備號(hào)

【嵌牛提問】動(dòng)態(tài)建立設(shè)備號(hào)和設(shè)備節(jié)點(diǎn)的基本步驟是什么

【嵌牛正文】

在Linux驅(qū)動(dòng)(三)字符設(shè)備驅(qū)動(dòng)框架中笆呆,我們簡(jiǎn)要介紹了如何編寫一個(gè)簡(jiǎn)單的驅(qū)動(dòng)框架,并總結(jié)了步驟

1民镜、生成設(shè)備號(hào)

2袜瞬、向內(nèi)核注冊(cè)該設(shè)備號(hào)

3冲杀、初始化設(shè)備對(duì)象,完成操作方法集

4睹酌、向內(nèi)核注冊(cè)該設(shè)備對(duì)象

5权谁、生成設(shè)備文件,供用戶層調(diào)用憋沿。

我們之前的步驟都是靜態(tài)的旺芽,

1、靜態(tài)生成設(shè)備號(hào)辐啄,這樣必須確保要申請(qǐng)的設(shè)備號(hào)是沒有被占用的采章。我們可以讓內(nèi)核幫我們動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào),可以確保生成的設(shè)備號(hào)是沒有被占用的壶辜。

2悯舟、設(shè)備對(duì)象空間也可以由內(nèi)核來(lái)分配。

3砸民、設(shè)備文件我們之前通過(guò)mknod來(lái)手動(dòng)創(chuàng)建图谷,我們現(xiàn)在在驅(qū)動(dòng)程序中直接完成設(shè)備文件的創(chuàng)建。

我們來(lái)看看相關(guān)的函數(shù)

1阱洪、自動(dòng)生成設(shè)備號(hào)并向內(nèi)核注冊(cè)alloc_chrdev_region

函數(shù)原型:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char *name)

參數(shù):

? ? ? ? ? dev: 要生成的設(shè)備號(hào)

? ? ? ? ? baseminor:次設(shè)備號(hào)

? ? ? ? ? count:生成的設(shè)備號(hào)數(shù)量

? ? ? ? ? name:設(shè)備號(hào)名稱

返回值:成功返回0便贵,錯(cuò)誤返回錯(cuò)誤碼

舉例:生成10個(gè)設(shè)備號(hào)。

dev_t devno;

int minor = 0;

int count = 10;

alloc_chrdev_region(&devno,minor,count, "xxx");

2冗荸、分配設(shè)備對(duì)象空間cdev_alloc

函數(shù)原型:struct cdev *cdev_alloc(void)

參數(shù):? ? ? ? 無(wú)

返回值:成功返回創(chuàng)建的設(shè)備對(duì)象地址承璃,錯(cuò)誤返回NULL

3、自動(dòng)生成設(shè)備節(jié)點(diǎn)

? ? ? (1)device_create創(chuàng)建設(shè)備節(jié)點(diǎn)

? ? ? 函數(shù)原型:struct device *device_create(struct class *class, struct device *parent,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_t devt, void *drvdata, const char *fmt, ...)

? ? ? 函數(shù)功能:生成一個(gè)設(shè)備節(jié)點(diǎn)

? ? ? 參數(shù):? class 設(shè)備類(看下一個(gè)函數(shù))

? ? ? ? ? ? ? ? ? ? parent:父類蚌本,沒有的話就用NULL

? ? ? ? ? ? ? ? ? ? devt:設(shè)備號(hào)

? ? ? ? ? ? ? ? ? ? drvdata:私有數(shù)據(jù)

? ? ? ? ? ? ? ? ? ? fmt:設(shè)備節(jié)點(diǎn)名稱

? ? ? ? ? ? ? ? ? ? .....:類似printf的格式

? ? ? ? 返回值:成功返回一個(gè)設(shè)備節(jié)點(diǎn)地址

? ? ? ? 創(chuàng)建會(huì)對(duì)應(yīng)銷毀設(shè)備節(jié)點(diǎn)函數(shù)

? ? ? ? (2)銷毀一個(gè)設(shè)備節(jié)點(diǎn)

? ? ? ? ? 函數(shù)原型:void device_destroy(struct class *class, dev_t devt)

? ? ? ? ? 函數(shù)功能:銷毀一個(gè)設(shè)備節(jié)點(diǎn)

? ? ? ? ? 參數(shù):? classs:設(shè)備類? devt:設(shè)備號(hào)

? ? ? (3)創(chuàng)建設(shè)備類

? ? ? 函數(shù)原型:class_create(owner, name)

? ? ? 函數(shù)功能:創(chuàng)建一個(gè)設(shè)備類

? ? ? 參數(shù):

? ? ? ? ? ? ? ? ? owner? 直接賦值為THIS_MODULE

? ? ? ? ? ? ? ? ? name? ? 類名稱

? ? ? ? 返回值:成功返回一個(gè)類的地址

? ? ? 創(chuàng)建設(shè)備類對(duì)應(yīng)是銷毀一個(gè)設(shè)備類

? ? ? ? (4)銷毀設(shè)備類

? ? ? ? 函數(shù)原型:void class_destroy(struct class *cls)

? ? ? ? 函數(shù)功能:銷毀一個(gè)設(shè)備類

? ? ? ? 參數(shù):cls 設(shè)備類

? ? ? ? ? 創(chuàng)建設(shè)備類和創(chuàng)建設(shè)備的返回值得錯(cuò)誤判斷需要用到專門的函數(shù)IS_ERR

? ? ? ? ? IS_ERR的原型 static inline long __must_check IS_ERR(const void *ptr) 參數(shù)是一個(gè)地址盔粹,將創(chuàng)建設(shè)備類或創(chuàng)建設(shè)備節(jié)點(diǎn)的返回值作為IS_ERR參數(shù),為真表示錯(cuò)誤程癌。

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/cdev.h>

#include <linux/fs.h>

#include <linux/slab.h>

#include <linux/device.h>

MODULE_LICENSE("GPL");

dev_t devno;

int major = 0;

int minor = 0;

int count = 1;

struct cdev *pdev;

struct class * pclass;

struct device * pdevice;

int demo_open(struct inode * inodep, struct file * filep)

{

printk("%s,%d\n", __func__, __LINE__);

return 0;

}

int demo_release(struct inode *inodep, struct file *filep)

{

printk("%s,%d\n", __func__, __LINE__);

return 0;

}

struct file_operations? fops = {

.owner =THIS_MODULE,

.open = demo_open,

.release = demo_release,

};

static int __init demo_init(void)

{

int ret = 0;

printk("%s,%d\n", __func__, __LINE__);

ret = alloc_chrdev_region(&devno,minor,count, "xxx");

if(ret)

{

printk("Failed to alloc_chrdev_region.\n");

return ret;

}

printk("devno:%d , major:%d? minor:%d\n", devno, MAJOR(devno), MINOR(devno));

pdev = cdev_alloc();

if(pdev == NULL)

{

printk("Failed to cdev_alloc.\n");

goto err1;

}

cdev_init(pdev, &fops);

ret = cdev_add(pdev, devno, count);

if(ret < 0)

{

? ? printk("Failed to cdev_add.");

goto err2;

}

pclass = class_create(THIS_MODULE, "myclass");

if(IS_ERR(pclass))

{

printk("Failed to class_create.\n");

ret = PTR_ERR(pclass);

goto err3;

}

pdevice = device_create(pclass, NULL, devno, NULL, "hello");

if(IS_ERR(pdevice))

{

printk("Failed to device_create.\n");

ret = PTR_ERR(pdevice);

goto err4;

}

return 0;

err4:

class_destroy(pclass);

err3:

cdev_del(pdev);

err2:

kfree(pdev);

err1:

unregister_chrdev_region(devno, count);

return ret;

}

static void __exit demo_exit(void)

{

printk("%s,%d\n", __func__, __LINE__);

device_destroy(pclass, devno);

class_destroy(pclass);

cdev_del(pdev);

kfree(pdev);

unregister_chrdev_region(devno, count);

}

module_init(demo_init);

module_exit(demo_exit);

利用之前的makefile舷嗡,make之后生成demo.ko文件。insmod demo.ko后就能生成設(shè)備

來(lái)源 CSDN

我們還可以查看一下/sys/class下

來(lái)源 CSDN

在class下生成了“myclass”類名嵌莉,進(jìn)入myclass文件夾下进萄,在myclass下也有hello這個(gè)設(shè)備節(jié)點(diǎn)

來(lái)源 CSDN

這里我們來(lái)介紹一下/sys這個(gè)文件夾

? ? ? ? Linux2.6以后的內(nèi)核所支持的sysfs文件系統(tǒng)被映射到此目錄上。linux設(shè)備驅(qū)動(dòng)模型中的總線锐峭、設(shè)備中鼠、驅(qū)動(dòng)都可以在sysfs文件系統(tǒng)中找到對(duì)應(yīng)的節(jié)點(diǎn)。

? ? ? ? sysfs把連接在系統(tǒng)上的設(shè)備和總線組織成為一個(gè)分級(jí)的文件沿癞。sysfs的一個(gè)目的就是展示設(shè)備驅(qū)動(dòng)模型中各組件的層次關(guān)系援雇。目錄下包括如下部分

來(lái)源 CSDN

blcok:所有的塊設(shè)備

bus:所有的總線

class:系統(tǒng)的設(shè)備類

devices:設(shè)備

Linux2.6以后的設(shè)備模型是總線、設(shè)備椎扬、驅(qū)動(dòng)模式惫搏。在sys目錄下也有體現(xiàn)

來(lái)源 CSDN

類中的設(shè)備和總線下的設(shè)備實(shí)際上都是設(shè)備文件夾具體文件的鏈接

下圖是平臺(tái)總線下的設(shè)備具温,都是鏈接于devices/platform下

來(lái)源 CSDN
來(lái)源 CSDN

上圖是在我們創(chuàng)建的myclass類中的設(shè)備文件,鏈接于devices/virtual/myclass目錄下

我們可以看到在/dev中有很多tty設(shè)備筐赔,我們也可以一下子生成多個(gè)設(shè)備铣猩,在上個(gè)程序的基礎(chǔ)上稍加修改即可。

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/cdev.h>

#include <linux/fs.h>

#include <linux/slab.h>

#include <linux/device.h>

MODULE_LICENSE("GPL");

dev_t devno;

int major = 0;

int minor = 0;

int count = 10;

struct cdev *pdev;

struct class * pclass;

struct device * pdevice;

int demo_open(struct inode * inodep, struct file * filep)

{

printk("%s,%d\n", __func__, __LINE__);

return 0;

}

int demo_release(struct inode *inodep, struct file *filep)

{

printk("%s,%d\n", __func__, __LINE__);

return 0;

}

struct file_operations? fops = {

.owner =THIS_MODULE,

.open = demo_open,

.release = demo_release,

};

static int __init demo_init(void)

{

int ret = 0;

int i = 0;

int j = 0;

printk("%s,%d\n", __func__, __LINE__);

ret = alloc_chrdev_region(&devno,minor,count, "xxx");

if(ret)

{

printk("Failed to alloc_chrdev_region.\n");

return ret;

}

printk("devno:%d , major:%d? minor:%d\n", devno, MAJOR(devno), MINOR(devno));

pdev = cdev_alloc();

if(pdev == NULL)

{

printk("Failed to cdev_alloc.\n");

goto err1;

}

cdev_init(pdev, &fops);

ret = cdev_add(pdev, devno, count);

if(ret < 0)

{

? ? printk("Failed to cdev_add.");

goto err2;

}

pclass = class_create(THIS_MODULE, "myclass");

if(IS_ERR(pclass))

{

printk("Failed to class_create.\n");

ret = PTR_ERR(pclass);

goto err3;

}

for(i = 0; i < count; i++)

{

pdevice = device_create(pclass, NULL, MKDEV(MAJOR(devno), MINOR(devno)+i), NULL, "hello%d", i);

if(IS_ERR(pdevice))

{

printk("Failed to device_create.\n");

ret = PTR_ERR(pdevice);

goto err4;

}

}

return 0;

err4:

for(j = 0; j < i; j++)

{

device_destroy(pclass, MKDEV(MAJOR(devno), MINOR(devno)+j));

}

class_destroy(pclass);

err3:

cdev_del(pdev);

err2:

kfree(pdev);

err1:

unregister_chrdev_region(devno, count);

return ret;

}

static void __exit demo_exit(void)

{

int i = 0;

printk("%s,%d\n", __func__, __LINE__);

for(i = 0; i < count; i++)

{

device_destroy(pclass, MKDEV(MAJOR(devno), MINOR(devno)+i));

}

class_destroy(pclass);

cdev_del(pdev);

kfree(pdev);

unregister_chrdev_region(devno, count);

}

module_init(demo_init);

module_exit(demo_exit);

把count值修改為10川陆,我們要?jiǎng)?chuàng)建10個(gè)設(shè)備剂习,創(chuàng)建設(shè)備時(shí)蛮位,連續(xù)創(chuàng)建10次较沪,注意次設(shè)備號(hào)要不同,并起不同的名字失仁。另外注意出錯(cuò)處理時(shí)尸曼,要不之前創(chuàng)建的設(shè)備都要銷毀掉。加載之后我們看一下生成了幾個(gè)設(shè)備

來(lái)源 CSDN

我們看到生成了hello0--hello9 十個(gè)設(shè)備萄焦。這十個(gè)設(shè)備是在一個(gè)類“myclass”下控轿,我們可以查看/sys/class/myclass下

來(lái)源 CSDN

————————————————

版權(quán)聲明:本文為CSDN博主「念念有余」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議拂封,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明茬射。

原文鏈接:https://blog.csdn.net/u012142460/article/details/78988741

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冒签,隨后出現(xiàn)的幾起案子在抛,更是在濱河造成了極大的恐慌,老刑警劉巖萧恕,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刚梭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡票唆,警方通過(guò)查閱死者的電腦和手機(jī)朴读,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)走趋,“玉大人衅金,你說(shuō)我怎么就攤上這事〔净停” “怎么了典挑?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)啦吧。 經(jīng)常有香客問我您觉,道長(zhǎng),這世上最難降的妖魔是什么授滓? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任琳水,我火速辦了婚禮肆糕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘在孝。我一直安慰自己诚啃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布私沮。 她就那樣靜靜地躺著始赎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仔燕。 梳的紋絲不亂的頭發(fā)上造垛,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音晰搀,去河邊找鬼五辽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛外恕,可吹牛的內(nèi)容都是我干的杆逗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼鳞疲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罪郊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起尚洽,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤悔橄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后翎朱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橄维,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年拴曲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了争舞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡澈灼,死狀恐怖竞川,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叁熔,我是刑警寧澤委乌,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站荣回,受9級(jí)特大地震影響遭贸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜心软,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一壕吹、第九天 我趴在偏房一處隱蔽的房頂上張望著蛙。 院中可真熱鬧,春花似錦耳贬、人聲如沸踏堡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顷蟆。三九已至,卻和暖如春腐魂,著一層夾襖步出監(jiān)牢的瞬間帐偎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工挤渔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肮街,地道東北人风题。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓判导,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親沛硅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眼刃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容