[PATCH 07/33] MFD: ucb1x00-ts: fix resume failure
Russell King - ARM Linux
linux at arm.linux.org.uk
Wed Jan 25 09:32:27 EST 2012
If the ucb1x00 touchscreen is resumed while the touchscreen is being
touched, the main thread stops responding. This occurs because two
things happen:
1. When we suspended, we were woken up, and executed the loop.
Finding that the touchscreen was not pressed, we prepare to
schedule for a maximum timeout, before being stopped in
try_to_freeze().
2. an irq occurs, we disable the irq, and mark it as disabled,
and wake the thread. This wake occurs while the thread is
still within __refrigerator()
3. The thread is unfrozen, and __refrigerator() sets the threads
state back to INTERRUPTIBLE.
We then drop into schedule_timeout() with an infinite timeout and the
IRQ disabled. This prevents any further screen touches activating
the thread.
Fix this by using kthread_freezable_should_stop() which handles the
freezing issues for us outside of the hotspot where the task state
matters. Include a flag to ignore the touchscreen until it is
released to avoid sending unintended data to the application.
Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>
---
drivers/mfd/ucb1x00-ts.c | 32 +++++---------------------------
1 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 38ffbd5..63a3cbd 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -47,7 +47,6 @@ struct ucb1x00_ts {
u16 x_res;
u16 y_res;
- unsigned int restart:1;
unsigned int adcsync:1;
};
@@ -207,15 +206,17 @@ static int ucb1x00_thread(void *_ts)
{
struct ucb1x00_ts *ts = _ts;
DECLARE_WAITQUEUE(wait, current);
+ bool frozen, ignore = false;
int valid = 0;
set_freezable();
add_wait_queue(&ts->irq_wait, &wait);
- while (!kthread_should_stop()) {
+ while (!kthread_freezable_should_stop(&frozen)) {
unsigned int x, y, p;
signed long timeout;
- ts->restart = 0;
+ if (frozen)
+ ignore = true;
ucb1x00_adc_enable(ts->ucb);
@@ -258,7 +259,7 @@ static int ucb1x00_thread(void *_ts)
* space. We therefore leave it to user space
* to do any filtering they please.
*/
- if (!ts->restart) {
+ if (!ignore) {
ucb1x00_ts_evt_add(ts, p, x, y);
valid = 1;
}
@@ -267,8 +268,6 @@ static int ucb1x00_thread(void *_ts)
timeout = HZ / 100;
}
- try_to_freeze();
-
schedule_timeout(timeout);
}
@@ -340,26 +339,6 @@ static void ucb1x00_ts_close(struct input_dev *idev)
ucb1x00_disable(ts->ucb);
}
-#ifdef CONFIG_PM
-static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
-{
- struct ucb1x00_ts *ts = dev->priv;
-
- if (ts->rtask != NULL) {
- /*
- * Restart the TS thread to ensure the
- * TS interrupt mode is set up again
- * after sleep.
- */
- ts->restart = 1;
- wake_up(&ts->irq_wait);
- }
- return 0;
-}
-#else
-#define ucb1x00_ts_resume NULL
-#endif
-
/*
* Initialisation.
@@ -425,7 +404,6 @@ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
static struct ucb1x00_driver ucb1x00_ts_driver = {
.add = ucb1x00_ts_add,
.remove = ucb1x00_ts_remove,
- .resume = ucb1x00_ts_resume,
};
static int __init ucb1x00_ts_init(void)
--
1.7.4.4
More information about the linux-arm-kernel
mailing list