linux device_attribute

  • 如何创建设备节点

1.struct device_attribute definition

struct attribute {
    const char        *name;       //  属性文件的名字 
    struct module    *owner;       //  属性文件的所有者
    mode_t            mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};

struct device_attribute {
    struct attribute    attr;       //  内置的attribute 结构体
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,   //属性文件的show方法(也就是读)
            char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr,  //属性文件的store方法(也就是写)
             const char *buf, size_t count);
};

  Device drivers can export attributes via their sysfs directories.Drivers can declare attributes using a DRIVER_ATTR macro that works identically to the DEVICE_ATTR macro.

  With DEVICE_ATTR, the driver can automatically create files in sys directory. We only need to implement show and store functions.

  Then in the application layer, we can read and write the files created by sys through the commands of cat and echo, and realize the interaction.

2.DEVICE_ATTR() macro definition

  DEVICE_ATTR() is defined in include/linux/device.h, as follows:

#define DEVICE_ATTR(_name, _mode, _show, store)
struct device_attribute dev_attr
##_name = __ATTR(_name, _mode, _show, _store)

Where _mode is defined as follows:

400: The owner can read and no one else can do anything.
644: The owner can read, but only the owner can edit.
660: Owners and group users are both readable and writable, and no one else can do anything.
664: Everyone can read it, but only the owner and group users can edit it.
700: The owner can read, write and execute, and other users can't operate at all.
744: Everyone can read, but only the owner can edit and execute.
755: Everyone can read and execute, but only the owner can edit.
777: Everyone can read, write and execute (this setting is usually not a good idea).

  Of course, it can also be replaced by macros such as S_IWUSR (user writes), S_IRUSR (user reads).

  DEVICE_ATTR宏展开:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = { \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
        .show   = _show,                                        \
        .store  = _store,                                       \
    }

  Take the following definition of DEVICE_ATTR() as an example:

static ssize_t show_my_device(struct device *dev,
                  struct device_attribute *attr, char *buf)   //cat Command time,This function will be called
{
    return buf;
}

static ssize_t set_my_device(struct device *dev,
                 struct device_attribute *attr,
                 const char *buf, size_t len)   //echo Command time,This function will be called.
{
    return len;
}
static DEVICE_ATTR(my_device_test, S_IWUSR|S_IRUSR, show_my_device, set_my_device);   //Define a name as my_device_test Device properties file

  Finally, the macro is expanded to:

struct device_attribute dev_attr_my_device_test ={  
    .attr = {.name = "my_device_test", .mode = S_IWUSR|S_IRUSR },     
    .show    = show_my_device,                 
    .store    = set_my_device,             
}

3.device_create_file/device_remove_file

  • int device_create_file(struct device *, struct device_attribute *);

    • 在/sys/devices/xxx/目录下创建device属性文件
  • void device_remove_file(struct device *, struct device_attribute *);

    • 移除/sys/devices/xxx/目录下的device属性文件

4.device_create_file/sysfs_create_group区别

   568 int device_create_file(struct device *dev,
   569                const struct device_attribute *attr)
   570 {
   571     int error = 0;                                      
   580     error = sysfs_create_file(&dev->kobj, &attr->attr);
   584 }

  101 int sysfs_create_group(struct kobject *kobj,
  102                const struct attribute_group *grp)
  103 {
  104     return internal_create_group(kobj, 0, grp);                                                        
  105 }
  106 

5.案例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/sysfs.h>

#define DEMO_NAME "demo_dev"

struct demo_dev {
	struct cdev chr_dev;
	struct device *demo_device;
	dev_t dev;
};

static dev_t devno;
static unsigned int major;
static struct demo_dev *cur;
static struct class *demo_class;

static ssize_t albert_show(struct device *dev, 
		struct device_attribute *attr, char *buf)
{
	printk("albert:%s\n",__func__);
	return 0;
}

static ssize_t albert_store(struct device *dev, 
		struct device_attribute *attr, const char *buf, size_t size)
{
	printk("albert:%s\n",__func__);
	return 0;	
}
static DEVICE_ATTR_RW(albert);

static ssize_t test_show(struct device *dev, 
		struct device_attribute *attr, char *buf)
{
	printk("albert:%s\n",__func__);
	return 0;
}

static ssize_t test_store(struct device *dev, 
		struct device_attribute *attr, const char *buf, size_t size)
{
	printk("albert:%s\n",__func__);
	return 0;	
}
static DEVICE_ATTR_RW(test);

static ssize_t nes_show(struct device *dev, 
		struct device_attribute *attr, char *buf)
{
	printk("albert:%s\n",__func__);
	return 0;
}

static ssize_t nes_store(struct device *dev, 
		struct device_attribute *attr, const char *buf, size_t size)
{
	printk("albert:%s\n",__func__);
	return 0;	
}
static DEVICE_ATTR_RW(nes);

static struct device_attribute *demo_attributes[] = {
	&dev_attr_nes,
	&dev_attr_albert,
	&dev_attr_test,
	NULL,
};


/*
 * static struct attribute *demo_attrs[] = {
 *     &dev_attr_nes.attr,
 * //	&dev_attr_test.attr,
 *     NULL,
 * };
 * ATTRIBUTE_GROUPS(demo);
 */

static int chr_open(struct inode *nd, struct file *filp)
{
	int major = MAJOR(nd->i_rdev);
	int minor = MINOR(nd->i_rdev);

	printk("chr_open, major = %d, minor = %d\n",major, minor);
	return 0;	
}

static ssize_t chr_read(struct file *f, char __user *u, size_t sz, loff_t *off)
{
	printk("in the chr_read() function!\n");
	return 0;
}

struct file_operations chr_ops = {
	.owner = THIS_MODULE,
	.open  = chr_open,
	.read  = chr_read,
};

static int demo_init(void)
{
	int ret, i;

	cur = kzalloc(sizeof(*cur), GFP_KERNEL);
	if (!cur) {
		printk("albert:Unable to alloc albert dev\n");
		return -ENOMEM;
	}

	demo_class = class_create(THIS_MODULE, "demo_class");
	if (IS_ERR(demo_class)) {
		pr_err("couldn't register class demo!\n");
		ret = PTR_ERR(demo_class);
		goto out_destroy_class;
	}

//	demo_class->dev_groups = demo_groups;

	ret = alloc_chrdev_region(&devno, 0, 1, DEMO_NAME);
	if (ret < 0)
		return ret;

	printk("albert:major = %d,minor = %d\n", MAJOR(devno), MINOR(devno));
	major = MAJOR(devno);
	cur->dev = MKDEV(major, 0);

	cdev_init(&cur->chr_dev, &chr_ops);
	ret = cdev_add(&cur->chr_dev, cur->dev, 1);
	if (ret < 0)
		return ret;

	cur->demo_device = device_create(demo_class, NULL, cur->dev, NULL, "demo_device");
	if (IS_ERR(cur->demo_device)) {
		pr_err("couldn't create demo device!\n");
		ret = PTR_ERR(cur->demo_device);
		goto out_destroy_device;
	}

	for (i = 0; i < ARRAY_SIZE(demo_attributes); i++) {
		ret = device_create_file(cur->demo_device, demo_attributes[i]);
		if (ret)
			while (i > 0) {
				i--;
				device_remove_file(cur->demo_device, demo_attributes[i]);
			}
	}
		
	return 0;

out_destroy_device:
	device_destroy(demo_class,cur->dev);
out_destroy_class:
	class_destroy(demo_class);
	return ret;
}

static void demo_exit(void)
{
	printk("removing chr_dev module!\n");
	cdev_del(&cur->chr_dev);
	unregister_chrdev_region(devno, 1);
	device_destroy(demo_class,cur->dev);
	class_destroy(demo_class);
}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值