【转】MTK TP驱动移植
原文地址:https://blog.csdn.net/u010245383/article/details/50995919
对于MTK TP驱动移植一般分为六部分:
1、硬件IO口配置;
2、TP驱动移植;
3、I2C通信;
4、中断触发;
5、数据上报;
6、虚拟按键;
硬件电路:
1、GPIO配置
打开 mediatek\dct\DrvGen.exe
选择 mediatek\custom\xiaoxi\kernel\dct\dct\codegen.dws 配置文件
配置EINT7_CTP引脚、CTP_RST复位引脚
2、TP驱动移植(以ft5x16为例)
在\mediatek\custom\common\kernel\touchpanel目录下创建ft5x16,将供应商提供的驱动驱动资料拷贝到该目录下;
修改配置文件:mediatek\config\prj\ProjectConfig.mk下的CUSTOM_KERNEL_TOUCHPANEL其值由改为ft5x16,表明对应ft5x16子目录;
打开ft5x16.c文件,修改一下:
1 static struct i2c_board_info __initdata ft5x16_i2c_tpd={ I2C_BOARD_INFO("ft5x16", (0x70>>1))}; //"ft5x16"为设备名 ,设备地址为高7位 2 3 static struct tpd_driver_t tpd_device_driver = { 4 .tpd_device_name = "FT5x16", 5 .tpd_local_init = tpd_local_init, 6 .suspend = tpd_suspend, 7 .resume = tpd_resume, 8 #ifdef TPD_HAVE_BUTTON 9 .tpd_have_button = 1, 10 #else 11 .tpd_have_button = 0, 12 #endif 13 }; 14 15 /* called when loaded into kernel */ 16 static int __init tpd_driver_init(void) { 17 printk("MediaTek FT5x16 touch panel driver init\n"); 18 /* 注册板级设备信息 */ 19 i2c_register_board_info(IIC_PORT, &ft5x16_i2c_tpd, 1); //IIC_PORT表示i2c控制器号,由电路原理图可知TP设备连接到i2c控制器0,ft5x16_i2c_tpd为i2c设备结构,1表示该i2c_board_info个数 20 if(tpd_driver_add(&tpd_device_driver) < 0) 21 printk("add FT5x16 driver failed\n"); 22 return 0; 23 }
重新编译:./mk n k && ./mk bootimage
3、I2C通信
新驱动编译进内核,启动内核后,我们怎样验证i2c接口能够正常通信呢?
系统启动后通过串口或adb shell进入系统命令行窗口,查询/sys/bus/i2c/devices目录下是否有0-0038信息,查询/sys/bus/i2c/drivers目录下是否存在‘ft5x16’设备名;先保证i2c能够正常通信;
4、中断触发
中断注册函数:mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE, tpd_eint_interrupt_handler, 1);
//tpd_eint_interrupt_handler函数为中断回调函数
5、数据上报
当触摸屏产生中断的时候就会调用到该接口;然后在中断处理函数中唤醒运行在子线程中的等待队列,再通过子线程获取TP数据并上报到系统;
1 static DECLARE_WAIT_QUEUE_HEAD(waiter); //初始化等待队列 2 3 thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); //新建线程 4 5 static int touch_event_handler(void *unused) 6 { 7 ...... 8 do 9 { 10 mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); 11 set_current_state(TASK_INTERRUPTIBLE); 12 wait_event_interruptible(waiter,tpd_flag!=0); //等待队列进入休眠,等待唤醒 13 tpd_flag = 0; 14 set_current_state(TASK_RUNNING); 15 ...... 16 if (tpd_touchinfo(&cinfo, &pinfo)) //获取TP数据 17 { 18 //TPD_DEBUG("point_num = %d\n",point_num); 19 TPD_DEBUG_SET_TIME; 20 if(point_num >0) 21 { 22 for(i =0; i<point_num; i++)//only support 3 point 23 { 24 cinfo.x[i] = cinfo.x[i]; 25 cinfo.y[i] = cinfo.y[i]; 26 27 tpd_down(cinfo.x[i], cinfo.y[i], cinfo.id[i]); //上报按下数据 28 printk(KERN_DEBUG"----calibration----- X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]); 29 } 30 input_sync(tpd->dev); 31 } 32 else 33 { 34 tpd_up(cinfo.x[0], cinfo.y[0]); //上报弹起数据 35 //TPD_DEBUG("release --->\n"); 36 //input_mt_sync(tpd->dev); 37 input_sync(tpd->dev); 38 } 39 } 40 ...... 41 42 }while(!kthread_should_stop()); 43 44 return 0; 45 }
TP数据可以通过打印的方式进行查看,也可以激活‘系统设置’中‘开发者选项’的‘指针位置’,现在触摸操作在LCD的轨迹,也可以在packages\apps\Launcher2\src\com\android\launcher2\Launcher.java的onCreate方法最后添加Settings.System.putInt(this.getContentResolver(),Settings.System.POINTER_LOCATION, 1); 在Launcher中开启‘指针位置’功能(需要mm Launcher模块并重新打包和烧录system.img文件);
注:如果TP获取到的数据比较乱的时候建议通过打开‘指针位置’功能进行查看,排除TP固件分辨与LCD没对应等问题;
6、虚拟按键
1 static struct tpd_driver_t tpd_device_driver = { 2 .tpd_device_name = "FT5x16", 3 .tpd_local_init = tpd_local_init, 4 .suspend = tpd_suspend, 5 .resume = tpd_resume, 6 #ifdef TPD_HAVE_BUTTON 7 .tpd_have_button = 1, 8 #else 9 .tpd_have_button = 0, 10 #endif 11 };
从tpd_driver_t结构可知tpd_have_button成员为虚拟按键标志位;由宏TPD_HAVA_BUTTON开关决定的,宏定义在tpd_custom_fts.h中;
在tpd_custom_fts.h中定义了一系列关于虚拟按键的宏:
#define TPD_HAVE_BUTTON //虚拟按键开关
#define TPD_BUTTON_WIDTH (200) //按键宽度
#define TPD_BUTTON_HEIGH (100) //按键高度
#define TPD_KEY_COUNT 3 //按键个数
#define TPD_KEYS {KEY_MENU, KEY_HOMEPAGE, KEY_BACK} //按键对应的功能
#define TPD_KEYS_DIM {{80,900,TPD_BUTTON_WIDTH,TPD_BUTTON_HEIGH}, {240,900,TPD_BUTTON_WIDTH,TPD_BUTTON_HEIGH}, {400,900,TPD_BUTTON_WIDTH,TPD_BUTTON_HEIGH}} //按键对应位置
TPD_KEYS_DIM中的坐标是该按键区域的中心点:
TP驱动简要分析
1 static struct tpd_driver_t tpd_device_driver = { 2 .tpd_device_name = FT5x16, 3 .tpd_local_init = tpd_local_init, //初始化函数 4 .suspend = tpd_suspend, 5 .resume = tpd_resume, 6 #ifdef TPD_HAVE_BUTTON 7 .tpd_have_button = 1, 8 #else 9 .tpd_have_button = 0, 10 #endif 11 }; 12 13 /* called when loaded into kernel */ 14 static int __init tpd_driver_init(void) { 15 printk("MediaTek FT5x16 touch panel driver init\n"); 16 i2c_register_board_info(0, &ft5x16_i2c_tpd, 1); //注册板级设备信息 17 if(tpd_driver_add(&tpd_device_driver) < 0) //添加驱动 18 printk("add FT5x16 driver failed\n"); 19 return 0; 20 }
MTK自己编写了一套TP框架,通过该框架管理TP设备,tpd_driver_add为框架的接口之一;系统通过tpd_driver_add添加驱动后会回调tpd_local_init函数;
1 #ifdef TPD_HAVE_BUTTON 2 static int tpd_keys_local[TPD_KEY_COUNT] = TPD_KEYS; //存放按键功能信息 3 static int tpd_keys_dim_local[TPD_KEY_COUNT][4] = TPD_KEYS_DIM; //存放虚拟按键信息 4 #endif 5 6 static int tpd_local_init(void) 7 { 8 TPD_DMESG("FTS I2C Touchscreen Driver (Built %s @ %s)\n", __DATE__, __TIME__); 9 10 if(i2c_add_driver(&tpd_i2c_driver)!=0) //注册i2c驱动 11 { 12 TPD_DMESG("FTS unable to add i2c driver.\n"); 13 return -1; 14 } 15 if(tpd_load_status == 0) 16 { 17 TPD_DMESG("FTS add error touch panel driver.\n"); 18 i2c_del_driver(&tpd_i2c_driver); 19 return -1; 20 } 21 22 #ifdef TPD_HAVE_BUTTON //如果定义虚拟按键,则初始化按键信息 23 tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data 24 #endif 25 26 #if (defined(TPD_WARP_START) && defined(TPD_WARP_END)) 27 TPD_DO_WARP = 1; 28 memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT*4); 29 memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT*4); 30 #endif 31 32 #if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION)) 33 memcpy(tpd_calmat, tpd_def_calmat_local, 8*4); 34 memcpy(tpd_def_calmat, tpd_def_calmat_local, 8*4); 35 #endif 36 TPD_DMESG("end %s, %d\n", __FUNCTION__, __LINE__); 37 tpd_type_cap = 1; 38 return 0; 39 }
向系统注册i2c驱动后,如果找到对应的设备就会调用tpd_probe函数;
1 static const struct i2c_device_id ft5x16_tpd_id[] = {{TPD_NAME,0},{}}; 2 3 static struct i2c_driver tpd_i2c_driver = { 4 .driver = { 5 .name = TPD_NAME, 6 }, 7 .probe = tpd_prob, 8 .remove = __devexit_p(tpd_remove), 9 .id_table = ft5x16_tpd_id, 10 .detect = tpd_detect, 11 }; 12 13 static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) 14 { 15 int retval = TPD_OK; 16 char data; 17 u8 report_rate=0; 18 int err=0; 19 int reset_count = 0; 20 u8 chip_id,i; 21 22 reset_proc: 23 i2c_client = client; 24 #ifdef MAIERXUN_TP_COM 25 if(touchpanel_flag){ 26 return 0; 27 } 28 #endif 29 //复位 30 //power on, need confirm with SA 31 mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); 32 mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); 33 mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO); 34 msleep(5); 35 TPD_DMESG(" fts ic reset\n"); 36 37 //打开TP电源 38 #ifdef TPD_POWER_SOURCE_CUSTOM 39 hwPowerOn(TPD_POWER_SOURCE_CUSTOM, VOL_3300, "TP"); 40 #else 41 hwPowerOn(MT65XX_POWER_LDO_VGP2, VOL_3300, "TP"); 42 #endif 43 44 mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); 45 mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); 46 mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); 47 48 #ifdef TPD_CLOSE_POWER_IN_SLEEP 49 hwPowerDown(TPD_POWER_SOURCE,"TP"); 50 hwPowerOn(TPD_POWER_SOURCE,VOL_3300,"TP"); 51 msleep(100); 52 53 #else /* 结束复位 */ 54 mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); 55 mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); 56 mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO); 57 msleep(5); 58 TPD_DMESG(" fts ic reset\n"); 59 mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); 60 mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); 61 mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); 62 #endif 63 64 /* 初始化中断引脚 */ 65 mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT); 66 mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN); 67 mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE); 68 mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP); 69 70 /* 中断配置和注册 */ 71 mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); 72 mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE, tpd_eint_interrupt_handler, 1); //注册中断处理函数,TP产生中断时就会回调tpd_eint_interrupt函数 73 mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); 74 75 msleep(400); 76 77 err=i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &data); 78 79 TPD_DMESG("gao_i2c:err %d,data:%d\n", err,data); 80 if(err< 0 || data!=0)// reg0 data running state is 0; other state is not 0 81 { 82 TPD_DMESG("I2C transfer error, line: %d\n", __LINE__); 83 #ifdef TPD_RESET_ISSUE_WORKAROUND 84 if ( reset_count < TPD_MAX_RESET_COUNT ) 85 { 86 reset_count++; 87 goto reset_proc; 88 } 89 #endif 90 //add at 20150330 by zhu 91 #ifdef MAIERXUN_TP_COM 92 touchpanel_flag=false; 93 #endif 94 return -1; 95 } 96 97 ...... 98 99 #ifdef VELOCITY_CUSTOM_FT5206 100 if((err = misc_register(&tpd_misc_device))) //注册混杂设备驱动 101 { 102 printk("mtk_tpd: tpd_misc_device register failed\n"); 103 104 } 105 #endif 106 107 #ifdef TPD_AUTO_UPGRADE 108 printk("********************Enter CTP Auto Upgrade********************\n"); 109 fts_ctpm_auto_upgrade(i2c_client); 110 #endif 111 thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); //创建子线程,通过该子线程获取和上报数据 112 if (IS_ERR(thread)) 113 { 114 retval = PTR_ERR(thread); 115 TPD_DMESG(TPD_DEVICE " failed to create kernel thread: %d\n", retval); 116 } 117 118 TPD_DMESG("FTS Touch Panel Device Probe %s\n", (retval < TPD_OK) ? "FAIL" : "PASS"); 119 120 /* 初始化TP的P-sensor功能,暂不分析 */ 121 #ifdef TPD_PROXIMITY 122 struct hwmsen_object obj_ps; 123 124 obj_ps.polling = 0;//interrupt mode 125 obj_ps.sensor_operate = tpd_ps_operate; 126 if((err = hwmsen_attach(ID_PROXIMITY, &obj_ps))) 127 { 128 APS_ERR("proxi_fts attach fail = %d\n", err); 129 } 130 else 131 { 132 APS_ERR("proxi_fts attach ok = %d\n", err); 133 } 134 #endif 135 136 #ifdef MAIERXUN_TP_COM 137 touchpanel_flag=true; 138 #endif 139 140 return 0; 141 142 }
/* 中断处理函数 */
1 static void tpd_eint_interrupt_handler(void) 2 { 3 //TPD_DEBUG("TPD interrupt has been triggered\n"); 4 TPD_DEBUG_PRINT_INT; 5 tpd_flag = 1; 6 wake_up_interruptible(&waiter); //唤醒等待队列 7 }
中断处理遵循中断上下文的设计原则,使得中断子程序只是简单唤醒等待队列就可以了,没有多余的操作;
/* 子线程处理函数 */
1 static int touch_event_handler(void *unused) 2 { 3 struct touch_info cinfo, pinfo; 4 int i=0; 5 6 struct sched_param param = { .sched_priority = RTPM_PRIO_TPD }; 7 sched_setscheduler(current, SCHED_RR, ¶m); 8 9 #ifdef TPD_PROXIMITY 10 int err; 11 hwm_sensor_data sensor_data; 12 u8 proximity_status; 13 14 #endif 15 u8 state; 16 17 do //进入while循环进行睡眠-等待唤醒的操作 18 { 19 mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); //中断使能(解除屏蔽) 20 set_current_state(TASK_INTERRUPTIBLE); 21 wait_event_interruptible(waiter,tpd_flag!=0); //进入睡眠等待唤醒 22 23 tpd_flag = 0; 24 25 set_current_state(TASK_RUNNING); 26 ...... 27 28 #ifdef TPD_PROXIMITY //TP的P-sensor功能,暂不分析 29 if (tpd_proximity_flag == 1) 30 { 31 i2c_smbus_read_i2c_block_data(i2c_client, 0xB0, 1, &state); 32 TPD_PROXIMITY_DEBUG("proxi_5206 0xB0 state value is 1131 0x%02X\n", state); 33 34 if(!(state&0x01)) 35 { 36 tpd_enable_ps(1); 37 } 38 39 i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &proximity_status); 40 TPD_PROXIMITY_DEBUG("proxi_5206 0x01 value is 1139 0x%02X\n", proximity_status); 41 42 if (proximity_status == 0xC0) 43 { 44 tpd_proximity_detect = 0; 45 } 46 else if(proximity_status == 0xE0) 47 { 48 tpd_proximity_detect = 1; 49 } 50 51 TPD_PROXIMITY_DEBUG("tpd_proximity_detect 1149 = %d\n", tpd_proximity_detect); 52 53 if ((err = tpd_read_ps())) 54 { 55 TPD_PROXIMITY_DMESG("proxi_5206 read ps data 1156: %d\n", err); 56 } 57 sensor_data.values[0] = tpd_get_ps_value(); 58 sensor_data.value_divide = 1; 59 sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM; 60 if ((err = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data))) 61 { 62 TPD_PROXIMITY_DMESG(" proxi_5206 call hwmsen_get_interrupt_data failed= %d\n", err); 63 } 64 } 65 #endif 66 67 if (tpd_touchinfo(&cinfo, &pinfo)) //获取TP设备数据,并把数据保存在cinfob buf中 68 { 69 //TPD_DEBUG("point_num = %d\n",point_num); 70 TPD_DEBUG_SET_TIME; 71 if(point_num >0) 72 { 73 for(i =0; i<point_num; i++)//only support 3 point 74 { 75 printk(KERN_DEBUG"X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]); 76 77 cinfo.x[i] = cinfo.x[i]; 78 cinfo.y[i] = cinfo.y[i]; 79 80 tpd_down(cinfo.x[i], cinfo.y[i], cinfo.id[i]); //按下数据处理 81 printk(KERN_DEBUG"----calibration----- X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]); 82 } 83 input_sync(tpd->dev); 84 } 85 else 86 { 87 tpd_up(cinfo.x[0], cinfo.y[0]); //弹起数据处理 88 //TPD_DEBUG("release --->\n"); 89 //input_mt_sync(tpd->dev); 90 input_sync(tpd->dev); 91 } 92 } 93 ...... 94 95 }while(!kthread_should_stop()); 96 97 return 0; 98 }
/* 获取TP数据 */
1 static int tpd_touchinfo(struct touch_info *cinfo, struct touch_info *pinfo) 2 { 3 int i = 0; 4 char data[128] = {0}; 5 u16 high_byte,low_byte,reg; 6 u8 report_rate =0; 7 8 p_point_num = point_num; 9 if (tpd_halt) 10 { 11 TPD_DMESG( "tpd_touchinfo return ..\n"); 12 return false; 13 } 14 mutex_lock(&i2c_access); 15 16 17 reg = 0x00; 18 fts_i2c_Read(i2c_client, ®, 1, data, 64); //获取TP数据,一些TP是支持多点触控的,所以有可能就产生多个触点的数据 19 mutex_unlock(&i2c_access); 20 21 /*get the number of the touch points*/ 22 point_num= data[2] & 0x0f; 23 24 TPD_DEBUG("point_num =%d\n",point_num); 25 26 /* 根据芯片协议解析数据并存放在cinfo buf中 */ 27 for(i = 0; i < point_num; i++) 28 { 29 cinfo->p[i] = data[3+6*i] >> 6; //event flag 30 cinfo->id[i] = data[3+6*i+2]>>4; //touch id 31 /*get the X coordinate, 2 bytes*/ 32 high_byte = data[3+6*i]; 33 high_byte <<= 8; 34 high_byte &= 0x0f00; 35 low_byte = data[3+6*i + 1]; 36 cinfo->x[i] = high_byte |low_byte; 37 38 39 /*get the Y coordinate, 2 bytes*/ 40 high_byte = data[3+6*i+2]; 41 high_byte <<= 8; 42 high_byte &= 0x0f00; 43 low_byte = data[3+6*i+3]; 44 cinfo->y[i] = high_byte |low_byte; 45 } 46 47 } 48 TPD_DEBUG(" cinfo->x[0] = %d, cinfo->y[0] = %d, cinfo->p[0] = %d\n", cinfo->x[0], cinfo->y[0], cinfo->p[0]); 49 50 return true; 51 }
1 static void tpd_down(int x, int y, int p) { 2 static int tpd_x = 0; 3 static int tpd_y = 0; 4 5 tpd_x = x; 6 tpd_y = y; 7 8 /* 通过输入子系统上报数据 */ 9 input_report_key(tpd->dev, BTN_TOUCH, 1); 10 input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 20); 11 input_report_abs(tpd->dev, ABS_MT_POSITION_X, x); 12 input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y); 13 14 printk(KERN_ERR, "D[%4d %4d %4d] ", x, y, p); 15 /* track id Start 0 */ 16 input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, p); 17 input_mt_sync(tpd->dev); 18 #ifndef MT6572 19 if (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode()) 20 #endif 21 { 22 tpd_button(x, y, 1); //虚拟按键的处理 23 } 24 TPD_EM_PRINT(x, y, x, y, p-1, 1); 25 } 26 27 static void tpd_up(int x, int y) { 28 29 input_report_key(tpd->dev, BTN_TOUCH, 0); 30 input_mt_sync(tpd->dev); 31 TPD_EM_PRINT(x, y, x, y, 0, 0); 32 33 #ifndef MT6572 34 if (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode()) 35 #endif 36 { 37 tpd_button(x, y, 0); 38 } 39 }
/* 虚拟按键判断和处理函数 */
1 void tpd_button(unsigned int x, unsigned int y, unsigned int down) { 2 int i; 3 if(down) { 4 for(i=0;i<tpd_keycnt;i++) 5 { 6 /* 判断数据是否落在虚拟按键的范围内,数据处理算法实现了以坐标点为中心的虚拟按键 */ 7 if(x>=tpd_keys_dim[i][0]-(tpd_keys_dim[i][2]/2) && 8 x<=tpd_keys_dim[i][0]+(tpd_keys_dim[i][2]/2) && 9 y>=tpd_keys_dim[i][1]-(tpd_keys_dim[i][3]/2) && 10 y<=tpd_keys_dim[i][1]+(tpd_keys_dim[i][3]/2) && 11 !(tpd->btn_state&(1<<i))) 12 { 13 input_report_key(tpd->kpd, tpd_keys[i], 1); //上报按键 14 input_sync(tpd->kpd); 15 tpd->btn_state|=(1<<i); 16 TPD_DEBUG("[mtk-tpd] press key %d (%d)\n",i, tpd_keys[i]); 17 printk("[mtk-tpd] press key %d (%d)\n",i, tpd_keys[i]); 18 } 19 } 20 } else { 21 for(i=0;i<tpd_keycnt;i++) { 22 if(tpd->btn_state&(1<<i)) { 23 input_report_key(tpd->kpd, tpd_keys[i], 0); 24 input_sync(tpd->kpd); 25 TPD_DEBUG("[mtk-tpd] release key %d (%d)\n",i, tpd_keys[i]); 26 printk("[mtk-tpd] release key %d (%d)\n",i, tpd_keys[i]); 27 } 28 } 29 tpd->btn_state=0; 30 } 31 } 32 tpd_keys_dim和tpd_keys的数据是通过tpd_button_setting初始化的,可以去看tpd_button_setting()的实现;
通过简单分析,由此可知MTK的TP驱动的整体框架跟普通TP驱动框架也是大致差不多;