summaryrefslogtreecommitdiffstats
path: root/drivers/media/rc/rc-main.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab2011-07-29 07:23:20 +0200
committerMauro Carvalho Chehab2011-07-31 05:50:56 +0200
commitb05681b91709a19b40a452f566cc852619b30082 (patch)
tree7802a9adcf6cb73b534e7f9b197ce7f8c4fcd602 /drivers/media/rc/rc-main.c
parent[media] gspca-stv06xx: Triple frame rate by decreasing the scan rate (diff)
downloadkernel-qcow2-linux-b05681b91709a19b40a452f566cc852619b30082.tar.gz
kernel-qcow2-linux-b05681b91709a19b40a452f566cc852619b30082.tar.xz
kernel-qcow2-linux-b05681b91709a19b40a452f566cc852619b30082.zip
[media] rc-main: Fix device de-registration logic
rc unregister logic were deadly broken, preventing some drivers to be removed. Among the broken things, rc_dev_uevent() is being called during device_del(), causing a data filling on an area that it is not ready anymore. Also, some drivers have a stop callback defined, that needs to be called before data removal, as it stops data polling. Acked-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/rc/rc-main.c')
-rw-r--r--drivers/media/rc/rc-main.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 51a23f48bc7d..666d4bb5b1fb 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -928,10 +928,6 @@ out:
static void rc_dev_release(struct device *device)
{
- struct rc_dev *dev = to_rc_dev(device);
-
- kfree(dev);
- module_put(THIS_MODULE);
}
#define ADD_HOTPLUG_VAR(fmt, val...) \
@@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct rc_dev *dev = to_rc_dev(device);
+ if (!dev || !dev->input_dev)
+ return -ENODEV;
+
if (dev->rc_map.name)
ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
if (dev->driver_name)
@@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device);
void rc_free_device(struct rc_dev *dev)
{
- if (dev) {
+ if (!dev)
+ return;
+
+ if (dev->input_dev)
input_free_device(dev->input_dev);
- put_device(&dev->dev);
- }
+
+ put_device(&dev->dev);
+
+ kfree(dev);
+ module_put(THIS_MODULE);
}
EXPORT_SYMBOL_GPL(rc_free_device);
@@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev)
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
+ /* Freeing the table should also call the stop callback */
+ ir_free_table(&dev->rc_map);
+ IR_dprintk(1, "Freed keycode table\n");
+
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
- ir_free_table(&dev->rc_map);
- IR_dprintk(1, "Freed keycode table\n");
+ device_del(&dev->dev);
- device_unregister(&dev->dev);
+ rc_free_device(dev);
}
+
EXPORT_SYMBOL_GPL(rc_unregister_device);
/*