某厂家linux3.6 s3c2416 触摸屏有时无法触摸的bug
2015-06-02 15:34
471 查看
参看s3c2410_ts.c
static void touch_timer_fire(unsigned long data)
{
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);
input_report_abs(ts.input, ABS_X, ts.xp);
input_report_abs(ts.input, ABS_Y, ts.yp);
input_report_key(ts.input, BTN_TOUCH, 1);
input_sync(ts.input);
ts.xp = 0;
ts.yp = 0;
ts.count = 0;
}
s3c_adc_start(ts.client, 0, 1 << ts.shift);
} else {
ts.xp = 0;
ts.yp = 0;
ts.count = 0;
input_report_key(ts.input, BTN_TOUCH, 0);
input_sync(ts.input);
writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
//up事件后,修改tsc寄存器
}
}
static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
{
if (select) {
writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
ts.io + S3C2410_ADCTSC);
} else {
mod_timer(&touch_timer, jiffies+1); //延迟调用
writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
}
}
通过以上可知,在AD转换指定采样点数后,在延迟一定时间后就会调用 touch_timer_fire,如果触摸屏没压下,就会修改tsc寄存器为等待触摸压下中断。
再查看触摸压下中断函数
static irqreturn_t stylus_irq(int irq, void *dev_id)
{
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. */
if (down)
s3c_adc_start(ts.client, 0, 1 << ts.shift); //触摸压下启动AD中断
else
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;
}
显然在触摸屏压下后,如果检测确认是触摸屏压下后,就会启动AD转换
查看adc.c文件
int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples)
{
struct adc_device *adc = adc_dev;
unsigned long flags;
if (!adc) {
printk(KERN_ERR "%s: failed to find adc\n", __func__);
return -EINVAL;
}
spin_lock_irqsave(&adc->lock, flags);
if (client->is_ts && adc->ts_pend) { //如果有触摸屏事件未处理,返回重试
spin_unlock_irqrestore(&adc->lock, flags);
return -EAGAIN;
}
client->channel = channel;
client->nr_samples = nr_samples;
//优先处理触摸屏事件
if (client->is_ts)
adc->ts_pend = client;
else
list_add_tail(&client->pend, &adc_pending);
//当前没有转换,尝试启动AD转换
if (!adc->cur)
s3c_adc_try(adc);
spin_unlock_irqrestore(&adc->lock, flags);
return 0;
}
目前认为该函数是有一定bug的,如果当前有转换任务,它会把触摸屏转换任务加入到ts_pend,返回结果依然是0,只有到下次继续加入触摸屏转换任务才会返回EAGAIN,
这就导致在一些情况下了,有新的触摸屏任务已经加入到队列,但是 touch_timer_fire已经调用,同时设置了tsc为触摸屏down中断,非auto xy pst自动xy转换,导致adc->cur一直有任务未处理,也就导致ts_pend挂起的任务得不到处理,最终导致ad任务无法启动了
该说解决方案了,既然是由于触摸屏任务队列导致的,去除掉不就OK了
int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples)
{
struct adc_device *adc = adc_dev;
unsigned long flags;
if (!adc) {
printk(KERN_ERR "%s: failed to find adc\n", __func__);
return -EINVAL;
}
spin_lock_irqsave(&adc->lock, flags);
if (client->is_ts && adc->cur) { //改成adc->cur
spin_unlock_irqrestore(&adc->lock, flags);
return -EAGAIN;
}
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;
}
OK解决
static void touch_timer_fire(unsigned long data)
{
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);
input_report_abs(ts.input, ABS_X, ts.xp);
input_report_abs(ts.input, ABS_Y, ts.yp);
input_report_key(ts.input, BTN_TOUCH, 1);
input_sync(ts.input);
ts.xp = 0;
ts.yp = 0;
ts.count = 0;
}
s3c_adc_start(ts.client, 0, 1 << ts.shift);
} else {
ts.xp = 0;
ts.yp = 0;
ts.count = 0;
input_report_key(ts.input, BTN_TOUCH, 0);
input_sync(ts.input);
writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
//up事件后,修改tsc寄存器
}
}
static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
{
if (select) {
writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
ts.io + S3C2410_ADCTSC);
} else {
mod_timer(&touch_timer, jiffies+1); //延迟调用
writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
}
}
通过以上可知,在AD转换指定采样点数后,在延迟一定时间后就会调用 touch_timer_fire,如果触摸屏没压下,就会修改tsc寄存器为等待触摸压下中断。
再查看触摸压下中断函数
static irqreturn_t stylus_irq(int irq, void *dev_id)
{
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. */
if (down)
s3c_adc_start(ts.client, 0, 1 << ts.shift); //触摸压下启动AD中断
else
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;
}
显然在触摸屏压下后,如果检测确认是触摸屏压下后,就会启动AD转换
查看adc.c文件
int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples)
{
struct adc_device *adc = adc_dev;
unsigned long flags;
if (!adc) {
printk(KERN_ERR "%s: failed to find adc\n", __func__);
return -EINVAL;
}
spin_lock_irqsave(&adc->lock, flags);
if (client->is_ts && adc->ts_pend) { //如果有触摸屏事件未处理,返回重试
spin_unlock_irqrestore(&adc->lock, flags);
return -EAGAIN;
}
client->channel = channel;
client->nr_samples = nr_samples;
//优先处理触摸屏事件
if (client->is_ts)
adc->ts_pend = client;
else
list_add_tail(&client->pend, &adc_pending);
//当前没有转换,尝试启动AD转换
if (!adc->cur)
s3c_adc_try(adc);
spin_unlock_irqrestore(&adc->lock, flags);
return 0;
}
目前认为该函数是有一定bug的,如果当前有转换任务,它会把触摸屏转换任务加入到ts_pend,返回结果依然是0,只有到下次继续加入触摸屏转换任务才会返回EAGAIN,
这就导致在一些情况下了,有新的触摸屏任务已经加入到队列,但是 touch_timer_fire已经调用,同时设置了tsc为触摸屏down中断,非auto xy pst自动xy转换,导致adc->cur一直有任务未处理,也就导致ts_pend挂起的任务得不到处理,最终导致ad任务无法启动了
该说解决方案了,既然是由于触摸屏任务队列导致的,去除掉不就OK了
int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples)
{
struct adc_device *adc = adc_dev;
unsigned long flags;
if (!adc) {
printk(KERN_ERR "%s: failed to find adc\n", __func__);
return -EINVAL;
}
spin_lock_irqsave(&adc->lock, flags);
if (client->is_ts && adc->cur) { //改成adc->cur
spin_unlock_irqrestore(&adc->lock, flags);
return -EAGAIN;
}
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;
}
OK解决
相关文章推荐
- linux free 命令中的 buffer & free
- linux重启防火墙
- Linux Shell脚本系列教程(七):脚本调试
- Linux命令-EOF
- Linux内存管理(最透彻的一篇)
- Linux Shell脚本系列教程(六):数组和关联数组
- Linux Shell脚本系列教程(五):数学运算
- Linux Shell脚本系列教程(四):使用函数添加环境变量
- linux下安装boost
- 一个北漂来到北京一年多的亲身感受
- Linux Shell脚本系列教程(三):变量和环境变量
- Centos mosquitto1.4.2 编译安装
- Linux下的I2S驱动学习
- linux下ln命令学习
- Linux Shell脚本系列教程(二):终端打印命令详解
- Linux LVM逻辑卷配置过程详解
- Linux Shell脚本系列教程(一):Shell入门
- 虚拟机中Linux与本机Windows之间的通讯调试
- linux挂载ipsan服务器
- SElinux下通过setroubleshoot工具排错