Commit 266c24ad authored by Patrick Mochel's avatar Patrick Mochel

Fix and prevent bugs in device_register()

When adding to the global device list, we were adding devices just after their parent, while we wanted to
add them just before. That way when we iterate over the list on suspend and shutdown, we'll hit all
children before the parents.

Make sure dev->driver_list and dev->bus_list are initialized when the device is registered

Remove device from global and parent's list if registration failed.
parent d8b2993c
......@@ -191,7 +191,6 @@ void driver_detach(struct device_driver * drv)
int device_register(struct device *dev)
{
int error;
struct device *prev_dev;
if (!dev || !strlen(dev->bus_id))
return -EINVAL;
......@@ -199,6 +198,8 @@ int device_register(struct device *dev)
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list);
INIT_LIST_HEAD(&dev->driver_list);
INIT_LIST_HEAD(&dev->bus_list);
spin_lock_init(&dev->lock);
atomic_set(&dev->refcount,2);
......@@ -208,12 +209,7 @@ int device_register(struct device *dev)
get_device(dev->parent);
spin_lock(&device_lock);
if (list_empty(&dev->parent->children))
prev_dev = dev->parent;
else
prev_dev = list_entry(dev->parent->children.prev, struct device, node);
list_add(&dev->g_list, &prev_dev->g_list);
list_add_tail(&dev->g_list,&dev->parent->g_list);
list_add_tail(&dev->node,&dev->parent->children);
spin_unlock(&device_lock);
}
......@@ -234,9 +230,15 @@ int device_register(struct device *dev)
platform_notify(dev);
register_done:
if (error) {
spin_lock(&device_lock);
list_del_init(&dev->g_list);
list_del_init(&dev->node);
spin_unlock(&device_lock);
if (dev->parent)
put_device(dev->parent);
}
put_device(dev);
if (error && dev->parent)
put_device(dev->parent);
return error;
}
......
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