sysfs接口整理

时间:2021-08-20 00:09:03

SYS节点

目录结构:

1sysfs相关知识点介绍(介绍sysfs的体系结构)

2sys节点核心知识(使用sys节点核心的知识)

3:代码实例(创建sys节点的代码实例)

1sysfs相关知识点介绍

1.1sysfs
虚拟文件系统

sysfs是一种基于ram的文件系统,它提供了一种用于向用户空间展现内核空间里的对象、属性和链接。sysfskobject层次紧密相连,它将kobject层次关系表现出来,使得用户空间可以看见这些层次关系。

sysfs

Linux
内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与
proc
有些类似,但除了与
proc
相同的具有查看和设定内核参数功能之外,还有为
Linux
统一设备模型作为管理之用。相比于
proc
文件系统,使用
sysfs
导出内核数据的方式更为统一,并且组织的方式更好sysfs
的挂载点
/sys

sysfs
文件系统总是被挂载在
/sys
挂载点上。虽然在较早期的2.6内核系统上并没有规定
sysfs
的标准挂载位置,可以把
sysfs
挂载在任何位置,但较近的2.6内核修正了这一规则,要求
sysfs
总是挂载在
/sys
目录上。

1.2初识
/sys

清单 1.
与 /sys
文件系统的一次交互(视内核版本号和外接设备的不同,在您的系统上执行这些命令的结果可能与此有所不同)

$ ls -F /sys
block/ bus/ class/ dev/ devices/ firmware/ fs/ kernel/ module/ power/
$ ls -F /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/
broken_parity_status enable modalias resource0 rom uevent
class irq msi_bus resource0_wc subsystem@ vendor
config local_cpulist power/ resource1 subsystem_device
device local_cpus resource resource2 subsystem_vendor

sys 文件系统下的目录结构

/sys 下的目录结构是经过精心设计的:在 /sys/devices下是所有设备的真实对象,包括如视频卡和以太网卡等真实的设备,也包括 ACPI 等不那么显而易见的真实设备、还有 tty, bonding 等纯粹虚拟的设备;在其它目录如 class, bus 等中则在分类的目录中含有大量对 devices 中真实对象引用的符号链接文件; 清单 1 中在 /sys 根目录下顶层目录的意义如下:

表 1. /sys 下的目录结构

/sys 下的子目录

所包含的内容

/sys/devices

这是内核对系统中所有设备的分层次表达模型,也是 /sys 文件系统管理设备的最重要的目录结构,下文会对它的内部结构作进一步分析;

/sys/dev

这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件,它是在内核 2.6.26 首次引入;

/sys/bus

这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分;

/sys/class

这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在 /sys/class/input 之下,而不论它们是以何种总线连接到系统。它也是构成 Linux 统一设备模型的一部分;

/sys/block

这 里是系统中当前所有的块设备所在,按照功能来说放置在 /sys/class 之下会更合适,但只是由于历史遗留因素而一直存在于 /sys/block, 但从 2.6.22 开始就已标记为过时,只有在打开了 CONFIG_SYSFS_DEPRECATED 配置下编译才会有这个目录的存在,并且在 2.6.26 内核中已正式移到 /sys/class/block, 旧的接口 /sys/block 为了向后兼容保留存在,但其中的内容已经变为指向它们在 /sys/devices/ 中真实设备的符号链接文件;

/sys/firmware

这里是系统加载固件机制的对用户空间的接口,关于固件有专用于固件加载的一套API,在附录 LDD3 一书中有关于内核支持固件加载机制的更详细的介绍;

/sys/fs

这 里按照设计是用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点,但目前只有 fuse,gfs2 等少数文件系统支持 sysfs 接口,一些传统的虚拟文件系统(VFS)层次控制参数仍然在 sysctl (/proc/sys/fs) 接口中中;

/sys/kernel

这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于 sysctl (/proc/sys/kernel) 接口中 ;

/sys/module

这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在 /sys/module 中:

  • 编译为外部模块(ko文件)在加载后会出现对应的 /sys/module/<module_name>/, 并且在这个目录下会出现一些属性文件和属性目录来表示此外部模块的一些信息,如版本号、加载状态、所提供的驱动程序等;

  • 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的 /sys/module/<module_name>, 这些模块的可用参数会出现在 /sys/modules/<modname>/parameters/<param_name> 中,

    • 如 /sys/module/printk/parameters/time 这个可读写参数控制着内联模块 printk 在打印内核消息时是否加上时间前缀;

    • 所 有内联模块的参数也可以由 "<module_name>.<param_name>=<value>" 的形式写在内核启动参数上,如启动内核时加上参数 "printk.time=1" 与 向 "/sys/module/printk/parameters/time" 写入1的效果相同;

  • 没有非0属性参数的内联模块不会出现于此。

/sys/power

这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。

/sys/slab (对应 2.6.23 内核,在 2.6.24 以后移至 /sys/kernel/slab)

从2.6.23 开始可以选择 SLAB 内存分配器的实现,并且新的 SLUB(Unqueued Slab Allocator)被设置为缺省值;如果编译了此选项,在 /sys 下就会出现 /sys/slab ,里面有每一个 kmem_cache 结构体的可调整参数。对应于旧的 SLAB 内存分配器下的 /proc/slabinfo 动态调整接口,新式的 /sys/kernel/slab/<slab_name> 接口中的各项信息和可调整项显得更为清晰。


1. sysfs 目录层次图

sysfs接口整理其中涉及到
ksets, kobjects, attrs
等很多术语,详细可以参见http://www.ibm.com/developerworks/cn/linux/l-cn-sysfs/

2sys节点核心知识

2.1sysfs接口函数的建立_DEVICE_ATTR

sysfs接口创建的宏DEVICE_ATTR,原型是:

#define
DEVICE_ATTR(_name, _mode, _show, _store) \

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

函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法

_show:表示的是读方法,

_stroe表示的是写方法。

当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等

如对设备的使用
DEVICE_ATTR

对驱动使用
DRIVER_ATTR

对总线使用
BUS_ATTR

对类别(class)使用
CLASS_ATTR

这四个高级的宏来自于<include/linux/device.h>

DEVICE_ATTR宏声明有四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

完成了DEVICE_ATTR函数宏的填充,下面就需要创建接口了

例如:

static
DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling,
set_polling);
static struct attribute *dev_attrs[] =
{
&dev_attr_polling.attr,
NULL,
};

当你想要实现的接口名字是polling的时候,需要实现结构体struct
attribute*dev_attrs[]

其中成员变量的名字必须是&dev_attr_polling.attr

然后再封装

static
struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};

在利用sysfs_create_group(&pdev->dev.kobj,
&dev_attr_grp);
创建接口

2.2:节点的深入理解:

2.21
目录的创建

对于每个注册到系统的kobject,在sysfs中都有一个目录来展现它,这个目录(AA)会作为某个目录(A)的子目录而被创建,我们知道目录AA代
表kobject,那么目录A则代表kobject->parent,显示这种目录层次关系可以很好地向用户展现kobject层次结构。在
sysfs中位于顶层的那些目录,分别代表着不同的子系统,每个新加入的kobject都应该归属于某一个子系统。

sysfs会把目录所代表的kobject存储在目录的dentry结构的d_fsdata字段,这样当文件打开和关闭的时候,sysfs可以直接对kobject做引用计数。

2.2.2
属性

在sysfs中,kobject的属性表现为一个普通的文件。sysfs将文件的I/O操作重定向到那些为该属性定义的方法,提供了一种读写属性的机制。

属性应该表现为ASCII文本文件,并且最好每个文件只包含一个值。当然,每个文件仅包含一个值可能会有害于效率,所以如果一个文件包含某种类型的数据的数组也是被接受的。不建议在一个文件中包含不同数据类型的数据和多行数据。

属性的定义如下:

struct
attribute {
char * name;
struct module *owner;
mode_t
mode;
};

int sysfs_create_file(struct kobject
* kobj, const struct attribute *
attr);在kobj所在目录下创建一个属性文件,文件名为attr->name
void
sysfs_remove_file(struct kobject * kobj, const struct attribute *
attr);将属性文件attr->name从kobj所在目录下移除
为了使对属性的读写变得有意义,一般将attribute结构嵌入到其他数据结构中。子系统通常都会定义自己的属性结构,并且提供添加和删除属性文件的包裹函数。

例如,设备驱动模型为device子系统定义了相应的属性结构device_attribute:

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

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属性文件系统提供了一个宏方便定义device属性:

#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,/
}

例如,定义一个device属性,名为foo,读写该文件的方法分别为show_foo和store_foo:

static DEVICE_ATTR(foo, S_IWUSR |
S_IRUGO, show_foo, store_foo);

将宏展开为:

static
struct device_attribute dev_attr_foo = {
.attr= {
.name =
"foo",
.mode = S_IWUSR | S_IRUGO,

},
.show = show_foo,
.store = store_foo,
};

子系统特定的回调函数

当子系统定义一个新的属性类型时,必须实现一组sysfs操作,从而将文件的读写调用(read/write调用)重定向到属性拥有者的show和store方法。

struct sysfs_ops {
ssize_t
(*show)(struct kobject *, struct attribute *, char *);
ssize_t
(*store)(struct kobject *, struct attribute *, const char
*);
};当读写一个文件时,sysfs将为此类型调用合适的方法,这些方法会将kobject结构和attribute结构转换为合适的指针类型,然后调用与之关
联的相关的方法。注意,子系统必须已经为此类型定义好了kobj_type作为此类型的描述符,因为sysfs_ops指针存储在kobj_type中。

举个例子:

#define
to_dev_attr(_attr) container_of(_attr, struct device_attribute,
attr)
#define to_dev(d) container_of(d, struct device, kobj)

static
ssize_t dev_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf)
{
struct device_attribute * dev_attr =
to_dev_attr(attr);
struct device * dev = to_dev(kobj);
ssize_t
ret = 0;

if
(dev_attr->show)
ret = dev_attr->show(dev, buf);
return
ret;
}

属性的读写

为了读写属性,当定义属性时,必须指定show和/或者store方法:

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

其他注意事项:

-
Writing causes the show() method to be rearmed regardless of current
file position.

-
缓冲区的大小应总是为PAGE_SIZE个字节。在i386上,PAGE_SIZE=4096

-
show方法应该返回放入缓冲区的字节数,即snprintf的返回值

-
show方法应该总是使用snprintf

-
store方法应该返回实际使用的字节数,可以使用strlen来得到

-
show和/或者store方法可能会出错,所以当失败时,记得返回错误值

-
The object passed to the methods will be pinned in memory via
sysfs
referencing counting its embedded object. However, the
physical 
entity (e.g. device) the object represents may not
be present. Be 
sure to have a way to check this, if
necessary. (???)
下面的代码展示了device属性的一个简单的实现:

static
ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s/n",
dev->name);
}

static
ssize_t store_name(struct device * dev, const char * buf)
{
sscanf(buf, "%20s", dev->name);
return strnlen(buf,
PAGE_SIZE);
}

static DEVICE_ATTR(name, S_IRUGO,
show_name, store_name);

注意,实际应用时,并不允许从用户空间设置设备的名字,这里仅举个例子

2.3:驱动的通用框架

2.3.1:代码实例:

#include<linux/module.h>

#include<linux/kernel.h>

#include<linux/init.h>

#include<linux/list.h>

#include<linux/spinlock.h>

#include<linux/device.h>

#include<linux/timer.h>

#include<linux/err.h>

#include<linux/ctype.h>

#include<linux/leds.h>

MODULE_LICENSE("GPL");

static char
*whom="world";

static int
howmany=1;

module_param(howmany,int,S_IRUGO);

module_param(whom,charp,S_IRUGO);

static int
__init hello_init(void)

{

int i=0;

for(i;i<howmany;i++)

printk(KERN_ALERT
"Hello worldi %d ",i);

return
0;

}

static void
__exit hello_exit(void)

{

printk(KERN_ALERT
"Hello exit");

}

module_init(hello_init);

module_exit(hello_exit);

2.3.2:makefile文件实例:

ifeq
($(KERNELRELEASE),)

KERNEL_DIR:=/usr/src/linux-headers-3.13.0-32-generic

PWD:=$(shell
pwd)

modules:

$(MAKE) -C
$(KERNEL_DIR) M=$(PWD) modules

modules_install:

$(MAKE) -C
$(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf
.*.cmd *.ko *.o modules.order Module.symvers *mod.c

.PHONY:
modules modules_install clean

else

modules-objs
:= ***.o

obj-m :=
***.o

endif

2.3.3:驱动加载

在Makefile所在目录下执行:make

成功终端显示如下:

make -C
/usr/src/linux-headers-3.13.0-32-generic
M=/home/archermind/zhaoxi/other/sys_ modules

make[1]:
Entering directory `/usr/src/linux-headers-3.13.0-32-generic'

CC [M]
/home/archermind/zhaoxi/other/sys_/mo.o

/home/archermind/zhaoxi/other/sys_/mo.c:
In function ‘hello_init’:

/home/archermind/zhaoxi/other/sys_/mo.c:19:1:
warning: statement with no effect [-Wunused-value]

Building
modules, stage 2.

MODPOST 1
modules

CC
/home/archermind/zhaoxi/other/sys_/mo.mod.o

LD [M]
/home/archermind/zhaoxi/other/sys_/mo.ko

make[1]:
Leaving directory `/usr/src/linux-headers-3.13.0-32-generic'

加载驱动:sudo
insmod ***.ko

卸载驱动:sudo
rmmod ***.ko

3:代码实例

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/list.h>

#include <linux/spinlock.h>

#include <linux/device.h>

#include <linux/timer.h>

#include <linux/sysfs.h>

#include <linux/kobject.h>

#include <linux/err.h>

#include <linux/ctype.h>

struct class *hello_class;

static struct kobject *example_kobj;

static int foo=2;

//sys
fs
中出现的文件

/*

DEVICE_ATTR(_name, _mode, _show, _store)

_name:名称,也就是将在sys
fs
中生成的文件名称。

_mode:上述文件的访问权限,与普通文件相同,UGO的格式。

_show:显示函数,cat该文件时,此函数被调用。

_store:写函数,echo内容到该文件时,此函数被调用。

*/

//show function

static ssize_t demo_show(struct device *dev,

struct device_attribute *attr, char *buf)

{

return scnprintf(buf, PAGE_SIZE, "%d\n",
foo);

}

static ssize_t demo_store(struct device *dev,

struct device_attribute *attr, const char *buf,
size_t count)

{

unsigned long num;

if (strict_strtoul(buf, 0, &num))

return -EINVAL;

if (num < 0)

return -EINVAL;

foo = num;

return count;

}

static DEVICE_ATTR(sys_demo, 0666, demo_show,
demo_store);

static struct attribute *dev_attrs[] = {

&dev_attr_sys_demo.attr,

NULL,

};

static struct attribute_group dev_attr_grp = {

.attrs = dev_attrs,

};

static int __init zhao_init(void)

{

int retval;

example_kobj =
kobject_create_and_add("class_sys", kernel_kobj);

if (!example_kobj)

return -ENOMEM;

/* Create the files associated with this kobject
*/

retval = sysfs_create_group(example_kobj,
&dev_attr_grp);

if (retval)

kobject_put(example_kobj);

return retval;

}

static void __exit zhao_exit(void)

{

kobject_put(example_kobj);

class_destroy(hello_class);

}

module_init(zhao_init);

module_exit(zhao_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("zhaoxi");

sudo insmod ***.ko

会在sys/kernel下出现目录class_sys,在class_sys出现文件sys_demo

cat 查看初始值2.
终端echo
3>sys_demo
写入新的值。

sysfs接口整理的更多相关文章

  1. sysfs接口函数的建立&lowbar;DEVICE&lowbar;ATTR&lpar;转&rpar;

    sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...

  2. sysfs接口函数到建立&lowbar;DEVICE&lowbar;ATTR

    sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...

  3. sysfs&lowbar;create&lowbar;group创建sysfs接口

    在调试驱动,可能需要对驱动里的某些变量进行读写,或函数调用.可通过sysfs接口创建驱动对应的属性,使得可以在用户空间通过sysfs接口的show和store函数与硬件交互: Syss接口可通过sys ...

  4. 各类无次数限制的免费API接口整理

    各类无次数限制的免费API接口整理,主要是聚合数据上和API Store上的一些,还有一些其他的. 聚合数据提供30大类,160种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免 ...

  5. linux gpio控制之sysfs接口

    在3.14及之后的linux中对gpio提供了sysfs接口,说明文档:Documents/gpio/sysfs.txt. Platforms which use the "gpiolib& ...

  6. 网络免费API接口整理

    转载自: https://www.cnblogs.com/doit8791/p/9351629.html 从网上看到一些免费API接口,在个人开发小程序等应用练手时可试用. 各类无次数限制的免费API ...

  7. Linux设备管理&lpar;五&rpar;&lowbar;写自己的sysfs接口

    我们在Linux设备管理(一)_kobject, kset,ktype分析一文中介绍了kobject的相关知识,在Linux设备管理(二)_从cdev_add说起和Linux设备管理(三)_总线设备的 ...

  8. 常用天气预报API接口整理&lpar;转&rpar;

    文章转自:http://www.nohacks.cn/post-35.html 自序: 由nohacks.cn 收集整理,来源于网络,版权归原作者所有,基本收集了网络上能使用的大部分天气API接口,作 ...

  9. JavaWeb中使用到的类与接口整理(一)servlet包

    javaweb学了半本,整理了一下Servlet技术模型.servlet容器模型.jsp技术模型中的类与接口,有助于理解web应用中的页面跳转和参数传递,目录: HttpServlet 可作Scope ...

随机推荐

  1. 重写TextField Rect 改变显示位置

    很简单很常用的一些东西,希望给需要的人帮助. 效果图如下: 自定义textField init() { super.init(frame: CGRect(x: , y: , width: yourWi ...

  2. 关于安装Ubuntu后触摸板无法使用的解决方案

    安装了Ubuntu后发现触摸板无法使用,以为是修改了安装文件导致(之前拿安装源文件做了小实验),于是重装,之后触摸板仍无法使用,在一个长满小广告的页面上找到了解决方案. 以下是原文章内容: 最近突然发 ...

  3. css实现元素居中

     参见详细教程,该教程涵盖了所有居中的情况: https://css-tricks.com/centering-css-complete-guide/ css元素居中 1.水平居中 1)文本,图片等行 ...

  4. Hadoop2&period;6&period;0&lpar;2&period;4~2&period;7&rpar;完全分布式搭建-入门向 新手向 详细流程

    .caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.tabl ...

  5. C&num;经典面试题 C&num; 中 Struct 与 Class 的区别,以及两者的适用场合

    在一家公司面试时,第一个问题就是问到这个 转载 文章 http://www.cnblogs.com/waitrabbit/archive/2008/05/18/1202064.html  来解释此问题 ...

  6. 情景linux--如何优雅地退出telnet

    情景linux--在脚本中如何优雅地退出telnet 情景 telnet命令是TELNET协议的用户接口,它支持两种模式:命令模式和会话模式.虽然telnet支持许多命令,但大部分情况下,我们只是使用 ...

  7. iOS中UIKit的外观属性及方法汇总

    这里将UIKit的外观属性及方法从头文件中抽取出来,以便查找及熟悉.(更新到iOS 8.0,从A-Z排序) UIActivityIndicatorView @property (readwrite,  ...

  8. 【译】如何使用Vue捕获网络摄像头视频

    几个月前,我一直关注着比特币的爆发并且在GDAX网站上注册账号.在注册验证的过程中,网站提示要通过计算机的网络摄像头提交我自己的一张照片作为照片ID.这是一个很酷的做法,让我思考一个问题:在网络浏览器 ...

  9. mysql基础理论

    第一节数据库管理系统概述 在www.db-engines.com/en/ 这个网站中可以看到对数据库的排名 数据库分为: 关系型数据库: mysql------mariaDB oracle 非关系型数 ...

  10. node中npm安装模块的网络问题

    最近使用node开发时,发现所有的依赖模块都安装不了啦,一直报错如下 rollbackFailedOptional: verb npm-session 5a4a66a1b8d06dc3 后来才发现是由 ...