sysfs____之ATTR实例

接下来的例子,我会在驱动中提取,来源是高通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);
//。。。
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值