Mtk Sensor 驱动框架变更简要分析

Mtk Android 8.0 以后版本,Sensor 部分主要修改了 data path 框架,原来数据通过输入子系统传递到应用层,现在采用 misc dev + poll 实现数据上报。下面以 GSensor 为例,分析数据上报过程。
首先注册混杂设备驱动:
acc_register_control_path --> acc_misc_init --> sensor_attr_register
其 file_operation 定义如下:

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

由于 ctl path 被延用,原来 sys 控制节点仍然有效,使能 GSensor 流程如下:enbale -> active -> batch,在 batch 函数启动定时器,循环读 GSensor 硬件数据。

startTimer(&cxt->hrTimer, atomic_read(&cxt->delay), true);

定时器回调函数会调用如下函数:

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];
    /* ACC_PR_ERR("x:%d,y:%d,z:%d,time:%lld\n", data->x, data->y, data->z, data->timestamp); */
    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);
    if (err < 0)
        pr_err_ratelimited("failed due to event buffer full\n");
    return err;
}

对数据进行分装后,调用 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 safe, this function don't support interrupt context */
    spin_lock(&client->buffer_lock);
    /*
     * Reserve below log if need debug LockProve
     * SE_ERR("[Lomen]sensor_input_event: printf key handle ID=%d, key addr=%p\n",
     * handle, (struct lock_class_key*)client->buffer_lock.rlock.dep_map.key);
     */
    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;
    /* remain 1 count */
    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;
}

上述函数主要做了两件事情,第一是将 sersor 数据添加到 GSensor 对应的全局的缓存队列中,第二是唤醒对应的等待队列。那么等待队列在哪里等待呢?这就要看应用层何时来取数据数据了。
通过上述准备工作,应用层可以通过 misc 设备节点读取数据了,相应的 poll 和 read 回调函数:
accel_poll --> 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) {
        /* SE_PR_ERR("sensor_event_poll handle:%d\n", handle); */
        mask |= POLLIN | POLLRDNORM;
    }

    return mask;
}

可以看到在 poll 接口中通过 poll_wait 休眠,与上述数据上报时的唤醒函数对应。当有传感器数据进入缓存队列时, poll_wait 被唤醒,此时执行 read 函数,将从 GSensor 的全局队列缓存中取出原始数据。

static ssize_t accel_read(struct file *file, char __user *buffer,
              size_t count, loff_t *ppos)
{
    ssize_t read_cnt = 0;

    read_cnt = sensor_event_read(acc_context_obj->mdev.minor, file, buffer, count, ppos);

    return read_cnt;
}

具体的处理函数如下:

ssize_t sensor_event_read(unsigned char handle, struct file *file, char __user *buffer,
              size_t count, loff_t *ppos)
{
    struct sensor_event_client *client = &event_obj->client[handle];
    struct sensor_event event;
    size_t read = 0;

    if (count != 0 && count < sizeof(struct sensor_event)) {
        SE_PR_ERR("sensor_event_read handle: %d err count(%d)\n", handle, (int)count);
        return -EINVAL;
    }

    for (;;) {

        if (client->head == client->tail) {
            /* SE_PR_ERR("sensor_event_read handle: %d  count 0\n", handle); */
            return 0;
        }

        if (count == 0) {
            SE_LOG("sensor_event_read count: %d\n", (int)count);
            break;
        }

        while (read + sizeof(struct sensor_event) <= count &&
               sensor_event_fetch_next(client, &event)) {
            if (copy_to_user(buffer + read, &event, sizeof(struct sensor_event)))
                return -EFAULT;
            read += sizeof(struct sensor_event);
        }
        if (read)
            break;
    }

    return read;
}

至此数据上报流程完成。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翻滚吧香香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值