summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2014-01-21 14:12:33 +0100
committerStefan Agner <stefan.agner@toradex.com>2014-01-23 09:50:31 +0100
commit79b001606a26055f4a4a7131c2e09b13ce8bcf99 (patch)
tree6c706a0d717081683fd592f05198d59c0360eec3
parent1d71afdc4e15256a448758fbd3c4f36e0012d0e0 (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.c14
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);