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; 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); enable_irq(priv->irq);
/* Read the events once to arm the IRQ */ /* Read the events once to arm the IRQ */
eeti_ts_read(&priv->work); 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; return 0;
} }
@ -139,8 +150,7 @@ static void eeti_ts_close(struct input_dev *dev)
{ {
struct eeti_ts_priv *priv = input_get_drvdata(dev); struct eeti_ts_priv *priv = input_get_drvdata(dev);
disable_irq(priv->irq); eeti_ts_stop(priv);
cancel_work_sync(&priv->work);
} }
static int __devinit eeti_ts_probe(struct i2c_client *client, 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; unsigned int irq_flags;
int err = -ENOMEM; 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 * 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 * 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); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) { if (!priv) {
@ -211,9 +223,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
goto err2; goto err2;
} }
/* Disable the irq for now. It will be enabled once the input device /*
* is opened. */ * Disable the device for now. It will be enabled once the
disable_irq(priv->irq); * input device is opened.
*/
eeti_ts_stop(priv);
device_init_wakeup(&client->dev, 0); device_init_wakeup(&client->dev, 0);
return 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); struct eeti_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv); 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); input_unregister_device(priv->input);
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(priv); 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) static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{ {
struct eeti_ts_priv *priv = i2c_get_clientdata(client); 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)) if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq); 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) static int eeti_ts_resume(struct i2c_client *client)
{ {
struct eeti_ts_priv *priv = i2c_get_clientdata(client); struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
if (device_may_wakeup(&client->dev)) if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq); 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; return 0;
} }
#else #else