mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
MFD: ucb1x00-ts: fix resume failure
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@arm.linux.org.uk>
This commit is contained in:
parent
c23bb602af
commit
0af5e4c36e
@ -47,7 +47,6 @@ struct ucb1x00_ts {
|
|||||||
u16 x_res;
|
u16 x_res;
|
||||||
u16 y_res;
|
u16 y_res;
|
||||||
|
|
||||||
unsigned int restart:1;
|
|
||||||
unsigned int adcsync:1;
|
unsigned int adcsync:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -207,15 +206,17 @@ static int ucb1x00_thread(void *_ts)
|
|||||||
{
|
{
|
||||||
struct ucb1x00_ts *ts = _ts;
|
struct ucb1x00_ts *ts = _ts;
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
|
bool frozen, ignore = false;
|
||||||
int valid = 0;
|
int valid = 0;
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
add_wait_queue(&ts->irq_wait, &wait);
|
add_wait_queue(&ts->irq_wait, &wait);
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_freezable_should_stop(&frozen)) {
|
||||||
unsigned int x, y, p;
|
unsigned int x, y, p;
|
||||||
signed long timeout;
|
signed long timeout;
|
||||||
|
|
||||||
ts->restart = 0;
|
if (frozen)
|
||||||
|
ignore = true;
|
||||||
|
|
||||||
ucb1x00_adc_enable(ts->ucb);
|
ucb1x00_adc_enable(ts->ucb);
|
||||||
|
|
||||||
@ -258,7 +259,7 @@ static int ucb1x00_thread(void *_ts)
|
|||||||
* space. We therefore leave it to user space
|
* space. We therefore leave it to user space
|
||||||
* to do any filtering they please.
|
* to do any filtering they please.
|
||||||
*/
|
*/
|
||||||
if (!ts->restart) {
|
if (!ignore) {
|
||||||
ucb1x00_ts_evt_add(ts, p, x, y);
|
ucb1x00_ts_evt_add(ts, p, x, y);
|
||||||
valid = 1;
|
valid = 1;
|
||||||
}
|
}
|
||||||
@ -267,8 +268,6 @@ static int ucb1x00_thread(void *_ts)
|
|||||||
timeout = HZ / 100;
|
timeout = HZ / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_to_freeze();
|
|
||||||
|
|
||||||
schedule_timeout(timeout);
|
schedule_timeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,26 +339,6 @@ static void ucb1x00_ts_close(struct input_dev *idev)
|
|||||||
ucb1x00_disable(ts->ucb);
|
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.
|
* Initialisation.
|
||||||
@ -425,7 +404,6 @@ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
|
|||||||
static struct ucb1x00_driver ucb1x00_ts_driver = {
|
static struct ucb1x00_driver ucb1x00_ts_driver = {
|
||||||
.add = ucb1x00_ts_add,
|
.add = ucb1x00_ts_add,
|
||||||
.remove = ucb1x00_ts_remove,
|
.remove = ucb1x00_ts_remove,
|
||||||
.resume = ucb1x00_ts_resume,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ucb1x00_ts_init(void)
|
static int __init ucb1x00_ts_init(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user