目录
问题描述:
解决方案:udev(嵌入式中用的是mdev)
相关函数
在调用device_create前要先用class_create创建一个类。Linux内核中有各种类,比如gpio、rtc、led等。类这个概念在Linux中被抽象成一种设备的集合。类在/sys/class目录中。编辑
class_create:
device_create:
问题描述:
使用mknod创建设备文件的缺点:需要手动创建与删除设备文件,那能不能自动生成设备文件呢?
解决方案:udev(嵌入式中用的是mdev)
-
什么是udev?应用层的一个应用程序
- 内核驱动和应用层udev之间有一套信息传输机制(netlink协议)
- 应用层启用udev,内核驱动中使用相应接口
- 驱动注册和注销时信息会被传给udev,由udev在应用层进行设备文件的创建和删除
注册完字符设备驱动后,添加设备类的操作,以让内核发信息给udev,让udev自动创建和删除设备文件
相关函数
- class_create
- device_create
- class_destroy
- device_destroy
在调用device_create前要先用class_create创建一个类。Linux内核中有各种类,比如gpio、rtc、led等。类这个概念在Linux中被抽象成一种设备的集合。类在/sys/class目录中。
class_create:
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
class_create函数在内核中是一个宏定义。其中参数owner通常为THIS_MODULE,name为类名。
device_create:
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
{
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
va_end(vargs);
return dev;
}
device_create用于创建设备。
class:该设备依附的类
parent:父设备
devt:设备号(此处的设备号为主次设备号)
drvdata:私有数据
fmt:设备名。
device_create能自动创建设备文件是依赖于udev这个应用程序。udev是一种工具,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。
模块安装函数中:
test_class = class_create(THIS_MODULE, "aston_class");
if (IS_ERR(test_class))
return -EINVAL;
// 最后1个参数字符串,就是我们将来要在/dev目录下创建的设备文件的名字
// 所以我们这里要的文件名是/dev/test
device_create(test_class, NULL, mydev, NULL, "test111");
模块卸载函数中:
device_destroy(test_class, mydev);
class_destroy(test_class);
这样就可以自动进行设备文件的创建和删除了
代码范例:
#define CHRDEV_MAJOR 240 // 主设备号
#define CHRDEV_MAION 0 // 次设备号
#define CHRDEV_COUNT 1 // 次设备号个数
#define CHRDEV_NAME "testchrdev"
struct led_cdev
{
struct cdev chrdevcdev;
int major;
dev_t dev;
struct class *led_dev_class;
};
static struct led_cdev leddev;
ssize_t chrdev_read (struct file *file, char __user *usr, size_t size, loff_t *loff)
{
printk("%s\r\n",__func__);
return 0;
}
int chrdev_open (struct inode *inode, struct file *file)
{
printk("%s\r\n",__func__);
return 0;
}
int chrdev_release (struct inode *inode, struct file *file)
{
printk("%s\r\n",__func__);
return 0;
}
struct file_operations fops =
{
.open = chrdev_open,
.read = chrdev_read,
.release = chrdev_release,
};
static int __init chrdev_init(void)
{
int ret = 0,error = 0;
struct device *devices;
error = alloc_chrdev_region(&leddev.dev,CHRDEV_MAION,CHRDEV_COUNT,CHRDEV_NAME); // 注册设备号
printk("MAJOR = %d MINOR = %d\r\n",MAJOR(leddev.dev),MINOR(leddev.dev));
if(error < 0){
printk("alloc_chrdev_region error\r\n");
ret = -EBUSY;
goto fail;
}
leddev.major = MAJOR(leddev.dev);
cdev_init(&leddev.chrdevcdev, &fops); // 绑定字符设备操作函数集
error = cdev_add(&leddev.chrdevcdev,leddev.dev,CHRDEV_COUNT); // 添加字符设备
if(error < 0){
printk("cdev_add error\r\n");
ret = -EBUSY;
goto fail1;
}
// 创建类,类名为testledclass
leddev.led_dev_class = class_create(THIS_MODULE, "testledclass");
if (IS_ERR(leddev.led_dev_class)){
printk("class_create error\r\n");
ret = -EBUSY;
goto fail2;
}
// 创建设备
devices = device_create(leddev.led_dev_class, NULL, MKDEV(leddev.major,0), NULL, "testled");
if(NULL == devices){
printk("device_create error\r\n");
ret = -EBUSY;
goto fail3;
}
return 0;
fail3:
class_destroy(leddev.led_dev_class);/* 删除类 */
fail2:
cdev_del(&leddev.chrdevcdev);/* 删除cdev */
fail1:
unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
fail:
return ret;
}
static void __exit chrdev_exit(void)
{
device_destroy(leddev.led_dev_class,MKDEV(leddev.major,0));/* 卸载设备 */
class_destroy(leddev.led_dev_class);/* 删除类 */
cdev_del(&leddev.chrdevcdev);/* 删除cdev */
unregister_chrdev_region(leddev.dev,CHRDEV_COUNT);
}
module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_DESCRIPTION("xxxxxx");
MODULE_AUTHOR("xxxxxx");
MODULE_LICENSE("GPL");