触摸屏中断产生以及AD转换,上报事件的过程

时间:2021-11-15 22:34:00

当我们按下触摸屏时:

1,首先进入触摸屏中断,RQ_TC

2,如果触摸屏是被按下的状态,则调用touch_timer_fire启动ADC中断adc_irq

3,如果1个时间滴答到来则进入定时器服务程序touch_timer_fire

4,判断触摸屏是否仍然处于按下状态

5,如果是,则上报事件和转换的数据,并重启ADC转换,重复第(2)

6,如果不是(松开),则上报事件和转换的数据,本次转换完成

 

函数追踪:

 

/*触摸屏中断服务程序*/

static irqreturn_t stylus_irq(int irq, void *dev_id)

{

       //printk("stylus_irq\n");

       /*用于记录这一次AD转换后的值*/

       unsigned long data0;

       unsigned long data1;

       bool down;

              /*本次读取时为了判断,还有获取坐标 */

       data0 = readl(ts.io + S3C2410_ADCDAT0);

       data1 = readl(ts.io + S3C2410_ADCDAT1);

       /*在等待中断的时候,获取触摸屏按下的状态*/

       down = get_down(data0, data1);

 

       /* TODO we should never get an interrupt with down set while

        * the timer is running, but maybe we ought to verify that the

        * timer isn't running anyways. */

        

       /*如果触摸屏被按下,则启动ADC*/

       if (down)

              s3c_adc_start(ts.client, 0, 1 << ts.shift);

       else/*如果是抬起状态,就结束了这一次的操作,所以就释放ADC资源的占有*/

              dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);

 

       if (ts.features & FEAT_PEN_IRQ) {

              /* Clear pen down/up interrupt  清中断*/

              writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);

       }

 

       return IRQ_HANDLED;

}

 

 

 

/*定时器中断服务程序*/

 /*如果是按下状态,则调用touch_timer_fire函数来启动ADC转换*/

static void touch_timer_fire(unsigned long data)

{    

       //printk("touch_timer_fire\n");

/*用于记录这一次AD转换后的值*/

       unsigned long data0;

       unsigned long data1;

       bool down;

       /*本次读取时只为了判断是否还是按下状态 */

       data0 = readl(ts.io + S3C2410_ADCDAT0);

       data1 = readl(ts.io + S3C2410_ADCDAT1);

 

       down = get_down(data0, data1);

 

       if (down) {

              if (ts.count == (1 << ts.shift)) {

                     ts.xp >>= ts.shift;

                     ts.yp >>= ts.shift;

                    

                     dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",

                            __func__, ts.xp, ts.yp, ts.count);

                       /*报告XY的绝对坐标值*/

                     input_report_abs(ts.input, ABS_X, ts.xp);

                     input_report_abs(ts.input, ABS_Y, ts.yp);

                     /*报告按键事件,键值为1(代表触摸屏对应的按键被按下)*/

                     input_report_key(ts.input, BTN_TOUCH, 1);

                       /*报告触摸屏的状态,1表明触摸屏被按下*/

                     input_report_abs(ts.input,ABS_PRESSURE,1);

                      /*等待接收方受到数据后回复确认,用于同步*/

                     input_sync(ts.input);

                                         ts.xp = 0;

                     ts.yp = 0;

                     ts.count = 0;

              }

/*如果状态还是按下,并且ADC还没有开始转换就启动ADC进行转换*/

              s3c_adc_start(ts.client, 0, 1 << ts.shift);

       } else {

              ts.xp = 0;

              ts.yp = 0;

              ts.count = 0;

               /*报告按键事件,键值为0(代表触摸屏对应的按键被释放)*/

              input_report_key(ts.input, BTN_TOUCH, 0);

              /*报告触摸屏的状态,0表明触摸屏没被按下*/

              input_report_abs(ts.input,ABS_PRESSURE,0);

              /*等待接收方收到数据后回复确认,用于同步*/

              input_sync(ts.input);

              /*将触摸屏重新设置为等待中断状态*/

              writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);

       }

}

 

 

int s3c_adc_start(struct s3c_adc_client *client,

                unsigned int channel, unsigned int nr_samples)

{

       //printk("adc_start..............\n");

       struct adc_device *adc = adc_dev;

       unsigned long flags;

 

      

       if (!adc) {

              printk(KERN_ERR "%s: failed to find adc\n", __func__);

              return -EINVAL;

       }

 

       if (client->is_ts && adc->ts_pend)

              return -EAGAIN;

       /*获取自旋锁,关中断,并保存状态字*/

       spin_lock_irqsave(&adc->lock, flags);

 

       client->channel = channel;

       client->nr_samples = nr_samples;

 

       if (client->is_ts)

              adc->ts_pend = client;

       else

              list_add_tail(&client->pend, &adc_pending); //插入链表末尾,    链表表头之前

 

       if (!adc->cur)

              s3c_adc_try(adc);   

      

       spin_unlock_irqrestore(&adc->lock, flags);

 

       return 0;

}

 

/*开始转换*/

static void s3c_adc_try(struct adc_device *adc)

{

       //printk("adc_try\n");

       struct s3c_adc_client *next = adc->ts_pend;

       /* 不为空*/

       if (!next && !list_empty(&adc_pending)) {

              next = list_first_entry(&adc_pending,

                                   struct s3c_adc_client, pend);

              list_del(&next->pend);

       } else

              adc->ts_pend = NULL; //若为空

 

       if (next) {

              adc_dbg(adc, "new client is %p\n", next);  //调试信息

              adc->cur = next;

              s3c_adc_select(adc, next);

              s3c_adc_convert(adc);

              s3c_adc_dbgshow(adc);

       }

}

 

/*设置并启动转换*/

static inline void s3c_adc_convert(struct adc_device *adc)

{

       /*读取出ADCCON      数据然后使能转换位ADCCON [0] */

      

       //printk("adc_convert..............\n");

       unsigned con = readl(adc->regs + S3C2410_ADCCON);

       con |= S3C2410_ADCCON_ENABLE_START;

       writel(con, adc->regs + S3C2410_ADCCON); //启动adc转换,进入adc服务程序

}

 

 

/*ADC中断服务程序*/

static irqreturn_t s3c_adc_irq(int irq, void *pw)

{

       //printk("adc_irqreturn_t..............\n");

       struct adc_device *adc = pw;

       struct s3c_adc_client *client = adc->cur;

       enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;

       unsigned data0, data1;

      

       if (!client) {

              dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);

              goto exit;

       }

 

       data0 = readl(adc->regs + S3C2410_ADCDAT0);

       data1 = readl(adc->regs + S3C2410_ADCDAT1);

       adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);

      

       /*进一次转换中断程序nr_samples 减一,总共转换四次*/

       client->nr_samples--;

 

       if (cpu == TYPE_S3C64XX) {

              /* S3C64XX ADC resolution is 12-bit */

              data0 &= 0xfff;

              data1 &= 0xfff;

       } else {

              data0 &= 0x3ff;

              data1 &= 0x3ff;

       }

       //printk("x_data:%d\n",data0);

       //printk("y_data:%d\n",data1);

 

       if (client->convert_cb)

              (client->convert_cb)(client, data0, data1, &client->nr_samples);

 

       if (client->nr_samples > 0) {           /*如果没有四次,则继续下一次转换*/

              /* fire another conversion for this */

 

              client->select_cb(client, 1);

              s3c_adc_convert(adc);

       } else {    

              /*获取自旋锁*/

              spin_lock(&adc->lock);

              (client->select_cb)(client, 0); /*否则启动定时器*/

 

              adc->cur = NULL;

 

              s3c_adc_try(adc);

              spin_unlock(&adc->lock);

       }

exit:

       if (cpu == TYPE_S3C64XX) {

              /* Clear ADC interrupt */

              writel(0, adc->regs + S3C64XX_ADCCLRINT);

       }

       return IRQ_HANDLED;

}