当我们按下触摸屏时:
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);
/*报告X、Y的绝对坐标值*/
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;
}