環境: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指令即可讀取資料