环境:MTK Android4.4
硬件:MT8127 MMA8653
日期:2015年6月19日
在MTK的Gsensor构架中有一个auto detect的功能,只要作用是可以添加多个GSensor驱动,然后会自动找到与硬件匹配的Gsensor驱动,这个功能是用hwmsen驱动模块来完成的。
先来看看驱动里是如何使用auto detect的
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
static struct sensor_init_info mma8653q_init_info = {
.name = "mma8653q", .init = mma8653q_local_init, .uninit = mma8653q_remove, }; //在模块初始化的时候把mma8653q_init_info加入到hwmsen中 static int __init mma8653q_init( void) { //... hwmsen_gsensor_add( & mma8653q_init_info); //... } static int mma8653q_i2c_probe(struct i2c_client * client, const struct i2c_device_id * id) { struct i2c_client * new_client; struct mma8653q_i2c_data * obj; struct hwmsen_object sobj; int err = 0; int retry = 0; GSE_FUN(); //获得8653的基本数据,I2C总线,hwmsen_convert(Gsensor数据轴和方向的定义)等 obj->hw = mma8653q_get_cust_acc_hw(); //获取hwmsen_convert map hwmsen_get_convert(obj->hw->direction, & obj->cvt); atomic_set( & obj->trace, 0); atomic_set( & obj->suspend, 0); #ifdef CONFIG_MMA8653Q_LOWPASS if(obj->hw->firlen > C_MAX_FIR_LENGTH) { atomic_set( & obj->firlen, C_MAX_FIR_LENGTH); } else { atomic_set( & obj->firlen, obj->hw->firlen); } if(atomic_read( & obj->firlen) > 0) { atomic_set( & obj->fir_en, 1); } #endif sobj.self = obj; sobj.polling = 1; //数据传输方式 sobj.sensor_operate = mma8653q_operate; //mma8653的接口函数 hwmsen_attach(ID_ACCELEROMETER, & sobj); //把sobj加入到队列中,如果相应ID队伍里不为空,则无法加入 #ifdef USE_EARLY_SUSPEND obj->early_drv.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 2, obj->early_drv.suspend = mma8653q_early_suspend, obj->early_drv.resume = mma8653q_late_resume, register_early_suspend( & obj->early_drv); #endif //=0时,加入成功,hwmsen不会再搜索并加入其他的gsensor驱动 mma8653q_init_flag = 0; } |
首先是整个hwmsen驱动的hwmsen_driver和hwmsen_device的匹配
1
2 3 4 5 6 7 8 9 10 11 |
static
struct platform_driver hwmsen_driver = {
.probe = hwmsen_probe, .remove = hwmsen_remove, .suspend = hwmsen_suspend, .resume = hwmsen_resume, .driver = { .name = HWM_SENSOR_DEV_NAME, // .owner = THIS_MODULE, } }; |
hwmsen_probe
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
static
int hwmsen_probe(
struct platform_device *pdev) {
//清空所有的列表,数据区等 init_static_data(); //设置总的hwmdev_object,主要是初始化队列,时间中断 //这个时间中断是用来轮询sensor数据时频率,这里为5hz即200ms hwm_obj = hwmsen_alloc_object(); //初始化化Input子系统 hwm_obj->idev = input_allocate_device(); set_bit(EV_REL, hwm_obj->idev->evbit); set_bit(EV_SYN, hwm_obj->idev->evbit); input_set_capability(hwm_obj->idev, EV_REL, EVENT_TYPE_SENSOR); hwm_obj->idev->name = HWM_INPUTDEV_NAME; input_register_device(hwm_obj->idev); input_set_drvdata(hwm_obj->idev, hwm_obj); //注册一个misc驱动,主要是提供对sensor操作的接口 hwm_obj->mdev.minor = MISC_DYNAMIC_MINOR; hwm_obj->mdev.name = HWM_SENSOR_DEV_NAME; hwm_obj->mdev.fops = &hwmsen_fops; misc_register(&hwm_obj->mdev); dev_set_drvdata(hwm_obj->mdev.this_device, hwm_obj); //创建属性文件 hwmsen_create_attr(hwm_obj->mdev.this_device) != 0); // add for fix resume bug atomic_set(&(hwm_obj->early_suspend), 0); hwm_obj->early_drv.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1, hwm_obj->early_drv.suspend = hwmsen_early_suspend, hwm_obj->early_drv.resume = hwmsen_late_resume, register_early_suspend(&hwm_obj->early_drv); wake_lock_init(&(hwm_obj->read_data_wake_lock), WAKE_LOCK_SUSPEND, "read_data_wake_lock"); // add for fix resume bug end return 0; } |
接下来按照上面的使用流程来分析hwmsen
hwmsen_gsensor_add, 就是把sensor_init_info结构体加入到list中
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
static struct platform_driver gsensor_driver = {
.probe = gsensor_probe, .remove = hwmsen_gsensor_remove, .driver = { .name = "gsensor", // .owner = THIS_MODULE, } }; int hwmsen_gsensor_add(struct sensor_init_info * obj) { for(i = 0; i < MAX_CHOOSE_G_NUM; i++ ) { if(NULL == gsensor_init_list[i]) { gsensor_init_list[i] = kzalloc(sizeof(struct sensor_init_info), GFP_KERNEL); if(NULL == gsensor_init_list[i]) { HWM_ERR( "kzalloc error"); return - 1; } //初始化obj的gsensor_driver。 obj->platform_diver_addr = & gsensor_driver; //把obj添加到队列中 gsensor_init_list[i] = obj; break; } } return err; } |
gsensor_driver如果与gsensor_device匹配上了之后就会调用gsensor_probe
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
static
int gsensor_probe(
struct platform_device *pdev) {
for(i = 0; i < MAX_CHOOSE_G_NUM; i++) { if( 0 != gsensor_init_list[i]) { //调用sensor_init_info的init函数,即hwmsen_msensor_add添加进来的结构体 err = gsensor_init_list[i]->init(); if( 0 == err) { strcpy(gsensor_name, gsensor_init_list[i]->name); HWM_LOG( " gsensor %s probe ok\n", gsensor_name); break; } } } return 0; } |
gsensor_probe会调用驱动的init函数,这里是mma8653q_local_init
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
static
int mma8653q_local_init(
void) {
struct acc_hw *hw = mma8653q_get_cust_acc_hw(); //上电,并增加i2c驱动 MMA8653Q_power(hw, 1); i2c_add_driver(&mma8653q_i2c_driver); //这里很奇怪,i2c_add_driver完之后如果找到了相应的i2c设备, //则会等执行完相应的i2c_probe,再执行到这里。 //i2c_probe会填充mma8653q_init_flag if(- 1 == mma8653q_init_flag) { return - 1; } return 0; } |
后面的就会在mma8653q_i2c_probe中执行,其主要是执行struct hwmsen_object sobj;并加入到hwmsen的sensor队列中。
hwmsen_get_convert:决定gsensor数据的格式
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
struct hwmsen_convert map[] = {
{ { 1, - 1, - 1}, { 0, 1, 2} }, { { - 1, 1, 1}, { 1, 0, 2} }, { { - 1, - 1, 1}, { 0, 1, 2} }, { { 1, - 1, 1}, { 1, 0, 2} }, { { - 1, 1, - 1}, { 0, 1, 2} }, { { 1, - 1, - 1}, { 1, 0, 2} }, { { 1, - 1, - 1}, { 1, 0, 2} }, { { - 1, - 1, - 1}, { 1, 0, 2} }, }; /*----------------------------------------------------------------------------*/ //通过direction在上面的map里找出gsensor数据的模式。 //每组的前3个为数据是否要倒转。 //每组的后面3个为x,y,z轴的摆放位置 int hwmsen_get_convert( int direction, struct hwmsen_convert *cvt) { if (!cvt) return -EINVAL; else if (direction >= sizeof(map) / sizeof(map[ 0])) return -EINVAL; * cvt = map[direction]; return 0; } |
hwmsen_attach:把sensor加入到总的sensor队列里,这个队列里可以有光感,陀螺仪等...
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
struct dev_context {
int polling_running; struct mutex lock; struct hwmsen_context* cxt[MAX_ANDROID_SENSOR_NUM+ 1]; }; int hwmsen_attach( int sensor, struct hwmsen_object *obj) { struct dev_context *mcxt = &dev_cxt; //确保每个sensor只有一个实例 if(mcxt->cxt[sensor] != NULL) { err = -EEXIST; goto err_exit; } else { //所有的Sensor列表,根据ID去放入相应的位置 mcxt->cxt[sensor] = kzalloc( sizeof( struct hwmsen_context), GFP_KERNEL); if(mcxt->cxt[sensor] == NULL) { err = -EPERM; goto err_exit; } atomic_set(&mcxt->cxt[sensor]->enable, 0); memcpy(&mcxt->cxt[sensor]->obj, obj, sizeof(*obj)); // add for android2.3 set sensors default polling delay time is 200ms atomic_set(&mcxt->cxt[sensor]->delay, 200); } } |
到这里hwmsens的初始化就完成了
接下来就先open hwmsen驱动,然后就把工作都交给了hwmsen的unlocked_ioctl,即hwmsen_unlocked_ioctl函数
里面的操作函数主要是调用hwmsen_attach函数传入的hwmsen_object里面的sensor_operate,即为mma8653q_operate
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
int mma8653q_operate(
void *self, uint32_t command,
void *buff_in,
int size_in,
void *buff_out, int size_out, int *actualout) { switch (command) { case SENSOR_DELAY: //... break; case SENSOR_ENABLE: //... break; case SENSOR_GET_DATA: //... break; default: //... break; } return err; } |
hwmsen_unlocked_ioctl首先是HWM_IO_ENABLE_SENSOR命令,调用的是hwmsen_enable();
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
static
int hwmsen_enable(
struct hwmdev_object *obj,
int sensor,
int enable) {
mutex_lock(&obj->dc->lock); cxt = obj->dc->cxt[sensor]; if(enable == 1) { enable_again = true; obj->active_data_sensor |= sensor_type; if((obj->active_sensor & sensor_type) == 0) { // no no-data active nodata模式 if (cxt->obj.sensor_operate(cxt->obj.self, SENSOR_ENABLE, &enable, sizeof( int), NULL, 0, NULL) != 0) //... atomic_set(&cxt->enable, 1); } //polling模式 // Need to complete the interrupt sensor work if(( 0 == obj->dc->polling_running) && (obj->active_data_sensor != 0)) { obj->dc->polling_running = 1; //使能定时器 mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay) / ( 1000 / HZ)); } } else { //... } } |
数据的读取:
在sensro初始化的时候,初始化了一个工作队列和一个定时器:
1
2 3 4 5 6 |
sensor_workqueue = create_singlethread_workqueue(
"sensor_polling");
INIT_WORK(&obj->report, hwmsen_work_func); init_timer(&obj->timer); obj->timer.expires = jiffies + atomic_read(&obj->delay) / ( 1000 / HZ); obj->timer.function = hwmsen_poll; obj->timer.data = ( unsigned long)obj; |
每次对sensor enable后就会使能这个定时器,会执行hwmsen_poll,这个函数会唤醒工作队列。工作队列会执行hwmsen_work_func函数
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
static void hwmsen_work_func( struct work_struct *work) { //遍历所有的sensor for(idx = 0; idx < MAX_ANDROID_SENSOR_NUM; idx++) { cxt = obj->dc->cxt[idx]; //我们是polling模式 // Interrupt sensor if(cxt->obj.polling == 0) { //... } //如果sensor指定了delay时间 //added to surpport set delay to specified sensor if(cxt->delayCount > 0) { cxt->delayCount--; if( 0 == cxt->delayCount) { cxt->delayCount = cxt->delayCountSet; } else { continue; } } //从sensor里获取数据 err = cxt->obj.sensor_operate(cxt->obj.self, SENSOR_GET_DATA, NULL, 0, &sensor_data, sizeof(hwm_sensor_data), &out_size); if(err) { HWM_ERR( "get data from sensor (%d) fails!!\n", idx); continue; } else { //LIGHT Sensor... if((idx == ID_LIGHT) || (idx == ID_PRESSURE) || (idx == ID_PROXIMITY) || (idx == ID_TEMPRERATURE)) { // data changed, update the data } } else { // data changed, update the data //填充数据 obj_data.sensors_data[idx].values[ 0] = sensor_data.values[ 0]; obj_data.sensors_data[idx].values[ 1] = sensor_data.values[ 1]; obj_data.sensors_data[idx].values[ 2] = sensor_data.values[ 2]; obj_data.sensors_data[idx].value_divide = sensor_data.value_divide; obj_data.sensors_data[idx].status = sensor_data.status; obj_data.sensors_data[idx].time = nt; event_type |= ( 1 << idx); } } } // //mutex_unlock(&obj_data.lock); if(enable_again == true) { event_type = obj->active_data_sensor; enable_again = false; //filter -1 value for(idx = 0; idx <= MAX_ANDROID_SENSOR_NUM; idx++) { if(ID_ACCELEROMETER == idx || ID_MAGNETIC == idx || ID_ORIENTATION == idx || ID_GYROSCOPE == idx || ID_TEMPRERATURE == idx || ID_LINEAR_ACCELERATION == idx || ID_ROTATION_VECTOR == idx || ID_GRAVITY == idx) { if(SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[ 0] || SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[ 1] || SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[ 2]) { event_type &= ~( 1 << idx); //HWM_LOG("idx=%d,obj->active_sensor after clear: %d\n",idx); } } if(ID_PROXIMITY == idx || ID_LIGHT == idx || ID_PRESSURE == idx) { if(SENSOR_INVALID_VALUE == obj_data.sensors_data[idx].values[ 0]) { event_type &= ~( 1 << idx); } } } } if((event_type & ( 1 << ID_PROXIMITY)) && SENSOR_INVALID_VALUE == obj_data.sensors_data[ID_PROXIMITY].values[ 0]) { event_type &= ~( 1 << ID_PROXIMITY); //HWM_LOG("remove ps event!!!!!!!!!!!\n"); } if(event_type != 0) { //上报sensro类型 input_report_rel(obj->idev, EVENT_TYPE_SENSOR, event_type); input_sync(obj->idev); //modified } else { } if(obj->dc->polling_running == 1) { mod_timer(&obj->timer, jiffies + atomic_read(&obj->delay) / ( 1000 / HZ)); } } |
然后会调用
hwmsen_unlocked_ioctl的HWM_IO_GET_SENSORS_DATA命令即可读取数据