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 | |
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>
-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 9029bd3f34e..6fb6bd8495e 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 |