Commit a7097ff8 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: make sure input interfaces pin parent input devices

Recent driver core change causes references to parent devices being
dropped early, at device_del() time, as opposed to when all children
are freed. This causes oops in evdev with grabbed devices. Take the
reference to the parent input device ourselves to ensure that it
stays around long enough.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 399f4862
...@@ -124,6 +124,7 @@ static void evdev_free(struct device *dev) ...@@ -124,6 +124,7 @@ static void evdev_free(struct device *dev)
{ {
struct evdev *evdev = container_of(dev, struct evdev, dev); struct evdev *evdev = container_of(dev, struct evdev, dev);
input_put_device(evdev->handle.dev);
kfree(evdev); kfree(evdev);
} }
...@@ -853,9 +854,6 @@ static void evdev_cleanup(struct evdev *evdev) ...@@ -853,9 +854,6 @@ static void evdev_cleanup(struct evdev *evdev)
evdev_hangup(evdev); evdev_hangup(evdev);
evdev_remove_chrdev(evdev); evdev_remove_chrdev(evdev);
if (evdev->grab)
evdev_ungrab(evdev, evdev->grab);
/* evdev is marked dead so no one else accesses evdev->open */ /* evdev is marked dead so no one else accesses evdev->open */
if (evdev->open) { if (evdev->open) {
input_flush_device(handle, NULL); input_flush_device(handle, NULL);
...@@ -896,7 +894,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -896,7 +894,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
evdev->exist = 1; evdev->exist = 1;
evdev->minor = minor; evdev->minor = minor;
evdev->handle.dev = dev; evdev->handle.dev = input_get_device(dev);
evdev->handle.name = evdev->name; evdev->handle.name = evdev->name;
evdev->handle.handler = handler; evdev->handle.handler = handler;
evdev->handle.private = evdev; evdev->handle.private = evdev;
......
...@@ -171,6 +171,7 @@ static void joydev_free(struct device *dev) ...@@ -171,6 +171,7 @@ static void joydev_free(struct device *dev)
{ {
struct joydev *joydev = container_of(dev, struct joydev, dev); struct joydev *joydev = container_of(dev, struct joydev, dev);
input_put_device(joydev->handle.dev);
kfree(joydev); kfree(joydev);
} }
...@@ -750,7 +751,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -750,7 +751,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
joydev->minor = minor; joydev->minor = minor;
joydev->exist = 1; joydev->exist = 1;
joydev->handle.dev = dev; joydev->handle.dev = input_get_device(dev);
joydev->handle.name = joydev->name; joydev->handle.name = joydev->name;
joydev->handle.handler = handler; joydev->handle.handler = handler;
joydev->handle.private = joydev; joydev->handle.private = joydev;
......
...@@ -414,6 +414,7 @@ static void mousedev_free(struct device *dev) ...@@ -414,6 +414,7 @@ static void mousedev_free(struct device *dev)
{ {
struct mousedev *mousedev = container_of(dev, struct mousedev, dev); struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
input_put_device(mousedev->handle.dev);
kfree(mousedev); kfree(mousedev);
} }
...@@ -865,7 +866,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, ...@@ -865,7 +866,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
mousedev->minor = minor; mousedev->minor = minor;
mousedev->exist = 1; mousedev->exist = 1;
mousedev->handle.dev = dev; mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = mousedev->name; mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler; mousedev->handle.handler = handler;
mousedev->handle.private = mousedev; mousedev->handle.private = mousedev;
......
...@@ -1227,12 +1227,13 @@ void input_free_device(struct input_dev *dev); ...@@ -1227,12 +1227,13 @@ void input_free_device(struct input_dev *dev);
static inline struct input_dev *input_get_device(struct input_dev *dev) static inline struct input_dev *input_get_device(struct input_dev *dev)
{ {
return to_input_dev(get_device(&dev->dev)); return dev ? to_input_dev(get_device(&dev->dev)) : NULL;
} }
static inline void input_put_device(struct input_dev *dev) static inline void input_put_device(struct input_dev *dev)
{ {
put_device(&dev->dev); if (dev)
put_device(&dev->dev);
} }
static inline void *input_get_drvdata(struct input_dev *dev) static inline void *input_get_drvdata(struct input_dev *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment