环境: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 mma8653q_i2c_probe(struct i2c_client * client, const struct i2c_device_id * id) { sobj.self = obj; |
首先是整个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,主要是初始化队列,时间中断 //初始化化Input子系统 input_register_device(hwm_obj->idev); //注册一个misc驱动,主要是提供对sensor操作的接口 //创建属性文件 // add for fix resume bug wake_lock_init(&(hwm_obj->read_data_wake_lock), WAKE_LOCK_SUSPEND, “read_data_wake_lock”); |
接下来按照上面的使用流程来分析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) { |
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驱动 //这里很奇怪,i2c_add_driver完之后如果找到了相应的i2c设备, |
后面的就会在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} }, }; |
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) { //确保每个sensor只有一个实例 |
到这里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模式 //如果sensor指定了delay时间 //从sensor里获取数据 if((event_type & ( 1 << ID_PROXIMITY)) && SENSOR_INVALID_VALUE == obj_data.sensors_data[ID_PROXIMITY].values[ 0]) { |
然后会调用
hwmsen_unlocked_ioctl的HWM_IO_GET_SENSORS_DATA命令即可读取数据