MTK平台下的sensor框架分析
关于Android平台下的sensor介绍
随着移动互联网技术的普及,人们对智能手机的需要也越来越多。而在众多
智能手机操作系统之中,Android 系统凭借着Google 的技术支持及其开源特性在短时间内迅速占领大量的市场。传感器系统可以让智能手机的功能更加丰富多
彩,所以传感器设备已经成为智能手机必备的组件之一。Android 系统可以支持
多种传感器,有的传感器已经在Android 的框架中使用,大多数传感器由应用程
序使用。
本文基于MTK6582 的平台上Android 系统的传感器模块进行移植和
开发,对Android 系统框架和开发环境进行了简介,对Android 系统的传感器模块的驱动层和硬件抽象层的开发进行深入的分析与研究,概括并总结了传感器模
块的工作原理和工作流程,对传感器的数据采集、数据传输、设备休眠和设备控
制等方面进行了具体的设计与实现,最终在MTK6582 的平台上实现了传感器模
块的驱动层和硬件抽象层。
Android 系统可大致分为四部分,应用层、框架层、硬件抽象层、Linux
驱动层,Android 系统的传感器模块涉及到了Android 系统的各个层次。应用
层以Java 为编程语言,一般为第三方开发的应用程序,也有一些是Google 自
己提供的应用程序,框架层是Google 自己开发的,有着完整代码的体系,提
供完善的接口,以便第三方开发应用程序。硬件抽象层是能以封闭源码形式提
供硬件驱动模块,可以把框架层与驱动层隔开,使得Android 框架层的开发能
在完全不考虑驱动程序的前提下进行。驱动层会根据硬件的设计对传感器进行
初始化和寄存器的读写,使传感器正常工作。
Android 系统支持多种传感器,包括加速度传感器、磁力域传感器、方向传感
器、陀螺仪、光线传感器、压力传感器、温度传感器、接近传感器,一般手
机都支持加速度传感器、磁力域传感器、方向传感器、光线传感器、接近传感
器,也有一些比较高端的手机支持陀螺仪。
Android系统sensor框架图:
我们着重讲解硬件抽象层(hardware abstractal level HAL)和内核层(linux内核)
1. 硬件抽象层
Android 的HAL(硬件抽象层)是Google 因应厂商“希望不公开源码”的要
求下所推出的新观念,让Android 不至过度依赖Linux kernel ,让Android framework 的开发能在不考虑驱动程序的前提下进行发展。
2、内核层
Android 的核心系统服务依赖于Linux2.6 内核,包括各种设备的驱动,如
显示驱动、键盘驱动、Flash 内存驱动、照相机驱动(Camera Driver)、音频驱动(Audio Driver)、蓝牙驱动(Bluetooth Driver)、WiFi 驱动、Binder IPC 驱动,以及Power Management(电源管理)、进程管理、内存管理、安全性管理和网络协议栈
等操作系统的基本部件。
1、HAL层的实现:
当Android系统启动时,SystemManager启动SensorDevice服务frameworks/base/cmds/system_server/library/system_init.cpp
1property_get("system_init.startsensorservice", propBuf, "1");
2if (strcmp(propBuf, "1") == 0) {
3// Start the sensor service
4 SensorService::instantiate();
5}
①SensorDevice()首先调用hw_get_module()函数获得Sensor设备模块,
②调用sensors_open这个工具函数,打开Sensor设备模块(调用其methods->open函数指针),返回Sensor设备的操作接口(这些接口在HAL层实现),保存在mSensorDevice中
调用sensors_open函数,函数接着调用module->methods->open()方法,这个open方法在哪里实现了??如下:
③调用Sensor模块的get_sensors_list方法获得传感器列表,
在调用get_sensors_list之前,系统已初始化sSensorList结构体,说明系统中有哪些sensor 资源。
④依次激活这些设备并且添加到mActivationCount设备信息向量中。
⑤最终调用dev->device.poll = data__poll函数,实现读取sensor数据。
static int data__poll(struct sensors_poll_device_t *dev,sensors_event *data,int count)
{
struct sensors_data_context_t *ctx = (struct sensors_data_context_t *)dev;
return ctx->poll((struct sensors_data_context_t *)dev,data,count);
}
即调用hwm__poll函数
hwm__poll()函数过大,就不贴上来了,简要分析其中一段代码:
res = ioctl(fd_io,HWM_IO_GET_SENSORS_DA TA,&sensors_data);
将获得的数据存放在结构体hwm_trans_data sensors_data中
ioctl(fd_io,HWM_IO_GET_SENSORS_DATA,&sensors_data);
这个函数将会调用驱动程序中提供的fops->unlocked_ioctl 函数
至此HAL层已讲解完毕。
2、LINUX DRIVER层的实现
通过以上分析可知,HAL层通过各种接口,最终调用ioctl函数,获取硬件数据。
内核空间向HAL层(用户空间)上传数据的方式大概可以分为两种
1、通过copy_from_user和copy_to_user函数实现内核空间和用户空间的数据交互
2、通过input子系统实现数据交互
在本平台中,使用的是第一种方式
sensor这一类设备是属于i2c设备,因此遵循i2c设备的那一套注册机制,而它本身实质上是字符设备,因此当用户层调用ioctl时,则会调用驱动程序中提供的fops->unlocked_ioctl 函数。
以tmd2772 光照感应传感器为例:
驱动层的tmd2772_unlocked_ioctl为用户层调用ioctl时,将调用的函数
在android系统中,提供了一套early_suspend和early_resume机制来管理电源。
所以在编写驱动程序时,必须对Early Suspend 进行注册。
注册early_suspend 之前先要设置early_suspend 的一些信息,如level ,
suspend、resume 的回调函数。
level分为以下三个层次:
level 字段用于调整该结构体在注册链表中的位置,启动suspend 时,level 的数值越小,调用回调函数的时间越早,resume 时则反过来。
suspend回调函数主要做的事情是:将任务加入到工作队列链表,睡眠。
resume回调函数主要做的事情是:从队列中取出任务,唤醒进程/线程。
3、MTK平台下的sensor
针对MTK平台,抽象出一层hwmsensor,来管理所有的模块,为上层提供统一的接口,屏蔽下层硬件不同而导致的差异性。
MTK代码里使用了一个hwmsensor模块控制所有的sensor。
代码路径:mediatek/kernel/drivers/hwmon/hwmsen/hwmsen_dev.c,编译成hwmsen_dev.o,系统起来后会生成/dev/hwmsensor设备。
使用sensor_operate接口管理所有sensor驱动,向上提供hwmsen_unlocked_ioctl接口
再往下就是具体的sensor驱动代码了,根据MTK的驱动结构完成sensor_operate接口,并调用hwmsen_dev.c里的hwmsen_attach函数,把sensor_operate接口加到hwmsen_dev的列表里,这样hwmsen_dev里就能调用所有sensor的sensor_operate函数。
以tmd2772为例:
定义此类传感器的数据结构体
struct tmd2772_priv *obj;
tmd2772_priv 结构体在
./mediatek/custom/project_name/kernel/alsps/tmd2772/cust_alsps.c中静态定义其中的一些数据参数,并且在该文件中提供了一个函数get_cust_alsps_hw获取该结构体的头指针。
在tmd2772_i2c_probe函数中,定义一个tmd2772_priv 结构体,并分配内存,初始化该结构体的其他参数。然后将其封装在名为struct hwmsen_object的结构体中,
即hwmsen_object.self = tmd2772_obj;
hwmsen_object结构体定义如下:
struct hwmsen_object{
void *self;
int polling;
int (*sensor_operate)(void *self,uint32_t command ,void *buff_in, int size_in,
void *buff_out, int size_out, int *actualout);
};
其中该结构体中定义了操作sensor的方法,在tmd2772_i2c_probe函数中完成定义
如下:
struct hwmsen_object obj_als;
obj_ps.sensor_operate = tmd2772_ps_operate;
之后调用hwmsen_attach函数,将hwmsen device与sensor device driver连接,hwmsen_attach(ID_LIGHT,&obj_als);
具体做法是将struct hwmsen_object obj_als结构体根据不同类型(ID_LIGHT)加入到全局静态的结构体dev_cxt中。
用户层如何获得数据?
如上面所上分析,会调用hwmsensor模块中的file_operations结构体中的unlocked_ioctl方法实现读取sensor数据。
hwmsensor模块中还提供一种中断方法,通过input子系统实现数据交互。
sensor提供了哪些接口?
在hwmsensor模块的probe函数中调用函数hwmsen_create_attr()创建接口,
device_create_file(dev,hwmsen_attr_list[idx]->https://www.360docs.net/doc/758091015.html,,err);
在sys/class/xxx下面有相关的接口。