ChangeSet 1.793.1.17, 2002/10/18 10:00:13-07:00, greg@kroah.com merge between the usb and driver model trees. diff -Nru a/drivers/base/core.c b/drivers/base/core.c --- a/drivers/base/core.c Fri Oct 18 14:43:06 2002 +++ b/drivers/base/core.c Fri Oct 18 14:43:06 2002 @@ -19,109 +19,12 @@ int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL; +DECLARE_MUTEX(device_sem); + spinlock_t device_lock = SPIN_LOCK_UNLOCKED; #define to_dev(node) container_of(node,struct device,driver_list) -static int probe(struct device * dev, struct device_driver * drv) -{ - dev->driver = drv; - return drv->probe ? drv->probe(dev) : -ENODEV; -} - -static void attach(struct device * dev) -{ - spin_lock(&device_lock); - list_add_tail(&dev->driver_list,&dev->driver->devices); - spin_unlock(&device_lock); - devclass_add_device(dev); -} - -/** - * found_match - do actual binding of device to driver - * @dev: device - * @drv: driver - * - * We're here because the bus's match callback returned success for this - * pair. We call the driver's probe callback to verify they're really a - * match made in heaven. - * - * In the future, we may want to notify userspace of the binding. (But, - * we might not want to do it here). - * - * We may also want to create a symlink in the driver's directory to the - * device's physical directory. - */ -static int found_match(struct device * dev, struct device_driver * drv) -{ - int error; - - if (!(error = probe(dev,get_driver(drv)))) { - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id,drv->name); - attach(dev); - } else { - put_driver(drv); - dev->driver = NULL; - } - /* return boolean: did driver bind? */ - return error == 0; -} - -/** - * device_attach - try to associated device with a driver - * @drv: current driver to try - * @data: device in disguise - * - * This function is used as a callback to bus_for_each_drv. - * It calls the bus's match callback to check if the driver supports - * the device. If so, it calls the found_match() function above to - * take care of all the details. - */ -static int do_device_attach(struct device_driver * drv, void * data) -{ - struct device * dev = (struct device *)data; - int error = 0; - - if (drv->bus->match && drv->bus->match(dev,drv)) - error = found_match(dev,drv); - /* stop bus_for_each_drv() once a driver binds to the device */ - return error; -} - -static int device_attach(struct device * dev) -{ - int error = 0; - if (!dev->driver) { - if (dev->bus) - error = bus_for_each_drv(dev->bus,dev,do_device_attach); - } else - attach(dev); - return error; -} - -static void device_detach(struct device * dev) -{ - struct device_driver * drv = dev->driver; - - if (drv) { - devclass_remove_device(dev); - if (drv && drv->remove) - drv->remove(dev); - dev->driver = NULL; - } -} - -static int do_driver_attach(struct device * dev, void * data) -{ - struct device_driver * drv = (struct device_driver *)data; - - if (!dev->driver) { - if (dev->bus->match && dev->bus->match(dev,drv)) - found_match(dev,drv); - } - /* continue bus_for_each_dev(), to attach to other devices */ - return 0; } int driver_attach(struct device_driver * drv) @@ -162,30 +65,21 @@ * Maintains a global list of all devices, in depth-first ordering. * The head for that list is device_root.g_list. */ -int device_register(struct device *dev) +int device_add(struct device *dev) { int error; if (!dev || !strlen(dev->bus_id)) return -EINVAL; - 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); - INIT_LIST_HEAD(&dev->intf_list); - spin_lock_init(&dev->lock); - atomic_set(&dev->refcount,2); - dev->present = 1; - spin_lock(&device_lock); + down(&device_sem); + dev->state = DEVICE_REGISTERED; if (dev->parent) { - get_device_locked(dev->parent); list_add_tail(&dev->g_list,&dev->parent->g_list); list_add_tail(&dev->node,&dev->parent->children); } else list_add_tail(&dev->g_list,&global_device_list); - spin_unlock(&device_lock); + up(&device_sem); pr_debug("DEV: registering device: ID = '%s', name = %s\n", dev->bus_id, dev->name); @@ -195,9 +89,6 @@ bus_add_device(dev); - /* bind to driver */ - device_attach(dev); - /* notify platform of device entry */ if (platform_notify) platform_notify(dev); @@ -205,35 +96,68 @@ /* notify userspace of device entry */ dev_hotplug(dev, "add"); + devclass_add_device(dev); register_done: if (error) { - spin_lock(&device_lock); + up(&device_sem); list_del_init(&dev->g_list); list_del_init(&dev->node); - spin_unlock(&device_lock); - if (dev->parent) - put_device(dev->parent); + up(&device_sem); } - put_device(dev); return error; } -struct device * get_device_locked(struct device * dev) +void device_initialize(struct device *dev) { - struct device * ret = dev; - if (dev && dev->present && atomic_read(&dev->refcount) > 0) - atomic_inc(&dev->refcount); - else - ret = NULL; - return ret; + 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); + INIT_LIST_HEAD(&dev->intf_list); + spin_lock_init(&dev->lock); + atomic_set(&dev->refcount,1); + dev->state = DEVICE_INITIALIZED; + if (dev->parent) + get_device(dev->parent); +} + +/** + * device_register - register a device + * @dev: pointer to the device structure + * + * First, make sure that the device has a parent, create + * a directory for it, then add it to the parent's list of + * children. + * + * Maintains a global list of all devices, in depth-first ordering. + * The head for that list is device_root.g_list. + */ +int device_register(struct device *dev) +{ + int error; + + if (!dev || !strlen(dev->bus_id)) + return -EINVAL; + + device_initialize(dev); + if (dev->parent) + get_device(dev->parent); + error = device_add(dev); + if (error && dev->parent) + put_device(dev->parent); + return error; } struct device * get_device(struct device * dev) { - struct device * ret; - spin_lock(&device_lock); - ret = get_device_locked(dev); - spin_unlock(&device_lock); + struct device * ret = dev; + down(&device_sem); + if (device_present(dev) && atomic_read(&dev->refcount) > 0) + atomic_inc(&dev->refcount); + else + ret = NULL; + up(&device_sem); return ret; } @@ -243,43 +167,23 @@ */ void put_device(struct device * dev) { - struct device * parent; - if (!atomic_dec_and_lock(&dev->refcount,&device_lock)) + down(&device_sem); + if (!atomic_dec_and_test(&dev->refcount)) { + up(&device_sem); return; - parent = dev->parent; - dev->parent = NULL; - spin_unlock(&device_lock); - - BUG_ON(dev->present); + } + list_del_init(&dev->node); + list_del_init(&dev->g_list); + up(&device_sem); - if (dev->release) - dev->release(dev); + BUG_ON((dev->state != DEVICE_GONE)); - if (parent) - put_device(parent); + device_del(dev); } -/** - * device_unregister - unlink device - * @dev: device going away - * - * The device has been removed from the system, so we disavow knowledge - * of it. It might not be the final reference to the device, so we mark - * it as !present, so no more references to it can be acquired. - * In the end, we decrement the final reference count for it. - */ -void device_unregister(struct device * dev) +void device_del(struct device * dev) { - spin_lock(&device_lock); - dev->present = 0; - list_del_init(&dev->node); - list_del_init(&dev->g_list); - list_del_init(&dev->bus_list); - list_del_init(&dev->driver_list); - spin_unlock(&device_lock); - - pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", - dev->bus_id,dev->name); + struct device * parent = dev->parent; /* Notify the platform of the removal, in case they * need to do anything... @@ -290,26 +194,37 @@ /* notify userspace that this device is about to disappear */ dev_hotplug (dev, "remove"); - device_detach(dev); bus_remove_device(dev); /* remove the driverfs directory */ device_remove_dir(dev); - put_device(dev); + if (dev->release) + dev->release(dev); + + if (parent) + put_device(parent); } -static int __init device_init(void) +/** + * device_unregister - unlink device + * @dev: device going away + * + * The device has been removed from the system, so we disavow knowledge + * of it. It might not be the final reference to the device, so we mark + * it as !present, so no more references to it can be acquired. + * In the end, we decrement the final reference count for it. + */ +void device_unregister(struct device * dev) { - int error; + down(&device_sem); + dev->state = DEVICE_GONE; + up(&device_sem); - error = init_driverfs_fs(); - if (error) - panic("DEV: could not initialize driverfs"); - return 0; + pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", + dev->bus_id,dev->name); + put_device(dev); } - -core_initcall(device_init); EXPORT_SYMBOL(device_register); EXPORT_SYMBOL(device_unregister);