对于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文件,修改一下:

[cpp] view plaincopy
  1. static struct i2c_board_info __initdata ft5x16_i2c_tpd={ I2C_BOARD_INFO("ft5x16", (0x70>>1))}; //"ft5x16"为设备名 ,设备地址为高7位
  2. static struct tpd_driver_t tpd_device_driver = {
  3. .tpd_device_name = "FT5x16",
  4. .tpd_local_init = tpd_local_init,
  5. .suspend = tpd_suspend,
  6. .resume = tpd_resume,
  7. #ifdef TPD_HAVE_BUTTON
  8. .tpd_have_button = 1,
  9. #else
  10. .tpd_have_button = 0,
  11. #endif
  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. /* 注册板级设备信息 */
  17. i2c_register_board_info(IIC_PORT, &ft5x16_i2c_tpd, 1);  //IIC_PORT表示i2c控制器号,由电路原理图可知TP设备连接到i2c控制器0,ft5x16_i2c_tpd为i2c设备结构,1表示该i2c_board_info个数
  18. if(tpd_driver_add(&tpd_device_driver) < 0)
  19. printk("add FT5x16 driver failed\n");
  20. return 0;
  21. }
  22. </span>

重新编译:./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数据并上报到系统;

[cpp] view plaincopy
  1. static DECLARE_WAIT_QUEUE_HEAD(waiter);  //初始化等待队列
  2. thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);  //新建线程
  3. static int touch_event_handler(void *unused)
  4. {
  5. ......
  6. do
  7. {
  8. mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
  9. set_current_state(TASK_INTERRUPTIBLE);
  10. wait_event_interruptible(waiter,tpd_flag!=0);  //等待队列进入休眠,等待唤醒
  11. tpd_flag = 0;
  12. set_current_state(TASK_RUNNING);
  13. ......
  14. if (tpd_touchinfo(&cinfo, &pinfo))   //获取TP数据
  15. {
  16. //TPD_DEBUG("point_num = %d\n",point_num);
  17. TPD_DEBUG_SET_TIME;
  18. if(point_num >0)
  19. {
  20. for(i =0; i<point_num; i++)//only support 3 point
  21. {
  22. cinfo.x[i] = cinfo.x[i];
  23. cinfo.y[i] = cinfo.y[i];
  24. tpd_down(cinfo.x[i], cinfo.y[i], cinfo.id[i]); //上报按下数据
  25. printk(KERN_DEBUG"----calibration----- X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]);
  26. }
  27. input_sync(tpd->dev);
  28. }
  29. else
  30. {
  31. tpd_up(cinfo.x[0], cinfo.y[0]);   //上报弹起数据
  32. //TPD_DEBUG("release --->\n");
  33. //input_mt_sync(tpd->dev);
  34. input_sync(tpd->dev);
  35. }
  36. }
  37. ......
  38. }while(!kthread_should_stop());
  39. return 0;
  40. }

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、虚拟按键

[cpp] view plaincopy
  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驱动简要分析

[cpp] view plaincopy
  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. /* called when loaded into kernel */
  13. static int __init tpd_driver_init(void) {
  14. printk("MediaTek FT5x16 touch panel driver init\n");
  15. i2c_register_board_info(0, &ft5x16_i2c_tpd, 1);  //注册板级设备信息
  16. if(tpd_driver_add(&tpd_device_driver) < 0)  //添加驱动
  17. printk("add FT5x16 driver failed\n");
  18. return 0;
  19. }

MTK自己编写了一套TP框架,通过该框架管理TP设备,tpd_driver_add为框架的接口之一;系统通过tpd_driver_add添加驱动后会回调tpd_local_init函数;

[cpp] view plaincopy
  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. static int tpd_local_init(void)
  6. {
  7. TPD_DMESG("FTS I2C Touchscreen Driver (Built %s @ %s)\n", __DATE__, __TIME__);
  8. if(i2c_add_driver(&tpd_i2c_driver)!=0)  //注册i2c驱动
  9. {
  10. TPD_DMESG("FTS unable to add i2c driver.\n");
  11. return -1;
  12. }
  13. if(tpd_load_status == 0)
  14. {
  15. TPD_DMESG("FTS add error touch panel driver.\n");
  16. i2c_del_driver(&tpd_i2c_driver);
  17. return -1;
  18. }
  19. #ifdef TPD_HAVE_BUTTON      //如果定义虚拟按键,则初始化按键信息
  20. tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local);// initialize tpd button data
  21. #endif
  22. #if (defined(TPD_WARP_START) && defined(TPD_WARP_END))
  23. TPD_DO_WARP = 1;
  24. memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT*4);
  25. memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT*4);
  26. #endif
  27. #if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION))
  28. memcpy(tpd_calmat, tpd_def_calmat_local, 8*4);
  29. memcpy(tpd_def_calmat, tpd_def_calmat_local, 8*4);
  30. #endif
  31. TPD_DMESG("end %s, %d\n", __FUNCTION__, __LINE__);
  32. tpd_type_cap = 1;
  33. return 0;
  34. }

向系统注册i2c驱动后,如果找到对应的设备就会调用tpd_probe函数;

[cpp] view plaincopy
  1. static const struct i2c_device_id ft5x16_tpd_id[] = {{TPD_NAME,0},{}};
  2. static struct i2c_driver tpd_i2c_driver = {
  3. .driver = {
  4. .name   = TPD_NAME,
  5. },
  6. .probe      = tpd_prob,
  7. .remove     = __devexit_p(tpd_remove),
  8. .id_table   = ft5x16_tpd_id,
  9. .detect     = tpd_detect,
  10. };
  11. static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id)
  12. {
  13. int retval = TPD_OK;
  14. char data;
  15. u8 report_rate=0;
  16. int err=0;
  17. int reset_count = 0;
  18. u8 chip_id,i;
  19. reset_proc:
  20. i2c_client = client;
  21. #ifdef MAIERXUN_TP_COM
  22. if(touchpanel_flag){
  23. return 0;
  24. }
  25. #endif
  26. //复位
  27. //power on, need confirm with SA
  28. mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
  29. mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);
  30. mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);
  31. msleep(5);
  32. TPD_DMESG(" fts ic reset\n");
  33. //打开TP电源
  34. #ifdef TPD_POWER_SOURCE_CUSTOM
  35. hwPowerOn(TPD_POWER_SOURCE_CUSTOM, VOL_3300, "TP");
  36. #else
  37. hwPowerOn(MT65XX_POWER_LDO_VGP2, VOL_3300, "TP");
  38. #endif
  39. mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
  40. mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);
  41. mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);
  42. #ifdef TPD_CLOSE_POWER_IN_SLEEP
  43. hwPowerDown(TPD_POWER_SOURCE,"TP");
  44. hwPowerOn(TPD_POWER_SOURCE,VOL_3300,"TP");
  45. msleep(100);
  46. #else  /* 结束复位 */
  47. mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
  48. mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);
  49. mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);
  50. msleep(5);
  51. TPD_DMESG(" fts ic reset\n");
  52. mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
  53. mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);
  54. mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);
  55. #endif
  56. /* 初始化中断引脚 */
  57. mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
  58. mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);
  59. mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE);
  60. mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP);
  61. /* 中断配置和注册 */
  62. mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);
  63. mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE, tpd_eint_interrupt_handler, 1);  //注册中断处理函数,TP产生中断时就会回调tpd_eint_interrupt函数
  64. mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
  65. msleep(400);
  66. err=i2c_smbus_read_i2c_block_data(i2c_client, 0x00, 1, &data);
  67. TPD_DMESG("gao_i2c:err %d,data:%d\n", err,data);
  68. if(err< 0 || data!=0)// reg0 data running state is 0; other state is not 0
  69. {
  70. TPD_DMESG("I2C transfer error, line: %d\n", __LINE__);
  71. #ifdef TPD_RESET_ISSUE_WORKAROUND
  72. if ( reset_count < TPD_MAX_RESET_COUNT )
  73. {
  74. reset_count++;
  75. goto reset_proc;
  76. }
  77. #endif
  78. //add at 20150330 by zhu
  79. #ifdef MAIERXUN_TP_COM
  80. touchpanel_flag=false;
  81. #endif
  82. return -1;
  83. }
  84. ......
  85. #ifdef VELOCITY_CUSTOM_FT5206
  86. if((err = misc_register(&tpd_misc_device)))  //注册混杂设备驱动
  87. {
  88. printk("mtk_tpd: tpd_misc_device register failed\n");
  89. }
  90. #endif
  91. #ifdef TPD_AUTO_UPGRADE
  92. printk("********************Enter CTP Auto Upgrade********************\n");
  93. fts_ctpm_auto_upgrade(i2c_client);
  94. #endif
  95. thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);  //创建子线程,通过该子线程获取和上报数据
  96. if (IS_ERR(thread))
  97. {
  98. retval = PTR_ERR(thread);
  99. TPD_DMESG(TPD_DEVICE " failed to create kernel thread: %d\n", retval);
  100. }
  101. TPD_DMESG("FTS Touch Panel Device Probe %s\n", (retval < TPD_OK) ? "FAIL" : "PASS");
  102. /* 初始化TP的P-sensor功能,暂不分析 */
  103. #ifdef TPD_PROXIMITY
  104. struct hwmsen_object obj_ps;
  105. obj_ps.polling = 0;//interrupt mode
  106. obj_ps.sensor_operate = tpd_ps_operate;
  107. if((err = hwmsen_attach(ID_PROXIMITY, &obj_ps)))
  108. {
  109. APS_ERR("proxi_fts attach fail = %d\n", err);
  110. }
  111. else
  112. {
  113. APS_ERR("proxi_fts attach ok = %d\n", err);
  114. }
  115. #endif
  116. #ifdef MAIERXUN_TP_COM
  117. touchpanel_flag=true;
  118. #endif
  119. return 0;
  120. }

/* 中断处理函数 */

[cpp] view plaincopy
  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. }

中断处理遵循中断上下文的设计原则,使得中断子程序只是简单唤醒等待队列就可以了,没有多余的操作;

/* 子线程处理函数 */

[cpp] view plaincopy
  1. static int touch_event_handler(void *unused)
  2. {
  3. struct touch_info cinfo, pinfo;
  4. int i=0;
  5. struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };
  6. sched_setscheduler(current, SCHED_RR, ¶m);
  7. #ifdef TPD_PROXIMITY
  8. int err;
  9. hwm_sensor_data sensor_data;
  10. u8 proximity_status;
  11. #endif
  12. u8 state;
  13. do  //进入while循环进行睡眠-等待唤醒的操作
  14. {
  15. mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);  //中断使能(解除屏蔽)
  16. set_current_state(TASK_INTERRUPTIBLE);
  17. wait_event_interruptible(waiter,tpd_flag!=0);  //进入睡眠等待唤醒
  18. tpd_flag = 0;
  19. set_current_state(TASK_RUNNING);
  20. ......
  21. #ifdef TPD_PROXIMITY  //TP的P-sensor功能,暂不分析
  22. if (tpd_proximity_flag == 1)
  23. {
  24. i2c_smbus_read_i2c_block_data(i2c_client, 0xB0, 1, &state);
  25. TPD_PROXIMITY_DEBUG("proxi_5206 0xB0 state value is 1131 0x%02X\n", state);
  26. if(!(state&0x01))
  27. {
  28. tpd_enable_ps(1);
  29. }
  30. i2c_smbus_read_i2c_block_data(i2c_client, 0x01, 1, &proximity_status);
  31. TPD_PROXIMITY_DEBUG("proxi_5206 0x01 value is 1139 0x%02X\n", proximity_status);
  32. if (proximity_status == 0xC0)
  33. {
  34. tpd_proximity_detect = 0;
  35. }
  36. else if(proximity_status == 0xE0)
  37. {
  38. tpd_proximity_detect = 1;
  39. }
  40. TPD_PROXIMITY_DEBUG("tpd_proximity_detect 1149 = %d\n", tpd_proximity_detect);
  41. if ((err = tpd_read_ps()))
  42. {
  43. TPD_PROXIMITY_DMESG("proxi_5206 read ps data 1156: %d\n", err);
  44. }
  45. sensor_data.values[0] = tpd_get_ps_value();
  46. sensor_data.value_divide = 1;
  47. sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM;
  48. if ((err = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data)))
  49. {
  50. TPD_PROXIMITY_DMESG(" proxi_5206 call hwmsen_get_interrupt_data failed= %d\n", err);
  51. }
  52. }
  53. #endif
  54. if (tpd_touchinfo(&cinfo, &pinfo))   //获取TP设备数据,并把数据保存在cinfob buf中
  55. {
  56. //TPD_DEBUG("point_num = %d\n",point_num);
  57. TPD_DEBUG_SET_TIME;
  58. if(point_num >0)
  59. {
  60. for(i =0; i<point_num; i++)//only support 3 point
  61. {
  62. printk(KERN_DEBUG"X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]);
  63. cinfo.x[i] = cinfo.x[i];
  64. cinfo.y[i] = cinfo.y[i];
  65. tpd_down(cinfo.x[i], cinfo.y[i], cinfo.id[i]);  //按下数据处理
  66. printk(KERN_DEBUG"----calibration----- X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]);
  67. }
  68. input_sync(tpd->dev);
  69. }
  70. else
  71. {
  72. tpd_up(cinfo.x[0], cinfo.y[0]); //弹起数据处理
  73. //TPD_DEBUG("release --->\n");
  74. //input_mt_sync(tpd->dev);
  75. input_sync(tpd->dev);
  76. }
  77. }
  78. ......
  79. }while(!kthread_should_stop());
  80. return 0;
  81. }

/* 获取TP数据 */

[cpp] view plaincopy
  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. p_point_num = point_num;
  8. if (tpd_halt)
  9. {
  10. TPD_DMESG( "tpd_touchinfo return ..\n");
  11. return false;
  12. }
  13. mutex_lock(&i2c_access);
  14. reg = 0x00;
  15. fts_i2c_Read(i2c_client, &reg, 1, data, 64);  //获取TP数据,一些TP是支持多点触控的,所以有可能就产生多个触点的数据
  16. mutex_unlock(&i2c_access);
  17. /*get the number of the touch points*/
  18. point_num= data[2] & 0x0f;
  19. TPD_DEBUG("point_num =%d\n",point_num);
  20. /* 根据芯片协议解析数据并存放在cinfo buf中 */
  21. for(i = 0; i < point_num; i++)
  22. {
  23. cinfo->p[i] = data[3+6*i] >> 6; //event flag
  24. cinfo->id[i] = data[3+6*i+2]>>4; //touch id
  25. /*get the X coordinate, 2 bytes*/
  26. high_byte = data[3+6*i];
  27. high_byte <<= 8;
  28. high_byte &= 0x0f00;
  29. low_byte = data[3+6*i + 1];
  30. cinfo->x[i] = high_byte |low_byte;
  31. /*get the Y coordinate, 2 bytes*/
  32. high_byte = data[3+6*i+2];
  33. high_byte <<= 8;
  34. high_byte &= 0x0f00;
  35. low_byte = data[3+6*i+3];
  36. cinfo->y[i] = high_byte |low_byte;
  37. }
  38. }
  39. TPD_DEBUG(" cinfo->x[0] = %d, cinfo->y[0] = %d, cinfo->p[0] = %d\n", cinfo->x[0], cinfo->y[0], cinfo->p[0]);
  40. return true;
  41. }
[cpp] view plaincopy
  1. static  void tpd_down(int x, int y, int p) {
  2. static int tpd_x = 0;
  3. static int tpd_y = 0;
  4. tpd_x = x;
  5. tpd_y = y;
  6. /* 通过输入子系统上报数据 */
  7. input_report_key(tpd->dev, BTN_TOUCH, 1);
  8. input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 20);
  9. input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
  10. input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
  11. printk(KERN_ERR, "D[%4d %4d %4d] ", x, y, p);
  12. /* track id Start 0 */
  13. input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, p);
  14. input_mt_sync(tpd->dev);
  15. #ifndef MT6572
  16. if (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode())
  17. #endif
  18. {
  19. tpd_button(x, y, 1); //虚拟按键的处理
  20. }
  21. TPD_EM_PRINT(x, y, x, y, p-1, 1);
  22. }
  23. static  void tpd_up(int x, int y) {
  24. input_report_key(tpd->dev, BTN_TOUCH, 0);
  25. input_mt_sync(tpd->dev);
  26. TPD_EM_PRINT(x, y, x, y, 0, 0);
  27. #ifndef MT6572
  28. if (FACTORY_BOOT == get_boot_mode()|| RECOVERY_BOOT == get_boot_mode())
  29. #endif
  30. {
  31. tpd_button(x, y, 0);
  32. }
  33. }

/* 虚拟按键判断和处理函数 */

[cpp] view plaincopy
  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驱动框架也是大致差不多;

MTK 驱动(51)---TP 驱动移植相关推荐

  1. input子系统与tp驱动

    1.层级结构 jiang-pc:~/build_projects2/build/60_ali/kernel-3.18/drivers/input$ ls apm-power.c ff-core.c g ...

  2. MTK 驱动(63)---MTK TP驱动移植

    MTK TP驱动移植 对于MTK TP驱动移植一般分为六部分: 1.硬件IO口配置: 2.TP驱动移植: 3.I2C通信: 4.中断触发: 5.数据上报: 6.虚拟按键: 硬件电路: 1.GPIO配置 ...

  3. MTK 驱动开发(29)---TP 驱动移植

    对于MTK TP驱动移植一般分为六部分: 1.硬件IO口配置: 2.TP驱动移植: 3.I2C通信: 4.中断触发: 5.数据上报: 6.虚拟按键: 硬件电路: 1.GPIO配置 打开 mediate ...

  4. MTK TP驱动移植

    对于MTK TP驱动移植一般分为六部分: 1.硬件IO口配置: 2.TP驱动移植: 3.I2C通信: 4.中断触发: 5.数据上报: 6.虚拟按键: 硬件电路: 1.GPIO配置 打开 mediate ...

  5. MTK平台TP驱动框架解析

    一,TP驱动代码的组成 MTK平台TP驱动主要包括两处文件: 1,kernel-3.18\drivers\input\touchscreen\mediatek\mtk_tpd.c 平台设备驱动,主要为 ...

  6. MTK 驱动(64)---Mtk touch panel驱动/TP驱动详解

    Mtk touch panel驱动/TP驱动详解 TP还算是比LCM好理解的多. 在启动过程中,先注册/mediatek/custom/command/kernel/touchpanel目录下的具体驱 ...

  7. MTK 驱动开发(27)---TP 驱动分析

    MTK TP 驱动分析    

  8. 基于MTK 的 TP 驱动分析

    1. 克隆服务器工程源码并切换分支 git clone git@192.168.20.2: mt658292_kk v9 git checkout -b submit_v9_dongxf_tp_mod ...

  9. MTK平台的LCM驱动移植

    一.Android系统开机启动过程及驱动概述: MTK平台的显示驱动分两块,一块在LK代码里面,一块在kernel代码里面: LK的lcm驱动路径在:vendor\mediatek\proprieta ...

最新文章

  1. 《JavaScript高效图形编程(修订版)》——6.2 位图、矢量图,或两者兼而有之?...
  2. 万里挑一!北大AI女神每天必看的几个优质公众号
  3. 注解配置声明式事务控制解析
  4. 真正拉开人与人之间的差距是什么?
  5. tutte定理证明hall定理_人教社课本现低级错误?“爱因斯坦用相对论证明勾股定理”...
  6. 解决 asp.net 伪静态 IIS设置后 真正的HTML无法显示的问题
  7. Redis--五种基础数据结构及应用场景
  8. 牛客网–华为机试在线训练4:字符串分隔
  9. CSS color设置与调色板
  10. bitmap位图详解
  11. 离线 维基百科 android,iPhone上的离线维基百科(附安装方法)
  12. 【python实战】二:乒乓球比赛对手问题
  13. 消息队列在linux下实现进程间的通信;消息盒子在单片机中的代码实现
  14. maven进行install时出现Fatal error compiling错误
  15. 今天安利几个App给你
  16. element el-transfer穿梭框的使用,自定义穿梭框的数据项
  17. 计算机键盘清洗怎么弄,笔记本电脑键盘怎么清洗干净(专业户教你清洗键盘简易方法)...
  18. 借助谷歌翻译API实现网站多国语言翻译功能
  19. css的height,min-height,max-height,min-width.....
  20. [转帖]Linux - NetworkManager网络管理工具

热门文章

  1. Particle Filter Tutorial 粒子滤波:从推导到应用(一)
  2. 【LeetCode】剑指 Offer 58 - II. 左旋转字符串
  3. 微信小程序|开发实战篇之八-list列表组件及其子组件
  4. 正则的简单学习与应用
  5. java设计模式6.代理模式
  6. 注册页面的JSON响应方式详细分析(与前端页面交互方式之一)
  7. 并发编程之——多进程
  8. JAVA 【引用类型】和【对象类型】在【继承】中的异同
  9. Android安全问题 抢先开机启动
  10. 容易被忽略的label标签