上一篇主要讲述了linux中触摸屏设备作为平台设备存在的模块加载和卸载函数,还有就是对应的probe函数和remove函数,这一篇说下在probe函数中注册的两个中断处理函数。
1、先来说第一个中断处理函数——触摸屏中断,对应的中断处理函数是stylus_updown,当触摸屏被按下时,会产生中断信号IRQ_PENDUP。函数源码如下:
static irqreturn_t stylus_updown(int irqno, void *param)
{
unsigned long data0;
unsigned long data1;
int updown;定义一个整型变量,用来表示触摸屏是否被按下,如果按下,这个值是1;如果没按下,这个值是0。
data0 = readl(ts_base+S3C_ADCDAT0);
data1 = readl(ts_base+S3C_ADCDAT1);读取寄存器ADCDAT0和寄存器ADCDAT1
updown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));
重点来分析,有如下定义:
#define S3C_ADCDAT0_UPDOWN(1<<15)
#define S3C_ADCDAT1_UPDOWN(1<<15)
从这里可知与这两个寄存器的第15位有关,而寄存器ADCDAT0和寄存器ADCDAT1分别表示X和Y方向检测到触摸屏是否被按下,也就是说只有当寄存器ADCDAT0和寄存器ADCDAT1两个寄存器的UPDOWN都等于0时,采表示触摸屏被按下。看下面这个图:
#ifdef CONFIG_TOUCHSCREEN_S3C_DEBUG
printk(KERN_INFO " %c\n",updown ? 'D' : 'U');
#endif
/* TODO we should never get an interrupt with updown set while
* the timer is running, but maybe we ought to verify that the
* timer isn't running anyways. */
if (updown) updown 等于1,表示触摸屏按下
{
downflag=1;
//printk("touch_timer_fire(0)\n");
touch_timer_fire(0);调用此函数处理触摸屏的按下,这个函数下面再讲。
}
if(ts->s3c_adc_con==ADC_TYPE_2) {
__raw_writel(0x0, ts_base+S3C_ADCCLRWK);
__raw_writel(0x0, ts_base+S3C_ADCCLRINT);
}
其中有如下定义:
#define S3C_ADCCLRINTS3C_ADCREG(0x18)
#define S3C_ADCCLRWKS3C_ADCREG(0x20)
直接看图:
好了现在可以分析我们上面没有分析的那一个函数了touch_timer_fire,源码如下:
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = readl(ts_base+S3C_ADCDAT0);
data1 = readl(ts_base+S3C_ADCDAT1);
updown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));
上面这些和刚才分析的一样,都是为了判断触摸屏是否被按下
if (updown) { 为1,触摸屏被按下
//printk("updown=1.\n");
if (ts->count) {
#ifdef CONFIG_TOUCHSCREEN_S3C_DEBUG
........
#endif
if(downflag==0)
{
input_report_abs(ts->dev, ABS_X, ts->xp);
input_report_abs(ts->dev, ABS_Y, ts->yp);
input_report_key(ts->dev, BTN_TOUCH, 1);
input_report_abs(ts->dev, ABS_PRESSURE, 1);
input_sync(ts->dev);
} 上面这一段用来向输入子系统报告当前触摸笔的位置
else
{
// printk("downflag=1.ignore this data.\n");
downflag=0;
}
}
ts->xp = 0;
ts->yp = 0;
ts->count = 0;
表示缓冲区中没有数据,也就是没有触摸屏按下时间发生
writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);主要是将AD转化模式设置在自动转化模式。
其中有如下定义:
#define S3C_ADCTSC_PULL_UP_DISABLE(1<<3)
#define AUTOPST (S3C_ADCTSC_YM_SEN | S3C_ADCTSC_YP_SEN | S3C_ADCTSC_XP_SEN | \
S3C_ADCTSC_AUTO_PST | S3C_ADCTSC_XY_PST(0))
writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);启动AD转化功能
}
else { 表示触摸屏没有被按下时的操作。
ts->count = 0;
input_report_key(ts->dev, BTN_TOUCH, 0);调用这个函数向输入子系统报告触摸屏被弹起事件,表示按键被释放。
input_report_abs(ts->dev, ABS_PRESSURE, 0); 发送触摸屏的一个绝对坐标
input_sync(ts->dev); 该函数通知事件发送者发送一个完整的报告。
writel(WAIT4INT(0), ts_base+S3C_ADCTSC); 把触摸屏的模式设为等待中断模式
}
}