资讯详情

accelerometer Sensor (加速度传感器)驱动上报数据流程分析

一.相关文件的位置

kernel-4.19/drivers/misc/mediatek/sensors-1.0/accelerometer/accel.c

kernel-4.19/drivers/misc/mediatek/sensors-1.0/accelerometer/accelhub/accelhub.c

kernel-4.19/drivers/misc/mediatek/sensors-1.0/hwmon/sensor_event/sensor_event.c

kernel-4.19/drivers/misc/mediatek/sensors-1.0/sensorHub/SCP_nanoHub.c

kernel-4.19/drivers/misc/mediatek/sensors-1.0/nanohub/main.c

文件 功能描述
accel.c accelerometer Sensor 驱动
accelhub.c 收集accelerometer Sensor数据
sensor_event.c 封装sensor驱动文件操作方法
SCP_nanoHub.c 收集处理sensor数据

数据报告流程分析

2.1 poll机制

获取sensor数据,使用poll获取数据的方法,poll可监控文件状态并返回,也可设置超时间。在这个驱动中poll函数里使用poll_wait()函数将过程挂起,直到有数据写入时唤醒。poll机制参考

POLL机制_One Piece&的博客-CSDN博客_poll机制

2.2 accelerometer Sensor在sensor1.0中的数据报告流程

在kernel-4.19/drivers/misc/mediatek/sensors-1.0/accelerometer/accel.c文件操作结构如下:

static const struct file_operations accel_fops = {  .owner = THIS_MODULE,  .open = accel_open,  .read = accel_read,  .poll = accel_poll, };

accel.c中的poll调用sensor_event.c文件中的sensor_event_poll()函数(alsps.c光感和mag.c磁场传感器等也是)。sensor_event_poll()函数实现如下:

unsigned int sensor_event_poll(unsigned char handle, struct file *file,poll_table *wait) {      struct sensor_event_client *client = &event_obj->client[handle];     unsigned int mask = 0;     poll_wait(file, &client->wait, wait);     if (client->head != client->tail) {         mask |= POLLIN | POLLRDNORM;     }     return mask;      }

可见其调用poll_wait()函数将当前过程添加到等待队列中,并在本文件中唤醒它sensor_input_event()函数中的函数如下:

int sensor_input_event(unsigned char handle, const struct sensor_event *event) {     struct sensor_event_client *client = &event_obj->client[handle];     unsigned int dummy = 0;      spin_lock(&client->buffer_lock);      if (unlikely(client->buffull == true)) {         pr_err_ratelimited(                 "input buffull, handle:%d, head:%d, tail:%d\n", handle,                 client->head, client->tail);         spin_unlock(&client->buffer_lock);         wake_up_interruptible(&client->wait);         return -1;     }     client->buffer[client->head  ] = *event;     client->head &= client->bufsize - 1;     dummy = client->head   1;     dummy &= client->bufsize - 1;     if (unlikely(dummy == client->tail))         client->buffull = true;     spin_unlock(&client->buffer_lock);      wake_up_interruptible(&client->wait);     return 0; }

在accel.c可以在文件中搜索,acc_data_report()中调用sensor_input_event()这个名字可以猜测是在报告传感器的数据,也就是说sensor有汇报数据的时候就能将poll唤醒,通知上层有数据可读。acc_data_report()如下:

int acc_data_report(struct acc_data *data) {     struct sensor_event event;     int err = 0;      memset(&event, 0, sizeof(struct sensor_event));      event.time_stamp = data->timestamp;     event.flush_action = DATA_ACTION;     event.status = data->status;     event.word[0] = data->x;     event.word[1] = data->y;     event.word[2] = data->z;     event.reserved = data->reserved[0];      if (event.reserved == 1)         mark_timestamp(ID_ACCELEROMETER, DATA_REPORT,                        ktime_get_boot_ns(), event.time_stamp);     err = sensor_input_event(acc_context_obj->mdev.minor, &event);     return err; }

acc_data_report()函数又过去了accelhub.c中的gsensor_recv_data()函数调用,然后检查gsensor_recv_data(),发现它在accelhub.c的probe通过调用函数scp_sensorHub_data_registration()函数和传感器ID建立关系:

err = scp_sensorHub_data_registration(ID_ACCELEROMETER,gsensor_recv_data);

&nbs;       scp_sensorHub_data_registration()函数位于SCP_nanoHub.c,可以看到这里把gsensor_recv_data()通过函数指针的方式放到了dispatch_data_cb[]数组中,以sensor的ID作为数组的索引scp_sensorHub_data_registration()函数如下:

int scp_sensorHub_data_registration(uint8_t sensor,SCP_sensorHub_handler handler) {
    struct SCP_sensorHub_data *obj = obj_data;

    if (sensor > ID_SENSOR_MAX_HANDLE)
        /*......*/
    if (handler == NULL)
        /*......*/
    obj->dispatch_data_cb[sensor] = handler;
    
    return 0;
}

        跟着函数名走下去,一直到SCP_sensorHub_direct_push_work()函数,发现是一个循环:

static int SCP_sensorHub_direct_push_work(void *data)
{
    for (;;) {
        wait_event(chre_kthread_wait,
                   READ_ONCE(chre_kthread_wait_condition));
        WRITE_ONCE(chre_kthread_wait_condition, false);
        mark_timestamp(0, WORK_START, ktime_get_boot_ns(), 0);
        SCP_sensorHub_read_wp_queue();//该函数会调用到gsensor_recv_data()
    }
    return 0;
}

        最后发现这是在sensorHub_probe()里面开启的一个内核线程:

static int sensorHub_probe(struct platform_device *pdev) {
    /*.......*/
    WRITE_ONCE(chre_kthread_wait_condition, false);
    task = kthread_run(SCP_sensorHub_direct_push_work,
                       NULL, "chre_kthread");
    if (IS_ERR(task)) {
        pr_err("SCP_sensorHub_direct_push_work create fail!\n");
        goto exit_direct_push;
    }
    sched_setscheduler(task, SCHED_FIFO, &param);
    /*.......*/
}

 三.小结:

        在上层需要获取sensor数据的时候,就会开启这个线程,不断地上报数据,这样就会触发poll返回有数据可读的消息,这时候再使用read()来读数据即可。至于数据是何时何地过来的,还在学习之中。另外,这只是sensor逻辑上的驱动,主要功能是处理上报数据。

        注:本人新手,后续会学习更新修正,希望巨佬们多多指教

标签: 传感器pr92682010402cb010传感器cb传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台