Linux驱动device_create创建字符设备文件

在Linux中有两种创建字符设备的方法,一种是通过mknod手动进行设备文件创建,第二种是通过device_create函数进行设备文件创建。在驱动开发中常用第二种方式进行设备文件的创建。

  • class_create和device_create
    先来了解一下跟设备文件创建相关的两个函数。
    class_create:在调用device_create前要先用class_create创建一个类。类这个概念在Linux中被抽象成一种设备的集合。类在/sys/class目录中。
    在这里插入图片描述
    Linux内核中有各种类,比如gpio、rtc、led等。
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})

class_create这个函数使用非常简单,在内核中是一个宏定义。其中参数owner通常为THIS_MODULE,name为类名。

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目录下就只包含系统中真正存在的设备。

下面就来写一个驱动程序并使用这两个函数来创建设备。
程序:

#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");

在程序中调用class_create创建一个类,类名为testledclass。然后在调用device_create自动创建设备文件,设备名为testled。加载驱动结果如下。
在这里插入图片描述

加载驱动后进入/sys/class目录中可以看到有一个名为testledclass的类。在/dev目录下可以找到一个名为testled的设备文件。然后我们也可以操作这个设备文件进行读写操作。

  • 11
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`device_create_file()`函数是在设备驱动程序中创建一个sysfs文件节点的函数。在Linux内核中,sysfs是一个虚拟文件系统,它允许内核和用户空间之间进行通信。sysfs文件系统中的每一个文件都是一个内核对象的属性,可以通过读写这些属性来控制和监视内核对象的状态。 `device_create_file()`函数需要三个参数:设备结构体(struct device *)、指向属性结构体(struct attribute *)的指针,以及sysfs文件节点名字的字符串。 以下是使用`device_create_file()`函数创建设备文件的示例代码: ```c #include <linux/device.h> static struct attribute my_attr = { .name = "my_attribute", .mode = S_IRUSR | S_IWUSR, }; static ssize_t my_attribute_show(struct device *dev, struct device_attribute *attr, char *buf) { // 读取属性值并将其写入到缓冲区buf中 } static ssize_t my_attribute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { // 将从buf中读取的属性值写入到设备中 } static DEVICE_ATTR(my_attribute, S_IRUSR | S_IWUSR, my_attribute_show, my_attribute_store); static int my_device_probe(struct platform_device *pdev) { // 创建设备节点 device_create_file(&pdev->dev, &dev_attr_my_attribute); return 0; } static int my_device_remove(struct platform_device *pdev) { // 删除设备节点 device_remove_file(&pdev->dev, &dev_attr_my_attribute); return 0; } ``` 在上面的代码中,我们定义了一个名为`my_attr`的属性结构体,并使用`DEVICE_ATTR()`宏将其转换为设备属性。然后,在设备的probe函数中使用`device_create_file()`函数创建设备文件`my_attribute`,在设备的remove函数中使用`device_remove_file()`函数删除该文件。在设备属性的`show`和`store`函数中,我们可以实现对设备属性的读写操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值