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-29 15:41:41 +0100 |
commit | e95019a4f20b8cdfbe03658e4f73b69cdcf97540 (patch) | |
tree | 624466592440ca50630ce56747cf546652e69fb7 | |
parent | dda7a631ac901e4d140e8a6612c5c6b5506b6a91 (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 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); |