Commit bf3204cbff7d2606e758afb0994e8da6ae1c6c26

Authored by Dmitry Torokhov
1 parent 558a5e296a

Input: fix locking in memoryless force-feedback devices

Now that input core acquires dev->event_lock spinlock and disables
interrupts when propagating input events, using spin_lock_bh() in
ff-memless driver is not allowed. Actually, the timer_lock itself
is not needed anymore, we should simply use dev->event_lock
as well.

Also do a small cleanup in force-feedback core.

Reported-by: kerneloops.org
Reported-by: http://www.kerneloops.org/searchweek.php?search=ml_ff_set_gain
Reported-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

Showing 3 changed files with 26 additions and 24 deletions Side-by-side Diff

drivers/input/ff-core.c
... ... @@ -337,16 +337,16 @@
337 337 dev->ff = ff;
338 338 dev->flush = flush_effects;
339 339 dev->event = input_ff_event;
340   - set_bit(EV_FF, dev->evbit);
  340 + __set_bit(EV_FF, dev->evbit);
341 341  
342 342 /* Copy "true" bits into ff device bitmap */
343 343 for (i = 0; i <= FF_MAX; i++)
344 344 if (test_bit(i, dev->ffbit))
345   - set_bit(i, ff->ffbit);
  345 + __set_bit(i, ff->ffbit);
346 346  
347 347 /* we can emulate RUMBLE with periodic effects */
348 348 if (test_bit(FF_PERIODIC, ff->ffbit))
349   - set_bit(FF_RUMBLE, dev->ffbit);
  349 + __set_bit(FF_RUMBLE, dev->ffbit);
350 350  
351 351 return 0;
352 352 }
... ... @@ -362,12 +362,14 @@
362 362 */
363 363 void input_ff_destroy(struct input_dev *dev)
364 364 {
365   - clear_bit(EV_FF, dev->evbit);
366   - if (dev->ff) {
367   - if (dev->ff->destroy)
368   - dev->ff->destroy(dev->ff);
369   - kfree(dev->ff->private);
370   - kfree(dev->ff);
  365 + struct ff_device *ff = dev->ff;
  366 +
  367 + __clear_bit(EV_FF, dev->evbit);
  368 + if (ff) {
  369 + if (ff->destroy)
  370 + ff->destroy(ff);
  371 + kfree(ff->private);
  372 + kfree(ff);
371 373 dev->ff = NULL;
372 374 }
373 375 }
drivers/input/ff-memless.c
... ... @@ -61,7 +61,6 @@
61 61 struct ml_effect_state states[FF_MEMLESS_EFFECTS];
62 62 int gain;
63 63 struct timer_list timer;
64   - spinlock_t timer_lock;
65 64 struct input_dev *dev;
66 65  
67 66 int (*play_effect)(struct input_dev *dev, void *data,
68 67  
69 68  
70 69  
71 70  
72 71  
73 72  
74 73  
75 74  
... ... @@ -368,39 +367,39 @@
368 367 {
369 368 struct input_dev *dev = (struct input_dev *)timer_data;
370 369 struct ml_device *ml = dev->ff->private;
  370 + unsigned long flags;
371 371  
372 372 debug("timer: updating effects");
373 373  
374   - spin_lock(&ml->timer_lock);
  374 + spin_lock_irqsave(&dev->event_lock, flags);
375 375 ml_play_effects(ml);
376   - spin_unlock(&ml->timer_lock);
  376 + spin_unlock_irqrestore(&dev->event_lock, flags);
377 377 }
378 378  
  379 +/*
  380 + * Sets requested gain for FF effects. Called with dev->event_lock held.
  381 + */
379 382 static void ml_ff_set_gain(struct input_dev *dev, u16 gain)
380 383 {
381 384 struct ml_device *ml = dev->ff->private;
382 385 int i;
383 386  
384   - spin_lock_bh(&ml->timer_lock);
385   -
386 387 ml->gain = gain;
387 388  
388 389 for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
389 390 __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags);
390 391  
391 392 ml_play_effects(ml);
392   -
393   - spin_unlock_bh(&ml->timer_lock);
394 393 }
395 394  
  395 +/*
  396 + * Start/stop specified FF effect. Called with dev->event_lock held.
  397 + */
396 398 static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
397 399 {
398 400 struct ml_device *ml = dev->ff->private;
399 401 struct ml_effect_state *state = &ml->states[effect_id];
400   - unsigned long flags;
401 402  
402   - spin_lock_irqsave(&ml->timer_lock, flags);
403   -
404 403 if (value > 0) {
405 404 debug("initiated play");
406 405  
... ... @@ -425,8 +424,6 @@
425 424 ml_play_effects(ml);
426 425 }
427 426  
428   - spin_unlock_irqrestore(&ml->timer_lock, flags);
429   -
430 427 return 0;
431 428 }
432 429  
... ... @@ -436,7 +433,7 @@
436 433 struct ml_device *ml = dev->ff->private;
437 434 struct ml_effect_state *state = &ml->states[effect->id];
438 435  
439   - spin_lock_bh(&ml->timer_lock);
  436 + spin_lock_irq(&dev->event_lock);
440 437  
441 438 if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
442 439 __clear_bit(FF_EFFECT_PLAYING, &state->flags);
... ... @@ -448,7 +445,7 @@
448 445 ml_schedule_timer(ml);
449 446 }
450 447  
451   - spin_unlock_bh(&ml->timer_lock);
  448 + spin_unlock_irq(&dev->event_lock);
452 449  
453 450 return 0;
454 451 }
... ... @@ -482,7 +479,6 @@
482 479 ml->private = data;
483 480 ml->play_effect = play_effect;
484 481 ml->gain = 0xffff;
485   - spin_lock_init(&ml->timer_lock);
486 482 setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
487 483  
488 484 set_bit(FF_GAIN, dev->ffbit);
include/linux/input.h
... ... @@ -1377,6 +1377,10 @@
1377 1377 * methods; erase() is optional. set_gain() and set_autocenter() need
1378 1378 * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
1379 1379 * bits.
  1380 + *
  1381 + * Note that playback(), set_gain() and set_autocenter() are called with
  1382 + * dev->event_lock spinlock held and interrupts off and thus may not
  1383 + * sleep.
1380 1384 */
1381 1385 struct ff_device {
1382 1386 int (*upload)(struct input_dev *dev, struct ff_effect *effect,