接下来的例子,我会在驱动中提取,来源是高通MSM8610下Android4.3对应的kernel
1、触屏虚拟按键(通用ATTR)
这个示例创建目录和attr是通用的,不管device,device_driver,还是class,只要是/sys目录下的任何目录路径下都可。
使用的结构是
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);
};
具体解释代码中见
/**
*基于新思电容触摸屏驱动v2.3上的synaptics_dsx_core.c,其中的虚拟按键就是使用sysfs的attr,
*Android HAL只认/sys/board_propertys/virtualkeys.$(PLATFORM_DRIVER_NAME)节点,
*PLATFORM_DRIVER_NAME为虚拟按键基于的触屏dev_name,我的是触屏dev_name是synaptics_dsx,所以
*我的虚拟按键节点路径就是/sys/board_properties/virtualkeys.synaptics_dsx读取这个attr节点
*就能获取到虚拟按键在触屏像素点的坐标范围和按键code,我读这个节点数据为
0x01:102:60:850:100:60 //102为HOME案件。虚拟按键版本号;code;x坐标;y坐标,x坐标直径方位,y坐标的直径范围
0x01:158:420:850:100:60 //158为BACK按键
*/
#define VIRTUAL_KEY_MAP_FILE_NAME "virtualkeys." PLATFORM_DRIVER_NAME
/*要创建的目录,用于存放一个attr*/
struct kobject *board_prop_dir;
static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,struct kobj_attribute *attr, char *buf)
/*定义一个attr,这是用最基本的kobject创建attr方法,是一个通用方法,不管是device,还是class,
*而XXX_ATTR这样的宏是针对于device或class等那4种框架基础上的,不是此处用的
*最多可以使用 __ATTR(_name,_mode,_show,_store)宏
**/
static struct kobj_attribute virtual_key_map_attr = {
//__ATTR(VIRTUAL_KEY_MAP_FILE_NAME, S_IRUGO, synaptics_rmi4_virtual_key_map_show, NULL);
.attr = {
.name = VIRTUAL_KEY_MAP_FILE_NAME,
.mode = S_IRUGO,
},
.show = synaptics_rmi4_virtual_key_map_show,
//当然你也可以实现store函数
};
/*attr的show方法
*注意属性分配的缓存大小都是PAGE_SIZE(一般为4K)的页大小
*/
static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int ii;
int cnt;
int count = 0;
for (ii = 0; ii < vir_button_map->nbuttons; ii++) {
cnt = snprintf(buf, PAGE_SIZE - count, "0x01:%d:%d:%d:%d:%d\n",
vir_button_map->map[ii * 5 + 0],
vir_button_map->map[ii * 5 + 1],
vir_button_map->map[ii * 5 + 2],
vir_button_map->map[ii * 5 + 3],
vir_button_map->map[ii * 5 + 4]);
buf += cnt;
count += cnt;
}
return count;
}
static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
{
int retval;
//...忽略无关的
/*参数2为NULL会在/sys/下创建board_properties目录<span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif;">,否则你就传入指定目录的koject*/</span>
board_prop_dir = kobject_create_and_add("board_properties", NULL);
if (!board_prop_dir) {
dev_err(&pdev->dev,
"%s: Failed to create board_properties directory\n",
__func__);
goto err_virtual_buttons;
} else {
retval = sysfs_create_file(board_prop_dir,
&virtual_key_map_attr.attr);
if (retval < 0) {
dev_err(&pdev->dev,
"%s: Failed to create virtual key map file\n",
__func__);
goto err_virtual_buttons;
}
}
//...忽略无关的
return retval;
}
static int __devexit synaptics_rmi4_remove(struct platform_device *pdev)
{
//...忽略无关的
if (board_prop_dir) {
sysfs_remove_file(board_prop_dir,
&virtual_key_map_attr.attr);
kobject_put(board_prop_dir);
}
//...忽略无关的
}
如果你要创建一组属性当然可以循环创建,其实有现成内核函数可用了
属性放在一起很直观
static struct kobj_attribute gsmi_clear_config_attr = {
.attr = {.name = "clear_config", .mode = 0200},
.store = gsmi_clear_config_store,
};
static struct kobj_attribute gsmi_clear_eventlog_attr = {
.attr = {.name = "clear_eventlog", .mode = 0200},
.store = gsmi_clear_eventlog_store,
};
/*成员必须以NULL结束,这个NULL是给sysfs_create_files创建attr节点结束标志*/
static const struct attribute *gsmi_attrs[] = {
&gsmi_clear_config_attr.attr,
&gsmi_clear_eventlog_attr.attr,
NULL,
};
static __init int gsmi_init(void)
{
//...
ret = sysfs_create_files(gsmi_kobj, gsmi_attrs);
if (ret) {
printk(KERN_INFO "gsmi: Failed to add attrs");
goto out_remove_bin_file;
}
//...
} <span style="white-space:pre"> </span> static void __exit gsmi_exit(void)
{
<span style="white-space:pre"> </span>//...
<span style="white-space:pre"> </span>sysfs_remove_files(gsmi_kobj, gsmi_attrs);
<span style="white-space:pre"> </span>//...
}
2、 光强/距离传感器cm36283(DEVICE_ATTR)
/* interface for exporting device attributes */
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);
};
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
/*
*该示例提取与cm36283光强/距离感应器中的光强配置attr
**/
static ssize_t ls_conf_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cm36283_info *lpi = lp_info;
/*有溢出安全问题,最好都用snprintf包括strcat,strcpy最好都用带n的函数*/
return sprintf(buf, "ALS_CONF = %x\n", lpi->ls_cmd);
}
static ssize_t ls_conf_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cm36283_info *lpi = lp_info;
int value = 0;
sscanf(buf, "0x%x", &value);
lpi->ls_cmd = value;
dev_dbg(&lpi->i2c_client->dev, "ALS_CONF:0x%x\n", lpi->ls_cmd);
_cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
return count;
}
/*变量名字实质还有个dev_attr_前缀,详见其宏定义*/
static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
static int cm36283_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
//。。。
ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf);
if (ret)
goto err_create_ls_device_file;
//。。。
}
static int cm36283_remove(struct i2c_client *)
{
//。。。
device_remove_file(lpi->ls_dev, &dev_attr_ls_conf);
//。。。
}