Linux sysfs文件系统

前言

ioctl:注册虚拟的字符设备文件,以这个虚拟设备上的 read/write/ioctl 等接口与用户交互

但这种方式有几个明显的缺点。

read/write接口功能单一,一般只能做一件事情

ioctl虽然可以根据cmd参数实现多重功能,但无法直接在 Shell 脚本中使用,为了使用 ioctl 的功能,还必须编写配套的 C语言的虚拟设备操作程序

ioctl二进制数据接口存在大小端问题 (big endian与little endian),不同平台CPU(32/64)不方便移植

proc:注册 proc 接口,接受用户的 read/write/ioctl 操作;

同样使用的是"read/open/ioctl"接口,因此也存在“设备文件”方式中的类似问题。

而且proc文件系统作为一个调试接口而存在,它提供简单的数据交互,但从内核与用户之间交互的数据量过大(大于Linux页框数据量)就需要特殊处理

sysfs:注册 sysfs 属性

1.什么是sysfs

  sysfs是linux系统下一个基于内存的文件系统,主要功能是将设备(device)和驱动(driver)数据内容或属性通过文件的方式从内核空间映射到用户空间,方便用户对设备和驱动进行访问和设置。实现了sysfs文件接口,会在指定目录下将驱动读写空间生成一个临时文件,该文件可以直接通过shell命令的“echo”、“cat”访问。


1.1 sysfs特性

sysfs提供一种机制,使得可以显式描述内核对象、对象属性及对象间关系。sysfs有两组接口,一组针对内核,用于将设备映射到文件系统中,另一组针对用户程序,用于读取或操作这些设备。描述了内核中的sysfs要素及其在用户空间的表现:
sysfs在内核中的组成要素
在用户空间的显示
 

内核对象(kobject)目录
对象属性(attribute)文件
对象关系(relationship)
链接(Symbolic Link)


  sysfs 一般是挂在是“/sys”目录下,sysfs把系统的设备的驱动映射成层次分明的目录结构,方便用户管理设备,顶级目录一般会包括block、bus、drivers、class、power、firmware等子目录。

devices内核对系统中所有设备的分层次表达模型,也是sysfs文件系统管理设备的最重要的目录结构
block系统的块设备符号链接,符号链接指向/sys/devices下的相应目录
bus系统总线设备,如i2c、spi、platform等,linux系统总线模型由“device”和“driver”组成,因此bus的子目录包括“device”和“driver”目录
class包含所有注册的到内核的设备类
dev包含字符设备(char)和块设备(block)的以主次(majior/minor)编码方式描述链接到实际设备(/sys/device)的链接文件
firmware系统加载固件机制的对用户空间的接口
fs用来描述系统中所有的文件系统,包括文件系统本身和按照文件系统分类存放的已挂载点
kernel存放内核中所有可调整的参数
module包含当前系统中已加载的模块,包括编译到内核和编译成模块(.ko)的驱动
 
power电源管理描述文件和控制接口


2.sysfs驱动接口实现

2.1 创建与释放目录(kobject)

2.1.1 使用device目录
       sysfs默认挂载在“/sys”目录下,对于内核态是“kobject”,对于用户态,一般映射在总线(bus)下对应的设备(device)目录下,如在“/sys/devices/platform/dev-name/”下。
kobject在设备结构体中的描述:

struct platform_device
     —>struct device dev
        —>struct kobject kobj

        设备驱动在创建时,即会创建该目录,因此,不需再手动手动创建,在创建映射文件时直接指定为该目录。
使用sysfs_create_file在sys下创建设备的属性节点

int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr); sysfs_create_file(&pdev->dev.kobj, &mydev_info_attribute);/* 在device下创建属性文件*/
sysfs_create_file(&pdev->dev.kobj, &dev_attr_mydev_info);


2.1.2 自定义目录
  如果不使用device下的目录,可在“/sys”目录下创建自定义目录,创建目录用“kobject_create_and_add”接口,原型位于“kernel/libkobject.c”中。

struct kobject_create_and_add(const char *name,struct kobject *parent);
引用        #include<linux/kobject.h>
name        目录名称
parent 父目录,NULL为默认在/sys目录下
返回        成功返回创建的目录句柄,失败返回NULL

struct kobject *soc_kobj;
soc_kobj = kobject_create_and_add("sys_test", NULL);
sysfs_create_file(soc_kobj, &mydev_info_attribute) //在sys/sys_test/创建
                                                      //属性文件mydev_info


注意:使用自定义目录作为kobject时,由于该创建的kobject目录没有对应的父设备,不可使用device_attribute


2.2 初始化attribute相关结构体

2.2.1 attribute结构体描述
内核对象(attribute)映射到用户态就是文件,一个简单的属性结构定义“struct attribute”,其原型如下,常用的元素的文件名称(name)和文件属性(mode)。

struct attribute {
    const char        *name;           //  属性文件的名字 
    struct module        *owner;       //  属性文件的所有者
    mode_t            mode;
};

2.2.2 kobj_attribute 
一个单独的属性结构并不包含读写其属性值的方法,对于kobject对象类型的属性

struct kobj_attribute {
    struct attribute attr;
    ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
        char *buf);
    ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
        const char *buf, size_t count);
};static struct kobj_attribute mydev_info_attribute= __ATTR(mydev_info, 
                                    0666, demo_info_show, demo_info_store);

2.2.3 device_attribute
1. 驱动设备(device)用“struct device_attribute”描述,对应的“show”和“store”则是需驱动工程师实现的函数实体

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);
};

2. linux内核定义了“DEVICE_ATTR”辅助宏,方便定义device_attribute描述变量
kernel/include/linux/device.h

/* DEVICE_ATTR */
#define DEVICE_ATTR(_name, _mode, _show, store) 
     struct device_attribute dev_attr##_name = __ATTR(_name, _mode, _show, _store)
/* __ATTR  */
#define __ATTR(_name,_mode,_show,_store) { 
.attr = {.name = __stringify(_name), .mode = _mode }, 
.show = _show,     
.store = _store,     
}

3. 用“DEVICE_ATTR”宏定义一个设备描述文件

static DEVICE_ATTR(mydev_info, 0660, demo_info_show, demo_info_store);        

/* 展开后 */
static struct device_attribute dev_attr_mydev_info = {
       .attr = {
.name = "mydev_info",
.mode = 0660
},
.show = demo_info_show,
.store = demo_info_store,
};

2.3 访问接口函数

该部分主要是是“echo”、“cat”在驱动最终调用的函数。
2.3.1 kobj_attribute 回调函数
对象是kobject 和kobj_attribute 

static ssize_t demo_info_show(struct kobject *kobj, 
                struct kobj_attribute *attr, char *buf)
{
   return sprintf(buf, "demo_info_show test %d\n", demo_info);
}
static ssize_t demo_info_store(struct kobject *kobj, 
                struct kobj_attribute *attr, const char *buf, size_t count)
{
   printk("\n from user,length=0x%X,content=%s\n",count,buf);
   return count;
}


2.3.1 device_attribute 回调函数
对象是device和device_attribute 

static ssize_t demo_info_show(struct device *dev,
                struct device_attribute *attr, char *buf)
{
        
   return scnprintf(buf, PAGE_SIZE, " demo_info_show test %d\n", demo_info);
}
static ssize_t demo_info_store(struct device *dev,
                struct device_attribute *attr, char *buf)
{
   printk("\n from user,length=0x%X,content=%s\n",count,buf);
   return count;
}


2.4 创建属性组


2.4.1 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);

sysfs_create_group(&pdev->dev.kobj, &touch_attr_group);/* 在device下创建属性文件组 */


2.4.2 定义对应的attribute结构体
 

static DEVICE_ATTR(device_file, 0666, tp_info_read, tp_info_write);
static DEVICE_ATTR(device_file0, 0444, tp_read, NULL);

static struct attribute *tp_attrs[] = {
    &dev_attr_device_file.attr,
    &dev_attr_device_file0.attr,
    &dev_attr_device_file1.attr,
    &dev_attr_device_file2.attr,
    NULL属性结构体数组最后一项必须以NULL结尾。
};

static const struct attribute_group touch_attr_group= {
        .attrs = tp_attrs,
};

3.其他创建文件的方式


3.1 device_create_file创建属性

devices (include/linux/device.h)
int device_create_file(struct device *dev,  const struct device_attribute *attr)
void device_remove_file(struct device *, struct device_attribute *);

device_create_file(&pdev->dev, &dev_attr_demo); DEVICE_ATTR(_name, _mode, _show, _store);


3.2 driver_create_file

int driver_create_file(struct device_driver *, struct driver_attribute *);
void driver_remove_file(struct device_driver *, struct driver_attribute *);

DRIVER_ATTR(_name, _mode, _show, _store)struct driver_attribute {
    struct attribute        attr;
    ssize_t (*show)(struct device_driver *, char * buf);
    ssize_t (*store)(struct device_driver *, const char * buf,
                         size_t count);
};


3.3 bus_create_file

int bus_create_file(struct bus_type *, struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);

BUS_ATTR(_name, _mode, _show, _store)
 
struct bus_attribute {
    struct attribute        attr;
    ssize_t (*show)(struct bus_type *, char * buf);
    ssize_t (*store)(struct bus_type *, const char * buf);
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值