diff options
author | Stefan Agner <stefan.agner@toradex.com> | 2014-01-21 14:12:33 +0100 |
---|---|---|
committer | Stefan Agner <stefan.agner@toradex.com> | 2014-01-23 09:50:31 +0100 |
commit | 79b001606a26055f4a4a7131c2e09b13ce8bcf99 (patch) | |
tree | 6c706a0d717081683fd592f05198d59c0360eec3 | |
parent | 1d71afdc4e15256a448758fbd3c4f36e0012d0e0 (diff) |
input: touchscreen: fix race condition in Fusion driver
When the next interrupt request apeares between the confirmation of
the previous (a write via I2C, fusion_F0710A_write_complete) and
the reenable of the GPIO interrupt, the driver hangs and no more
touch inputs are reported.
This patch moves the confirmation after the reenabling of the GPIO
interrupt.
-rw-r--r-- | drivers/input/touchscreen/fusion_F0710A.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/input/touchscreen/fusion_F0710A.c b/drivers/input/touchscreen/fusion_F0710A.c index 08beda06c2e6..44942b3dbcb4 100644 --- a/drivers/input/touchscreen/fusion_F0710A.c +++ b/drivers/input/touchscreen/fusion_F0710A.c @@ -126,8 +126,6 @@ static int fusion_F0710A_read_sensor(void) if (ret < 0) { dev_err(&fusion_F0710A.client->dev, "Read block failed: %d\n", ret); - /* Clear fusion_F0710A interrupt */ - fusion_F0710A_write_complete(); return ret; } @@ -150,10 +148,9 @@ static int fusion_F0710A_read_sensor(void) fusion_F0710A.z2 = DATA(fusion_F0710A_SEC_PRESS); fusion_F0710A.tip2 = DATA(fusion_F0710A_SEC_TIDTS)&0x0f; fusion_F0710A.tid2 =(DATA(fusion_F0710A_SEC_TIDTS)&0xf0)>>4; - #undef DATA - /* Clear fusion_F0710A interrupt */ - return fusion_F0710A_write_complete(); + + return 0; } #define val_cut_max(x, max, reverse) \ @@ -173,11 +170,13 @@ static void fusion_F0710A_wq(struct work_struct *work) int x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0; if (fusion_F0710A_read_sensor() < 0) - return; + goto restore_irq; +#ifdef DEBUG printk(KERN_DEBUG "tip1, tid1, x1, y1, z1 (%x,%x,%d,%d,%d); tip2, tid2, x2, y2, z2 (%x,%x,%d,%d,%d)\n", fusion_F0710A.tip1, fusion_F0710A.tid1, fusion_F0710A.x1, fusion_F0710A.y1, fusion_F0710A.z1, fusion_F0710A.tip2, fusion_F0710A.tid2, fusion_F0710A.x2, fusion_F0710A.y2, fusion_F0710A.z2); +#endif /* DEBUG */ val_cut_max(fusion_F0710A.x1, fusion_F0710A.info.xres-1, fusion_F0710A.info.xy_reverse); val_cut_max(fusion_F0710A.y1, fusion_F0710A.info.yres-1, fusion_F0710A.info.xy_reverse); @@ -242,8 +241,11 @@ static void fusion_F0710A_wq(struct work_struct *work) input_sync(dev); +restore_irq: enable_irq(fusion_F0710A.client->irq); + /* Clear fusion_F0710A interrupt */ + fusion_F0710A_write_complete(); } static DECLARE_WORK(fusion_F0710A_work, fusion_F0710A_wq); |