summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2014-01-21 14:12:33 +0100
committerMax Krummenacher <max.krummenacher@toradex.com>2014-07-08 14:38:34 +0200
commita2366c712a759ff9a23f8832af6c74ea0fb7afa9 (patch)
tree8775b426e99df649dea64be4bc936650fbbb304c /drivers
parentf2a963d1de2cdc6da15d13305e2b8dec8039b633 (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. (cherry picked from commit e95019a4f20b8cdfbe03658e4f73b69cdcf97540)
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);