在调试驱动,或驱动涉及一些参数的输入输出时,难免需要对驱动里的某些变量或内核参数进行读写,或函数调用。此时sysfs接口就很有用了,它可以使得可以在用户空间直接对驱动的这些变量读写或调用驱动的某些函数。sysfs接口与proc文件系统很相似,有人将proc文件系统形容为Windows XP,而将sysfs接口形容为Windows 7。
而在Android系统中,振动器、背光、电源系统等往往使用sysfs接口作为内核空间和用户空间的接口,驱动程序需要提供这些接口内容。
上一个例程:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kobject.h>
static ssize_t sysfs_read(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", "sysfs test read,created by vincent");
}
static ssize_t sysfs_write(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,ssize_t count)
{
int i;
printk("\nfrom user,length=0x%X,content=%s\n",count,buf);
if(count)
return count;
else
return 1 ;
}
static struct kobj_attribute my_sysfs_read =__ATTR(read, S_IRUGO, sysfs_read, NULL);
static struct kobj_attribute my_sysfs_write =__ATTR(write, S_IWUGO, NULL,sysfs_write);
static struct attribute *my_sysfs_test[] = {
&my_sysfs_read.attr,
&my_sysfs_write.attr,
NULL,
};
static struct attribute_group my_attr_group = {
.attrs = my_sysfs_test,
};
static int sysfs_status = 0 ;
struct kobject *soc_kobj = NULL;
int helloworld_init(void)
{
int ret = 0;
printk("\nHello Android driver : %s\n",__func__);
printk("Compile Driver Via eclipse IDE: %s\n",__func__);
soc_kobj = kobject_create_and_add("my_sysfs_test", NULL);
if (!soc_kobj)
goto err_board_obj;
ret = sysfs_create_group(soc_kobj, &my_attr_group);
if (ret)
goto err_soc_sysfs_create;
sysfs_status = 1;
/* init func must contain a return vaule,otherwise meet warning when insmod this module */
return 0;
sysfs_status = 0;
err_soc_sysfs_create:
kobject_put(soc_kobj);
sysfs_remove_group(soc_kobj, &my_attr_group);
printk("\nsysfs_create_group ERROR : %s\n",__func__);
return 0;
err_board_obj:
printk("\nobject_create_and_add ERROR : %s\n",__func__);
return 0;
}
void helloworld_exit(void)
{
printk("\nExit Android driver : %s\n",__func__);
printk("Compile Driver Via eclipse IDE: %s\n",__func__);
if(sysfs_status == 1)
{
sysfs_status = 0;
kobject_put(soc_kobj);
sysfs_remove_group(soc_kobj, &my_attr_group);
}
}
MODULE_AUTHOR("vincent wu");
MODULE_LICENSE("Dual BSD/GPL");
module_init(helloworld_init);
module_exit(helloworld_exit);
在定义sysfs接口属性时,各个命名字符要一致,看以下颜色标注:
static struct kobj_attribute my_sysfs_read =__ATTR(read, S_IRUGO, sysfs_read, NULL);
static struct kobj_attribute my_sysfs_write =__ATTR(write, S_IWUGO, NULL,sysfs_write);
static struct attribute *my_sysfs_test[] = {
};
使用:
1.编译,insmod 驱动。
2.cd /sys ,发现多了一个创建的"my_sysfs_test"目录。
3.cd my_sysfs_test,发现多了两个创建的"read","write"目录。
4.cat read ,控制台输出"sysfs test read,created by vincent",这里实际会调用上面的sysfs_read函数。
5.echo hi sysfs > write ,这里实际会调用上面的sysfs_write函数输出。
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attributedev_attr_##_name = __ATTR(_name, _mode, _show, _store)
示例:
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
注意,在使用以上宏定义一个sysfs接口时,已经由宏定义了接口属性名字的前缀为“dev_attr_",所以在定义属性结构体时,要使用一样的名字字符,如下所示:
static struct attribute *my_sysfs_test[] = {
};
”XXX"与“YYY”和“_name"一致。
由此可见,通过上面的方式可以方便定制属性名字,而使用宏DEVICE_ATTR则受约束。