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:
Родитель
5f57d67da8
Коммит
7fbef0d1e2
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче