summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/input/ff-memless.c27
-rw-r--r--drivers/input/input.c3
-rw-r--r--include/linux/input.h3
3 files changed, 27 insertions, 6 deletions
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 937370d04928..d1fefd1dfc0d 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -484,17 +484,31 @@ static void ml_ff_destroy(struct ff_device *ff)
struct ml_device *ml = ff->private;
/*
- * Even though we stop all playing effects when tearing down
- * an input device (via input_device_flush() that calls into
- * input_ff_flush() that stops and erases all effects), we
- * do not actually stop the timer, and therefore we should
- * do it here.
+ * The timer is normally shut down in ml_ff_stop() when the device
+ * is unregistered. However, we still shut it down here as a safety
+ * net and for cases where the device was never registered (e.g.
+ * error paths during probe).
*/
- timer_delete_sync(&ml->timer);
+ timer_shutdown_sync(&ml->timer);
kfree(ml->private);
}
+static void ml_ff_stop(struct ff_device *ff)
+{
+ struct ml_device *ml = ff->private;
+
+ /*
+ * Even though we stop all playing effects when tearing down an
+ * input device (by the way of evdev calling input_flush_device()
+ * that calls into input_ff_flush() that stops and erases all
+ * effects), we do not actually shutdown the timer, and therefore
+ * we should do it here to prevent it firing after the input
+ * device is unregistered and its associated resources are freed.
+ */
+ timer_shutdown_sync(&ml->timer);
+}
+
/**
* input_ff_create_memless() - create memoryless force-feedback device
* @dev: input device supporting force-feedback
@@ -529,6 +543,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
ff->playback = ml_ff_playback;
ff->set_gain = ml_ff_set_gain;
ff->destroy = ml_ff_destroy;
+ ff->stop = ml_ff_stop;
/* we can emulate periodic effects with RUMBLE */
if (test_bit(FF_RUMBLE, ff->ffbit)) {
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 39d9d2b1e3ca..cf6fecea79b8 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -2212,6 +2212,9 @@ static void __input_unregister_device(struct input_dev *dev)
input_wakeup_procfs_readers();
}
+ if (dev->ff && dev->ff->stop)
+ dev->ff->stop(dev->ff);
+
device_del(&dev->dev);
}
diff --git a/include/linux/input.h b/include/linux/input.h
index 06ca62328db1..3022bb730898 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -543,6 +543,8 @@ extern const struct class input_class;
* @set_autocenter: Called to auto-center device
* @destroy: called by input core when parent input device is being
* destroyed
+ * @stop: called by input core when parent input device is being
+ * unregistered
* @private: driver-specific data, will be freed automatically
* @ffbit: bitmap of force feedback capabilities truly supported by
* device (not emulated like ones in input_dev->ffbit)
@@ -571,6 +573,7 @@ struct ff_device {
void (*set_autocenter)(struct input_dev *dev, u16 magnitude);
void (*destroy)(struct ff_device *);
+ void (*stop)(struct ff_device *);
void *private;