我们在开发或调试设备驱动时常常用到/sys目录下的东西,甚至有的时候完全依赖这个目录下的东东,而不用/dev下的设备,比如一些传感器,vibrator,leds等。安卓驱动的HAL层大量使用了这个/sys下的属性节点。那么这个/sys目录下的是干什么的呢?为什么要这个目录?原来的/proc目录下比较混乱,后来将与设备相关的都放到/sys下。
它的出现是用于解决linux2.6之前的以下问题
#没有统一的机制表达驱动程序和设备的关系。
#不存在一般的热插拔(hotplug)机制。
#procfs 文件系统过度混乱,包含了许多不是进程(process)的信息。
其实这是个虚拟文件系统,用于导出内核对象(kobject),动态的生成的,与/proc类似,没有实际的存放介质,它一开始是一ramfs为基础的,断电就没有了,内存中。这个文件系统不仅可以把设备(devices)和驱动程序(drivers) 的信息从内核输出到 用户空间,也可以用来对设备和驱动程序做设置。用户可以在用户空间操作sysfs节点以达到修改设备驱动属性值,甚至达到/dev下的read,write,ioctl等的操作。/sys目录会将设备以层次结构的方式呈现,你经常会看到/sys/class/下有input,rtc,block等分类,也能看到/sys/bus/下有spi,iic等总线类别。
总之,sysfs是内核空间和用户空间的沟通手段,可以将设备驱动信息给你用户空间看,还能让你操作设备驱动。
sysfs文件系统中提供了四类文件的创建与管理,分别是目录、普通文件、软链接文件、二进制文件。目录层次往往代表着设备驱动模型的结构,软链接文件则代表着不同部分间的关系。比如某个设备的目录只出现在/sys/devices下,其它地方涉及到它时只好用软链接文件链接过去,保持了设备唯一的实例。而普通文件和二进制文件往往代表了设备的属性,读写这些文件需要调用相应的属性读写。这个过程跟kobject联系在一起,就像基类一样,每一个sysfs文件都有一个kobject,以kobject.parent建立层次关系,所以kobject也很重要,要一起看了。
先看下linux/sysfs.h
struct attribute {
const char *name;
umode_t mode;
};
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
};
//struct attribute_group创建一组节点,由sysfs_create_group()创建
/**
* Use these macros to make defining attributes easier. See include/linux/device.h
* for examples..
*/
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \
}
#define __ATTR_NULL { .attr = { .name = NULL } }
#define attr_name(_attr) (_attr).attr.name
struct bin_attribute {
struct attribute attr;
size_t size;
void *private;
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
const void *(*namespace)(struct kobject *, const struct attribute *);
};
1、目录
创建://如果parent为NULL就会在/sys/创建name目录,要想在xxx目录下创建目录就将parent赋值为xxx.kobject
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
释放:
//kobj为kobject_create_and_add()函数的返回值
void kobject_put(struct kobject *kobj)
2、文件
&dev_attr_events.attr,
&dev_attr_events_async.attr,
&dev_attr_events_poll_msecs.attr,
NULL,
};