linux中sysfs創建設備節點的方法和DEVICE_ATTR


使用DEVICE_ATTR宏,可以定義一個struct device_attribute設備屬性,使用函數sysfs_create_group或sysfs_create_file便可以在設備目錄下創建具有show和store方法的節點。能方便的進行調試。

一、使用DEVICE_ATTR構建device attribute

下面將順着我們直接使用的DEVICE_ATTR來分析一下,這個宏究竟都做了哪些事情。

 DEVICE_ATTR的定義:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

 

 而__ATTR宏的定義在include/linux/sysfs.h文件中,如下:

#define __ATTR(_name, _mode, _show, _store) {                \
    .attr = {.name = __stringify(_name),                \
         .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },        \
    .show    = _show,                        \
    .store    = _store,                        \
}

 那么struct device_attribute的定義又是怎么樣的呢?該結構體的定義在include /linux/device.h,其定義如下:

/* interface for exporting device attributes */
struct device_attribute {
    struct attribute    attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,
            char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr,
             const char *buf, size_t count);
};

 而其中的struct attribute的定義在include/linux/device.h中,如下:

struct attribute {
    const char        *name;
    umode_t            mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    bool            ignore_lockdep:1;
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};

 總結一下:

DEVICE_ATTR(_name, _mode, _show, _store)等價於:
struct device_attribute dev_attr_##_name = {
    .attr = {.name = __stringify(_name),
             .mode = VERIFY_OCTAL_PERMISSIONS(_mode)},
    .show = _show,
    .store = _store,
}

 其中:.show和.store的類型定義如下:

 show函數的詳細描述:

    ssize_t (*show)(struct device *dev, struct device_attribute *attr,
            char *buf);
  •  入參buf是需要我們填充的string即我們cat屬性節點時要顯示的內容;
  • 函數的返回值是我們填充buf的長度,且長度應當小於一個頁面的大小(4096字節);
  • 其他參數一般不用關心。

例如:

static ssize_t show_my_device(struct device *dev,
                              struct device_attribute *attr, char *buf) //cat命令時,將會調用該函數
{
    return sprintf(buf, "%s\n", mybuf);
}

store函數的詳細描述:

   ssize_t (*store)(struct device *dev, struct device_attribute *attr,
             const char *buf, size_t count);
  •  入參buf是用戶傳入的字符串,即echo到屬性節點的內容;
  • 入參count是buf中字符串的長度。
  • 函數的返回值通常返回count即可。
  • 其他參數一般不用關心。

例如:

static ssize_t store_my_device(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count) //echo命令時,將會調用該函數
{
    sprintf(mybuf, "%s", buf);
    return count;
}

mode的權限定義在kernel/include/uapi/linux/stat.h中。

#define S_IRWXU 00700 //用戶可讀寫和執行
#define S_IRUSR 00400//用戶可讀
#define S_IWUSR 00200//用戶可寫
#define S_IXUSR 00100//用戶可執行

#define S_IRWXG 00070//用戶組可讀寫和執行
#define S_IRGRP 00040//用戶組可讀
#define S_IWGRP 00020//用戶組可寫
#define S_IXGRP 00010//用戶組可執行

#define S_IRWXO 00007//其他可讀寫和執行
#define S_IROTH 00004//其他可讀
#define S_IWOTH 00002//其他可寫
#define S_IXOTH 00001//其他可執行

  至此,我們已經定義好了.show和.store函數,那么就可以使用DEVICE_ATTR了。

static DEVICE_ATTR(my_device_test, S_IWUSR | S_IRUSR, show_my_device, store_my_device);

 

二、將device attribute添加到sysfs中

上面我們已經創建好了所需要的device attribute,下面就要將這些attribute添加到sysfs中了,此處可用的函數由sysfs_create_file和sysfs_create_group。

1、只有一個節點的創建sysfs_create_file

此處在驅動的probe或module_init函數調用sysfs_create_file即可,在module_exit或remove函數中調用sysfs_remove_file來移除節點。

int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);

以下是全部的代碼:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>

static char sysfs_buff[100] = "my_sysfs_test_string";
static ssize_t show_sys_device(struct device *dev,
                              struct device_attribute *attr, char *buf) //cat命令時,將會調用該函數
{
    return sprintf(buf, "%s\n", sysfs_buff);
}

static ssize_t store_sys_device(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count) //echo命令時,將會調用該函數
{
    sprintf(sysfs_buff, "%s", buf);
    return count;
}
static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
//定義一個名字為sys_device_file的設備屬性文件

struct file_operations mytest_ops = {
    .owner = THIS_MODULE,
};

static int major;
static struct class *cls;
struct device *mydev;
static int mytest_init(void)
{
    
    major = register_chrdev(0, "mytest", &mytest_ops);
    cls = class_create(THIS_MODULE, "mytest_class");
    mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //創建mytest_device設備

    if (sysfs_create_file(&(mydev->kobj), &dev_attr_sys_device_file.attr))
    { //在mytest_device設備目錄下創建一個sys_device_file屬性文件
        return -1;
    }

    return 0;
}

static void mytest_exit(void)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, "mytest");
    sysfs_remove_file(&(mydev->kobj), &dev_attr_sys_device_file.attr);
}

module_init(mytest_init);
module_exit(mytest_exit);
MODULE_LICENSE("GPL");

 

2、多個節點的創建sysfs_create_group

 定義attribute屬性結構體數組到屬性組中:

static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file0, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file1, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file2, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);

static struct attribute *sys_device_attributes[] = {
    &dev_attr_sys_device_file.attr,
    &dev_attr_sys_device_file0.attr,
    &dev_attr_sys_device_file1.attr,
    &dev_attr_sys_device_file2.attr,
    NULL////屬性結構體數組最后一項必須以NULL結尾。
};

static const struct attribute_group sys_device_attr_group = {
    .attrs = sys_device_attributes,
};

 下面就可以利用sysfs_create_group和sysfs_create_group來添加、移除屬性節點組了。

定義如下:

 

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)

 

全部代碼如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>

static char sysfs_buff[100] = "my_sysfs_test_string";
static ssize_t show_sys_device(struct device *dev,
                              struct device_attribute *attr, char *buf) //cat命令時,將會調用該函數
{
    return sprintf(buf, "%s\n", sysfs_buff);
}

static ssize_t store_sys_device(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count) //echo命令時,將會調用該函數
{
    sprintf(sysfs_buff, "%s", buf);
    return count;
}

//定義多個sys_device_file的設備屬性文件

static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file0, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file1, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file2, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);

static struct attribute *sys_device_attributes[] = {
    &dev_attr_sys_device_file.attr,
    &dev_attr_sys_device_file0.attr,
    &dev_attr_sys_device_file1.attr,
    &dev_attr_sys_device_file2.attr,
    NULL////屬性結構體數組最后一項必須以NULL結尾。
};

static const struct attribute_group sys_device_attr_group = {
    .attrs = sys_device_attributes,
};

struct file_operations mytest_ops = {
    .owner = THIS_MODULE,
};

static int major;
static struct class *cls;
struct device *mydev;
static int mytest_init(void)
{
    
    major = register_chrdev(0, "mytest", &mytest_ops);
    cls = class_create(THIS_MODULE, "mytest_class");
    mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //創建mytest_device設備

    if (sysfs_create_group(&(mydev->kobj), &sys_device_attr_group))
    { 
        //在mytest_device設備目錄下創建多個sys_device_file屬性文件
        return -1;
    }

    return 0;
}

static void mytest_exit(void)
{
    device_destroy(cls, MKDEV(major, 0));
    class_destroy(cls);
    unregister_chrdev(major, "mytest");
    sysfs_remove_group(&(mydev->kobj), &sys_device_attr_group);
}

module_init(mytest_init);
module_exit(mytest_exit);
MODULE_LICENSE("GPL");

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM