- 如何创建设备节点
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");