您的位置:首页 > 运维架构 > Linux

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

2015-06-02 15:34 423 查看
参看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解决
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: