summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-02-13 19:46:10 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2012-02-17 10:27:15 +0100
commit491cc29b0a2cf7c675e94e00eed2d58934a76011 (patch)
treed13a6da9097f609037b53a02a5861b568d950a97 /drivers/base
parent62d8b2f8c088f73cf929d6c5be360846c6bfb556 (diff)
downloadbarebox-491cc29b0a2cf7c675e94e00eed2d58934a76011.tar.gz
barebox-491cc29b0a2cf7c675e94e00eed2d58934a76011.tar.xz
devices: unregister children when unregistering a device
We currently do not allow to unregister a device when it has children. However, the return value is seldomly checked. Also this breaks for hot pluggable devices like USB which we have to unregister when they disappear. The best way to fix this is to unregister our children and also the partitions on the unregistered device. We unregister the device first and then afterwards the children. We do this because for example network devices have a miidev as child which they unregister themselves. So we only have to unregister the children which are not cleaned up by the drivers, namely fs devices. Also, unregister all partitions on a disappearing device. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/driver.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 0132e7dcf8..3777f82d64 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -137,16 +137,26 @@ EXPORT_SYMBOL(register_device);
int unregister_device(struct device_d *old_dev)
{
- debug("unregister_device: %s\n", dev_name(old_dev));
+ struct cdev *cdev, *ct;
+ struct device_d *child, *dt;
- if (!list_empty(&old_dev->children)) {
- errno = -EBUSY;
- return errno;
- }
+ dev_dbg(old_dev, "unregister\n");
if (old_dev->driver)
old_dev->bus->remove(old_dev);
+ list_for_each_entry_safe(child, dt, &old_dev->children, sibling) {
+ dev_dbg(old_dev, "unregister child %s\n", dev_name(child));
+ unregister_device(child);
+ }
+
+ list_for_each_entry_safe(cdev, ct, &old_dev->cdevs, devices_list) {
+ if (cdev->flags & DEVFS_IS_PARTITION) {
+ dev_dbg(old_dev, "unregister part %s\n", cdev->name);
+ devfs_del_partition(cdev->name);
+ }
+ }
+
list_del(&old_dev->list);
list_del(&old_dev->active);