一.相关文件位置
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);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逻辑上的驱动,主要功能是处理上报数据。
注:本人新手,后续会学习更新修正,希望巨佬们多多指教