歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux設備管理(五)_寫自己的sysfs接口

我們在Linux設備管理(一)_kobject, kset,ktype分析一文中介紹了kobject的相關知識,在Linux設備管理(二)_從cdev_add說起和Linux設備管理(三)_總線設備的掛接舉例介紹了內核中是如何進行設備管理的,並在Linux設備管理(四)_從sysfs回到ktype一文中結合sysfs機制和kobject對內核的設備管理機制進行一定深度的討論,從中可以看出,字符設備的cdev本身的kobject是沒有初始化的,也沒有在sysfs中創建任何目錄,平台設備是將設備掛接到總線上,在掛接的過程中就會在相應的sysfs目錄創建相應的文件。在這裡,本文將搭建一個sysfs模塊接口的框架,此後,就可以為我們自己的驅動在sysfs中添加屬性讀寫接口。

准備屬性和回調接口

我們知道,呈現在sysfs中的文件名其實都是內核中ktype的屬性值,而從用戶空間對這些屬性值進行讀寫其實就是回調了我們在ktype結構中注冊讀寫函數,所以,這裡我們准備了兩個函數,值得注意的是,內核會將用戶空間的buf轉換到內核空間並當作參數傳入回調函數,所以我們就不用再進行這個轉換。這裡由於沒有實際的屬性,我就只是打印一下信息,實際使用的時候這兩個函數要對內核中的真實屬性進行讀寫。

static char kbuf[1024] = {0};
static ssize_t my_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
    char info[]="my_show is called\n";
    return scnprintf(buf,sizeof(info),info);
}

static ssize_t my_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
    printk("%s is called\n",__func__);
    strncpy(kbuf,buf,count);
    printk("user_buf:%s,count:%ld|after copy,kbuf:%s\n",buf,count,kbuf);
    return count;
}

構造kobj_attribute

准備好了原材料,第一道工序就是將屬性和回調接口封裝到一個kobj_attribute結構對象中,當然對這個屬性的讀寫權限等信息也應該進行封裝,我們來回顧一下這個結構

//linux/kobject.h
139 struct kobj_attribute {  
140         struct attribute attr;
141         ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
142                         char *buf);
143         ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
144                          const char *buf, size_t count);
145 };

//linux/sysfs.h
 29 struct attribute { 
 30         const char              *name;
 31         umode_t                 mode;   //權限
 32         ...
 37 };

當然,內核也給我們提供了相應的宏來快速的構造這個結構

//linux/sysfs.h
100 #define __ATTR(_name, _mode, _show, _store) {                           \
101         .attr = {.name = __stringify(_name),                            \
102                  .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },             \
103         .show   = _show,                                                \
104         .store  = _store,                                               \
105 }   

使用了這個宏,我們就可以快速的構造我們的kobj_attribute結構

//show是name,就是sys中的文件名
static struct kobj_attribute my_sysfs_read =__ATTR(show, S_IRUSR, my_show, NULL);

static struct kobj_attribute my_sysfs_write =__ATTR(write, S_IWUSR, NULL,my_store);

構造attribute數組

一個kobject網完對應多個attribute,此時就需要將這些attribute封裝成一個結構體數組,注意這個數組最後一個元素一定要是NULL

static struct attribute *my_sysfs_attr[] = {
    &my_sysfs_read.attr,
    &my_sysfs_write.attr,
    NULL,
};

如果這些屬性直接放到kobject的目錄中,我們可以直接使用sysfs_create_file(),但通常情況下,我們更多的將上述的struct attribute進行進一步的封裝,並使用sysfs_create_group()來創建一個名為attribute_group.name的、包含struct attribute中的屬性目錄,這種方式更加的靈活,因為如果我們不指定目錄的名字,那麼效果個sysfs_create_file()是一樣的。

static struct attribute_group my_sysfs_attr_group = {
    .name = "sub_my_attr",      //不寫這個成員就不會創建子文件夾
    .attrs = my_sysfs_attr,
};

struct kobject *my_kobj = NULL;
int mysys_init(void)
{
    ...
    my_kobj = kobject_create_and_add("my_sysfs", NULL);
    sysfs_create_group(my_kobj, &my_sysfs_attr_group);
    ...
}

void mysys_exit(void)
{
    ...
    sysfs_remove_group(my_kobj, &my_sysfs_attr_group);
    kobject_put(my_kobj);
}

輸出

將上述的程序編譯成模塊,我們就可以觀察到下面的輸出結果。

Copyright © Linux教程網 All Rights Reserved