cregit-Linux how code gets into the kernel

Release 4.11 drivers/base/dd.c

Directory: drivers/base
/*
 * 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 <linux/pinctrl/devinfo.h>

#include "base.h"
#include "power/power.h"

/*
 * Deferred Probe infrastructure.
 *
 * Sometimes driver probe order matters, but the kernel doesn't always have
 * dependency information which means some drivers will get probed before a
 * resource it depends on is available.  For example, an SDHCI driver may
 * first need a GPIO line from an i2c GPIO controller before it can be
 * initialized.  If a required resource is not available yet, a driver can
 * request probing to be deferred by returning -EPROBE_DEFER from its probe hook
 *
 * Deferred probe maintains two lists of devices, a pending list and an active
 * list.  A driver returning -EPROBE_DEFER causes the device to be added to the
 * pending list.  A successful driver probe will trigger moving all devices
 * from the pending to the active list so that the workqueue will eventually
 * retry them.
 *
 * The deferred_probe_mutex must be held any time the deferred_probe_*_list
 * of the (struct device*)->p->deferred_probe pointers are manipulated
 */
static DEFINE_MUTEX(deferred_probe_mutex);
static LIST_HEAD(deferred_probe_pending_list);
static LIST_HEAD(deferred_probe_active_list);

static atomic_t deferred_trigger_count = ATOMIC_INIT(0);

/*
 * In some cases, like suspend to RAM or hibernation, It might be reasonable
 * to prohibit probing of devices as it could be unsafe.
 * Once defer_all_probes is true all drivers probes will be forcibly deferred.
 */

static bool defer_all_probes;

/*
 * deferred_probe_work_func() - Retry probing devices in the active list.
 */

static void deferred_probe_work_func(struct work_struct *work) { struct device *dev; struct device_private *private; /* * This block processes every device in the deferred 'active' list. * Each device is removed from the active list and passed to * bus_probe_device() to re-attempt the probe. The loop continues * until every device in the active list is removed and retried. * * Note: Once the device is removed from the list and the mutex is * released, it is possible for the device get freed by another thread * and cause a illegal pointer dereference. This code uses * get/put_device() to ensure the device structure cannot disappear * from under our feet. */ mutex_lock(&deferred_probe_mutex); while (!list_empty(&deferred_probe_active_list)) { private = list_first_entry(&deferred_probe_active_list, typeof(*dev->p), deferred_probe); dev = private->device; list_del_init(&private->deferred_probe); get_device(dev); /* * Drop the mutex while probing each device; the probe path may * manipulate the deferred list */ mutex_unlock(&deferred_probe_mutex); /* * Force the device to the end of the dpm_list since * the PM code assumes that the order we add things to * the list is a good order for suspend but deferred * probe makes that very unsafe. */ device_pm_lock(); device_pm_move_last(dev); device_pm_unlock(); dev_dbg(dev, "Retrying from deferred list\n"); bus_probe_device(dev); mutex_lock(&deferred_probe_mutex); put_device(dev); } mutex_unlock(&deferred_probe_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Grant C. Likely9677.42%125.00%
Greg Kroah-Hartman1612.90%250.00%
Mark Brown129.68%125.00%
Total124100.00%4100.00%

static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
static void driver_deferred_probe_add(struct device *dev) { mutex_lock(&deferred_probe_mutex); if (list_empty(&dev->p->deferred_probe)) { dev_dbg(dev, "Added to deferred list\n"); list_add_tail(&dev->p->deferred_probe, &deferred_probe_pending_list); } mutex_unlock(&deferred_probe_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Grant C. Likely5291.23%133.33%
Greg Kroah-Hartman47.02%133.33%
Kuninori Morimoto11.75%133.33%
Total57100.00%3100.00%


void driver_deferred_probe_del(struct device *dev) { mutex_lock(&deferred_probe_mutex); if (!list_empty(&dev->p->deferred_probe)) { dev_dbg(dev, "Removed from deferred list\n"); list_del_init(&dev->p->deferred_probe); } mutex_unlock(&deferred_probe_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Grant C. Likely5092.59%150.00%
Greg Kroah-Hartman47.41%150.00%
Total54100.00%2100.00%

static bool driver_deferred_probe_enable = false; /** * driver_deferred_probe_trigger() - Kick off re-probing deferred devices * * This functions moves all devices from the pending list to the active * list and schedules the deferred probe workqueue to process them. It * should be called anytime a driver is successfully bound to a device. * * Note, there is a race condition in multi-threaded probe. In the case where * more than one device is probing at the same time, it is possible for one * probe to complete successfully while another is about to defer. If the second * depends on the first, then it will get put on the pending list after the * trigger event has already occurred and will be stuck there. * * The atomic 'deferred_trigger_count' is used to determine if a successful * trigger has occurred in the midst of probing a driver. If the trigger count * changes in the midst of a probe, then deferred processing should be triggered * again. */
static void driver_deferred_probe_trigger(void) { if (!driver_deferred_probe_enable) return; /* * A successful probe means that all the devices in the pending list * should be triggered to be reprobed. Move all the deferred devices * into the active list so they can be retried by the workqueue */ mutex_lock(&deferred_probe_mutex); atomic_inc(&deferred_trigger_count); list_splice_tail_init(&deferred_probe_pending_list, &deferred_probe_active_list); mutex_unlock(&deferred_probe_mutex); /* * Kick the re-probe thread. It may already be scheduled, but it is * safe to kick it again. */ schedule_work(&deferred_probe_work); }

Contributors

PersonTokensPropCommitsCommitProp
Grant C. Likely4693.88%250.00%
Greg Kroah-Hartman24.08%125.00%
Bhaktipriya Shridhar12.04%125.00%
Total49100.00%4100.00%

/** * device_block_probing() - Block/defere device's probes * * It will disable probing of devices and defer their probes instead. */
void device_block_probing(void) { defer_all_probes = true; /* sync with probes to avoid races. */ wait_for_device_probe(); }

Contributors

PersonTokensPropCommitsCommitProp
Grygorii Strashko15100.00%1100.00%
Total15100.00%1100.00%

/** * device_unblock_probing() - Unblock/enable device's probes * * It will restore normal behavior and trigger re-probing of deferred * devices. */
void device_unblock_probing(void) { defer_all_probes = false; driver_deferred_probe_trigger(); }

Contributors

PersonTokensPropCommitsCommitProp
Grygorii Strashko14100.00%1100.00%
Total14100.00%1100.00%

/** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until * late_initcall time. */
static int deferred_probe_initcall(void) { driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); /* Sort as many dependencies as possible before exiting initcalls */ flush_work(&deferred_probe_work); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Grant C. Likely2288.00%266.67%
Bhaktipriya Shridhar312.00%133.33%
Total25100.00%3100.00%

late_initcall(deferred_probe_initcall); /** * device_is_bound() - Check if device is bound to a driver * @dev: device to check * * Returns true if passed device has already finished probing successfully * against a driver. * * This function must be called with the device lock held. */
bool device_is_bound(struct device *dev) { return dev->p && klist_node_attached(&dev->p->knode_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel728.00%120.00%
Daniel Ritz728.00%120.00%
Tomeu Vizoso520.00%120.00%
Rafael J. Wysocki416.00%120.00%
Greg Kroah-Hartman28.00%120.00%
Total25100.00%5100.00%


static void driver_bound(struct device *dev) { if (device_is_bound(dev)) { 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->driver->name, __func__, dev_name(dev)); klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); device_links_driver_bound(dev); device_pm_check_callbacks(dev); /* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices */ driver_deferred_probe_del(dev); driver_deferred_probe_trigger(); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); }

Contributors

PersonTokensPropCommitsCommitProp
Tomeu Vizoso2118.26%213.33%
Benjamin Herrenschmidt2017.39%16.67%
Stefani Seibold1916.52%16.67%
Andrew Morton1714.78%16.67%
Patrick Mochel108.70%16.67%
Grant C. Likely86.96%16.67%
Frank Rowand76.09%16.67%
Rafael J. Wysocki54.35%16.67%
Greg Kroah-Hartman43.48%320.00%
Kay Sievers21.74%16.67%
Daniel Ritz10.87%16.67%
Harvey Harrison10.87%16.67%
Total115100.00%15100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel4134.45%120.00%
Andrew Morton3731.09%120.00%
Magnus Damm2218.49%120.00%
Kay Sievers1310.92%120.00%
Greg Kroah-Hartman65.04%120.00%
Total119100.00%5100.00%


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"); } }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers5296.30%150.00%
Greg Kroah-Hartman23.70%150.00%
Total54100.00%2100.00%

/** * 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); else if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DRIVER_NOT_BOUND, dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko2341.07%133.33%
Kay Sievers1832.14%133.33%
Cornelia Huck1526.79%133.33%
Total56100.00%3100.00%

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 = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs; if (defer_all_probes) { /* * Value of defer_all_probes can be set only by * device_defer_all_probes_enable() which, in turn, will call * wait_for_device_probe() right after that to avoid any races. */ dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); driver_deferred_probe_add(dev); return ret; } ret = device_links_check_suppliers(dev); if (ret) return ret; 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)); re_probe: dev->driver = drv; /* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) goto pinctrl_bind_failed; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; } if (dev->pm_domain && dev->pm_domain->activate) { ret = dev->pm_domain->activate(dev); if (ret) goto probe_failed; } /* * Ensure devices are listed in devices_kset in correct order * It's important to move Dev to the end of devices_kset before * calling .probe, because it could be recursive and parent Dev * should always go first */ devices_kset_move_last(dev); 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; } if (test_remove) { test_remove = false; if (dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); pm_runtime_reinit(dev); goto re_probe; } pinctrl_init_done(dev); if (dev->pm_domain && dev->pm_domain->sync) dev->pm_domain->sync(dev); 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: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DRIVER_NOT_BOUND, dev); pinctrl_bind_failed: device_links_no_driver(dev); devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); pm_runtime_reinit(dev); switch (ret) { case -EPROBE_DEFER: /* Driver requested deferred probing */ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add(dev); /* Did a trigger occur while probing? Need to re-trigger if yes */ if (local_trigger_count != atomic_read(&deferred_trigger_count)) driver_deferred_probe_trigger(); break; case -ENODEV: case -ENXIO: pr_debug("%s: probe of %s rejects match %d\n", drv->name, dev_name(dev), ret); break; default: /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %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; }

Contributors

PersonTokensPropCommitsCommitProp
Rob Herring10817.88%27.14%
Patrick Mochel9115.07%27.14%
Rafael J. Wysocki9115.07%27.14%
Kay Sievers457.45%27.14%
Grant C. Likely416.79%27.14%
Greg Kroah-Hartman406.62%27.14%
Grygorii Strashko345.63%27.14%
Russell King284.64%13.57%
Andy Shevchenko254.14%13.57%
Sergei Shtylyov182.98%13.57%
Tejun Heo172.81%13.57%
Wolfram Sang152.48%13.57%
Linus Walleij142.32%13.57%
Cornelia Huck101.66%27.14%
Hans de Goede71.16%13.57%
Andrew Morton60.99%13.57%
Douglas Anderson50.83%13.57%
Ulf Hansson50.83%13.57%
Harvey Harrison30.50%13.57%
Mark Brown10.17%13.57%
Total604100.00%28100.00%

/** * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman3497.14%150.00%
Harvey Harrison12.86%150.00%
Total35100.00%2100.00%

/** * wait_for_device_probe * Wait for device probing to be completed. */
void wait_for_device_probe(void) { /* wait for the deferred probe workqueue to finish */ flush_work(&deferred_probe_work); /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); async_synchronize_full(); }

Contributors

PersonTokensPropCommitsCommitProp
Arjan van de Ven1341.94%125.00%
Lei Ming1135.48%125.00%
Grygorii Strashko412.90%125.00%
Bhaktipriya Shridhar39.68%125.00%
Total31100.00%4100.00%

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. * * If the device has a parent, runtime-resume the parent before driver probing. */
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_suppliers(dev); if (dev->parent) pm_runtime_get_sync(dev->parent); pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); if (dev->parent) pm_runtime_put(dev->parent); pm_runtime_put_suppliers(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman4641.07%321.43%
Rafael J. Wysocki4540.18%321.43%
Alan Stern108.93%17.14%
Kay Sievers32.68%17.14%
Cornelia Huck32.68%17.14%
Patrick Mochel21.79%214.29%
Harvey Harrison10.89%17.14%
Ulf Hansson10.89%17.14%
Duncan Sands10.89%17.14%
Total112100.00%14100.00%


bool driver_allows_async_probing(struct device_driver *drv) { switch (drv->probe_type) { case PROBE_PREFER_ASYNCHRONOUS: return true; case PROBE_FORCE_SYNCHRONOUS: return false; default: if (module_requested_async_probing(drv->owner)) return true; return false; } }

Contributors

PersonTokensPropCommitsCommitProp
Luis R. Rodriguez2963.04%250.00%
Dmitry Torokhov1736.96%250.00%
Total46100.00%4100.00%

struct device_attach_data { struct device *dev; /* * Indicates whether we are are considering asynchronous probing or * not. Only initial binding after device or driver registration * (including deferral processing) may be done asynchronously, the * rest is always synchronous, as we expect it is being done by * request from userspace. */ bool check_async; /* * Indicates if we are binding synchronous or asynchronous drivers. * When asynchronous probing is enabled we'll execute 2 passes * over drivers: first pass doing synchronous probing and second * doing asynchronous probing (if synchronous did not succeed - * most likely because there was no driver requiring synchronous * probing - and we found asynchronous driver during first pass). * The 2 passes are done because we can't shoot asynchronous * probe for given device and driver from bus_for_each_drv() since * driver pointer is not guaranteed to stay valid once * bus_for_each_drv() iterates to the next driver on the bus. */ bool want_async; /* * We'll set have_async to 'true' if, while scanning for matching * driver, we'll encounter one that requests asynchronous probing. */ bool have_async; };
static int __device_attach_driver(struct device_driver *drv, void *_data) { struct device_attach_data *data = _data; struct device *dev = data->dev; bool async_allowed; int ret; /* * Check if device has already been claimed. This may * happen with driver loading, device discovery/registration, * and deferred probe processing happens all at once with * multiple threads. */ if (dev->driver) return -EBUSY; ret = driver_match_device(drv, dev); if (ret == 0) { /* no match */ return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d", ret); return ret; } /* ret > 0 means positive match */ async_allowed = driver_allows_async_probing(drv); if (async_allowed) data->have_async = true; if (data->check_async && async_allowed != data->want_async) return 0; return driver_probe_device(drv, dev); }

Contributors

PersonTokensPropCommitsCommitProp
Tomeu Vizoso5837.91%116.67%
Dmitry Torokhov5737.25%116.67%
Patrick Mochel2717.65%233.33%
Lei Ming106.54%116.67%
Greg Kroah-Hartman10.65%116.67%
Total153100.00%6100.00%


static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) { struct device *dev = _dev; struct device_attach_data data = { .dev = dev, .check_async = true, .want_async = true, }; device_lock(dev); if (dev->parent) pm_runtime_get_sync(dev->parent); bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); dev_dbg(dev, "async probe completed\n"); pm_request_idle(dev); if (dev->parent) pm_runtime_put(dev->parent); device_unlock(dev); put_device(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov8275.93%150.00%
Rafael J. Wysocki2624.07%150.00%
Total108100.00%2100.00%


static int __device_attach(struct device *dev, bool allow_async) { int ret = 0; device_lock(dev); if (dev->driver) { if (device_is_bound(dev)) { ret = 1; goto out_unlock; } ret = device_bind_driver(dev); if (ret == 0) ret = 1; else { dev->driver = NULL; ret = 0; } } else { struct device_attach_data data = { .dev = dev, .check_async = allow_async, .want_async = false, }; if (dev->parent) pm_runtime_get_sync(dev->parent); ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); if (!ret && allow_async && data.have_async) { /* * If we could not find appropriate driver * synchronously and we are allowed to do * async probes and there are drivers that * want to probe asynchronously, we'll * try them. */ dev_dbg(dev, "scheduling asynchronous probe\n"); get_device(dev); async_schedule(__device_attach_async_helper, dev); } else { pm_request_idle(dev); } if (dev->parent) pm_runtime_put(dev->parent); } out_unlock: device_unlock(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov6432.82%214.29%
Patrick Mochel5729.23%321.43%
Rafael J. Wysocki3015.38%214.29%
Sebastian Ott178.72%17.14%
Cornelia Huck157.69%214.29%
Andrew Morton84.10%17.14%
Greg Kroah-Hartman21.03%17.14%
Ulf Hansson10.51%17.14%
Tomeu Vizoso10.51%17.14%
Total195100.00%14100.00%

/** * 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) { return __device_attach(dev, false); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov18100.00%1100.00%
Total18100.00%1100.00%

EXPORT_SYMBOL_GPL(device_attach);
void device_initial_probe(struct device *dev) { __device_attach(dev, true); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov17100.00%1100.00%
Total17100.00%1100.00%


static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; int ret; /* * 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. */ ret = driver_match_device(drv, dev); if (ret == 0) { /* no match */ return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d", ret); return ret; } /* ret > 0 means positive match */ 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; }

Contributors

PersonTokensPropCommitsCommitProp
Tomeu Vizoso5840.00%112.50%
Patrick Mochel4833.10%337.50%
Alan Stern2315.86%112.50%
Arjan van de Ven96.21%112.50%
Greg Kroah-Hartman42.76%112.50%
Lei Ming32.07%112.50%
Total145100.00%8100.00%

/** * 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); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel2187.50%266.67%
Andrew Morton312.50%133.33%
Total24100.00%3100.00%

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 *parent) { struct device_driver *drv; drv = dev->driver; if (drv) { if (driver_allows_async_probing(drv)) async_synchronize_full(); while (device_links_busy(dev)) { device_unlock(dev); if (parent) device_unlock(parent); device_links_unbind_consumers(dev); if (parent) device_lock(parent); device_lock(dev); /* * A concurrent invocation of the same function might * have released the driver successfully while this one * was waiting, so check for that. */ if (dev->driver != drv) return; } pm_runtime_get_sync(dev); pm_runtime_clean_up_links(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); device_links_driver_cleanup(dev); devres_release_all(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); pm_runtime_reinit(dev); klist_remove(&dev->p->knode_driver); device_pm_check_callbacks(dev); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBOUND_DRIVER, dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki9837.98%627.27%
Patrick Mochel4718.22%29.09%
Joerg Roedel228.53%14.55%
Benjamin Herrenschmidt207.75%14.55%
Russell King186.98%14.55%
Alan Stern166.20%313.64%
Dmitry Torokhov103.88%14.55%
Hans de Goede72.71%14.55%
Tomeu Vizoso51.94%14.55%
Tejun Heo51.94%14.55%
Ulf Hansson51.94%14.55%
Greg Kroah-Hartman41.55%29.09%
Kay Sievers10.39%14.55%
Total258100.00%22100.00%


void device_release_driver_internal(struct device *dev, struct device_driver *drv, struct device *parent) { if (parent) device_lock(parent); device_lock(dev); if (!drv || drv == dev->driver) __device_release_driver(dev, parent); device_unlock(dev); if (parent) device_unlock(parent); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki4365.15%240.00%
Patrick Mochel1116.67%120.00%
Alan Stern1015.15%120.00%
Greg Kroah-Hartman23.03%120.00%
Total66100.00%5100.00%

/** * 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. * * If this function is to be called with @dev->parent lock held, ensure that * the device's consumers are unbound in advance or that their locks can be * acquired under the @dev->parent lock. */
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_release_driver_internal(dev, NULL, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki1995.00%150.00%
Patrick Mochel15.00%150.00%
Total20100.00%2100.00%

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); device_release_driver_internal(dev, drv, dev->parent); put_device(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Alan Stern8968.99%337.50%
Greg Kroah-Hartman2317.83%225.00%
Patrick Mochel1410.85%225.00%
Rafael J. Wysocki32.33%112.50%
Total129100.00%8100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel39013.79%44.82%
Rafael J. Wysocki36913.05%910.84%
Grant C. Likely36212.80%33.61%
Dmitry Torokhov28810.18%33.61%
Greg Kroah-Hartman2348.27%1113.25%
Tomeu Vizoso1495.27%33.61%
Alan Stern1485.23%67.23%
Kay Sievers1344.74%22.41%
Rob Herring1083.82%22.41%
Andrew Morton802.83%22.41%
Grygorii Strashko742.62%22.41%
Andy Shevchenko481.70%11.20%
Russell King461.63%11.20%
Cornelia Huck431.52%44.82%
Benjamin Herrenschmidt401.41%11.20%
Arjan van de Ven331.17%33.61%
Luis R. Rodriguez291.03%22.41%
Lei Ming250.88%22.41%
Joerg Roedel220.78%11.20%
Tejun Heo220.78%11.20%
Magnus Damm220.78%11.20%
Stefani Seibold190.67%11.20%
Sergei Shtylyov180.64%11.20%
Linus Walleij170.60%11.20%
Sebastian Ott170.60%11.20%
Wolfram Sang150.53%11.20%
Hans de Goede140.50%11.20%
Mark Brown130.46%22.41%
Ulf Hansson120.42%22.41%
Daniel Ritz80.28%11.20%
Bhaktipriya Shridhar70.25%11.20%
Frank Rowand70.25%11.20%
Harvey Harrison60.21%11.20%
Douglas Anderson50.18%11.20%
Thierry Reding10.04%11.20%
Kuninori Morimoto10.04%11.20%
Shailendra Verma10.04%11.20%
Duncan Sands10.04%11.20%
Total2828100.00%83100.00%
Directory: drivers/base
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.