1489 lines · 36.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * bus.c - bus driver management * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (c) 2007 Novell Inc. * Copyright (c) 2023 Greg Kroah-Hartman <gregkh@linuxfoundation.org> */ #include <linux/async.h>#include <linux/device/bus.h>#include <linux/device.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/string.h>#include <linux/mutex.h>#include <linux/sysfs.h>#include "base.h"#include "power/power.h" /* /sys/devices/system */static struct kset *system_kset; /* /sys/bus */static struct kset *bus_kset; #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) /* * sysfs bindings for drivers */ #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) #define DRIVER_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \	struct driver_attribute driver_attr_##_name =		\		__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) static int __must_check bus_rescan_devices_helper(struct device *dev,						void *data); /** * bus_to_subsys - Turn a struct bus_type into a struct subsys_private * * @bus: pointer to the struct bus_type to look up * * The driver core internals needs to work on the subsys_private structure, not * the external struct bus_type pointer.  This function walks the list of * registered busses in the system and finds the matching one and returns the * internal struct subsys_private that relates to that bus. * * Note, the reference count of the return value is INCREMENTED if it is not * NULL.  A call to subsys_put() must be done when finished with the pointer in * order for it to be properly freed. */struct subsys_private *bus_to_subsys(const struct bus_type *bus){	struct subsys_private *sp = NULL;	struct kobject *kobj; 	if (!bus || !bus_kset)		return NULL; 	spin_lock(&bus_kset->list_lock); 	if (list_empty(&bus_kset->list))		goto done; 	list_for_each_entry(kobj, &bus_kset->list, entry) {		struct kset *kset = container_of(kobj, struct kset, kobj); 		sp = container_of_const(kset, struct subsys_private, subsys);		if (sp->bus == bus)			goto done;	}	sp = NULL;done:	sp = subsys_get(sp);	spin_unlock(&bus_kset->list_lock);	return sp;} static const struct bus_type *bus_get(const struct bus_type *bus){	struct subsys_private *sp = bus_to_subsys(bus); 	if (sp)		return bus;	return NULL;} static void bus_put(const struct bus_type *bus){	struct subsys_private *sp = bus_to_subsys(bus); 	/* two puts are required as the call to bus_to_subsys incremented it again */	subsys_put(sp);	subsys_put(sp);} static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,			     char *buf){	struct driver_attribute *drv_attr = to_drv_attr(attr);	struct driver_private *drv_priv = to_driver(kobj);	ssize_t ret = -EIO; 	if (drv_attr->show)		ret = drv_attr->show(drv_priv->driver, buf);	return ret;} static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,			      const char *buf, size_t count){	struct driver_attribute *drv_attr = to_drv_attr(attr);	struct driver_private *drv_priv = to_driver(kobj);	ssize_t ret = -EIO; 	if (drv_attr->store)		ret = drv_attr->store(drv_priv->driver, buf, count);	return ret;} static const struct sysfs_ops driver_sysfs_ops = {	.show	= drv_attr_show,	.store	= drv_attr_store,}; static void driver_release(struct kobject *kobj){	struct driver_private *drv_priv = to_driver(kobj); 	pr_debug("driver: '%s': %s\n", kobject_name(kobj), __func__);	kfree(drv_priv);} static const struct kobj_type driver_ktype = {	.sysfs_ops	= &driver_sysfs_ops,	.release	= driver_release,}; /* * sysfs bindings for buses */static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,			     char *buf){	struct bus_attribute *bus_attr = to_bus_attr(attr);	struct subsys_private *subsys_priv = to_subsys_private(kobj);	/* return -EIO for reading a bus attribute without show() */	ssize_t ret = -EIO; 	if (bus_attr->show)		ret = bus_attr->show(subsys_priv->bus, buf);	return ret;} static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,			      const char *buf, size_t count){	struct bus_attribute *bus_attr = to_bus_attr(attr);	struct subsys_private *subsys_priv = to_subsys_private(kobj);	/* return -EIO for writing a bus attribute without store() */	ssize_t ret = -EIO; 	if (bus_attr->store)		ret = bus_attr->store(subsys_priv->bus, buf, count);	return ret;} static const struct sysfs_ops bus_sysfs_ops = {	.show	= bus_attr_show,	.store	= bus_attr_store,}; int bus_create_file(const struct bus_type *bus, struct bus_attribute *attr){	struct subsys_private *sp = bus_to_subsys(bus);	int error; 	if (!sp)		return -EINVAL; 	error = sysfs_create_file(&sp->subsys.kobj, &attr->attr); 	subsys_put(sp);	return error;}EXPORT_SYMBOL_GPL(bus_create_file); void bus_remove_file(const struct bus_type *bus, struct bus_attribute *attr){	struct subsys_private *sp = bus_to_subsys(bus); 	if (!sp)		return; 	sysfs_remove_file(&sp->subsys.kobj, &attr->attr);	subsys_put(sp);}EXPORT_SYMBOL_GPL(bus_remove_file); static void bus_release(struct kobject *kobj){	struct subsys_private *priv = to_subsys_private(kobj); 	lockdep_unregister_key(&priv->lock_key);	kfree(priv);} static const struct kobj_type bus_ktype = {	.sysfs_ops	= &bus_sysfs_ops,	.release	= bus_release,}; static int bus_uevent_filter(const struct kobject *kobj){	const struct kobj_type *ktype = get_ktype(kobj); 	if (ktype == &bus_ktype)		return 1;	return 0;} static const struct kset_uevent_ops bus_uevent_ops = {	.filter = bus_uevent_filter,}; /* Manually detach a device from its associated driver. */static ssize_t unbind_store(struct device_driver *drv, const char *buf,			    size_t count){	const struct bus_type *bus = bus_get(drv->bus);	struct device *dev;	int err = -ENODEV; 	dev = bus_find_device_by_name(bus, NULL, buf);	if (dev && dev->driver == drv) {		device_driver_detach(dev);		err = count;	}	put_device(dev);	bus_put(bus);	return err;}static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); /* * Manually attach a device to a driver. * Note: the driver must want to bind to the device, * it is not possible to override the driver's id table. */static ssize_t bind_store(struct device_driver *drv, const char *buf,			  size_t count){	const struct bus_type *bus = bus_get(drv->bus);	struct device *dev;	int err = -ENODEV; 	dev = bus_find_device_by_name(bus, NULL, buf);	if (dev && driver_match_device(drv, dev)) {		err = device_driver_attach(drv, dev);		if (!err) {			/* success */			err = count;		}	}	put_device(dev);	bus_put(bus);	return err;}static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); static ssize_t drivers_autoprobe_show(const struct bus_type *bus, char *buf){	struct subsys_private *sp = bus_to_subsys(bus);	int ret; 	if (!sp)		return -EINVAL; 	ret = sysfs_emit(buf, "%d\n", sp->drivers_autoprobe);	subsys_put(sp);	return ret;} static ssize_t drivers_autoprobe_store(const struct bus_type *bus,				       const char *buf, size_t count){	struct subsys_private *sp = bus_to_subsys(bus); 	if (!sp)		return -EINVAL; 	if (buf[0] == '0')		sp->drivers_autoprobe = 0;	else		sp->drivers_autoprobe = 1; 	subsys_put(sp);	return count;} static ssize_t drivers_probe_store(const struct bus_type *bus,				   const char *buf, size_t count){	struct device *dev;	int err = -EINVAL; 	dev = bus_find_device_by_name(bus, NULL, buf);	if (!dev)		return -ENODEV;	if (bus_rescan_devices_helper(dev, NULL) == 0)		err = count;	put_device(dev);	return err;} static struct device *next_device(struct klist_iter *i){	struct klist_node *n = klist_next(i);	struct device *dev = NULL;	struct device_private *dev_prv; 	if (n) {		dev_prv = to_device_private_bus(n);		dev = dev_prv->device;	}	return dev;} static struct device *prev_device(struct klist_iter *i){	struct klist_node *n = klist_prev(i);	struct device *dev = NULL;	struct device_private *dev_prv; 	if (n) {		dev_prv = to_device_private_bus(n);		dev = dev_prv->device;	}	return dev;} /** * bus_for_each_dev - device iterator. * @bus: bus type. * @start: device to start iterating from. * @data: data for the callback. * @fn: function to be called for each device. * * Iterate over @bus's list of devices, and call @fn for each, * passing it @data. If @start is not NULL, we use that device to * begin iterating from. * * We check the return of @fn each time. If it returns anything * other than 0, we break out and return that value. * * NOTE: The device that returns a non-zero value is not retained * in any way, nor is its refcount incremented. If the caller needs * to retain this data, it should do so, and increment the reference * count in the supplied callback. */int bus_for_each_dev(const struct bus_type *bus, struct device *start,		     void *data, device_iter_t fn){	struct subsys_private *sp = bus_to_subsys(bus);	struct klist_iter i;	struct device *dev;	int error = 0; 	if (!sp)		return -EINVAL; 	klist_iter_init_node(&sp->klist_devices, &i,			     (start ? &start->p->knode_bus : NULL));	while (!error && (dev = next_device(&i)))		error = fn(dev, data);	klist_iter_exit(&i);	subsys_put(sp);	return error;}EXPORT_SYMBOL_GPL(bus_for_each_dev); /** * bus_find_device - device iterator for locating a particular device. * @bus: bus type * @start: Device to begin with * @data: Data to pass to match function * @match: Callback function to check device * * This is similar to the bus_for_each_dev() 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, this function will * return to the caller and not iterate over any more devices. */struct device *bus_find_device(const struct bus_type *bus,			       struct device *start, const void *data,			       device_match_t match){	struct subsys_private *sp = bus_to_subsys(bus);	struct klist_iter i;	struct device *dev; 	if (!sp)		return NULL; 	klist_iter_init_node(&sp->klist_devices, &i,			     (start ? &start->p->knode_bus : NULL));	while ((dev = next_device(&i))) {		if (match(dev, data)) {			get_device(dev);			break;		}	}	klist_iter_exit(&i);	subsys_put(sp);	return dev;}EXPORT_SYMBOL_GPL(bus_find_device); struct device *bus_find_device_reverse(const struct bus_type *bus,				       struct device *start, const void *data,				       device_match_t match){	struct subsys_private *sp = bus_to_subsys(bus);	struct klist_iter i;	struct device *dev; 	if (!sp)		return NULL; 	klist_iter_init_node(&sp->klist_devices, &i,			     (start ? &start->p->knode_bus : NULL));	while ((dev = prev_device(&i))) {		if (match(dev, data)) {			get_device(dev);			break;		}	}	klist_iter_exit(&i);	subsys_put(sp);	return dev;}EXPORT_SYMBOL_GPL(bus_find_device_reverse); static struct device_driver *next_driver(struct klist_iter *i){	struct klist_node *n = klist_next(i);	struct driver_private *drv_priv; 	if (n) {		drv_priv = container_of(n, struct driver_private, knode_bus);		return drv_priv->driver;	}	return NULL;} /** * bus_for_each_drv - driver iterator * @bus: bus we're dealing with. * @start: driver to start iterating on. * @data: data to pass to the callback. * @fn: function to call for each driver. * * This is nearly identical to the device iterator above. * We iterate over each driver that belongs to @bus, and call * @fn for each. If @fn returns anything but 0, we break out * and return it. If @start is not NULL, we use it as the head * of the list. * * NOTE: we don't return the driver that returns a non-zero * value, nor do we leave the reference count incremented for that * driver. If the caller needs to know that info, it must set it * in the callback. It must also be sure to increment the refcount * so it doesn't disappear before returning to the caller. */int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,		     void *data, int (*fn)(struct device_driver *, void *)){	struct subsys_private *sp = bus_to_subsys(bus);	struct klist_iter i;	struct device_driver *drv;	int error = 0; 	if (!sp)		return -EINVAL; 	klist_iter_init_node(&sp->klist_drivers, &i,			     start ? &start->p->knode_bus : NULL);	while ((drv = next_driver(&i)) && !error)		error = fn(drv, data);

Lines 1–500 of 1489.