Chinaunix首页 | 论坛 | 博客
  • 博客访问: 201547
  • 博文数量: 71
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-11 22:28
个人简介

一个懒惰的文艺工程师!

文章分类

全部博文(71)

文章存档

2015年(1)

2014年(7)

2013年(63)

我的朋友

分类: LINUX

2013-11-08 21:48:03

内核linux2.6.35 andorid2.3 触摸屏型号ft5xo6
首先给出该触摸屏的一些结构体---->drivers/input/touchscreen/ft5x06_ts.h

点击(此处)折叠或打开

  1. #ifndef __LINUX_FT5X0X_TS_H__
  2. #define __LINUX_FT5X0X_TS_H__

  3. #define SCREEN_MIN_X 0
  4. #define SCREEN_MAX_X 320
  5. #define SCREEN_MIN_Y 0
  6. #define SCREEN_MAX_Y 240
  7. #define PRESS_MAX 255

  8. #define MIN_X_CTP 0
  9. #define MAX_X_CTP 896
  10. #define MIN_Y_CTP 0
  11. #define MAX_Y_CTP 640


  12. #define EVENT_PENDOWN 0
  13. #define EVENT_REPEAT 2
  14. #define EVENT_PENUP 1

  15. #define I2C_CTPM_ADDRESS 0x38


  16. #define FT5X0X_NAME    "ft5x06-ts"//"synaptics_i2c_rmi"//"synaptics-rmi-ts"//

  17. struct ft5x0x_ts_platform_data{
  18.     u16    intr;        /* irq number    */
  19. };



  20. #ifndef ABS_MT_TOUCH_MAJOR
  21. #define ABS_MT_TOUCH_MAJOR    0x30    /* touching ellipse */
  22. #define ABS_MT_TOUCH_MINOR    0x31    /* (omit if circular) */
  23. #define ABS_MT_WIDTH_MAJOR    0x32    /* approaching ellipse */
  24. #define ABS_MT_WIDTH_MINOR    0x33    /* (omit if circular) */
  25. #define ABS_MT_ORIENTATION    0x34    /* Ellipse orientation */
  26. #define ABS_MT_POSITION_X    0x35    /* Center X ellipse position */
  27. #define ABS_MT_POSITION_Y    0x36    /* Center Y ellipse position */
  28. #define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */
  29. #define ABS_MT_BLOB_ID        0x38    /* Group set of pkts as blob */
  30. #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
  31. #endif /* ABS_MT_TOUCH_MAJOR */


  32. #endif
还有一些在ft5x06_ts.c中

点击(此处)折叠或打开

  1. struct ts_event {
  2.     u16    x1;
  3.     u16    y1;
  4.     u16    x2;
  5.     u16    y2;
  6.     u16    x3;
  7.     u16    y3;
  8.     u16    x4;
  9.     u16    y4;
  10.     u16    x5;
  11.     u16    y5;
  12.     u16    pressure;
  13.     u8 touch_point;
  14. };

  15. struct ft5x0x_ts_data {
  16.     struct input_dev    *input_dev;
  17.     struct ts_event        event;
  18.     struct work_struct     pen_event_work;
  19.     struct workqueue_struct *ts_workqueue;
  20.     struct early_suspend    early_suspend;
  21. };
触摸屏属于I2C子设备,按照I2C子系统来写驱动,首先添加I2C信息。---->arch/arm/mach-s5pv210/smdkc110.c

点击(此处)折叠或打开

  1. static struct i2c_board_info i2c_devs1[] __initdata = {
  2. #ifdef CONFIG_VIDEO_TV20
  3.     {
  4.        I2C_BOARD_INFO("ft5x06-ts", (0x38)),//初始化i2c_board_info的type和addr成员(#define I2C_BOARD_INFO(dev_type, dev_addr) \.type = dev_type, .addr = (dev_addr))
  5.        .irq = IRQ_EINT(2),//中断号
  6.     },
  7. #endif
  8. };
在arch/arm/mach-s5pv210/mach-smdkc110.c中的machine_init()函数中会调用i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));函数注册i2c子设备
之后,系统会创建一个i2c_devinfo结构体,然后将其挂如控制器设备链表中。代码如下:

点击(此处)折叠或打开

  1. int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
  2. {
  3.     int status;

  4.     down_write(&__i2c_board_lock);

  5.     /* dynamic bus numbers will be assigned after the last static one */
  6.     if (busnum >= __i2c_first_dynamic_bus_num)
  7.         __i2c_first_dynamic_bus_num = busnum + 1;

  8.     for (status = 0; len; len--, info++) {//i2c_dev(x)数组有几个成员,就创建几个i2c_devinfo结构体
  9.         struct i2c_devinfo    *devinfo;

  10.         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
  11.         if (!devinfo) {
  12.             pr_debug("i2c-core: can't register boardinfo!\n");
  13.             status = -ENOMEM;
  14.             break;
  15.         }

  16.         devinfo->busnum = busnum;//挂接在那个i2c控制器上
  17.         devinfo->board_info = *info;//type 和addr
  18.         list_add_tail(&devinfo->list, &__i2c_board_list);//将devinfo添加到控制器的设备链表
  19.     }

  20.     up_write(&__i2c_board_lock);

  21.     return status
当i2c控制器驱动加载时回去扫描这条链表,调用流程为匹配i2c控制器设备,调用probe函数,在probe函数中调用i2c_add_numbered_adapter或i2c_add_adapter。在添加adapter时调用i2c_register_adapter()-->
i2c_scan_static_board_info()--->i2c_new_device创建client,注册client设备(device_register)。
触摸屏设备驱动
drivers/input/touchscreen/ft5x06_ts.c 
首先:

点击(此处)折叠或打开

  1. static int __init ft5x0x_ts_init(void)
  2. {
  3.     return i2c_add_driver(&ft5x0x_ts_driver);//设备驱动结构体
  4. }

  5. static void __exit ft5x0x_ts_exit(void)
  6. {
  7.     i2c_del_driver(&ft5x0x_ts_driver);
  8. }
ft5x0x_ts_driver如下:

点击(此处)折叠或打开

  1. static const struct i2c_device_id ft5x0x_ts_id[] = {
  2.     { FT5X0X_NAME, 0 },{ }
  3. };

  4. MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);

  5. static struct i2c_driver ft5x0x_ts_driver = {
  6.     .driver    = {
  7.         .name    = FT5X0X_NAME,    
  8.     },
  9.     .probe        = ft5x0x_ts_probe,
  10.     .remove        = ft5x0x_ts_remove,    
  11.     .id_table    = ft5x0x_ts_id,//id_table如上
  12.     

  13. };
i2c_add_driver()分析

点击(此处)折叠或打开

  1. static inline int i2c_add_driver(struct i2c_driver *driver)
  2. {
  3.     return i2c_register_driver(THIS_MODULE, driver);
  4. }
i2c_register_driver()分析:

点击(此处)折叠或打开

  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
  2. {
  3.     int res;

  4.     /* Can't register until after driver model init */
  5.     if (unlikely(WARN_ON(!i2c_bus_type.p)))//调试用
  6.         return -EAGAIN;

  7.     /* add the driver to the list of i2c drivers in the driver core */
  8.     driver->driver.owner = owner;
  9.     driver->driver.bus = &i2c_bus_type;

  10.     /* When registration returns, the driver core
  11.      * will have called probe() for all matching-but-unbound devices.
  12.      */
  13.     res = driver_register(&driver->driver);//注册,匹配成功会调用触摸屏的probe函数
  14.     if (res)
  15.         return res;

  16.     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

  17.     INIT_LIST_HEAD(&driver->clients);
  18.     /* Walk the adapters that are already present */
  19.     mutex_lock(&core_lock);
  20.     bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
  21.     mutex_unlock(&core_lock);

  22.     return 0;
  23. }
probe函数分析

点击(此处)折叠或打开

  1. static int ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3.     struct ft5x0x_ts_data *ft5x0x_ts;//在ft5x06_ts.h中定义
  4.     struct input_dev *input_dev;
  5.     int err = 0;
  6.     unsigned char uc_reg_value;
  7.     
  8.     printk("==ft5x0x_ts_probe=\n");
  9.     
  10.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {//验证i2c控制器的能力,实现了那些函数,这里验证是否实现了I2C_FUNC_I2C函数
  11.         err = -ENODEV;
  12.         goto exit_check_functionality_failed;
  13.     }

  14.     printk("==kzalloc=\n");
  15.     ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);//分配空间
  16.     if (!ft5x0x_ts)    {
  17.         err = -ENOMEM;
  18.         goto exit_alloc_data_failed;
  19.     }


  20.     this_client = client;
  21.     i2c_set_clientdata(client, ft5x0x_ts);//设置屏相关的数据client->dev->p->driver_data = data;


  22.     INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);//初始化工作队列

  23.     ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));//创建工作线程
  24.     if (!ft5x0x_ts->ts_workqueue) {
  25.         err = -ESRCH;
  26.         goto exit_create_singlethread;
  27.     }

  28.     err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x06_ts", ft5x0x_ts);//申请中断
  29.     if (err < 0) {
  30.         dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
  31.         goto exit_irq_request_failed;
  32.     }

  33.     disable_irq(this_client->irq);//关闭中断

  34.     input_dev = input_allocate_device();//分配input_dev结构体
  35.     if (!input_dev) {
  36.         err = -ENOMEM;
  37.         dev_err(&client->dev, "failed to allocate input device\n");
  38.         goto exit_input_dev_alloc_failed;
  39.     }
  40.     
  41.     ft5x0x_ts->input_dev = input_dev;

  42. #ifdef CONFIG_FT5X0X_MULTITOUCH//多点触摸
  43.       set_bit(EV_ABS, input_dev->evbit);//那类事件
  44.     set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);//设置adsbit代表那些事件
  45.     set_bit(ABS_MT_POSITION_X, input_dev->absbit);
  46.     set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
  47.     set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);

  48.     input_set_abs_params(input_dev,
  49.              ABS_MT_POSITION_X, 0, SCREEN_MAX_X-1, 0, 0);
  50.     input_set_abs_params(input_dev,
  51.              ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y-1, 0, 0);
  52.     input_set_abs_params(input_dev,
  53.              ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
  54.     input_set_abs_params(input_dev,
  55.              ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
  56. #else
  57.     set_bit(ABS_X, input_dev->absbit);
  58.     set_bit(ABS_Y, input_dev->absbit);
  59.     set_bit(ABS_PRESSURE, input_dev->absbit);
  60.     set_bit(BTN_TOUCH, input_dev->keybit);

  61.     input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
  62.     input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
  63.     input_set_abs_params(input_dev,
  64.              ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);
  65. #endif

  66.     set_bit(EV_SYN, input_dev->evbit);
  67.        set_bit(BTN_TOUCH, input_dev->keybit);
  68.     set_bit(EV_KEY, input_dev->evbit);

  69.     input_dev->name        = FT5X0X_NAME;        //dev_name(&client->dev)//以上是设置input_dev
  70.     err = input_register_device(input_dev);//注册input_dev
  71.     if (err) {
  72.         dev_err(&client->dev,
  73.         "ft5x0x_ts_probe: failed to register input device: %s\n",
  74.         dev_name(&client->dev));
  75.         goto exit_input_register_device_failed;
  76.     }

  77.     ft5x06_hw_init();//硬件相关初始化

  78.     msleep(50);

  79.     uc_reg_value = ft5x0x_read_fw_ver();//读取硬件版本
  80.     printk("[FST] Firmware version = 0x%x\n", uc_reg_value);

  81.     enable_irq(this_client->irq);//使能中断

  82.     printk("==probe over =\n");
  83.     return 0;

  84. exit_input_register_device_failed://以下是错误处理
  85.     input_free_device(input_dev);
  86. exit_input_dev_alloc_failed:
  87. free_irq(client->irq, ft5x0x_ts);
  88. exit_irq_request_failed:
  89.     cancel_work_sync(&ft5x0x_ts->pen_event_work);
  90.     destroy_workqueue(ft5x0x_ts->ts_workqueue);
  91. exit_create_singlethread:
  92.     printk("==singlethread error =\n");
  93.     i2c_set_clientdata(client, NULL);
  94.     kfree(ft5x0x_ts);
  95. exit_alloc_data_failed:
  96. exit_check_functionality_failed:
  97.     return err;
  98. }
ft5x06_hw_init();分析

点击(此处)折叠或打开

  1. static void ft5x06_hw_init(void)
  2. {
  3.     if ((gpio_request(S5PV210_GPG3(2), "ft5406 wake-up"))< 0)
  4.     {
  5.         printk("gpio_request failed for GPIOWake[%d]\n\n",S5PV210_GPG3(2));
  6.     }    
  7.     else if ((gpio_direction_output(S5PV210_GPG3(2),1)) < 0)//将触摸屏从睡眠模式唤醒
  8.     {
  9.         printk("gpio_direction_output failed for GPIOWake[%d]\n\n",S5PV210_GPG3(2));
  10.         gpio_free(S5PV210_GPG3(2));
  11.     }
  12.     
  13.     msleep(5);
  14.     gpio_free(S5PV210_GPG3(2));
  15. }
i2c读写函数

点击(此处)折叠或打开

  1. static int ft5x0x_i2c_rxdata(char *rxdata, int length)
  2. {
  3.     int ret;

  4.     struct i2c_msg msgs[] = {
  5.         {
  6.             .addr    = this_client->addr,
  7.             .flags    = 0,//写
  8.             .len    = 1,//数据长度,单位字节
  9.             .buf    = rxdata,是//护具
  10.         },
  11.         {
  12.             .addr    = this_client->addr,
  13.             .flags    = I2C_M_RD,//读
  14.             .len    = length,//读的字节数
  15.             .buf    = rxdata,//存放数据的位置
  16.         },
  17.     };

  18.     ret = i2c_transfer(this_client->adapter, msgs, 2);
  19.     if (ret < 0)
  20.         pr_err("msg %s i2c read error: %d\n", __func__, ret);
  21.     
  22.     return ret;
  23. }

  24. static int ft5x0x_i2c_txdata(char *txdata, int length)
  25. {
  26.     int ret;

  27.     struct i2c_msg msg[] = {
  28.         {
  29.             .addr    = this_client->addr,
  30.             .flags    = 0,//写
  31.             .len    = length,//写的字节数
  32.             .buf    = txdata,//要写的数据
  33.         },
  34.     };

  35.     ret = i2c_transfer(this_client->adapter, msg, 1);
  36.     if (ret < 0)
  37.         pr_err("%s i2c write error: %d\n", __func__, ret);

  38.     return ret;
  39. }
工作队列函数实现

点击(此处)折叠或打开

  1. static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
  2. {
  3.     int ret = -1;

  4.     ret = ft5x0x_read_data();    
  5.     if (ret == 0) {    
  6.         ft5x0x_report_value();
  7.     }

  8.   enable_irq(this_client->irq);
  9. }
读取事件数据函数实现ft5x0x_read_data

点击(此处)折叠或打开

  1. static int ft5x0x_read_data(void)
  2. {
  3.     struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
  4.     struct ts_event *event = &data->event;

  5.     u8 buf[26] = {0};
  6.        unsigned long x_tmp[5]={0},y_tmp[5]={0};
  7.     
  8.     int ret = -1;    

  9.        buf[0]=0xf9;
  10.      ret = ft5x0x_i2c_rxdata(buf, 26);

  11.     if (ret < 0) {
  12.         printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
  13.         return ret;    
  14.                            }
  15.     memset(event, 0, sizeof(struct ts_event));

  16.     event->touch_point = buf[3] & 0x07;// 000 0111

  17.     if (event->touch_point == 0) {
  18.         ft5x0x_ts_release();
  19.         return 1;
  20.     }


  21.     switch (event->touch_point) {
  22.         case 5:

  23.                        x_tmp[4] = (((buf[21] & 0x0f) << 8 | buf[22]))*SCREEN_MAX_X;
  24.                        do_div(x_tmp[4],MAX_X_CTP);
  25.                        event->x5= (s16)x_tmp[4];

  26.                        y_tmp[4] = (((buf[23] & 0x0f) << 8 | buf[24]))*SCREEN_MAX_Y;
  27.                        do_div(y_tmp[4],MAX_Y_CTP);
  28.                        event->y5 =(s16)y_tmp[4];    
  29.                 

  30.         case 4:
  31.              x_tmp[3] = (((buf[17] & 0x0f) << 8 | buf[18]))*SCREEN_MAX_X;
  32.                        do_div(x_tmp[3],MAX_X_CTP);
  33.                        event->x4 = (s16)x_tmp[3];

  34.                        y_tmp[3] = (((buf[19] & 0x0f) << 8 | buf[20]))*SCREEN_MAX_Y;
  35.                        do_div(y_tmp[3],MAX_Y_CTP);
  36.                        event->y4 =(s16)y_tmp[3];    

  37.         case 3:
  38.                        x_tmp[2] = (((buf[13] & 0x0f) << 8 | buf[14]))*SCREEN_MAX_X;
  39.                        do_div(x_tmp[2],MAX_X_CTP);
  40.                        event->x3 = (s16)x_tmp[2];

  41.                        y_tmp[2] = (((buf[15] & 0x0f) << 8 | buf[16]))*SCREEN_MAX_Y;
  42.                        do_div(y_tmp[2],MAX_Y_CTP);
  43.                        event->y3 =(s16)y_tmp[2];    

  44.         case 2:
  45.                        x_tmp[1] = (((buf[9] & 0x0f) << 8 | buf[10]))*SCREEN_MAX_X;
  46.                        do_div(x_tmp[1],MAX_X_CTP);
  47.                        event->x2 = (s16)x_tmp[1];

  48.                        y_tmp[1] = (((buf[11] & 0x0f) << 8 | buf[12]))*SCREEN_MAX_Y;
  49.                        do_div(y_tmp[1],MAX_Y_CTP);
  50.                        event->y2 =(s16)y_tmp[1];    
  51.             
  52.         case 1:
  53.              x_tmp[0] = (((buf[5] & 0x0f) << 8 | buf[6]))*SCREEN_MAX_X;
  54.                        do_div(x_tmp[0],MAX_X_CTP);
  55.                        event->x1 = (s16)x_tmp[0];

  56.                        y_tmp[0] = (((buf[7] & 0x0f) << 8 | buf[8]))*SCREEN_MAX_Y;
  57.                        do_div(y_tmp[0],MAX_Y_CTP);
  58.                        event->y1 =(s16)y_tmp[0];    
  59.             break;
  60.         default:
  61.          return -1;
  62.     }
  63.     event->pressure = 200;

  64.     dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
  65.         event->x1, event->y1, event->x2, event->y2);

  66.     return 0;
  67. }
上报数据

点击(此处)折叠或打开

  1. static void ft5x0x_report_value(void)
  2. {
  3.     struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
  4.     struct ts_event *event = &data->event;    

  5.     switch(event->touch_point) {
  6.         case 5:
  7.             input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
  8.             input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x5);
  9.             input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5);
  10.             input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
  11.              input_report_key(data->input_dev, BTN_TOUCH, 1);
  12.             input_mt_sync(data->input_dev);
  13.             printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
  14.         case 4:
  15.             input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
  16.             input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x4);
  17.             input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4);
  18.             input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
  19.              input_report_key(data->input_dev, BTN_TOUCH, 1);
  20.             input_mt_sync(data->input_dev);
  21.             printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
  22.         case 3:
  23.             input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
  24.             input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x3);
  25.             input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3);
  26.             input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
  27.              input_report_key(data->input_dev, BTN_TOUCH, 1);
  28.             input_mt_sync(data->input_dev);
  29.             printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
  30.         case 2:
  31.             input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
  32.             input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2);
  33.             input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
  34.             input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
  35.              input_report_key(data->input_dev, BTN_TOUCH, 1);
  36.             input_mt_sync(data->input_dev);
  37.             printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
  38.         case 1:
  39.             input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
  40.             input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
  41.             input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
  42.             input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
  43.              input_report_key(data->input_dev, BTN_TOUCH, 1);
  44.             input_mt_sync(data->input_dev);
  45.             printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);

  46.             break;

  47.         default:
  48.             printk("==touch_point default =\n");
  49.             break;
  50.     }
  51.     input_sync(data->input_dev);

  52.     dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
  53.         event->x1, event->y1, event->x2, event->y2);
  54. }    /*end ft5x0x_report_value*/

中断函数实现

点击(此处)折叠或打开

  1. static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
  2. {
  3.     struct ft5x0x_ts_data *ft5x0x_ts = dev_id;

  4.     disable_irq_nosync(this_client->irq);    
  5.     
  6.     if (!work_pending(&ft5x0x_ts->pen_event_work)) {
  7.         queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
  8.     }
  9.     
  10.     return IRQ_HANDLED;
  11. }
要完全贯通的理解整个原理,还需要input子系统,i2c子系统,工作队列机制,中断机制和上层应用的结合。









阅读(1907) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~