下图就是对应的流程框架图:
事件上报流程:
一旦上层打开设备文件就会调用==> evdev_open函数,evdev_open分配并初始化一个client结构体,并将它和evdev关联起来,关联的内容是,将client->evdev指向它所表示的evdev,
==> 调用evdev_attach_client()将client挂到evdev->client_list上,我们驱动层上报的输入事件
的键值,就是存放在evdev->buffer中的。
==> 调用evdev_open_device()函数,通过调用核心层input.c中的input_open_device函数实现的,打开输入设备使设备准备好接收或者发送数据。
==> 调用evdev_read函数实现事件处理层对上层的读操作,我们的事件处理层对上层的读操作,用一个等待队列wake_up_interruptible(&evdev->wait)实现阻塞,这样就能保证,我们只有在触摸按键事件发生,中断到来,我们才去上报按键事件,并唤醒阻塞,让事件处理层的evdev_read将键值最终通过copy_to_user送到用户空间。
mtk的mtk_tpd.c怎么做兼容多个TP:
关键代码:遍历mtk的tpd_driver_list里面的所有的驱动,判断名字是否为NULL,每一个module touch IC驱动都会添加到这个静态数组里面对于if (tpd_load_status == 1)这个条件,
会判断我们所遍历的每一个module IC驱动的初始化函数,probe成功即i2c通信成功的话就会将tpd_load_status置1(具体驱动的probe函数中),所以我们就是通过这个值判断哪一个驱动的。
具体TP ic驱动里面,主要进行IC的上电、申请中断号注册中断处理函数、Update FW等动作。
重点有两个函数:事件处理线程、中断处理函数
中断处理函数:
一旦触摸事件发生,则触发中断,此中断处理函数唤醒等待队列。
static irqreturn_t tpd_eint_interrupt_handler(void)
{
TPD_DEBUG_PRINT_INT;
tpd_flag = 1;
wake_up_interruptible(&waiter);//唤醒等待队列
return IRQ_HANDLED;
}
事件处理线程:
static int touch_event_handler(void *unused)
{
…
sched_setscheduler(current, SCHED_RR, ¶m);
do {
set_current_state(TASK_INTERRUPTIBLE);//设置Task 的状态为可中断的等待状态
if (tpd_eint_mode) {
wait_event_interruptible(waiter, tpd_flag != 0);//满足tpd_flag!=0 就唤醒队列
tpd_flag = 0;//改变条件
} else {
msleep(tpd_polling_time);
}
set_current_state(TASK_RUNNING);//设置Task 的状态为执行态
…
#if defined(CONFIG_GTP_SLIDE_WAKEUP)
if (DOZE_ENABLED == doze_status) {
ret = gtp_i2c_read(i2c_client_point, doze_buf, 3);
GTP_DEBUG(“0x814B = 0x%02X”, doze_buf[2]);
if (ret > 0) {
if (0xAA == doze_buf[2]) {
GTP_INFO(“Forward slide up screen!”);
doze_status = DOZE_WAKEUP;
input_report_key(tpd->dev,
KEY_POWER, 1);
input_sync(tpd->dev);
input_report_key(tpd->dev,
KEY_POWER, 0);
input_sync(tpd->dev);
/* clear 0x814B */
doze_buf[2] = 0x00;
gtp_i2c_write(i2c_client_point,
doze_buf, 3);
} else if (0xBB == doze_buf[2]) {
GTP_INFO(“Back slide up screen!”);
doze_status = DOZE_WAKEUP;
input_report_key(tpd->dev,
KEY_POWER, 1);
input_sync(tpd->dev);
…
}
! |