diff options
| author | Daniel Mack <daniel@caiaq.de> | 2010-04-19 03:42:16 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-04-20 03:44:20 -0400 |
| commit | 7fbef0d1e278a0a8c803a4d2b1e2bd5740bffa52 (patch) | |
| tree | 7f5119a737e3d6d345de75d4075c10ff7579cf61 /drivers/input/touchscreen | |
| parent | 5f57d67da87332a9a1ba8fa7a33bf0680e1c76e7 (diff) | |
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>
Diffstat (limited to 'drivers/input/touchscreen')
| -rw-r--r-- | drivers/input/touchscreen/eeti_ts.c | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 9029bd3f34e5..6fb6bd8495e7 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c | |||
| @@ -123,14 +123,25 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id) | |||
| 123 | return IRQ_HANDLED; | 123 | return IRQ_HANDLED; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | static int eeti_ts_open(struct input_dev *dev) | 126 | static void eeti_ts_start(struct eeti_ts_priv *priv) |
| 127 | { | 127 | { |
| 128 | struct eeti_ts_priv *priv = input_get_drvdata(dev); | ||
| 129 | |||
| 130 | enable_irq(priv->irq); | 128 | enable_irq(priv->irq); |
| 131 | 129 | ||
| 132 | /* Read the events once to arm the IRQ */ | 130 | /* Read the events once to arm the IRQ */ |
| 133 | eeti_ts_read(&priv->work); | 131 | eeti_ts_read(&priv->work); |
| 132 | } | ||
| 133 | |||
| 134 | static void eeti_ts_stop(struct eeti_ts_priv *priv) | ||
| 135 | { | ||
| 136 | disable_irq(priv->irq); | ||
| 137 | cancel_work_sync(&priv->work); | ||
| 138 | } | ||
| 139 | |||
| 140 | static int eeti_ts_open(struct input_dev *dev) | ||
| 141 | { | ||
| 142 | struct eeti_ts_priv *priv = input_get_drvdata(dev); | ||
| 143 | |||
| 144 | eeti_ts_start(priv); | ||
| 134 | 145 | ||
| 135 | return 0; | 146 | return 0; |
| 136 | } | 147 | } |
| @@ -139,8 +150,7 @@ static void eeti_ts_close(struct input_dev *dev) | |||
| 139 | { | 150 | { |
| 140 | struct eeti_ts_priv *priv = input_get_drvdata(dev); | 151 | struct eeti_ts_priv *priv = input_get_drvdata(dev); |
| 141 | 152 | ||
| 142 | disable_irq(priv->irq); | 153 | eeti_ts_stop(priv); |
| 143 | cancel_work_sync(&priv->work); | ||
| 144 | } | 154 | } |
| 145 | 155 | ||
| 146 | static int __devinit eeti_ts_probe(struct i2c_client *client, | 156 | static int __devinit eeti_ts_probe(struct i2c_client *client, |
| @@ -152,10 +162,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, | |||
| 152 | unsigned int irq_flags; | 162 | unsigned int irq_flags; |
| 153 | int err = -ENOMEM; | 163 | int err = -ENOMEM; |
| 154 | 164 | ||
| 155 | /* In contrast to what's described in the datasheet, there seems | 165 | /* |
| 166 | * In contrast to what's described in the datasheet, there seems | ||
| 156 | * to be no way of probing the presence of that device using I2C | 167 | * to be no way of probing the presence of that device using I2C |
| 157 | * commands. So we need to blindly believe it is there, and wait | 168 | * commands. So we need to blindly believe it is there, and wait |
| 158 | * for interrupts to occur. */ | 169 | * for interrupts to occur. |
| 170 | */ | ||
| 159 | 171 | ||
| 160 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 172 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
| 161 | if (!priv) { | 173 | if (!priv) { |
| @@ -211,9 +223,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, | |||
| 211 | goto err2; | 223 | goto err2; |
| 212 | } | 224 | } |
| 213 | 225 | ||
| 214 | /* Disable the irq for now. It will be enabled once the input device | 226 | /* |
| 215 | * is opened. */ | 227 | * Disable the device for now. It will be enabled once the |
| 216 | disable_irq(priv->irq); | 228 | * input device is opened. |
| 229 | */ | ||
| 230 | eeti_ts_stop(priv); | ||
| 217 | 231 | ||
| 218 | device_init_wakeup(&client->dev, 0); | 232 | device_init_wakeup(&client->dev, 0); |
| 219 | return 0; | 233 | return 0; |
| @@ -234,6 +248,12 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) | |||
| 234 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); | 248 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); |
| 235 | 249 | ||
| 236 | free_irq(priv->irq, priv); | 250 | free_irq(priv->irq, priv); |
| 251 | /* | ||
| 252 | * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it | ||
| 253 | * so that device still works if we reload the driver. | ||
| 254 | */ | ||
| 255 | enable_irq(priv->irq); | ||
| 256 | |||
| 237 | input_unregister_device(priv->input); | 257 | input_unregister_device(priv->input); |
| 238 | i2c_set_clientdata(client, NULL); | 258 | i2c_set_clientdata(client, NULL); |
| 239 | kfree(priv); | 259 | kfree(priv); |
| @@ -245,6 +265,14 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) | |||
| 245 | static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) | 265 | static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) |
| 246 | { | 266 | { |
| 247 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); | 267 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); |
| 268 | struct input_dev *input_dev = priv->input; | ||
| 269 | |||
| 270 | mutex_lock(&input_dev->mutex); | ||
| 271 | |||
| 272 | if (input_dev->users) | ||
| 273 | eeti_ts_stop(priv); | ||
| 274 | |||
| 275 | mutex_unlock(&input_dev->mutex); | ||
| 248 | 276 | ||
| 249 | if (device_may_wakeup(&client->dev)) | 277 | if (device_may_wakeup(&client->dev)) |
| 250 | enable_irq_wake(priv->irq); | 278 | enable_irq_wake(priv->irq); |
| @@ -255,10 +283,18 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) | |||
| 255 | static int eeti_ts_resume(struct i2c_client *client) | 283 | static int eeti_ts_resume(struct i2c_client *client) |
| 256 | { | 284 | { |
| 257 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); | 285 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); |
| 286 | struct input_dev *input_dev = priv->input; | ||
| 258 | 287 | ||
| 259 | if (device_may_wakeup(&client->dev)) | 288 | if (device_may_wakeup(&client->dev)) |
| 260 | disable_irq_wake(priv->irq); | 289 | disable_irq_wake(priv->irq); |
| 261 | 290 | ||
| 291 | mutex_lock(&input_dev->mutex); | ||
| 292 | |||
| 293 | if (input_dev->users) | ||
| 294 | eeti_ts_start(priv); | ||
| 295 | |||
| 296 | mutex_unlock(&input_dev->mutex); | ||
| 297 | |||
| 262 | return 0; | 298 | return 0; |
| 263 | } | 299 | } |
| 264 | #else | 300 | #else |
