在調試驅動,或驅動涉及一些參數的輸入輸出時,難免需要對驅動裏的某些變量或內核參數進行讀寫,或函數調用。此時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[] = {
&my_sysfs_read.attr,
&my_sysfs_write.attr,
NULL,
};
使用:
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[] = {
&dev_attr_XXX.attr,
&dev_attr_YYY.attr,
NULL,
};
”XXX"與“YYY”和“_name"一致。
由此可見,通過上面的方式可以方便定製屬性名字,而使用宏DEVICE_ATTR則受約束。