姓名:鄭煜爍? 學(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è)備
我們還可以查看一下/sys/class下
在class下生成了“myclass”類名嵌莉,進(jìn)入myclass文件夾下进萄,在myclass下也有hello這個(gè)設(shè)備節(jié)點(diǎn)
這里我們來(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)系援雇。目錄下包括如下部分
blcok:所有的塊設(shè)備
bus:所有的總線
class:系統(tǒng)的設(shè)備類
devices:設(shè)備
Linux2.6以后的設(shè)備模型是總線、設(shè)備椎扬、驅(qū)動(dòng)模式惫搏。在sys目錄下也有體現(xiàn)
類中的設(shè)備和總線下的設(shè)備實(shí)際上都是設(shè)備文件夾具體文件的鏈接
下圖是平臺(tái)總線下的設(shè)備具温,都是鏈接于devices/platform下
上圖是在我們創(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è)備
我們看到生成了hello0--hello9 十個(gè)設(shè)備萄焦。這十個(gè)設(shè)備是在一個(gè)類“myclass”下控轿,我們可以查看/sys/class/myclass下
————————————————
版權(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