cregit-Linux how code gets into the kernel

Release 4.7 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 struct workqueue_struct *deferred_wq;

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 likelygrant likely9677.42%125.00%
greg kroah-hartmangreg kroah-hartman1612.90%250.00%
mark brownmark 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 likelygrant likely5291.23%133.33%
greg kroah-hartmangreg kroah-hartman47.02%133.33%
kuninori morimotokuninori 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 likelygrant likely5092.59%150.00%
greg kroah-hartmangreg 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. */ queue_work(deferred_wq, &deferred_probe_work); }

Contributors

PersonTokensPropCommitsCommitProp
grant likelygrant likely4996.08%266.67%
greg kroah-hartmangreg kroah-hartman23.92%133.33%
Total51100.00%3100.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 strashkogrygorii 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 strashkogrygorii 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) { deferred_wq = create_singlethread_workqueue("deferwq"); if (WARN_ON(!deferred_wq)) return -ENOMEM; driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); /* Sort as many dependencies as possible before exiting initcalls */ flush_workqueue(deferred_wq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
grant likelygrant likely43100.00%2100.00%
Total43100.00%2100.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 mochelpatrick mochel728.00%120.00%
daniel ritzdaniel ritz728.00%120.00%
tomeu vizosotomeu vizoso520.00%120.00%
rafael j. wysockirafael j. wysocki416.00%120.00%
greg kroah-hartmangreg 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_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 vizosotomeu vizoso2119.09%214.29%
benjamin herrenschmidtbenjamin herrenschmidt2018.18%17.14%
stefani seiboldstefani seibold1917.27%17.14%
andrew mortonandrew morton1715.45%17.14%
patrick mochelpatrick mochel109.09%17.14%
grant likelygrant likely87.27%17.14%
frank rowandfrank rowand76.36%17.14%
greg kroah-hartmangreg kroah-hartman43.64%321.43%
kay sieverskay sievers21.82%17.14%
daniel ritzdaniel ritz10.91%17.14%
harvey harrisonharvey harrison10.91%17.14%
Total110100.00%14100.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 mochelpatrick mochel4134.45%120.00%
andrew mortonandrew morton3731.09%120.00%
magnus dammmagnus damm2218.49%120.00%
kay sieverskay sievers1310.92%120.00%
greg kroah-hartmangreg 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 sieverskay sievers5296.30%150.00%
greg kroah-hartmangreg 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 shevchenkoandy shevchenko2341.07%133.33%
kay sieverskay sievers1832.14%133.33%
cornelia huckcornelia 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); 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; } 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 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; } 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: 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
patrick mochelpatrick mochel9119.08%28.00%
rafael j. wysockirafael j. wysocki7215.09%14.00%
kay sieverskay sievers459.43%28.00%
grant likelygrant likely418.60%28.00%
greg kroah-hartmangreg kroah-hartman408.39%28.00%
grygorii strashkogrygorii strashko347.13%28.00%
russell kingrussell king285.87%14.00%
andy shevchenkoandy shevchenko255.24%14.00%
sergei shtylyovsergei shtylyov183.77%14.00%
tejun heotejun heo173.56%14.00%
wolfram sangwolfram sang153.14%14.00%
linus walleijlinus walleij142.94%14.00%
cornelia huckcornelia huck102.10%28.00%
hans de goedehans de goede71.47%14.00%
andrew mortonandrew morton61.26%14.00%
ulf hanssonulf hansson51.05%14.00%
douglas andersondouglas anderson51.05%14.00%
harvey harrisonharvey harrison30.63%14.00%
mark brownmark brown10.21%14.00%
Total477100.00%25100.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-hartmangreg kroah-hartman3497.14%150.00%
harvey harrisonharvey 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 */ if (driver_deferred_probe_enable) flush_workqueue(deferred_wq); /* 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 venarjan van de ven1338.24%133.33%
lei minglei ming1132.35%133.33%
grygorii strashkogrygorii strashko1029.41%133.33%
Total34100.00%3100.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); 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); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
greg kroah-hartmangreg kroah-hartman4645.10%323.08%
rafael j. wysockirafael j. wysocki3534.31%215.38%
alan sternalan stern109.80%17.69%
cornelia huckcornelia huck32.94%17.69%
kay sieverskay sievers32.94%17.69%
patrick mochelpatrick mochel21.96%215.38%
harvey harrisonharvey harrison10.98%17.69%
ulf hanssonulf hansson10.98%17.69%
duncan sandsduncan sands10.98%17.69%
Total102100.00%13100.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. rodriguezluis r. rodriguez2963.04%250.00%
dmitry torokhovdmitry 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 vizosotomeu vizoso5837.91%116.67%
dmitry torokhovdmitry torokhov5737.25%116.67%
patrick mochelpatrick mochel2717.65%233.33%
lei minglei ming106.54%116.67%
greg kroah-hartmangreg 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 torokhovdmitry torokhov8275.93%150.00%
rafael j. wysockirafael 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 torokhovdmitry torokhov6432.82%214.29%
patrick mochelpatrick mochel5729.23%321.43%
rafael j. wysockirafael j. wysocki3015.38%214.29%
sebastian ottsebastian ott178.72%17.14%
cornelia huckcornelia huck157.69%214.29%
andrew mortonandrew morton84.10%17.14%
greg kroah-hartmangreg kroah-hartman21.03%17.14%
tomeu vizosotomeu vizoso10.51%17.14%
ulf hanssonulf hansson10.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 torokhovdmitry 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 torokhovdmitry 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 vizosotomeu vizoso5840.00%112.50%
patrick mochelpatrick mochel4833.10%337.50%
alan sternalan stern2315.86%112.50%
arjan van de venarjan van de ven96.21%112.50%
greg kroah-hartmangreg kroah-hartman42.76%112.50%
lei minglei 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 mochelpatrick mochel2187.50%266.67%
andrew mortonandrew 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_driver *drv; drv = dev->driver; if (drv) { if (driver_allows_async_probing(drv)) async_synchronize_full(); 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; 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
patrick mochelpatrick mochel4724.61%210.00%
rafael j. wysockirafael j. wysocki3116.23%420.00%
joerg roedeljoerg roedel2211.52%15.00%
benjamin herrenschmidtbenjamin herrenschmidt2010.47%15.00%
russell kingrussell king189.42%15.00%
alan sternalan stern168.38%315.00%
dmitry torokhovdmitry torokhov105.24%15.00%
hans de goedehans de goede73.66%15.00%
tejun heotejun heo52.62%15.00%
ulf hanssonulf hansson52.62%15.00%
tomeu vizosotomeu vizoso52.62%15.00%
greg kroah-hartmangreg kroah-hartman42.09%210.00%
kay sieverskay sievers10.52%15.00%
Total191100.00%20100.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. */
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); }

Contributors

PersonTokensPropCommitsCommitProp
patrick mochelpatrick mochel1246.15%133.33%
alan sternalan stern1246.15%133.33%
greg kroah-hartmangreg kroah-hartman27.69%133.33%
Total26100.00%3100.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); 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); } }

Contributors

PersonTokensPropCommitsCommitProp
alan sternalan stern12574.40%337.50%
greg kroah-hartmangreg kroah-hartman2716.07%337.50%
patrick mochelpatrick mochel169.52%225.00%
Total168100.00%8100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
grant likelygrant likely39214.92%33.90%
patrick mochelpatrick mochel39214.92%45.19%
dmitry torokhovdmitry torokhov28810.96%33.90%
greg kroah-hartmangreg kroah-hartman2399.10%1114.29%
rafael j. wysockirafael j. wysocki2027.69%67.79%
alan sternalan stern1867.08%67.79%
tomeu vizosotomeu vizoso1495.67%33.90%
kay sieverskay sievers1345.10%22.60%
grygorii strashkogrygorii strashko803.05%22.60%
andrew mortonandrew morton803.05%22.60%
andy shevchenkoandy shevchenko481.83%11.30%
russell kingrussell king461.75%11.30%
cornelia huckcornelia huck431.64%45.19%
benjamin herrenschmidtbenjamin herrenschmidt401.52%11.30%
arjan van de venarjan van de ven331.26%33.90%
luis r. rodriguezluis r. rodriguez291.10%22.60%
lei minglei ming250.95%22.60%
joerg roedeljoerg roedel220.84%11.30%
magnus dammmagnus damm220.84%11.30%
tejun heotejun heo220.84%11.30%
stefani seiboldstefani seibold190.72%11.30%
sergei shtylyovsergei shtylyov180.69%11.30%
linus walleijlinus walleij170.65%11.30%
sebastian ottsebastian ott170.65%11.30%
wolfram sangwolfram sang150.57%11.30%
hans de goedehans de goede140.53%11.30%
mark brownmark brown130.49%22.60%
ulf hanssonulf hansson120.46%22.60%
daniel ritzdaniel ritz80.30%11.30%
frank rowandfrank rowand70.27%11.30%
harvey harrisonharvey harrison60.23%11.30%
douglas andersondouglas anderson50.19%11.30%
thierry redingthierry reding10.04%11.30%
shailendra vermashailendra verma10.04%11.30%
duncan sandsduncan sands10.04%11.30%
kuninori morimotokuninori morimoto10.04%11.30%
Total2627100.00%77100.00%
Directory: drivers/base
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}