diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-29 01:23:20 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-30 23:50:56 -0400 |
commit | b05681b91709a19b40a452f566cc852619b30082 (patch) | |
tree | 7802a9adcf6cb73b534e7f9b197ce7f8c4fcd602 /drivers/media/rc/rc-main.c | |
parent | eaceba650dea4af61f6f3a4919caa096bb4c2929 (diff) |
[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.c | 29 |
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: | |||
928 | 928 | ||
929 | static void rc_dev_release(struct device *device) | 929 | static void rc_dev_release(struct device *device) |
930 | { | 930 | { |
931 | struct rc_dev *dev = to_rc_dev(device); | ||
932 | |||
933 | kfree(dev); | ||
934 | module_put(THIS_MODULE); | ||
935 | } | 931 | } |
936 | 932 | ||
937 | #define ADD_HOTPLUG_VAR(fmt, val...) \ | 933 | #define ADD_HOTPLUG_VAR(fmt, val...) \ |
@@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) | |||
945 | { | 941 | { |
946 | struct rc_dev *dev = to_rc_dev(device); | 942 | struct rc_dev *dev = to_rc_dev(device); |
947 | 943 | ||
944 | if (!dev || !dev->input_dev) | ||
945 | return -ENODEV; | ||
946 | |||
948 | if (dev->rc_map.name) | 947 | if (dev->rc_map.name) |
949 | ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); | 948 | ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); |
950 | if (dev->driver_name) | 949 | if (dev->driver_name) |
@@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device); | |||
1013 | 1012 | ||
1014 | void rc_free_device(struct rc_dev *dev) | 1013 | void rc_free_device(struct rc_dev *dev) |
1015 | { | 1014 | { |
1016 | if (dev) { | 1015 | if (!dev) |
1016 | return; | ||
1017 | |||
1018 | if (dev->input_dev) | ||
1017 | input_free_device(dev->input_dev); | 1019 | input_free_device(dev->input_dev); |
1018 | put_device(&dev->dev); | 1020 | |
1019 | } | 1021 | put_device(&dev->dev); |
1022 | |||
1023 | kfree(dev); | ||
1024 | module_put(THIS_MODULE); | ||
1020 | } | 1025 | } |
1021 | EXPORT_SYMBOL_GPL(rc_free_device); | 1026 | EXPORT_SYMBOL_GPL(rc_free_device); |
1022 | 1027 | ||
@@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev) | |||
1143 | if (dev->driver_type == RC_DRIVER_IR_RAW) | 1148 | if (dev->driver_type == RC_DRIVER_IR_RAW) |
1144 | ir_raw_event_unregister(dev); | 1149 | ir_raw_event_unregister(dev); |
1145 | 1150 | ||
1151 | /* Freeing the table should also call the stop callback */ | ||
1152 | ir_free_table(&dev->rc_map); | ||
1153 | IR_dprintk(1, "Freed keycode table\n"); | ||
1154 | |||
1146 | input_unregister_device(dev->input_dev); | 1155 | input_unregister_device(dev->input_dev); |
1147 | dev->input_dev = NULL; | 1156 | dev->input_dev = NULL; |
1148 | 1157 | ||
1149 | ir_free_table(&dev->rc_map); | 1158 | device_del(&dev->dev); |
1150 | IR_dprintk(1, "Freed keycode table\n"); | ||
1151 | 1159 | ||
1152 | device_unregister(&dev->dev); | 1160 | rc_free_device(dev); |
1153 | } | 1161 | } |
1162 | |||
1154 | EXPORT_SYMBOL_GPL(rc_unregister_device); | 1163 | EXPORT_SYMBOL_GPL(rc_unregister_device); |
1155 | 1164 | ||
1156 | /* | 1165 | /* |