summaryrefslogtreecommitdiff
path: root/drivers
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-29 15:41:41 +0100
commite95019a4f20b8cdfbe03658e4f73b69cdcf97540 (patch)
tree624466592440ca50630ce56747cf546652e69fb7 /drivers
parentdda7a631ac901e4d140e8a6612c5c6b5506b6a91 (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.
Diffstat (limited to 'drivers')
-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 371e4c0981d1..2cd2096c3b98 100644
--- a/drivers/input/touchscreen/fusion_F0710A.c
+++ b/drivers/input/touchscreen/fusion_F0710A.c
@@ -130,8 +130,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;
}
@@ -154,10 +152,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) \
@@ -177,11 +174,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);
@@ -264,8 +263,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);