天天看點

android g-sensor 驅動源碼分析

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