aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-04-19 03:42:16 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-04-20 03:44:20 -0400
commit7fbef0d1e278a0a8c803a4d2b1e2bd5740bffa52 (patch)
tree7f5119a737e3d6d345de75d4075c10ff7579cf61
parent5f57d67da87332a9a1ba8fa7a33bf0680e1c76e7 (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.c56
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
126static int eeti_ts_open(struct input_dev *dev) 126static 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
134static void eeti_ts_stop(struct eeti_ts_priv *priv)
135{
136 disable_irq(priv->irq);
137 cancel_work_sync(&priv->work);
138}
139
140static 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
146static int __devinit eeti_ts_probe(struct i2c_client *client, 156static 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)
245static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) 265static 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)
255static int eeti_ts_resume(struct i2c_client *client) 283static 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