Input: eeti_ts - cancel pending work when going to suspend

This fixes a race between the suspend code and input events.

Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
Daniel Mack 2010-04-19 00:42:16 -07:00 committed by Dmitry Torokhov
parent 5f57d67da8
commit 7fbef0d1e2

View File

@ -123,14 +123,25 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int eeti_ts_open(struct input_dev *dev)
static void eeti_ts_start(struct eeti_ts_priv *priv)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
enable_irq(priv->irq);
/* Read the events once to arm the IRQ */
eeti_ts_read(&priv->work);
}
static void eeti_ts_stop(struct eeti_ts_priv *priv)
{
disable_irq(priv->irq);
cancel_work_sync(&priv->work);
}
static int eeti_ts_open(struct input_dev *dev)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
eeti_ts_start(priv);
return 0;
}
@ -139,8 +150,7 @@ static void eeti_ts_close(struct input_dev *dev)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
disable_irq(priv->irq);
cancel_work_sync(&priv->work);
eeti_ts_stop(priv);
}
static int __devinit eeti_ts_probe(struct i2c_client *client,
@ -152,10 +162,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
unsigned int irq_flags;
int err = -ENOMEM;
/* In contrast to what's described in the datasheet, there seems
/*
* In contrast to what's described in the datasheet, there seems
* to be no way of probing the presence of that device using I2C
* commands. So we need to blindly believe it is there, and wait
* for interrupts to occur. */
* for interrupts to occur.
*/
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
@ -211,9 +223,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
goto err2;
}
/* Disable the irq for now. It will be enabled once the input device
* is opened. */
disable_irq(priv->irq);
/*
* Disable the device for now. It will be enabled once the
* input device is opened.
*/
eeti_ts_stop(priv);
device_init_wakeup(&client->dev, 0);
return 0;
@ -234,6 +248,12 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
/*
* eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
* so that device still works if we reload the driver.
*/
enable_irq(priv->irq);
input_unregister_device(priv->input);
i2c_set_clientdata(client, NULL);
kfree(priv);
@ -245,6 +265,14 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
mutex_lock(&input_dev->mutex);
if (input_dev->users)
eeti_ts_stop(priv);
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
@ -255,10 +283,18 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
static int eeti_ts_resume(struct i2c_client *client)
{
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
eeti_ts_start(priv);
mutex_unlock(&input_dev->mutex);
return 0;
}
#else