近日研究红外传感器驱动,发现adb shell进入sys/kernel目录下存在pac7673文件夹,其中实现两个接口,分别是enable_proximity和poll_period_ms_proximity,同过echo和cat分别可以对这两个接口进行读和写,我们来看下在驱动中他是如何实现的。
首先在红外传感器pac7673驱动包含了pac7673.h这个头文件,里面先定义了一个结构体
struct sensor_device_attribute{
struct device_attribute dev_attr;
int index;
};
其中结构体device_attribute在device.h中定义,路径为kernel/include/linux/device.h。
还有这样的宏定义:
#define SENSOR_ATTR(_name, _mode, _show, _store, _index) \
{ .dev_attr = __ATTR(_name, _mode, _show, _store), \
.index = _index }
#define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index) \
struct sensor_device_attribute sensor_dev_attr_##_name \
= SENSOR_ATTR(_name, _mode, _show, _store, _index)
函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法,_show表示的是读方法,_stroe表示的是写方法。
当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等
如对设备的使用 DEVICE_ATTR,对总线使用 BUS_ATTR,对驱动使用 DRIVER_ATTR ,对类 别 (class) 使用 CLASS_ATTR, 这四个高级的宏来自于
typedef struct {
struct i2c_client *client;
struct pac7673_platform_data *pdata;
struct class *pac7673_class;
struct device *pac7673_device;
struct input_dev *input_dev;
*struct kobject *kobj;*
struct delayed_work pac7673_work;
unsigned int major_id;
int irq;
atomic_t enabled;
atomic_t period_ms;
struct wake_lock irq_lock;
} pac7673_data_t;
接下来在probe函数中做了如下处理
pac7673data.kobj = kobject_create_and_add("pac7673", kernel_kobj);
if (!pac7673data.kobj) {
goto failed_kobj_create;
}
err = sysfs_create_group(pac7673data.kobj, &pac7673_attribute_group);
if (err) {
goto failed_sysfs_create_group;
}
先通过kobject_create_and_add(“pac7673”, kernel_kobj)创建了一个名为pac7673的文件夹,再通过sysfs_create_group(pac7673data.kobj, &pac7673_attribute_group)创建目录下的属性文件组
,其中pac7673_attribute_group使我们自定义的相关属性文件,这样我们就在文件系统注册了这样的一个接口。
接下来就是对接口的一些配置
static SENSOR_DEVICE_ATTR(enable_proximity, S_IRUGO | S_IWUGO,
pac7673_show_enable, pac7673_store_enable, 0);
static SENSOR_DEVICE_ATTR(poll_period_ms_proximity, S_IRUGO | S_IWUGO,
pac7673_show_polling_rate, pac7673_store_polling_rate, 0);
这样就在pac7673目录下生成两个文件接口enable_proximity和poll_period_ms_proximity。
再把这两个接口添加到属性组中去
static struct attribute *pac7673_attributes[] = {
&sensor_dev_attr_enable_proximity.dev_attr.attr,
&sensor_dev_attr_poll_period_ms_proximity.dev_attr.attr,
NULL
};
static const struct attribute_group pac7673_attribute_group = {
.attrs = pac7673_attributes,
};
结构体数组pac7673_attributes[]中成员变量的名字必须是&sensor_dev_attr_enable_proximity.dev_attr.attr和&sensor_dev_attr_poll_period_ms_proximity.dev_attr.attr。
最后再来看具体的功能函数的实现
static ssize_t pac7673_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
ret = sprintf(buf, "%d\n", atomic_read(&pac7673data.enabled));
return ret;
}
static ssize_t pac7673_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long enable;
if (strict_strtoul(buf, 10, &enable))
return -EINVAL;
if (atomic_read(&pac7673data.enabled) == !!enable) {
return size;
}
atomic_set(&pac7673data.enabled, !!enable);
if (!!enable) {
enable_irq(pac7673data.irq);
pac7673_write_reg(0x11, 0x8c);
} else {
pac7673_write_reg(0x11, 0x0c);
disable_irq(pac7673data.irq);
}
return size;
}
这两个函数分别是实现enable_proximity接口的读写功能。
static ssize_t pac7673_show_polling_rate(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
ret = sprintf(buf, "%d\n", atomic_read(&pac7673data.period_ms));
return ret;
}
static ssize_t pac7673_store_polling_rate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
unsigned long interval_ms;
if (strict_strtoul(buf, 10, &interval_ms))
return -EINVAL;
if (interval_ms < 10)
interval_ms = 10;
if (interval_ms > 500)
interval_ms = 500;
atomic_set(&pac7673data.period_ms, interval_ms);
return size;
}
这两个函数是实现poll_period_ms_proximity接口读写功能。
上面几个函数功能是对pac7673_data_t结构体中定义的atomic_t enabled和atomic_t period_ms这两个参数进行读写。分别控制的是中断的使能和工作队列的延时时间。
到这两个syfs系统接口就实现了。