431 lines · 10.3 KB · C
RawDownload
/* * drivers/base/dd.c - The core device/driver interactions. * * This file contains the (sometimes tricky) code that controls the * interactions between devices and drivers, which primarily includes * driver binding and unbinding. * * All of this code used to exist in drivers/base/bus.c, but was * relocated to here in the name of compartmentalization (since it wasn't * strictly code just for the 'struct bus_type'. * * Copyright (c) 2002-5 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007-2009 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (c) 2007-2009 Novell Inc. * * This file is released under the GPLv2 */ #include <linux/device.h>#include <linux/delay.h>#include <linux/module.h>#include <linux/kthread.h>#include <linux/wait.h>#include <linux/async.h>#include <linux/pm_runtime.h> #include "base.h"#include "power/power.h"  static void driver_bound(struct device *dev){	if (klist_node_attached(&dev->p->knode_driver)) {		printk(KERN_WARNING "%s: device %s already bound\n",			__func__, kobject_name(&dev->kobj));		return;	} 	pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),		 __func__, dev->driver->name); 	klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); 	if (dev->bus)		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,					     BUS_NOTIFY_BOUND_DRIVER, dev);} static int driver_sysfs_add(struct device *dev){	int ret; 	if (dev->bus)		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,					     BUS_NOTIFY_BIND_DRIVER, dev); 	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,			  kobject_name(&dev->kobj));	if (ret == 0) {		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,					"driver");		if (ret)			sysfs_remove_link(&dev->driver->p->kobj,					kobject_name(&dev->kobj));	}	return ret;} static void driver_sysfs_remove(struct device *dev){	struct device_driver *drv = dev->driver; 	if (drv) {		sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));		sysfs_remove_link(&dev->kobj, "driver");	}} /** * device_bind_driver - bind a driver to one device. * @dev: device. * * Allow manual attachment of a driver to a device. * Caller must have already set @dev->driver. * * Note that this does not modify the bus reference count * nor take the bus's rwsem. Please verify those are accounted * for before calling this. (It is ok to call with no other effort * from a driver's probe() method.) * * This function must be called with the device lock held. */int device_bind_driver(struct device *dev){	int ret; 	ret = driver_sysfs_add(dev);	if (!ret)		driver_bound(dev);	return ret;}EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0);static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); static int really_probe(struct device *dev, struct device_driver *drv){	int ret = 0; 	atomic_inc(&probe_count);	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",		 drv->bus->name, __func__, drv->name, dev_name(dev));	WARN_ON(!list_empty(&dev->devres_head)); 	dev->driver = drv;	if (driver_sysfs_add(dev)) {		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",			__func__, dev_name(dev));		goto probe_failed;	} 	if (dev->bus->probe) {		ret = dev->bus->probe(dev);		if (ret)			goto probe_failed;	} else if (drv->probe) {		ret = drv->probe(dev);		if (ret)			goto probe_failed;	} 	driver_bound(dev);	ret = 1;	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",		 drv->bus->name, __func__, dev_name(dev), drv->name);	goto done; probe_failed:	devres_release_all(dev);	driver_sysfs_remove(dev);	dev->driver = NULL; 	if (ret != -ENODEV && ret != -ENXIO) {		/* driver matched but the probe failed */		printk(KERN_WARNING		       "%s: probe of %s failed with error %d\n",		       drv->name, dev_name(dev), ret);	} else {		pr_debug("%s: probe of %s rejects match %d\n",		       drv->name, dev_name(dev), ret);	}	/*	 * Ignore errors returned by ->probe so that the next driver can try	 * its luck.	 */	ret = 0;done:	atomic_dec(&probe_count);	wake_up(&probe_waitqueue);	return ret;} /** * driver_probe_done * Determine if the probe sequence is finished or not. * * Should somehow figure out how to use a semaphore, not an atomic variable... */int driver_probe_done(void){	pr_debug("%s: probe_count = %d\n", __func__,		 atomic_read(&probe_count));	if (atomic_read(&probe_count))		return -EBUSY;	return 0;} /** * wait_for_device_probe * Wait for device probing to be completed. */void wait_for_device_probe(void){	/* wait for the known devices to complete their probing */	wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);	async_synchronize_full();}EXPORT_SYMBOL_GPL(wait_for_device_probe); /** * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held.  When called for a * USB interface, @dev->parent lock must be held as well. */int driver_probe_device(struct device_driver *drv, struct device *dev){	int ret = 0; 	if (!device_is_registered(dev))		return -ENODEV; 	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",		 drv->bus->name, __func__, dev_name(dev), drv->name); 	pm_runtime_get_noresume(dev);	pm_runtime_barrier(dev);	ret = really_probe(dev, drv);	pm_runtime_put_sync(dev); 	return ret;} static int __device_attach(struct device_driver *drv, void *data){	struct device *dev = data; 	if (!driver_match_device(drv, dev))		return 0; 	return driver_probe_device(drv, dev);} /** * device_attach - try to attach device to a driver. * @dev: device. * * Walk the list of drivers that the bus has and call * driver_probe_device() for each pair. If a compatible * pair is found, break out and return. * * Returns 1 if the device was bound to a driver; * 0 if no matching driver was found; * -ENODEV if the device is not registered. * * When called for a USB interface, @dev->parent lock must be held. */int device_attach(struct device *dev){	int ret = 0; 	device_lock(dev);	if (dev->driver) {		if (klist_node_attached(&dev->p->knode_driver)) {			ret = 1;			goto out_unlock;		}		ret = device_bind_driver(dev);		if (ret == 0)			ret = 1;		else {			dev->driver = NULL;			ret = 0;		}	} else {		pm_runtime_get_noresume(dev);		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);		pm_runtime_put_sync(dev);	}out_unlock:	device_unlock(dev);	return ret;}EXPORT_SYMBOL_GPL(device_attach); static int __driver_attach(struct device *dev, void *data){	struct device_driver *drv = data; 	/*	 * Lock device and try to bind to it. We drop the error	 * here and always return 0, because we need to keep trying	 * to bind to devices and some drivers will return an error	 * simply if it didn't support the device.	 *	 * driver_probe_device() will spit a warning if there	 * is an error.	 */ 	if (!driver_match_device(drv, dev))		return 0; 	if (dev->parent)	/* Needed for USB */		device_lock(dev->parent);	device_lock(dev);	if (!dev->driver)		driver_probe_device(drv, dev);	device_unlock(dev);	if (dev->parent)		device_unlock(dev->parent); 	return 0;} /** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the driver with each one.  If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. */int driver_attach(struct device_driver *drv){	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}EXPORT_SYMBOL_GPL(driver_attach); /* * __device_release_driver() must be called with @dev lock held. * When called for a USB interface, @dev->parent lock must be held as well. */static void __device_release_driver(struct device *dev){	struct device_driver *drv; 	drv = dev->driver;	if (drv) {		pm_runtime_get_sync(dev); 		driver_sysfs_remove(dev); 		if (dev->bus)			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,						     BUS_NOTIFY_UNBIND_DRIVER,						     dev); 		pm_runtime_put_sync(dev); 		if (dev->bus && dev->bus->remove)			dev->bus->remove(dev);		else if (drv->remove)			drv->remove(dev);		devres_release_all(dev);		dev->driver = NULL;		klist_remove(&dev->p->knode_driver);		if (dev->bus)			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,						     BUS_NOTIFY_UNBOUND_DRIVER,						     dev); 	}} /** * device_release_driver - manually detach device from driver. * @dev: device. * * Manually detach device from driver. * When called for a USB interface, @dev->parent lock must be held. */void device_release_driver(struct device *dev){	/*	 * If anyone calls device_release_driver() recursively from	 * within their ->remove callback for the same device, they	 * will deadlock right here.	 */	device_lock(dev);	__device_release_driver(dev);	device_unlock(dev);}EXPORT_SYMBOL_GPL(device_release_driver); /** * driver_detach - detach driver from all devices it controls. * @drv: driver. */void driver_detach(struct device_driver *drv){	struct device_private *dev_prv;	struct device *dev; 	for (;;) {		spin_lock(&drv->p->klist_devices.k_lock);		if (list_empty(&drv->p->klist_devices.k_list)) {			spin_unlock(&drv->p->klist_devices.k_lock);			break;		}		dev_prv = list_entry(drv->p->klist_devices.k_list.prev,				     struct device_private,				     knode_driver.n_node);		dev = dev_prv->device;		get_device(dev);		spin_unlock(&drv->p->klist_devices.k_lock); 		if (dev->parent)	/* Needed for USB */			device_lock(dev->parent);		device_lock(dev);		if (dev->driver == drv)			__device_release_driver(dev);		device_unlock(dev);		if (dev->parent)			device_unlock(dev->parent);		put_device(dev);	}} /* * These exports can't be _GPL due to .h files using this within them, and it * might break something that was previously working... */void *dev_get_drvdata(const struct device *dev){	if (dev && dev->p)		return dev->p->driver_data;	return NULL;}EXPORT_SYMBOL(dev_get_drvdata); int dev_set_drvdata(struct device *dev, void *data){	int error; 	if (!dev->p) {		error = device_private_init(dev);		if (error)			return error;	}	dev->p->driver_data = data;	return 0;}EXPORT_SYMBOL(dev_set_drvdata);