概述
(一) XXXX — 内核加载驱动模块是调用:XXXX_init() 方法:
a) 调用gsensor_fetch_sysconfig_para()解析sys_config1.fex文件,读取到IIC的地址等,并赋值给u_i2c_addr.normal_i2c;
b) 调用总线的设备驱动加载函数–i2c_add_driver开始向IIC注册driver i2c_add_driver(&XXXX _driver);
;
c) 完成注册后将调用XXXX_probe()方法 — 针对设备做初始化:
i. 初始化一些变量,为(struct XXXX_data *data) (私有数据)结构体申请内存;
ii. 初始化私有(XXXX_data)数据、初始化设备的寄存器等;
iii. 调用IIC接口i2c_smbus_read_word_data()读取IIC上bma250的chip id;
iv. 将设备驱动的私有数据(XXXX_data)连接到设备client(i2c_client)中 i2c_set_clientdata(client, data);
v. 创建工作队列,创建的工作队列,就是在一个工作者线程,通过IIC不断的去查询读取controller上的数据–INIT_DELAYED_WORK(&data->work, XXXX _work_func):
vi. XXXX _work_func是自定义的功能函数,用于查询读取Sensor数据的,并上报Input子系统:
static void XXXX _work_func(struct work_struct *work){
通过work得到整个私有数据(work也在私有数据中,描述的是定时工作之类的信息);
定义上报的数据变量—包括x y z;
通过i2c读取设备上的数据;
通过input_report_abs上报数据 ,使用input_sync通知input;
schedule_delayed_work(&bma250->work, delay); //设定delay时间后再次执行这个函数。
}
vii. 将XXXX驱动注册到linux input子系统
XXXX_input_init(data):
static int bma250_input_init(struct _data * XXXX){
申请一个新的input设备,即为一个input_dev申请内存空间 input_allocate_device
设置input设备支持的数据类型 input_set_abs_params
向input系统注册 input_register_device
}
viii. 创建sysfs接口 — 在驱动层创建了sysfs接口,HAL层通过这些sysfs接口,对Sensor进行操作,如使能、设置delay等。
sysfs_create_group(&data->input->dev.kobj, &bma250_attribute_group);
#define DEVICE_ATTR(_name, _mode, _show, _store) struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法:
当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等:
对设备的使用 DEVICE_ATTR
对驱动使用 DRIVER_ATTR
对总线使用 BUS_ATTR
对类别 (class) 使用 CLASS_ATTR
对于DEVICE_ATTR(_name, _mode, _show, _store)的四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。
static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling, set_polling);
当你想要实现的接口名字是polling的时候,需要实现结构体struct attribute *dev_attrs[]。其中成员变量的名字必须是&dev_attr_polling.attr。
static struct attribute *dev_attrs[] = {
&dev_attr_polling.attr,
NULL,
};
然后再封装:
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
在利用sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);创建接口
XXXX驱动sysfs接口建立,上面介绍的三个步骤来实现。
1、调用宏DEVICE_ATTR完成对功能函数的注册
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP, XXXX _delay_show,
XXXX _delay_store);
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, XXXX _enable_show,
XXXX _enable_store);
static struct attribute * XXXX _attributes[] = {
&dev_attr_delay.attr,
&dev_attr_enable.attr,
NULL
};
对于XXXX Gsensor,用到的接口是对Gsensor使能和设置delay。设置delay的功能函数——读、写分别是XXXX _delay_show、XXXX _delay_store。使能的功能函数——读写分别是XXXX _enable_show、XXXX _enable_store。这里提到的四个函数,是需要在Gsensor驱动中实现的。
2、封装bma250_attributes数据结构
static struct attribute_group bma250_attribute_group = {
.attrs = bma250_attributes
};
3、真正创建接口
在XXXX的初始化函数probe中——XXXX _probe(),调用:
err = sysfs_create_group(&data->input->dev.kobj,& XXXX _attribute_group);
到此,完成了sysfs接口的创建,我们可以在根文件系统中看/sys/class/input/input3/目录,在该目录下我们可以看到多个节点,其中就包含了enable和delay。我们以enable为例子,可以有两种方法完成对Gsensor的使能工作:
- 直接使用shell命令
$cd /sys/class/input/input3
$echo 1 > enable
将1写到enable节点,那么将“1”作为参数调用到驱动的XXXX _enable_store()方法,完成对Gsensor的使能工作。
2) 代码写设备节点
char buffer[20];
int len = sprintf(buffer, "%dn", 1);
fd = open(“/sys/class/input/input3/enable”, O_RDWR);
write(fd, value, len);
(二) 在Android的HAL层,通过对/sys/class/input/input3/enable节点的写操作,使能Gsensor。调用到的方法是XXXX _enable_store():
a)
static ssize_t XXXX _enable_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count){
……
XXXX_set_enable(dev,data);
……
return count;
}
static void XXXX_set_enable(struct device *dev, int enable){
struct i2c_client *client = to_i2c_client(dev);
struct XXXX_data * XXXX= i2c_get_clientdata(client);
int pre_enable = atomic_read(&XXXX->enable);
mutex_lock(&XXXX->enable_mutex);
if (enable) {
if (pre_enable ==0) {
XXXX_set_mode(XXXX-> XXXX_client, XXXX_MODE_NORMAL);
schedule_delayed_work(&XXXX->work,msecs_to_jiffies(atomic_read(&XXXX->delay)));
atomic_set(&XXXX->enable, 1);
}
}……
}
我们看到了,在使能函数中,调用了schedule_delayed_work()开始工作队列,于是调用了功能函数XXXX_work_func()
static void XXXX_work_func(struct work_struct *work){
struct XXXX_data * XXXX= container_of((struct delayed_work *)work, struct XXXX_data, work);
static struct XXXXacc acc;
unsigned long delay = msecs_to_jiffies(atomic_read(&XXXX->delay));
XXXX _read_accel_xyz(XXXX-> XXXX _client, &acc);//读取数据
input_report_abs(XXXX->input, ABS_X, acc.x); //上报数据
input_report_abs(XXXX->input, ABS_Y, acc.y);
input_report_abs(XXXX->input, ABS_Z, acc.z);
bma_dbg("acc.x %d, acc.y %d, acc.z %dn", acc.x, acc.y, acc.z);
input_sync(XXXX->input);
mutex_lock(&XXXX->value_mutex);
XXXX ->value = acc;
mutex_unlock(&XXXX->value_mutex);
schedule_delayed_work(&XXXX->work, delay); //继续开始下一个工作队列
}
在上面代码中,调用XXXX _read_accel_xyz()方法读取Gsensor的三个数据,然后调用Input系统的接口函数input_report_abs()进行数据的上报。可以看到,当读取一次数据后,继续调用schedule_delayed_work()开始下一个工作队列,由此,功能函数XXXX_work_func()将会按照一个的频率被执行。
b) 那么对于HAL层,将通过/dev/input/event3设备节点读取到Gsensor数据。到此,Gsensor驱动的工作流程完毕。
(三) 模块的卸载XXXX_exit:i2c_del_driver(&XXXX_driver);
最后
以上就是勤恳含羞草为你收集整理的Gsensor的驱动流程 -- 基于IIC的全部内容,希望文章能够帮你解决Gsensor的驱动流程 -- 基于IIC所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复