某厂家linux3.6 s3c2416 触摸屏有时无法触摸的bug

参看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解决

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值