cregit-Linux how code gets into the kernel

Release 4.14 drivers/base/core.c

Directory: drivers/base
/*
 * drivers/base/core.c - core driver model code (device registration, etc)
 *
 * Copyright (c) 2002-3 Patrick Mochel
 * Copyright (c) 2002-3 Open Source Development Labs
 * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de>
 * Copyright (c) 2006 Novell, Inc.
 *
 * This file is released under the GPLv2
 *
 */

#include <linux/device.h>
#include <linux/err.h>
#include <linux/fwnode.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kdev_t.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/genhd.h>
#include <linux/kallsyms.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/netdevice.h>
#include <linux/sched/signal.h>
#include <linux/sysfs.h>

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

#ifdef CONFIG_SYSFS_DEPRECATED
#ifdef CONFIG_SYSFS_DEPRECATED_V2

long sysfs_deprecated = 1;
#else

long sysfs_deprecated = 0;
#endif

static int __init sysfs_deprecated_setup(char *arg) { return kstrtol(arg, 10, &sysfs_deprecated); }

Contributors

PersonTokensPropCommitsCommitProp
Andi Kleen2090.91%133.33%
Jingoo Han14.55%133.33%
Hanjun Guo14.55%133.33%
Total22100.00%3100.00%

early_param("sysfs.deprecated", sysfs_deprecated_setup); #endif /* Device links support. */ #ifdef CONFIG_SRCU static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu);
static inline void device_links_write_lock(void) { mutex_lock(&device_links_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki15100.00%1100.00%
Total15100.00%1100.00%


static inline void device_links_write_unlock(void) { mutex_unlock(&device_links_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki15100.00%1100.00%
Total15100.00%1100.00%


int device_links_read_lock(void) { return srcu_read_lock(&device_links_srcu); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki14100.00%1100.00%
Total14100.00%1100.00%


void device_links_read_unlock(int idx) { srcu_read_unlock(&device_links_srcu, idx); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki16100.00%1100.00%
Total16100.00%1100.00%

#else /* !CONFIG_SRCU */ static DECLARE_RWSEM(device_links_lock);
static inline void device_links_write_lock(void) { down_write(&device_links_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki15100.00%1100.00%
Total15100.00%1100.00%


static inline void device_links_write_unlock(void) { up_write(&device_links_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki15100.00%1100.00%
Total15100.00%1100.00%


int device_links_read_lock(void) { down_read(&device_links_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki16100.00%1100.00%
Total16100.00%1100.00%


void device_links_read_unlock(int not_used) { up_read(&device_links_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki14100.00%1100.00%
Total14100.00%1100.00%

#endif /* !CONFIG_SRCU */ /** * device_is_dependent - Check if one device depends on another one * @dev: Device to check dependencies for. * @target: Device to check against. * * Check if @target depends on @dev or any device dependent on it (its child or * its consumer etc). Return 1 if that is the case or 0 otherwise. */
static int device_is_dependent(struct device *dev, void *target) { struct device_link *link; int ret; if (WARN_ON(dev == target)) return 1; ret = device_for_each_child(dev, target, device_is_dependent); if (ret) return ret; list_for_each_entry(link, &dev->links.consumers, s_node) { if (WARN_ON(link->consumer == target)) return 1; ret = device_is_dependent(link->consumer, target); if (ret) break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki96100.00%1100.00%
Total96100.00%1100.00%


static int device_reorder_to_tail(struct device *dev, void *not_used) { struct device_link *link; /* * Devices that have not been registered yet will be put to the ends * of the lists during the registration, so skip them here. */ if (device_is_registered(dev)) devices_kset_move_last(dev); if (device_pm_initialized(dev)) device_pm_move_last(dev); device_for_each_child(dev, NULL, device_reorder_to_tail); list_for_each_entry(link, &dev->links.consumers, s_node) device_reorder_to_tail(link->consumer, NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki74100.00%1100.00%
Total74100.00%1100.00%

/** * device_link_add - Create a link between two devices. * @consumer: Consumer end of the link. * @supplier: Supplier end of the link. * @flags: Link flags. * * The caller is responsible for the proper synchronization of the link creation * with runtime PM. First, setting the DL_FLAG_PM_RUNTIME flag will cause the * runtime PM framework to take the link into account. Second, if the * DL_FLAG_RPM_ACTIVE flag is set in addition to it, the supplier devices will * be forced into the active metastate and reference-counted upon the creation * of the link. If DL_FLAG_PM_RUNTIME is not set, DL_FLAG_RPM_ACTIVE will be * ignored. * * If the DL_FLAG_AUTOREMOVE is set, the link will be removed automatically * when the consumer device driver unbinds from it. The combination of both * DL_FLAG_AUTOREMOVE and DL_FLAG_STATELESS set is invalid and will cause NULL * to be returned. * * A side effect of the link creation is re-ordering of dpm_list and the * devices_kset list by moving the consumer device and all devices depending * on it to the ends of these lists (that does not happen to devices that have * not been registered when this function is called). * * The supplier device is required to be registered when this function is called * and NULL will be returned if that is not the case. The consumer device need * not be registered, however. */
struct device_link *device_link_add(struct device *consumer, struct device *supplier, u32 flags) { struct device_link *link; if (!consumer || !supplier || ((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE))) return NULL; device_links_write_lock(); device_pm_lock(); /* * If the supplier has not been fully registered yet or there is a * reverse dependency between the consumer and the supplier already in * the graph, return NULL. */ if (!device_pm_initialized(supplier) || device_is_dependent(consumer, supplier)) { link = NULL; goto out; } list_for_each_entry(link, &supplier->links.consumers, s_node) if (link->consumer == consumer) goto out; link = kzalloc(sizeof(*link), GFP_KERNEL); if (!link) goto out; if (flags & DL_FLAG_PM_RUNTIME) { if (flags & DL_FLAG_RPM_ACTIVE) { if (pm_runtime_get_sync(supplier) < 0) { pm_runtime_put_noidle(supplier); kfree(link); link = NULL; goto out; } link->rpm_active = true; } pm_runtime_new_link(consumer); } get_device(supplier); link->supplier = supplier; INIT_LIST_HEAD(&link->s_node); get_device(consumer); link->consumer = consumer; INIT_LIST_HEAD(&link->c_node); link->flags = flags; /* Determine the initial link state. */ if (flags & DL_FLAG_STATELESS) { link->status = DL_STATE_NONE; } else { switch (supplier->links.status) { case DL_DEV_DRIVER_BOUND: switch (consumer->links.status) { case DL_DEV_PROBING: /* * Balance the decrementation of the supplier's * runtime PM usage counter after consumer probe * in driver_probe_device(). */ if (flags & DL_FLAG_PM_RUNTIME) pm_runtime_get_sync(supplier); link->status = DL_STATE_CONSUMER_PROBE; break; case DL_DEV_DRIVER_BOUND: link->status = DL_STATE_ACTIVE; break; default: link->status = DL_STATE_AVAILABLE; break; } break; case DL_DEV_UNBINDING: link->status = DL_STATE_SUPPLIER_UNBIND; break; default: link->status = DL_STATE_DORMANT; break; } } /* * Move the consumer and all of the devices depending on it to the end * of dpm_list and the devices_kset list. * * It is necessary to hold dpm_list locked throughout all that or else * we may end up suspending with a wrong ordering of it. */ device_reorder_to_tail(consumer, NULL); list_add_tail_rcu(&link->s_node, &supplier->links.consumers); list_add_tail_rcu(&link->c_node, &consumer->links.suppliers); dev_info(consumer, "Linked as a consumer to %s\n", dev_name(supplier)); out: device_pm_unlock(); device_links_write_unlock(); return link; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki38099.74%375.00%
Lukas Wunner10.26%125.00%
Total381100.00%4100.00%

EXPORT_SYMBOL_GPL(device_link_add);
static void device_link_free(struct device_link *link) { put_device(link->consumer); put_device(link->supplier); kfree(link); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki30100.00%1100.00%
Total30100.00%1100.00%

#ifdef CONFIG_SRCU
static void __device_link_free_srcu(struct rcu_head *rhead) { device_link_free(container_of(rhead, struct device_link, rcu_head)); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki24100.00%1100.00%
Total24100.00%1100.00%


static void __device_link_del(struct device_link *link) { dev_info(link->consumer, "Dropping the link to %s\n", dev_name(link->supplier)); if (link->flags & DL_FLAG_PM_RUNTIME) pm_runtime_drop_link(link->consumer); list_del_rcu(&link->s_node); list_del_rcu(&link->c_node); call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki71100.00%2100.00%
Total71100.00%2100.00%

#else /* !CONFIG_SRCU */
static void __device_link_del(struct device_link *link) { dev_info(link->consumer, "Dropping the link to %s\n", dev_name(link->supplier)); list_del(&link->s_node); list_del(&link->c_node); device_link_free(link); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki48100.00%1100.00%
Total48100.00%1100.00%

#endif /* !CONFIG_SRCU */ /** * device_link_del - Delete a link between two devices. * @link: Device link to delete. * * The caller must ensure proper synchronization of this function with runtime * PM. */
void device_link_del(struct device_link *link) { device_links_write_lock(); device_pm_lock(); __device_link_del(link); device_pm_unlock(); device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki27100.00%1100.00%
Total27100.00%1100.00%

EXPORT_SYMBOL_GPL(device_link_del);
static void device_links_missing_supplier(struct device *dev) { struct device_link *link; list_for_each_entry(link, &dev->links.suppliers, c_node) if (link->status == DL_STATE_CONSUMER_PROBE) WRITE_ONCE(link->status, DL_STATE_AVAILABLE); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki41100.00%1100.00%
Total41100.00%1100.00%

/** * device_links_check_suppliers - Check presence of supplier drivers. * @dev: Consumer device. * * Check links from this device to any suppliers. Walk the list of the device's * links to suppliers and see if all of them are available. If not, simply * return -EPROBE_DEFER. * * We need to guarantee that the supplier will not go away after the check has * been positive here. It only can go away in __device_release_driver() and * that function checks the device's links to consumers. This means we need to * mark the link as "consumer probe in progress" to make the supplier removal * wait for us to complete (or bad things may happen). * * Links with the DL_FLAG_STATELESS flag set are ignored. */
int device_links_check_suppliers(struct device *dev) { struct device_link *link; int ret = 0; device_links_write_lock(); list_for_each_entry(link, &dev->links.suppliers, c_node) { if (link->flags & DL_FLAG_STATELESS) continue; if (link->status != DL_STATE_AVAILABLE) { device_links_missing_supplier(dev); ret = -EPROBE_DEFER; break; } WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE); } dev->links.status = DL_DEV_PROBING; device_links_write_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki86100.00%1100.00%
Total86100.00%1100.00%

/** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. * * The probe has been successful, so update links from this device to any * consumers by changing their status to "available". * * Also change the status of @dev's links to suppliers to "active". * * Links with the DL_FLAG_STATELESS flag set are ignored. */
void device_links_driver_bound(struct device *dev) { struct device_link *link; device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { if (link->flags & DL_FLAG_STATELESS) continue; WARN_ON(link->status != DL_STATE_DORMANT); WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } list_for_each_entry(link, &dev->links.suppliers, c_node) { if (link->flags & DL_FLAG_STATELESS) continue; WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_ACTIVE); } dev->links.status = DL_DEV_DRIVER_BOUND; device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki103100.00%1100.00%
Total103100.00%1100.00%

/** * __device_links_no_driver - Update links of a device without a driver. * @dev: Device without a drvier. * * Delete all non-persistent links from this device to any suppliers. * * Persistent links stay around, but their status is changed to "available", * unless they already are in the "supplier unbind in progress" state in which * case they need not be updated. * * Links with the DL_FLAG_STATELESS flag set are ignored. */
static void __device_links_no_driver(struct device *dev) { struct device_link *link, *ln; list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { if (link->flags & DL_FLAG_STATELESS) continue; if (link->flags & DL_FLAG_AUTOREMOVE) __device_link_del(link); else if (link->status != DL_STATE_SUPPLIER_UNBIND) WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } dev->links.status = DL_DEV_NO_DRIVER; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki79100.00%1100.00%
Total79100.00%1100.00%


void device_links_no_driver(struct device *dev) { device_links_write_lock(); __device_links_no_driver(dev); device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki21100.00%1100.00%
Total21100.00%1100.00%

/** * device_links_driver_cleanup - Update links after driver removal. * @dev: Device whose driver has just gone away. * * Update links to consumers for @dev by changing their status to "dormant" and * invoke %__device_links_no_driver() to update links to suppliers for it as * appropriate. * * Links with the DL_FLAG_STATELESS flag set are ignored. */
void device_links_driver_cleanup(struct device *dev) { struct device_link *link; device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { if (link->flags & DL_FLAG_STATELESS) continue; WARN_ON(link->flags & DL_FLAG_AUTOREMOVE); WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND); WRITE_ONCE(link->status, DL_STATE_DORMANT); } __device_links_no_driver(dev); device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki72100.00%1100.00%
Total72100.00%1100.00%

/** * device_links_busy - Check if there are any busy links to consumers. * @dev: Device to check. * * Check each consumer of the device and return 'true' if its link's status * is one of "consumer probe" or "active" (meaning that the given consumer is * probing right now or its driver is present). Otherwise, change the link * state to "supplier unbind" to prevent the consumer from being probed * successfully going forward. * * Return 'false' if there are no probing or active consumers. * * Links with the DL_FLAG_STATELESS flag set are ignored. */
bool device_links_busy(struct device *dev) { struct device_link *link; bool ret = false; device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { if (link->flags & DL_FLAG_STATELESS) continue; if (link->status == DL_STATE_CONSUMER_PROBE || link->status == DL_STATE_ACTIVE) { ret = true; break; } WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND); } dev->links.status = DL_DEV_UNBINDING; device_links_write_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki86100.00%1100.00%
Total86100.00%1100.00%

/** * device_links_unbind_consumers - Force unbind consumers of the given device. * @dev: Device to unbind the consumers of. * * Walk the list of links to consumers for @dev and if any of them is in the * "consumer probe" state, wait for all device probes in progress to complete * and start over. * * If that's not the case, change the status of the link to "supplier unbind" * and check if the link was in the "active" state. If so, force the consumer * driver to unbind and start over (the consumer will not re-probe as we have * changed the state of the link already). * * Links with the DL_FLAG_STATELESS flag set are ignored. */
void device_links_unbind_consumers(struct device *dev) { struct device_link *link; start: device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { enum device_link_state status; if (link->flags & DL_FLAG_STATELESS) continue; status = link->status; if (status == DL_STATE_CONSUMER_PROBE) { device_links_write_unlock(); wait_for_device_probe(); goto start; } WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND); if (status == DL_STATE_ACTIVE) { struct device *consumer = link->consumer; get_device(consumer); device_links_write_unlock(); device_release_driver_internal(consumer, NULL, consumer->parent); put_device(consumer); goto start; } } device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki122100.00%1100.00%
Total122100.00%1100.00%

/** * device_links_purge - Delete existing links to other devices. * @dev: Target device. */
static void device_links_purge(struct device *dev) { struct device_link *link, *ln; /* * Delete all of the remaining links from this device to any other * devices (either consumers or suppliers). */ device_links_write_lock(); list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { WARN_ON(link->status == DL_STATE_ACTIVE); __device_link_del(link); } list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) { WARN_ON(link->status != DL_STATE_DORMANT && link->status != DL_STATE_NONE); __device_link_del(link); } device_links_write_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki84100.00%1100.00%
Total84100.00%1100.00%

/* Device links support end. */ int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; struct kobject *sysfs_dev_char_kobj; struct kobject *sysfs_dev_block_kobj; static DEFINE_MUTEX(device_hotplug_lock);
void lock_device_hotplug(void) { mutex_lock(&device_hotplug_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki13100.00%1100.00%
Total13100.00%1100.00%


void unlock_device_hotplug(void) { mutex_unlock(&device_hotplug_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki13100.00%1100.00%
Total13100.00%1100.00%


int lock_device_hotplug_sysfs(void) { if (mutex_trylock(&device_hotplug_lock)) return 0; /* Avoid busy looping (5 ms of sleep should do). */ msleep(5); return restart_syscall(); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki28100.00%1100.00%
Total28100.00%1100.00%

#ifdef CONFIG_BLOCK
static inline int device_is_not_partition(struct device *dev) { return !(dev->type == &part_type); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman23100.00%1100.00%
Total23100.00%1100.00%

#else
static inline int device_is_not_partition(struct device *dev) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman15100.00%1100.00%
Total15100.00%1100.00%

#endif /** * dev_driver_string - Return a device's driver name, if at all possible * @dev: struct device to get the name of * * Will return the device's driver's name if it is bound to a device. If * the device is not bound to a driver, it will return the name of the bus * it is attached to. If it is not attached to a bus either, an empty * string will be returned. */
const char *dev_driver_string(const struct device *dev) { struct device_driver *drv; /* dev->driver can change to NULL underneath us because of unbinding, * so be careful about accessing it. dev->bus and dev->class should * never change once they are set, so they don't need special care. */ drv = ACCESS_ONCE(dev->driver); return drv ? drv->name : (dev->bus ? dev->bus->name : (dev->class ? dev->class->name : "")); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Stern4878.69%250.00%
Jean Delvare1321.31%250.00%
Total61100.00%4100.00%

EXPORT_SYMBOL(dev_driver_string); #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct device_attribute *dev_attr = to_dev_attr(attr); struct device *dev = kobj_to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { print_symbol("dev_attr_show: %s returned bad count\n", (unsigned long)dev_attr->show); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel6368.48%116.67%
Andrew Morton1819.57%116.67%
Greg Kroah-Hartman66.52%116.67%
Dmitry Torokhov22.17%116.67%
Yani Ioannou22.17%116.67%
Lars-Peter Clausen11.09%116.67%
Total92100.00%6100.00%


static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct device_attribute *dev_attr = to_dev_attr(attr); struct device *dev = kobj_to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->store) ret = dev_attr->store(dev, dev_attr, buf, count); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel6993.24%240.00%
Dmitry Torokhov22.70%120.00%
Yani Ioannou22.70%120.00%
Lars-Peter Clausen11.35%120.00%
Total74100.00%5100.00%

static const struct sysfs_ops dev_sysfs_ops = { .show = dev_attr_show, .store = dev_attr_store, }; #define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr)
ssize_t device_store_ulong(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_ext_attribute *ea = to_ext_attr(attr); char *end; unsigned long new = simple_strtoul(buf, &end, 0); if (end == buf) return -EINVAL; *(unsigned long *)(ea->var) = new; /* Always return full write size even if we didn't consume all */ return size; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers79100.00%1100.00%
Total79100.00%1100.00%

EXPORT_SYMBOL_GPL(device_store_ulong);
ssize_t device_show_ulong(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_ext_attribute *ea = to_ext_attr(attr); return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers51100.00%1100.00%
Total51100.00%1100.00%

EXPORT_SYMBOL_GPL(device_show_ulong);
ssize_t device_store_int(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_ext_attribute *ea = to_ext_attr(attr); char *end; long new = simple_strtol(buf, &end, 0); if (end == buf || new > INT_MAX || new < INT_MIN) return -EINVAL; *(int *)(ea->var) = new; /* Always return full write size even if we didn't consume all */ return size; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers85100.00%1100.00%
Total85100.00%1100.00%

EXPORT_SYMBOL_GPL(device_store_int);
ssize_t device_show_int(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_ext_attribute *ea = to_ext_attr(attr); return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers50100.00%1100.00%
Total50100.00%1100.00%

EXPORT_SYMBOL_GPL(device_show_int);
ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_ext_attribute *ea = to_ext_attr(attr); if (strtobool(buf, ea->var) < 0) return -EINVAL; return size; }

Contributors

PersonTokensPropCommitsCommitProp
Borislav Petkov53100.00%1100.00%
Total53100.00%1100.00%

EXPORT_SYMBOL_GPL(device_store_bool);
ssize_t device_show_bool(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_ext_attribute *ea = to_ext_attr(attr); return snprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var)); }

Contributors

PersonTokensPropCommitsCommitProp
Borislav Petkov50100.00%1100.00%
Total50100.00%1100.00%

EXPORT_SYMBOL_GPL(device_show_bool); /** * device_release - free device structure. * @kobj: device's kobject. * * This is called once the reference count for the object * reaches 0. We forward the call to the device's release * method, which should handle actually freeing the structure. */
static void device_release(struct kobject *kobj) { struct device *dev = kobj_to_dev(kobj); struct device_private *p = dev->p; /* * Some platform devices are driven without driver attached * and managed resources may have been acquired. Make sure * all resources are released. * * Drivers still can add resources into device after device * is deleted but alive, so release devres here to avoid * possible memory leak. */ devres_release_all(dev); if (dev->release) dev->release(dev); else if (dev->type && dev->type->release) dev->type->release(dev); else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", dev_name(dev)); kfree(p); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman4539.82%440.00%
Patrick Mochel3329.20%110.00%
Kay Sievers2522.12%220.00%
Lei Ming65.31%110.00%
Arjan van de Ven32.65%110.00%
Lars-Peter Clausen10.88%110.00%
Total113100.00%10100.00%


static const void *device_namespace(struct kobject *kobj) { struct device *dev = kobj_to_dev(kobj); const void *ns = NULL; if (dev->class && dev->class->ns_type) ns = dev->class->namespace(dev); return ns; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann5598.21%150.00%
Lars-Peter Clausen11.79%150.00%
Total56100.00%2100.00%

static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, .namespace = device_namespace, };
static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); if (ktype == &device_ktype) { struct device *dev = kobj_to_dev(kobj); if (dev->bus) return 1; if (dev->class) return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman6395.45%350.00%
Kay Sievers11.52%116.67%
Lars-Peter Clausen11.52%116.67%
Cornelia Huck11.52%116.67%
Total66100.00%6100.00%


static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) { struct device *dev = kobj_to_dev(kobj); if (dev->bus) return dev->bus->name; if (dev->class) return dev->class->name; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman5494.74%240.00%
Dmitry Torokhov11.75%120.00%
Kay Sievers11.75%120.00%
Lars-Peter Clausen11.75%120.00%
Total57100.00%5100.00%


static int dev_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env) { struct device *dev = kobj_to_dev(kobj); int retval = 0; /* add device node properties if present */ if (MAJOR(dev->devt)) { const char *tmp; const char *name; umode_t mode = 0; kuid_t uid = GLOBAL_ROOT_UID; kgid_t gid = GLOBAL_ROOT_GID; add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); name = device_get_devnode(dev, &mode, &uid, &gid, &tmp); if (name) { add_uevent_var(env, "DEVNAME=%s", name); if (mode) add_uevent_var(env, "DEVMODE=%#o", mode & 0777); if (!uid_eq(uid, GLOBAL_ROOT_UID)) add_uevent_var(env, "DEVUID=%u", from_kuid(&init_user_ns, uid)); if (!gid_eq(gid, GLOBAL_ROOT_GID)) add_uevent_var(env, "DEVGID=%u", from_kgid(&init_user_ns, gid)); kfree(tmp); } } if (dev->type && dev->type->name) add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) add_uevent_var(env, "DRIVER=%s", dev->driver->name); /* Add common DT information about the device */ of_device_uevent(dev, env); /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: bus uevent() returned %d\n", dev_name(dev), __func__, retval); } /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("device: '%s': %s: class uevent() " "returned %d\n", dev_name(dev), __func__, retval); } /* have the device type specific function add its stuff */ if (dev->type && dev->type->uevent) { retval = dev->type->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: dev_type uevent() " "returned %d\n", dev_name(dev), __func__, retval); } return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers20350.75%945.00%
Greg Kroah-Hartman17944.75%525.00%
Grant C. Likely82.00%15.00%
Alexander Nyberg41.00%15.00%
Harvey Harrison30.75%15.00%
Al Viro10.25%15.00%
Stefan Weil10.25%15.00%
Lars-Peter Clausen10.25%15.00%
Total400100.00%20100.00%

static const struct kset_uevent_ops device_uevent_ops = { .filter = dev_uevent_filter, .name = dev_uevent_name, .uevent = dev_uevent, };
static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kobject *top_kobj; struct kset *kset; struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; /* search the kset, the device belongs to */ top_kobj = &dev->kobj; while (!top_kobj->kset && top_kobj->parent) top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; /* respect filter */ if (kset->uevent_ops && kset->uevent_ops->filter) if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); if (!env) return -ENOMEM; /* let the kset specific function add its keys */ retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ for (i = 0; i < env->envp_idx; i++) count += sprintf(&buf[count], "%s\n", env->envp[i]); out: kfree(env); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers21391.42%360.00%
Greg Kroah-Hartman208.58%240.00%
Total233100.00%5100.00%


static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { if (kobject_synth_uevent(&dev->kobj, buf, count)) dev_err(dev, "uevent: failed to send synthetic uevent\n"); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers4185.42%360.00%
Peter Rajnoha612.50%120.00%
Greg Kroah-Hartman12.08%120.00%
Total48100.00%5100.00%

static DEVICE_ATTR_RW(uevent);
static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { bool val; device_lock(dev); val = !dev->offline; device_unlock(dev); return sprintf(buf, "%u\n", val); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki4998.00%266.67%
Greg Kroah-Hartman12.00%133.33%
Total50100.00%3100.00%


static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { bool val; int ret; ret = strtobool(buf, &val); if (ret < 0) return ret; ret = lock_device_hotplug_sysfs(); if (ret) return ret; ret = val ? device_online(dev) : device_offline(dev); unlock_device_hotplug(); return ret < 0 ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki8698.85%266.67%
Greg Kroah-Hartman11.15%133.33%
Total87100.00%3100.00%

static DEVICE_ATTR_RW(online);
int device_add_groups(struct device *dev, const struct attribute_group **groups) { return sysfs_create_groups(&dev->kobj, groups); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov1553.57%125.00%
Greg Kroah-Hartman1242.86%250.00%
David Brownell13.57%125.00%
Total28100.00%4100.00%

EXPORT_SYMBOL_GPL(device_add_groups);
void device_remove_groups(struct device *dev, const struct attribute_group **groups) { sysfs_remove_groups(&dev->kobj, groups); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman2074.07%250.00%
Dmitry Torokhov622.22%125.00%
David Brownell13.70%125.00%
Total27100.00%4100.00%

EXPORT_SYMBOL_GPL(device_remove_groups); union device_attr_group_devres { const struct attribute_group *group; const struct attribute_group **groups; };
static int devm_attr_group_match(struct device *dev, void *res, void *data) { return ((union device_attr_group_devres *)res)->group == data; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov33100.00%1100.00%
Total33100.00%1100.00%


static void devm_attr_group_remove(struct device *dev, void *res) { union device_attr_group_devres *devres = res; const struct attribute_group *group = devres->group; dev_dbg(dev, "%s: removing group %p\n", __func__, group); sysfs_remove_group(&dev->kobj, group); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov53100.00%1100.00%
Total53100.00%1100.00%


static void devm_attr_groups_remove(struct device *dev, void *res) { union device_attr_group_devres *devres = res; const struct attribute_group **groups = devres->groups; dev_dbg(dev, "%s: removing groups %p\n", __func__, groups); sysfs_remove_groups(&dev->kobj, groups); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov54100.00%1100.00%
Total54100.00%1100.00%

/** * devm_device_add_group - given a device, create a managed attribute group * @dev: The device to create the group for * @grp: The attribute group to create * * This function creates a group for the first time. It will explicitly * warn and error if any of the attribute files being created already exist. * * Returns 0 on success or error code on failure. */
int devm_device_add_group(struct device *dev, const struct attribute_group *grp) { union device_attr_group_devres *devres; int error; devres = devres_alloc(devm_attr_group_remove, sizeof(*devres), GFP_KERNEL); if (!devres) return -ENOMEM; error = sysfs_create_group(&dev->kobj, grp); if (error) { devres_free(devres); return error; } devres->group = grp; devres_add(dev, devres); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov90100.00%1100.00%
Total90100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_device_add_group); /** * devm_device_remove_group: remove a managed group from a device * @dev: device to remove the group from * @grp: group to remove * * This function removes a group of attributes from a device. The attributes * previously have to have been created for this group, otherwise it will fail. */
void devm_device_remove_group(struct device *dev, const struct attribute_group *grp) { WARN_ON(devres_release(dev, devm_attr_group_remove, devm_attr_group_match, /* cast away const */ (void *)grp)); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov35100.00%1100.00%
Total35100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_device_remove_group); /** * devm_device_add_groups - create a bunch of managed attribute groups * @dev: The device to create the group for * @groups: The attribute groups to create, NULL terminated * * This function creates a bunch of managed attribute groups. If an error * occurs when creating a group, all previously created groups will be * removed, unwinding everything back to the original state when this * function was called. It will explicitly warn and error if any of the * attribute files being created already exist. * * Returns 0 on success or error code from sysfs_create_group on failure. */
int devm_device_add_groups(struct device *dev, const struct attribute_group **groups) { union device_attr_group_devres *devres; int error; devres = devres_alloc(devm_attr_groups_remove, sizeof(*devres), GFP_KERNEL); if (!devres) return -ENOMEM; error = sysfs_create_groups(&dev->kobj, groups); if (error) { devres_free(devres); return error; } devres->groups = groups; devres_add(dev, devres); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov91100.00%1100.00%
Total91100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_device_add_groups); /** * devm_device_remove_groups - remove a list of managed groups * * @dev: The device for the groups to be removed from * @groups: NULL terminated list of groups to be removed * * If groups is not NULL, remove the specified groups from the device. */
void devm_device_remove_groups(struct device *dev, const struct attribute_group **groups) { WARN_ON(devres_release(dev, devm_attr_groups_remove, devm_attr_group_match, /* cast away const */ (void *)groups)); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov36100.00%1100.00%
Total36100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_device_remove_groups);
static int device_add_attrs(struct device *dev) { struct class *class = dev->class; const struct device_type *type = dev->type; int error; if (class) { error = device_add_groups(dev, class->dev_groups); if (error) return error; } if (type) { error = device_add_groups(dev, type->groups); if (error) goto err_remove_class_groups; } error = device_add_groups(dev, dev->groups); if (error) goto err_remove_type_groups; if (device_supports_offline(dev) && !dev->offline_disabled) { error = device_create_file(dev, &dev_attr_online); if (error) goto err_remove_dev_groups; } return 0; err_remove_dev_groups: device_remove_groups(dev, dev->groups); err_remove_type_groups: if (type) device_remove_groups(dev, type->groups); err_remove_class_groups: if (class) device_remove_groups(dev, class->dev_groups); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman7341.24%444.44%
Rafael J. Wysocki4123.16%222.22%
Dmitry Torokhov3519.77%111.11%
Kay Sievers2715.25%111.11%
Stephen Hemminger10.56%111.11%
Total177100.00%9100.00%


static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; const struct device_type *type = dev->type; device_remove_file(dev, &dev_attr_online); device_remove_groups(dev, dev->groups); if (type) device_remove_groups(dev, type->groups); if (class) device_remove_groups(dev, class->dev_groups); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman3547.95%337.50%
Kay Sievers1723.29%112.50%
Dmitry Torokhov1216.44%112.50%
Rafael J. Wysocki79.59%112.50%
Stephen Hemminger11.37%112.50%
Stefan Achatz11.37%112.50%
Total73100.00%8100.00%


static ssize_t dev_show(struct device *dev, struct device_attribute *attr, char *buf) { return print_dev_t(buf, dev->devt); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman30100.00%2100.00%
Total30100.00%2100.00%

static DEVICE_ATTR_RO(dev); /* /sys/devices/ */ struct kset *devices_kset; /** * devices_kset_move_before - Move device in the devices_kset's list. * @deva: Device to move. * @devb: Device @deva should come before. */
static void devices_kset_move_before(struct device *deva, struct device *devb) { if (!devices_kset) return; pr_debug("devices_kset: Moving %s before %s\n", dev_name(deva), dev_name(devb)); spin_lock(&devices_kset->list_lock); list_move_tail(&deva->kobj.entry, &devb->kobj.entry); spin_unlock(&devices_kset->list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Grygorii Strashko70100.00%1100.00%
Total70100.00%1100.00%

/** * devices_kset_move_after - Move device in the devices_kset's list. * @deva: Device to move * @devb: Device @deva should come after. */
static void devices_kset_move_after(struct device *deva, struct device *devb) { if (!devices_kset) return; pr_debug("devices_kset: Moving %s after %s\n", dev_name(deva), dev_name(devb)); spin_lock(&devices_kset->list_lock); list_move(&deva->kobj.entry, &devb->kobj.entry); spin_unlock(&devices_kset->list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Grygorii Strashko70100.00%1100.00%
Total70100.00%1100.00%

/** * devices_kset_move_last - move the device to the end of devices_kset's list. * @dev: device to move */
void devices_kset_move_last(struct device *dev) { if (!devices_kset) return; pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); spin_lock(&devices_kset->list_lock); list_move_tail(&dev->kobj.entry, &devices_kset->list); spin_unlock(&devices_kset->list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Grygorii Strashko57100.00%1100.00%
Total57100.00%1100.00%

/** * device_create_file - create sysfs attribute file for device. * @dev: device. * @attr: device attribute descriptor. */
int device_create_file(struct device *dev, const struct device_attribute *attr) { int error = 0; if (dev) { WARN(((attr->attr.mode & S_IWUGO) && !attr->store), "Attribute %s: write permission without 'store'\n", attr->attr.name); WARN(((attr->attr.mode & S_IRUGO) && !attr->show), "Attribute %s: read permission without 'show'\n", attr->attr.name); error = sysfs_create_file(&dev->kobj, &attr->attr); } return error; }

Contributors

PersonTokensPropCommitsCommitProp
Felipe Balbi4443.56%125.00%
Patrick Mochel4241.58%125.00%
Dave Young1413.86%125.00%
Phil Carmody10.99%125.00%
Total101100.00%4100.00%

EXPORT_SYMBOL_GPL(device_create_file); /** * device_remove_file - remove sysfs attribute file. * @dev: device. * @attr: device attribute descriptor. */
void device_remove_file(struct device *dev, const struct device_attribute *attr) { if (dev) sysfs_remove_file(&dev->kobj, &attr->attr); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel3296.97%150.00%
Phil Carmody13.03%150.00%
Total33100.00%2100.00%

EXPORT_SYMBOL_GPL(device_remove_file); /** * device_remove_file_self - remove sysfs attribute file from its own method. * @dev: device. * @attr: device attribute descriptor. * * See kernfs_remove_self() for details. */
bool device_remove_file_self(struct device *dev, const struct device_attribute *attr) { if (dev) return sysfs_remove_file_self(&dev->kobj, &attr->attr); else return false; }

Contributors

PersonTokensPropCommitsCommitProp
Tejun Heo38100.00%1100.00%
Total38100.00%1100.00%

EXPORT_SYMBOL_GPL(device_remove_file_self); /** * device_create_bin_file - create sysfs binary attribute file for device. * @dev: device. * @attr: device binary attribute descriptor. */
int device_create_bin_file(struct device *dev, const struct bin_attribute *attr) { int error = -EINVAL; if (dev) error = sysfs_create_bin_file(&dev->kobj, attr); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman4097.56%150.00%
Phil Carmody12.44%150.00%
Total41100.00%2100.00%

EXPORT_SYMBOL_GPL(device_create_bin_file); /** * device_remove_bin_file - remove sysfs binary attribute file * @dev: device. * @attr: device binary attribute descriptor. */
void device_remove_bin_file(struct device *dev, const struct bin_attribute *attr) { if (dev) sysfs_remove_bin_file(&dev->kobj, attr); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman2996.67%150.00%
Phil Carmody13.33%150.00%
Total30100.00%2100.00%

EXPORT_SYMBOL_GPL(device_remove_bin_file);
static void klist_children_get(struct klist_node *n) { struct device_private *p = to_device_private_parent(n); struct device *dev = p->device; get_device(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman1851.43%375.00%
James Bottomley1748.57%125.00%
Total35100.00%4100.00%


static void klist_children_put(struct klist_node *n) { struct device_private *p = to_device_private_parent(n); struct device *dev = p->device; put_device(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman1851.43%375.00%
James Bottomley1748.57%125.00%
Total35100.00%4100.00%

/** * device_initialize - init device structure. * @dev: device. * * This prepares the device for use by other layers by initializing * its fields. * It is the first half of device_register(), if called by * that function, though it can also be called separately, so one * may use @dev's fields. In particular, get_device()/put_device() * may be used for reference counting of @dev after calling this * function. * * All fields in @dev must be initialized by the caller to 0, except * for those explicitly set to some other value. The simplest * approach is to use kzalloc() to allocate the structure containing * @dev. * * NOTE: Use put_device() to give up your reference instead of freeing * @dev directly once you have called this function. */
void device_initialize(struct device *dev) { dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); INIT_LIST_HEAD(&dev->dma_pools); mutex_init(&dev->mutex); lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); #ifdef CONFIG_GENERIC_MSI_IRQ INIT_LIST_HEAD(&dev->msi_list); #endif INIT_LIST_HEAD(&dev->links.consumers); INIT_LIST_HEAD(&dev->links.suppliers); dev->links.status = DL_DEV_NO_DRIVER; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki2822.76%15.56%
Patrick Mochel1814.63%527.78%
Tejun Heo1613.01%15.56%
Jiang Liu1310.57%15.56%
Linus Torvalds118.94%15.56%
Greg Kroah-Hartman118.94%422.22%
Christoph Hellwig86.50%15.56%
Peter Zijlstra86.50%15.56%
Alan Stern54.07%15.56%
Deepak Saxena32.44%15.56%
Thomas Gleixner21.63%15.56%
Total123100.00%18100.00%

EXPORT_SYMBOL_GPL(device_initialize);
struct kobject *virtual_device_parent(struct device *dev) { static struct kobject *virtual_dir = NULL; if (!virtual_dir) virtual_dir = kobject_create_and_add("virtual", &devices_kset->kobj); return virtual_dir; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers2050.00%125.00%
Greg Kroah-Hartman1640.00%125.00%
Cornelia Huck37.50%125.00%
Dmitry Torokhov12.50%125.00%
Total40100.00%4100.00%

struct class_dir { struct kobject kobj; struct class *class; }; #define to_class_dir(obj) container_of(obj, struct class_dir, kobj)
static void class_dir_release(struct kobject *kobj) { struct class_dir *dir = to_class_dir(kobj); kfree(dir); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann26100.00%1100.00%
Total26100.00%1100.00%


static const struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj) { struct class_dir *dir = to_class_dir(kobj); return dir->class->ns_type; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann31100.00%1100.00%
Total31100.00%1100.00%

static struct kobj_type class_dir_ktype = { .release = class_dir_release, .sysfs_ops = &kobj_sysfs_ops, .child_ns_type = class_dir_child_ns_type };
static struct kobject * class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) { struct class_dir *dir; int retval; dir = kzalloc(sizeof(*dir), GFP_KERNEL); if (!dir) return NULL; dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); dir->kobj.kset = &class->p->glue_dirs; retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { kobject_put(&dir->kobj); return NULL; } return &dir->kobj; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann11999.17%150.00%
Kay Sievers10.83%150.00%
Total120100.00%2100.00%

static DEFINE_MUTEX(gdp_mutex);
static struct kobject *get_device_parent(struct device *dev, struct device *parent) { if (dev->class) { struct kobject *kobj = NULL; struct kobject *parent_kobj; struct kobject *k; #ifdef CONFIG_BLOCK /* block disks show up in /sys/block */ if (sysfs_deprecated && dev->class == &block_class) { if (parent && parent->class == &block_class) return &parent->kobj; return &block_class.p->subsys.kobj; } #endif /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live * in a "glue" directory to prevent namespace collisions. */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); else if (parent->class && !dev->class->ns_type) return &parent->kobj; else parent_kobj = &parent->kobj; mutex_lock(&gdp_mutex); /* find our class-directory at the parent and reference it */ spin_lock(&dev->class->p->glue_dirs.list_lock); list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } spin_unlock(&dev->class->p->glue_dirs.list_lock); if (kobj) { mutex_unlock(&gdp_mutex); return kobj; } /* or create a new class-directory at the parent device */ k = class_dir_create_and_add(dev->class, parent_kobj); /* do not emit an uevent for this simple "glue" directory */ mutex_unlock(&gdp_mutex); return k; } /* subsystems can specify a default root directory for their devices */ if (!parent && dev->bus && dev->bus->dev_root) return &dev->bus->dev_root->kobj; if (parent) return &parent->kobj; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers17866.42%533.33%
Greg Kroah-Hartman3814.18%320.00%
Tejun Heo217.84%16.67%
Cornelia Huck155.60%16.67%
Eric W. Biedermann82.99%213.33%
Randy Dunlap51.87%16.67%
Andi Kleen20.75%16.67%
Adrian Bunk10.37%16.67%
Total268100.00%15100.00%


static inline bool live_in_glue_dir(struct kobject *kobj, struct device *dev) { if (!kobj || !dev->class || kobj->kset != &dev->class->p->glue_dirs) return false; return true; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers2452.17%342.86%
Ming Lei1532.61%114.29%
Cornelia Huck510.87%228.57%
Greg Kroah-Hartman24.35%114.29%
Total46100.00%7100.00%


static inline struct kobject *get_glue_dir(struct device *dev) { return dev->kobj.parent; }

Contributors

PersonTokensPropCommitsCommitProp
Cornelia Huck1361.90%150.00%
Ming Lei838.10%150.00%
Total21100.00%2100.00%

/* * make sure cleaning up dir as the last step, we need to make * sure .release handler of kobject is run with holding the * global lock */
static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { /* see if we live in a "glue" directory */ if (!live_in_glue_dir(glue_dir, dev)) return; mutex_lock(&gdp_mutex); kobject_put(glue_dir); mutex_unlock(&gdp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Ming Lei4293.33%150.00%
Cornelia Huck36.67%150.00%
Total45100.00%2100.00%


static int device_add_class_symlinks(struct device *dev) { struct device_node *of_node = dev_of_node(dev); int error; if (of_node) { error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node"); if (error) dev_warn(dev, "Error %d creating of_node link\n",error); /* An error here doesn't warrant bringing down the device */ } if (!dev->class) return 0; error = sysfs_create_link(&dev->kobj, &dev->class->p->subsys.kobj, "subsystem"); if (error) goto out_devnode; if (dev->parent && device_is_not_partition(dev)) { error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); if (error) goto out_subsys; } #ifdef CONFIG_BLOCK /* /sys/block has directories and does not need symlinks */ if (sysfs_deprecated && dev->class == &block_class) return 0; #endif /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); if (error) goto out_device; return 0; out_device: sysfs_remove_link(&dev->kobj, "device"); out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); out_devnode: sysfs_remove_link(&dev->kobj, "of_node"); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Cornelia Huck10845.76%19.09%
Benjamin Herrenschmidt5925.00%19.09%
Kay Sievers5523.31%436.36%
Greg Kroah-Hartman52.12%218.18%
Randy Dunlap52.12%19.09%
Dmitry Torokhov20.85%19.09%
Andi Kleen20.85%19.09%
Total236100.00%11100.00%


static void device_remove_class_symlinks(struct device *dev) { if (dev_of_node(dev)) sysfs_remove_link(&dev->kobj, "of_node"); if (!dev->class) return; if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&dev->kobj, "subsystem"); #ifdef CONFIG_BLOCK if (sysfs_deprecated && dev->class == &block_class) return; #endif sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers6358.33%541.67%
Benjamin Herrenschmidt1715.74%18.33%
Cornelia Huck109.26%18.33%
Eric W. Biedermann65.56%18.33%
Greg Kroah-Hartman54.63%216.67%
Randy Dunlap54.63%18.33%
Andi Kleen21.85%18.33%
Total108100.00%12100.00%

/** * dev_set_name - set a device name * @dev: device * @fmt: format string for the device's name */
int dev_set_name(struct device *dev, const char *fmt, ...) { va_list vargs; int err; va_start(vargs, fmt); err = kobject_set_name_vargs(&dev->kobj, fmt, vargs); va_end(vargs); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Rothwell4382.69%133.33%
Kay Sievers815.38%133.33%
Roland Dreier11.92%133.33%
Total52100.00%3100.00%

EXPORT_SYMBOL_GPL(dev_set_name); /** * device_to_dev_kobj - select a /sys/dev/ directory for the device * @dev: device * * By default we select char/ for new entries. Setting class->dev_obj * to NULL prevents an entry from being created. class->dev_kobj must * be set (or cleared) before any devices are registered to the class * otherwise device_create_sys_dev_entry() and * device_remove_sys_dev_entry() will disagree about the presence of * the link. */
static struct kobject *device_to_dev_kobj(struct device *dev) { struct kobject *kobj; if (dev->class) kobj = dev->class->dev_kobj; else kobj = sysfs_dev_char_kobj; return kobj; }

Contributors

PersonTokensPropCommitsCommitProp
Dan J Williams40100.00%1100.00%
Total40100.00%1100.00%


static int device_create_sys_dev_entry(struct device *dev) { struct kobject *kobj = device_to_dev_kobj(dev); int error = 0; char devt_str[15]; if (kobj) { format_dev_t(devt_str, dev->devt); error = sysfs_create_link(kobj, &dev->kobj, devt_str); } return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dan J Williams64100.00%1100.00%
Total64100.00%1100.00%


static void device_remove_sys_dev_entry(struct device *dev) { struct kobject *kobj = device_to_dev_kobj(dev); char devt_str[15]; if (kobj) { format_dev_t(devt_str, dev->devt); sysfs_remove_link(kobj, devt_str); } }

Contributors

PersonTokensPropCommitsCommitProp
Dan J Williams49100.00%1100.00%
Total49100.00%1100.00%


int device_private_init(struct device *dev) { dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); if (!dev->p) return -ENOMEM; dev->p->device = dev; klist_init(&dev->p->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->p->deferred_probe); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman73100.00%2100.00%
Total73100.00%2100.00%

/** * device_add - add device to device hierarchy. * @dev: device. * * This is part 2 of device_register(), though may be called * separately _iff_ device_initialize() has been called separately. * * This adds @dev to the kobject hierarchy via kobject_add(), adds it * to the global and sibling lists for the device, then * adds it to the other relevant subsystems of the driver model. * * Do not call this routine or device_register() more than once for * any device structure. The driver model core is not designed to work * with devices that get unregistered and then spring back to life. * (Among other things, it's very hard to guarantee that all references * to the previous incarnation of @dev have been dropped.) Allocate * and register a fresh new struct device instead. * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up your * reference instead. */
int device_add(struct device *dev) { struct device *parent; struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; struct kobject *glue_dir = NULL; dev = get_device(dev); if (!dev) goto done; if (!dev->p) { error = device_private_init(dev); if (error) goto done; } /* * for statically allocated devices, which should all be converted * some day, we need to initialize the name. We prevent reading back * the name, and force the use of dev_name() */ if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL; } /* subsystems can specify simple device enumeration */ if (!dev_name(dev) && dev->bus && dev->bus->dev_name) dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); if (!dev_name(dev)) { error = -EINVAL; goto name_error; } pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); if (kobj) dev->kobj.parent = kobj; /* use parent numa_node */ if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); if (error) { glue_dir = get_glue_dir(dev); goto Error; } /* notify platform of device entry */ if (platform_notify) platform_notify(dev); error = device_create_file(dev, &dev_attr_uevent); if (error) goto attrError; error = device_add_class_symlinks(dev); if (error) goto SymlinkError; error = device_add_attrs(dev); if (error) goto AttrsError; error = bus_add_device(dev); if (error) goto BusError; error = dpm_sysfs_add(dev); if (error) goto DPMError; device_pm_add(dev); if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev); if (error) goto DevAttrError; error = device_create_sys_dev_entry(dev); if (error) goto SysEntryError; devtmpfs_create_node(dev); } /* Notify clients of device addition. This call must come * after dpm_sysfs_add() and before kobject_uevent(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_ADD); bus_probe_device(dev); if (parent) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); if (dev->class) { mutex_lock(&dev->class->p->mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices); /* notify any interfaces that the device is here */ list_for_each_entry(class_intf, &dev->class->p->interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->p->mutex); } done: put_device(dev); return error; SysEntryError: if (MAJOR(dev->devt)) device_remove_file(dev, &dev_attr_dev); DevAttrError: device_pm_remove(dev); dpm_sysfs_remove(dev); DPMError: bus_remove_device(dev); BusError: device_remove_attrs(dev); AttrsError: device_remove_class_symlinks(dev); SymlinkError: device_remove_file(dev, &dev_attr_uevent); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); glue_dir = get_glue_dir(dev); kobject_del(&dev->kobj); Error: cleanup_glue_dir(dev, glue_dir); put_device(parent); name_error: kfree(dev->p); dev->p = NULL; goto done; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman20531.20%1828.57%
Kay Sievers12418.87%1015.87%
Patrick Mochel9414.31%1015.87%
Sergey Klyaus568.52%11.59%
Cornelia Huck406.09%69.52%
Alan Stern274.11%34.76%
Ming Lei263.96%11.59%
Dan J Williams203.04%11.59%
Yinghai Lu152.28%11.59%
Brian Walsh101.52%11.59%
Zhen Lei91.37%11.59%
Tejun Heo81.22%34.76%
Linus Torvalds71.07%11.59%
Thomas Gleixner71.07%11.59%
James Bottomley40.61%11.59%
Dave Young20.30%11.59%
Jianpeng Ma (马建朋)10.15%11.59%
Frank A. Uepping10.15%11.59%
Harvey Harrison10.15%11.59%
Total657100.00%63100.00%

EXPORT_SYMBOL_GPL(device_add); /** * device_register - register a device with the system. * @dev: pointer to the device structure * * This happens in two clean steps - initialize the device * and add it to the system. The two steps can be called * separately, but this is the easiest and most common. * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. * * For more information, see the kerneldoc for device_initialize() * and device_add(). * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up the * reference initialized in this function instead. */
int device_register(struct device *dev) { device_initialize(dev); return device_add(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro1885.71%133.33%
Linus Torvalds29.52%133.33%
Patrick Mochel14.76%133.33%
Total21100.00%3100.00%

EXPORT_SYMBOL_GPL(device_register); /** * get_device - increment reference count for device. * @dev: device. * * This simply forwards the call to kobject_get(), though * we do take care to provide for the case that we get a NULL * pointer passed in. */
struct device *get_device(struct device *dev) { return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel2796.43%480.00%
Lars-Peter Clausen13.57%120.00%
Total28100.00%5100.00%

EXPORT_SYMBOL_GPL(get_device); /** * put_device - decrement reference count. * @dev: device in question. */
void put_device(struct device *dev) { /* might_sleep(); */ if (dev) kobject_put(&dev->kobj); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1460.87%125.00%
Patrick Mochel417.39%125.00%
Hannes Reinecke417.39%125.00%
Kay Sievers14.35%125.00%
Total23100.00%4100.00%

EXPORT_SYMBOL_GPL(put_device); /** * device_del - delete device from system. * @dev: device. * * This is the first part of the device unregistration * sequence. This removes the device from the lists we control * from here, has it removed from the other driver model * subsystems it was added to in device_add(), and removes it * from the kobject hierarchy. * * NOTE: this should be called manually _iff_ device_add() was * also called manually. */
void device_del(struct device *dev) { struct device *parent = dev->parent; struct kobject *glue_dir = NULL; struct class_interface *class_intf; /* Notify clients of device removal. This call must come * before dpm_sysfs_remove(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); device_links_purge(dev); dpm_sysfs_remove(dev); if (parent) klist_del(&dev->p->knode_parent); if (MAJOR(dev->devt)) { devtmpfs_delete_node(dev); device_remove_sys_dev_entry(dev); device_remove_file(dev, &dev_attr_dev); } if (dev->class) { device_remove_class_symlinks(dev); mutex_lock(&dev->class->p->mutex); /* notify any interfaces that the device is now gone */ list_for_each_entry(class_intf, &dev->class->p->interfaces, node) if (class_intf->remove_dev) class_intf->remove_dev(dev, class_intf); /* remove the device from the class list */ klist_del(&dev->knode_class); mutex_unlock(&dev->class->p->mutex); } device_remove_file(dev, &dev_attr_uevent); device_remove_attrs(dev); bus_remove_device(dev); device_pm_remove(dev); driver_deferred_probe_del(dev); device_remove_properties(dev); /* Notify the platform of the removal, in case they * need to do anything... */ if (platform_notify_remove) platform_notify_remove(dev); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_REMOVED_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); glue_dir = get_glue_dir(dev); kobject_del(&dev->kobj); cleanup_glue_dir(dev, glue_dir); put_device(parent); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman8329.75%821.05%
Patrick Mochel4114.70%718.42%
Kay Sievers3211.47%718.42%
Alan Stern2810.04%25.26%
Joerg Roedel227.89%12.63%
Ming Lei176.09%12.63%
Linus Torvalds124.30%12.63%
Tejun Heo72.51%25.26%
Dan J Williams72.51%12.63%
Grant C. Likely51.79%12.63%
LongX Zhang51.79%12.63%
Rafael J. Wysocki51.79%12.63%
Benjamin Herrenschmidt51.79%12.63%
Lukas Wunner51.79%12.63%
Catalin Marinas20.72%12.63%
Dave Young20.72%12.63%
Al Viro10.36%12.63%
Total279100.00%38100.00%

EXPORT_SYMBOL_GPL(device_del); /** * device_unregister - unregister device from system. * @dev: device going away. * * We do this in two parts, like we do device_register(). First, * we remove it from all the subsystems with device_del(), then * we decrement the reference count via put_device(). If that * is the final reference count, the device will be cleaned up * via device_release() above. Otherwise, the structure will * stick around until the final reference to the device is dropped. */
void device_unregister(struct device *dev) { pr_debug("device: '%s': %s\n", dev_name(dev), __func__); device_del(dev); put_device(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro1134.38%111.11%
Patrick Mochel1031.25%444.44%
Linus Torvalds515.62%111.11%
Kay Sievers39.38%111.11%
Greg Kroah-Hartman26.25%111.11%
Harvey Harrison13.12%111.11%
Total32100.00%9100.00%

EXPORT_SYMBOL_GPL(device_unregister);
static struct device *prev_device(struct klist_iter *i) { struct klist_node *n = klist_prev(i); struct device *dev = NULL; struct device_private *p; if (n) { p = to_device_private_parent(n); dev = p->device; } return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko57100.00%1100.00%
Total57100.00%1100.00%


static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); struct device *dev = NULL; struct device_private *p; if (n) { p = to_device_private_parent(n); dev = p->device; } return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman3052.63%266.67%
Patrick Mochel2747.37%133.33%
Total57100.00%3100.00%

/** * device_get_devnode - path of device node file * @dev: device * @mode: returned file access mode * @uid: returned file owner * @gid: returned file group * @tmp: possibly allocated string * * Return the relative path of a possible device node. * Non-default names may need to allocate a memory to compose * a name. This memory is returned in tmp and needs to be * freed by the caller. */
const char *device_get_devnode(struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid, const char **tmp) { char *s; *tmp = NULL; /* the device type may provide a specific name */ if (dev->type && dev->type->devnode) *tmp = dev->type->devnode(dev, mode, uid, gid); if (*tmp) return *tmp; /* the class may provide a specific name */ if (dev->class && dev->class->devnode) *tmp = dev->class->devnode(dev, mode); if (*tmp) return *tmp; /* return name without allocation, tmp == NULL */ if (strchr(dev_name(dev), '!') == NULL) return dev_name(dev); /* replace '!' in the name with '/' */ s = kstrdup(dev_name(dev), GFP_KERNEL); if (!s) return NULL; strreplace(s, '!', '/'); return *tmp = s; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers16193.60%350.00%
Rasmus Villemoes84.65%116.67%
Greg Kroah-Hartman21.16%116.67%
Al Viro10.58%116.67%
Total172100.00%6100.00%

/** * device_for_each_child - device child iterator. * @parent: parent struct device. * @fn: function to be called for each device. * @data: data for the callback. * * Iterate over @parent's child devices, and call @fn for each, * passing it @data. * * We check the return of @fn each time. If it returns anything * other than 0, we break out and return that value. */
int device_for_each_child(struct device *parent, void *data, int (*fn)(struct device *dev, void *data)) { struct klist_iter i; struct device *child; int error = 0; if (!parent->p) return 0; klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i)) && !error) error = fn(child, data); klist_iter_exit(&i); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mochel8686.00%240.00%
Greg Kroah-Hartman1414.00%360.00%
Total100100.00%5100.00%

EXPORT_SYMBOL_GPL(device_for_each_child); /** * device_for_each_child_reverse - device child iterator in reversed order. * @parent: parent struct device. * @fn: function to be called for each device. * @data: data for the callback. * * Iterate over @parent's child devices, and call @fn for each, * passing it @data. * * We check the return of @fn each time. If it returns anything * other than 0, we break out and return that value. */
int device_for_each_child_reverse(struct device *parent, void *data, int (*fn)(struct device *dev, void *data)) { struct klist_iter i; struct device *child; int error = 0; if (!parent->p) return 0; klist_iter_init(&parent->p->klist_children, &i); while ((child = prev_device(&i)) && !error) error = fn(child, data); klist_iter_exit(&i); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko100100.00%1100.00%
Total100100.00%1100.00%

EXPORT_SYMBOL_GPL(device_for_each_child_reverse); /** * device_find_child - device iterator for locating a particular device. * @parent: parent struct device * @match: Callback function to check device * @data: Data to pass to match function * * This is similar to the device_for_each_child() function above, but it * returns a reference to a device that is 'found' for later use, as * determined by the @match callback. * * The callback should return 0 if the device doesn't match and non-zero * if it does. If the callback returns non-zero and a reference to the * current device can be obtained, this function will return to the caller * and not iterate over any more devices. * * NOTE: you will need to drop the reference with put_device() after use. */
struct device *device_find_child(struct device *parent, void *data, int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *child; if (!parent) return NULL; klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i))) if (match(child, data) && get_device(child)) break; klist_iter_exit(&i); return child; }

Contributors

PersonTokensPropCommitsCommitProp
Cornelia Huck9495.92%133.33%
Greg Kroah-Hartman44.08%266.67%
Total98100.00%3100.00%

EXPORT_SYMBOL_GPL(device_find_child);
int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); if (!devices_kset) return -ENOMEM; dev_kobj = kobject_create_and_add("dev", NULL); if (!dev_kobj) goto dev_kobj_err; sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); if (!sysfs_dev_block_kobj) goto block_kobj_err; sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); if (!sysfs_dev_char_kobj) goto char_kobj_err; return 0; char_kobj_err: kobject_put(sysfs_dev_block_kobj); block_kobj_err: kobject_put(dev_kobj); dev_kobj_err: kset_unregister(devices_kset); return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Dan J Williams7670.37%125.00%
Greg Kroah-Hartman2018.52%125.00%
Patrick Mochel1211.11%250.00%
Total108100.00%4100.00%


static int device_check_offline(struct device *dev, void *not_used) { int ret; ret = device_for_each_child(dev, NULL, device_check_offline); if (ret) return ret; return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki52100.00%1100.00%
Total52100.00%1100.00%

/** * device_offline - Prepare the device for hot-removal. * @dev: Device to be put offline. * * Execute the device bus type's .offline() callback, if present, to prepare * the device for a subsequent hot-removal. If that succeeds, the device must * not be used until either it is removed or its bus type's .online() callback * is executed. * * Call under device_hotplug_lock. */
int device_offline(struct device *dev) { int ret; if (dev->offline_disabled) return -EPERM; ret = device_for_each_child(dev, NULL, device_check_offline); if (ret) return ret; device_lock(dev); if (device_supports_offline(dev)) { if (dev->offline) { ret = 1; } else { ret = dev->bus->offline(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_OFFLINE); dev->offline = true; } } } device_unlock(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki112100.00%1100.00%
Total112100.00%1100.00%

/** * device_online - Put the device back online after successful device_offline(). * @dev: Device to be put back online. * * If device_offline() has been successfully executed for @dev, but the device * has not been removed subsequently, execute its bus type's .online() callback * to indicate that the device can be used again. * * Call under device_hotplug_lock. */
int device_online(struct device *dev) { int ret = 0; device_lock(dev); if (device_supports_offline(dev)) { if (dev->offline) { ret = dev->bus->online(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_ONLINE); dev->offline = false; } } else { ret = 1; } } device_unlock(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki86100.00%1100.00%
Total86100.00%1100.00%

struct root_device { struct device dev; struct module *owner; };
static inline struct root_device *to_root_device(struct device *d) { return container_of(d, struct root_device, dev); }

Contributors

PersonTokensPropCommitsCommitProp
Wagner Ferenc2184.00%133.33%
Mark McLoughlin312.00%133.33%
Josh Triplett14.00%133.33%
Total25100.00%3100.00%


static void root_device_release(struct device *dev) { kfree(to_root_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Mark McLoughlin19100.00%1100.00%
Total19100.00%1100.00%

/** * __root_device_register - allocate and register a root device * @name: root device name * @owner: owner module of the root device, usually THIS_MODULE * * This function allocates a root device and registers it * using device_register(). In order to free the returned * device, use root_device_unregister(). * * Root devices are dummy devices which allow other devices * to be grouped under /sys/devices. Use this function to * allocate a root device and then use it as the parent of * any device which should appear under /sys/devices/{name} * * The /sys/devices/{name} directory will also contain a * 'module' symlink which points to the @owner directory * in sysfs. * * Returns &struct device pointer on success, or ERR_PTR() on error. * * Note: You probably want to use root_device_register(). */
struct device *__root_device_register(const char *name, struct module *owner) { struct root_device *root; int err = -ENOMEM; root = kzalloc(sizeof(struct root_device), GFP_KERNEL); if (!root) return ERR_PTR(err); err = dev_set_name(&root->dev, "%s", name); if (err) { kfree(root); return ERR_PTR(err); } root->dev.release = root_device_release; err = device_register(&root->dev); if (err) { put_device(&root->dev); return ERR_PTR(err); } #ifdef CONFIG_MODULES /* gotta find a "cleaner" way to do this */ if (owner) { struct module_kobject *mk = &owner->mkobj; err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module"); if (err) { device_unregister(&root->dev); return ERR_PTR(err); } root->owner = owner; } #endif return &root->dev; }

Contributors

PersonTokensPropCommitsCommitProp
Mark McLoughlin19198.45%133.33%
Greg Kroah-Hartman21.03%133.33%
Christoph Egger10.52%133.33%
Total194100.00%3100.00%

EXPORT_SYMBOL_GPL(__root_device_register); /** * root_device_unregister - unregister and free a root device * @dev: device going away * * This function unregisters and cleans up a device that was created by * root_device_register(). */
void root_device_unregister(struct device *dev) { struct root_device *root = to_root_device(dev); if (root->owner) sysfs_remove_link(&root->dev.kobj, "module"); device_unregister(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Mark McLoughlin43100.00%1100.00%
Total43100.00%1100.00%

EXPORT_SYMBOL_GPL(root_device_unregister);
static void device_create_release(struct device *dev) { pr_debug("device: '%s': %s\n", dev_name(dev), __func__); kfree(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman2485.71%250.00%
Kay Sievers310.71%125.00%
Harvey Harrison13.57%125.00%
Total28100.00%4100.00%


static struct device * device_create_groups_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args) { struct device *dev = NULL; int retval = -ENODEV; if (class == NULL || IS_ERR(class)) goto error; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { retval = -ENOMEM; goto error; } device_initialize(dev); dev->devt = devt; dev->class = class; dev->parent = parent; dev->groups = groups; dev->release = device_create_release; dev_set_drvdata(dev, drvdata); retval = kobject_set_name_vargs(&dev->kobj, fmt, args); if (retval) goto error; retval = device_add(dev); if (retval) goto error; return dev; error: put_device(dev); return ERR_PTR(retval); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman15481.91%342.86%
Guenter Roeck157.98%114.29%
Kay Sievers126.38%114.29%
David Herrmann63.19%114.29%
Cornelia Huck10.53%114.29%
Total188100.00%7100.00%

/** * device_create_vargs - creates a device and registers it with sysfs * @class: pointer to the struct class that this device should be registered to * @parent: pointer to the parent struct device of this new device, if any * @devt: the dev_t for the char device to be added * @drvdata: the data to be added to the device for callbacks * @fmt: string for the device's name * @args: va_list for the device's name * * This function can be used by char device classes. A struct device * will be created in sysfs, registered to the specified class. * * A "dev" file will be created, showing the dev_t for the device, if * the dev_t is not 0,0. * If a pointer to a parent struct device is passed in, the newly created * struct device will be a child of that device in sysfs. * The pointer to the struct device will be returned from the call. * Any further sysfs files that might be required can be created using this * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. * * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */
struct device *device_create_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, va_list args) { return device_create_groups_vargs(class, parent, devt, drvdata, NULL, fmt, args); }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck50100.00%1100.00%
Total50100.00%1100.00%

EXPORT_SYMBOL_GPL(device_create_vargs); /** * device_create - creates a device and registers it with sysfs * @class: pointer to the struct class that this device should be registered to * @parent: pointer to the parent struct device of this new device, if any * @devt: the dev_t for the char device to be added * @drvdata: the data to be added to the device for callbacks * @fmt: string for the device's name * * This function can be used by char device classes. A struct device * will be created in sysfs, registered to the specified class. * * A "dev" file will be created, showing the dev_t for the device, if * the dev_t is not 0,0. * If a pointer to a parent struct device is passed in, the newly created * struct device will be a child of that device in sysfs. * The pointer to the struct device will be returned from the call. * Any further sysfs files that might be required can be created using this * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. * * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) { va_list vargs; struct device *dev; va_start(vargs, fmt); dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); va_end(vargs); return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman71100.00%2100.00%
Total71100.00%2100.00%

EXPORT_SYMBOL_GPL(device_create); /** * device_create_with_groups - creates a device and registers it with sysfs * @class: pointer to the struct class that this device should be registered to * @parent: pointer to the parent struct device of this new device, if any * @devt: the dev_t for the char device to be added * @drvdata: the data to be added to the device for callbacks * @groups: NULL-terminated list of attribute groups to be created * @fmt: string for the device's name * * This function can be used by char device classes. A struct device * will be created in sysfs, registered to the specified class. * Additional attributes specified in the groups parameter will also * be created automatically. * * A "dev" file will be created, showing the dev_t for the device, if * the dev_t is not 0,0. * If a pointer to a parent struct device is passed in, the newly created * struct device will be a child of that device in sysfs. * The pointer to the struct device will be returned from the call. * Any further sysfs files that might be required can be created using this * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. * * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */
struct device *device_create_with_groups(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, ...) { va_list vargs; struct device *dev; va_start(vargs, fmt); dev = device_create_groups_vargs(class, parent, devt, drvdata, groups, fmt, vargs); va_end(vargs); return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck80100.00%1100.00%
Total80100.00%1100.00%

EXPORT_SYMBOL_GPL(device_create_with_groups);
static int __match_devt(struct device *dev, const void *data) { const dev_t *devt = data; return dev->devt == *devt; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman1341.94%125.00%
Dave Young1341.94%125.00%
Rafael J. Wysocki39.68%125.00%
Michał Mirosław26.45%125.00%
Total31100.00%4100.00%

/** * device_destroy - removes a device that was created with device_create() * @class: pointer to the struct class that this device was registered with * @devt: the dev_t of the device that was previously registered * * This call unregisters and cleans up a device that was created with a * call to device_create(). */
void device_destroy(struct class *class, dev_t devt) { struct device *dev; dev = class_find_device(class, NULL, &devt, __match_devt); if (dev) { put_device(dev); device_unregister(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki2552.08%125.00%
Greg Kroah-Hartman1225.00%250.00%
Dave Young1122.92%125.00%
Total48100.00%4100.00%

EXPORT_SYMBOL_GPL(device_destroy); /** * device_rename - renames a device * @dev: the pointer to the struct device to be renamed * @new_name: the new name of the device * * It is the responsibility of the caller to provide mutual * exclusion between two different calls of device_rename * on the same device to ensure that new_name is valid and * won't conflict with other devices. * * Note: Don't call this function. Currently, the networking layer calls this * function, but that will change. The following text from Kay Sievers offers * some insight: * * Renaming devices is racy at many levels, symlinks and other stuff are not * replaced atomically, and you get a "move" uevent, but it's not easy to * connect the event to the old and new device. Device nodes are not renamed at * all, there isn't even support for that in the kernel now. * * In the meantime, during renaming, your target name might be taken by another * driver, creating conflicts. Or the old name is taken directly after you * renamed it -- then you get events for the same DEVPATH, before you even see * the "move" event. It's just a mess, and nothing new should ever rely on * kernel device renaming. Besides that, it's not even implemented now for * other things than (driver-core wise very simple) network devices. * * We are currently about to change network renaming in udev to completely * disallow renaming of devices in the same namespace as the kernel uses, * because we can't solve the problems properly, that arise with swapping names * of multiple interfaces without races. Means, renaming of eth[0-9]* will only * be allowed to some other name than eth[0-9]*, for the aforementioned * reasons. * * Make up a "real" name in the driver before you register anything, or add * some other attributes for userspace to find the device, or use udev to add * symlinks -- but never rename kernel devices later, it's a complete mess. We * don't even want to get into that and try to implement the missing pieces in * the core. We really have other pieces to fix in the driver core mess. :) */
int device_rename(struct device *dev, const char *new_name) { struct kobject *kobj = &dev->kobj; char *old_device_name = NULL; int error; dev = get_device(dev); if (!dev) return -EINVAL; dev_dbg(dev, "renaming to %s\n", new_name); old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); if (!old_device_name) { error = -ENOMEM; goto out; } if (dev->class) { error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, kobj, old_device_name, new_name, kobject_namespace(kobj)); if (error) goto out; } error = kobject_rename(kobj, new_name); if (error) goto out; out: put_device(dev); kfree(old_device_name); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman7748.43%218.18%
Eric W. Biedermann3522.01%19.09%
Tejun Heo1610.06%19.09%
Cornelia Huck148.81%19.09%
Kay Sievers74.40%327.27%
Jesper Juhl74.40%19.09%
Ethan Zhao21.26%19.09%
Johannes Berg10.63%19.09%
Total159100.00%11100.00%

EXPORT_SYMBOL_GPL(device_rename);
static int device_move_class_links(struct device *dev, struct device *old_parent, struct device *new_parent) { int error = 0; if (old_parent) sysfs_remove_link(&dev->kobj, "device"); if (new_parent) error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman3859.38%150.00%
Cornelia Huck2640.62%150.00%
Total64100.00%2100.00%

/** * device_move - moves a device to a new parent * @dev: the pointer to the struct device to be moved * @new_parent: the new parent of the device (can by NULL) * @dpm_order: how to reorder the dpm_list */
int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order) { int error; struct device *old_parent; struct kobject *new_parent_kobj; dev = get_device(dev); if (!dev) return -EINVAL; device_pm_lock(); new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), __func__, new_parent ? dev_name(new_parent) : "<NULL>"); error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } old_parent = dev->parent; dev->parent = new_parent; if (old_parent) klist_remove(&dev->p->knode_parent); if (new_parent) { klist_add_tail(&dev->p->knode_parent, &new_parent->p->klist_children); set_dev_node(dev, dev_to_node(new_parent)); } if (dev->class) { error = device_move_class_links(dev, old_parent, new_parent); if (error) { /* We ignore errors on cleanup since we're hosed anyway... */ device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) klist_remove(&dev->p->knode_parent); dev->parent = old_parent; if (old_parent) { klist_add_tail(&dev->p->knode_parent, &old_parent->p->klist_children); set_dev_node(dev, dev_to_node(old_parent)); } } cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } } switch (dpm_order) { case DPM_ORDER_NONE: break; case DPM_ORDER_DEV_AFTER_PARENT: device_pm_move_after(dev, new_parent); devices_kset_move_after(dev, new_parent); break; case DPM_ORDER_PARENT_BEFORE_DEV: device_pm_move_before(new_parent, dev); devices_kset_move_before(new_parent, dev); break; case DPM_ORDER_DEV_LAST: device_pm_move_last(dev); devices_kset_move_last(dev); break; } put_device(old_parent); out: device_pm_unlock(); put_device(dev); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Cornelia Huck30781.00%541.67%
Yinghai Lu307.92%18.33%
Grygorii Strashko195.01%18.33%
Greg Kroah-Hartman143.69%216.67%
Kay Sievers61.58%18.33%
Rabin Vincent20.53%18.33%
Harvey Harrison10.26%18.33%
Total379100.00%12100.00%

EXPORT_SYMBOL_GPL(device_move); /** * device_shutdown - call ->shutdown() on each device to shutdown. */
void device_shutdown(void) { struct device *dev, *parent; spin_lock(&devices_kset->list_lock); /* * Walk the devices list backward, shutting down each in turn. * Beware that device unplug events may also start pulling * devices offline, even as the system is shutting down. */ while (!list_empty(&devices_kset->list)) { dev = list_entry(devices_kset->list.prev, struct device, kobj.entry); /* * hold reference count of device's parent to * prevent it from being freed because parent's * lock is to be held */ parent = get_device(dev->parent); get_device(dev); /* * Make sure the device is off the kset list, in the * event that dev->*->shutdown() doesn't remove it. */ list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); /* hold lock to avoid race with probe/release */ if (parent) device_lock(parent); device_lock(dev); /* Don't allow any more runtime suspends */ pm_runtime_get_noresume(dev); pm_runtime_barrier(dev); if (dev->class && dev->class->shutdown_pre) { if (initcall_debug) dev_info(dev, "shutdown_pre\n"); dev->class->shutdown_pre(dev); } if (dev->bus && dev->bus->shutdown) { if (initcall_debug) dev_info(dev, "shutdown\n"); dev->bus->shutdown(dev); } else if (dev->driver && dev->driver->shutdown) { if (initcall_debug) dev_info(dev, "shutdown\n"); dev->driver->shutdown(dev); } device_unlock(dev); if (parent) device_unlock(parent); put_device(dev); put_device(parent); spin_lock(&devices_kset->list_lock); } spin_unlock(&devices_kset->list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Hugh Daschbach8031.01%111.11%
Greg Kroah-Hartman7629.46%111.11%
Ming Lei4216.28%111.11%
Josh Zimmerman3112.02%111.11%
Liu ShuoX103.88%111.11%
Alan Stern72.71%111.11%
Benson Leung51.94%111.11%
Peter Chen41.55%111.11%
Michal Suchanek31.16%111.11%
Total258100.00%9100.00%

/* * Device logging functions */ #ifdef CONFIG_PRINTK
static int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) { const char *subsys; size_t pos = 0; if (dev->class) subsys = dev->class->name; else if (dev->bus) subsys = dev->bus->name; else return 0; pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys); if (pos >= hdrlen) goto overflow; /* * Add device identifier DEVICE=: * b12:8 block dev_t * c127:3 char dev_t * n8 netdev ifindex * +sound:card0 subsystem:devname */ if (MAJOR(dev->devt)) { char c; if (strcmp(subsys, "block") == 0) c = 'b'; else c = 'c'; pos++; pos += snprintf(hdr + pos, hdrlen - pos, "DEVICE=%c%u:%u", c, MAJOR(dev->devt), MINOR(dev->devt)); } else if (strcmp(subsys, "net") == 0) { struct net_device *net = to_net_dev(dev); pos++; pos += snprintf(hdr + pos, hdrlen - pos, "DEVICE=n%u", net->ifindex); } else { pos++; pos += snprintf(hdr + pos, hdrlen - pos, "DEVICE=+%s:%s", subsys, dev_name(dev)); } if (pos >= hdrlen) goto overflow; return pos; overflow: dev_WARN(dev, "device/subsystem name too long"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kay Sievers17167.06%116.67%
Joe Perches5019.61%350.00%
Ben Hutchings3011.76%116.67%
Jim Cromie41.57%116.67%
Total255100.00%6100.00%


int dev_vprintk_emit(int level, const struct device *dev, const char *fmt, va_list args) { char hdr[128]; size_t hdrlen; hdrlen = create_syslog_header(dev, hdr, sizeof(hdr)); return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches65100.00%1100.00%
Total65100.00%1100.00%

EXPORT_SYMBOL(dev_vprintk_emit);
int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...) { va_list args; int r; va_start(args, fmt); r = dev_vprintk_emit(level, dev, fmt, args); va_end(args); return r; }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL(dev_printk_emit);
static void __dev_printk(const char *level, const struct device *dev, struct va_format *vaf) { if (dev) dev_printk_emit(level[1] - '0', dev, "%s %s: %pV", dev_driver_string(dev), dev_name(dev), vaf); else printk("%s(NULL device *): %pV", level, vaf); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches5385.48%466.67%
Kay Sievers711.29%116.67%
Jim Cromie23.23%116.67%
Total62100.00%6100.00%


void dev_printk(const char *level, const struct device *dev, const char *fmt, ...) { struct va_format vaf; va_list args; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; __dev_printk(level, dev, &vaf); va_end(args); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches65100.00%2100.00%
Total65100.00%2100.00%

EXPORT_SYMBOL(dev_printk); #define define_dev_printk_level(func, kern_level) \ void func(const struct device *dev, const char *fmt, ...) \ { \ struct va_format vaf; \ va_list args; \ \ va_start(args, fmt); \ \ vaf.fmt = fmt; \ vaf.va = &args; \ \ __dev_printk(kern_level, dev, &vaf); \ \ va_end(args); \ } \ EXPORT_SYMBOL(func); define_dev_printk_level(dev_emerg, KERN_EMERG); define_dev_printk_level(dev_alert, KERN_ALERT); define_dev_printk_level(dev_crit, KERN_CRIT); define_dev_printk_level(dev_err, KERN_ERR); define_dev_printk_level(dev_warn, KERN_WARNING); define_dev_printk_level(dev_notice, KERN_NOTICE); define_dev_printk_level(_dev_info, KERN_INFO); #endif
static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) { return fwnode && !IS_ERR(fwnode->secondary); }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki23100.00%1100.00%
Total23100.00%1100.00%

/** * set_primary_fwnode - Change the primary firmware node of a given device. * @dev: Device to handle. * @fwnode: New primary firmware node of the device. * * Set the device's firmware node pointer to @fwnode, but if a secondary * firmware node of the device is present, preserve it. */
void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) { if (fwnode) { struct fwnode_handle *fn = dev->fwnode; if (fwnode_is_primary(fn)) fn = fn->secondary; if (fn) { WARN_ON(fwnode->secondary); fwnode->secondary = fn; } dev->fwnode = fwnode; } else { dev->fwnode = fwnode_is_primary(dev->fwnode) ? dev->fwnode->secondary : NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki7785.56%150.00%
Mika Westerberg1314.44%150.00%
Total90100.00%2100.00%

EXPORT_SYMBOL_GPL(set_primary_fwnode); /** * set_secondary_fwnode - Change the secondary firmware node of a given device. * @dev: Device to handle. * @fwnode: New secondary firmware node of the device. * * If a primary firmware node of the device is present, set its secondary * pointer to @fwnode. Otherwise, set the device's firmware node pointer to * @fwnode. */
void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode) { if (fwnode) fwnode->secondary = ERR_PTR(-ENODEV); if (fwnode_is_primary(dev->fwnode)) dev->fwnode->secondary = fwnode; else dev->fwnode = fwnode; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki53100.00%1100.00%
Total53100.00%1100.00%

/** * device_set_of_node_from_dev - reuse device-tree node of another device * @dev: device whose device-tree node is being set * @dev2: device whose device-tree node is being reused * * Takes another reference to the new device-tree node after first dropping * any reference held to the old node. */
void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) { of_node_put(dev->of_node); dev->of_node = of_node_get(dev2->of_node); dev->of_node_reused = true; }

Contributors

PersonTokensPropCommitsCommitProp
Johan Hovold40100.00%1100.00%
Total40100.00%1100.00%

EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);

Overall Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki234421.32%83.12%
Greg Kroah-Hartman175215.93%4919.14%
Kay Sievers173115.74%3112.11%
Cornelia Huck6465.88%145.47%
Patrick Mochel6035.48%249.38%
Dmitry Torokhov5214.74%83.12%
Joe Perches3683.35%51.95%
Eric W. Biedermann3082.80%31.17%
Mark McLoughlin2802.55%10.39%
Dan J Williams2722.47%10.39%
Grygorii Strashko2191.99%10.39%
Andy Shevchenko1631.48%10.39%
Guenter Roeck1521.38%10.39%
Ming Lei1511.37%20.78%
Alan Stern1221.11%72.73%
Tejun Heo1201.09%72.73%
Borislav Petkov1131.03%10.39%
Linus Torvalds850.77%10.39%
Benjamin Herrenschmidt840.76%31.17%
Hugh Daschbach800.73%10.39%
Sergey Klyaus560.51%10.39%
David Graham White550.50%10.39%
Andi Kleen550.50%10.39%
Stephen Rothwell480.44%10.39%
Johan Hovold460.42%10.39%
Dave Young450.41%31.17%
Yinghai Lu450.41%10.39%
Felipe Balbi440.40%10.39%
James Bottomley380.35%20.78%
Al Viro320.29%20.78%
Josh Zimmerman310.28%10.39%
Ben Hutchings300.27%10.39%
Joerg Roedel220.20%10.39%
Andrew Morton210.19%10.39%
Wagner Ferenc210.19%10.39%
Grant C. Likely190.17%20.78%
Randy Dunlap170.15%31.17%
Jiang Liu130.12%10.39%
Mika Westerberg130.12%10.39%
Jean Delvare130.12%20.78%
Brian Walsh100.09%10.39%
Liu ShuoX100.09%10.39%
Thomas Gleixner90.08%20.78%
Zhen Lei90.08%10.39%
Rasmus Villemoes80.07%10.39%
Lars-Peter Clausen80.07%10.39%
Christoph Hellwig80.07%10.39%
Peter Zijlstra80.07%10.39%
Matthew Wilcox80.07%20.78%
Harvey Harrison70.06%10.39%
Jesper Juhl70.06%10.39%
Peter Chen70.06%10.39%
Lukas Wunner70.06%20.78%
Lei Ming60.05%10.39%
David Herrmann60.05%10.39%
Yijing Wang60.05%10.39%
Johannes Berg60.05%20.78%
Jim Cromie60.05%10.39%
Peter Rajnoha60.05%10.39%
LongX Zhang50.05%10.39%
Benson Leung50.05%10.39%
Alexander Nyberg40.04%10.39%
Yani Ioannou40.04%10.39%
Hannes Reinecke40.04%10.39%
Phil Carmody40.04%20.78%
Deepak Saxena30.03%10.39%
Ingo Molnar30.03%10.39%
Arjan van de Ven30.03%10.39%
Robert P. J. Day30.03%10.39%
Michal Suchanek30.03%10.39%
David S. Miller30.03%10.39%
Emese Revfy20.02%20.78%
Ethan Zhao20.02%10.39%
Jani Nikula20.02%10.39%
Dave Jones20.02%10.39%
Rabin Vincent20.02%10.39%
David Brownell20.02%10.39%
Catalin Marinas20.02%10.39%
Stephen Hemminger20.02%10.39%
Michał Mirosław20.02%10.39%
Peter Korsgaard10.01%10.39%
Jianpeng Ma (马建朋)10.01%10.39%
Josh Triplett10.01%10.39%
Frank A. Uepping10.01%10.39%
Timur Tabi10.01%10.39%
Jingoo Han10.01%10.39%
Roland Dreier10.01%10.39%
Hanjun Guo10.01%10.39%
Stefan Weil10.01%10.39%
Christoph Egger10.01%10.39%
Adrian Bunk10.01%10.39%
Stefan Achatz10.01%10.39%
Yan Hong10.01%10.39%
Total10995100.00%256100.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.