accelerometer Sensor (加速度传感器)驱动上报数据流程分析
时间:2022-08-29 16:30:00
一.相关文件的位置
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, ¶m);
/*.......*/
}
三.小结:
在上层需要获取sensor数据的时候,就会开启这个线程,不断地上报数据,这样就会触发poll返回有数据可读的消息,这时候再使用read()来读数据即可。至于数据是何时何地过来的,还在学习之中。另外,这只是sensor逻辑上的驱动,主要功能是处理上报数据。
注:本人新手,后续会学习更新修正,希望巨佬们多多指教