162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * driver.c - centralized device driver management 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002-3 Patrick Mochel 662306a36Sopenharmony_ci * Copyright (c) 2002-3 Open Source Development Labs 762306a36Sopenharmony_ci * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> 862306a36Sopenharmony_ci * Copyright (c) 2007 Novell Inc. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/device/driver.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/sysfs.h> 1862306a36Sopenharmony_ci#include "base.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic struct device *next_device(struct klist_iter *i) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct klist_node *n = klist_next(i); 2362306a36Sopenharmony_ci struct device *dev = NULL; 2462306a36Sopenharmony_ci struct device_private *dev_prv; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (n) { 2762306a36Sopenharmony_ci dev_prv = to_device_private_driver(n); 2862306a36Sopenharmony_ci dev = dev_prv->device; 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci return dev; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/** 3462306a36Sopenharmony_ci * driver_set_override() - Helper to set or clear driver override. 3562306a36Sopenharmony_ci * @dev: Device to change 3662306a36Sopenharmony_ci * @override: Address of string to change (e.g. &device->driver_override); 3762306a36Sopenharmony_ci * The contents will be freed and hold newly allocated override. 3862306a36Sopenharmony_ci * @s: NUL-terminated string, new driver name to force a match, pass empty 3962306a36Sopenharmony_ci * string to clear it ("" or "\n", where the latter is only for sysfs 4062306a36Sopenharmony_ci * interface). 4162306a36Sopenharmony_ci * @len: length of @s 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Helper to set or clear driver override in a device, intended for the cases 4462306a36Sopenharmony_ci * when the driver_override field is allocated by driver/bus code. 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Returns: 0 on success or a negative error code on failure. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ciint driver_set_override(struct device *dev, const char **override, 4962306a36Sopenharmony_ci const char *s, size_t len) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci const char *new, *old; 5262306a36Sopenharmony_ci char *cp; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!override || !s) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * The stored value will be used in sysfs show callback (sysfs_emit()), 5962306a36Sopenharmony_ci * which has a length limit of PAGE_SIZE and adds a trailing newline. 6062306a36Sopenharmony_ci * Thus we can store one character less to avoid truncation during sysfs 6162306a36Sopenharmony_ci * show. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci if (len >= (PAGE_SIZE - 1)) 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * Compute the real length of the string in case userspace sends us a 6862306a36Sopenharmony_ci * bunch of \0 characters like python likes to do. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci len = strlen(s); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!len) { 7362306a36Sopenharmony_ci /* Empty string passed - clear override */ 7462306a36Sopenharmony_ci device_lock(dev); 7562306a36Sopenharmony_ci old = *override; 7662306a36Sopenharmony_ci *override = NULL; 7762306a36Sopenharmony_ci device_unlock(dev); 7862306a36Sopenharmony_ci kfree(old); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci cp = strnchr(s, len, '\n'); 8462306a36Sopenharmony_ci if (cp) 8562306a36Sopenharmony_ci len = cp - s; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci new = kstrndup(s, len, GFP_KERNEL); 8862306a36Sopenharmony_ci if (!new) 8962306a36Sopenharmony_ci return -ENOMEM; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci device_lock(dev); 9262306a36Sopenharmony_ci old = *override; 9362306a36Sopenharmony_ci if (cp != s) { 9462306a36Sopenharmony_ci *override = new; 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci /* "\n" passed - clear override */ 9762306a36Sopenharmony_ci kfree(new); 9862306a36Sopenharmony_ci *override = NULL; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci device_unlock(dev); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci kfree(old); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_set_override); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/** 10962306a36Sopenharmony_ci * driver_for_each_device - Iterator for devices bound to a driver. 11062306a36Sopenharmony_ci * @drv: Driver we're iterating. 11162306a36Sopenharmony_ci * @start: Device to begin with 11262306a36Sopenharmony_ci * @data: Data to pass to the callback. 11362306a36Sopenharmony_ci * @fn: Function to call for each device. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Iterate over the @drv's list of devices calling @fn for each one. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ciint driver_for_each_device(struct device_driver *drv, struct device *start, 11862306a36Sopenharmony_ci void *data, int (*fn)(struct device *, void *)) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct klist_iter i; 12162306a36Sopenharmony_ci struct device *dev; 12262306a36Sopenharmony_ci int error = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (!drv) 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci klist_iter_init_node(&drv->p->klist_devices, &i, 12862306a36Sopenharmony_ci start ? &start->p->knode_driver : NULL); 12962306a36Sopenharmony_ci while (!error && (dev = next_device(&i))) 13062306a36Sopenharmony_ci error = fn(dev, data); 13162306a36Sopenharmony_ci klist_iter_exit(&i); 13262306a36Sopenharmony_ci return error; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_for_each_device); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * driver_find_device - device iterator for locating a particular device. 13862306a36Sopenharmony_ci * @drv: The device's driver 13962306a36Sopenharmony_ci * @start: Device to begin with 14062306a36Sopenharmony_ci * @data: Data to pass to match function 14162306a36Sopenharmony_ci * @match: Callback function to check device 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * This is similar to the driver_for_each_device() function above, but 14462306a36Sopenharmony_ci * it returns a reference to a device that is 'found' for later use, as 14562306a36Sopenharmony_ci * determined by the @match callback. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * The callback should return 0 if the device doesn't match and non-zero 14862306a36Sopenharmony_ci * if it does. If the callback returns non-zero, this function will 14962306a36Sopenharmony_ci * return to the caller and not iterate over any more devices. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistruct device *driver_find_device(struct device_driver *drv, 15262306a36Sopenharmony_ci struct device *start, const void *data, 15362306a36Sopenharmony_ci int (*match)(struct device *dev, const void *data)) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct klist_iter i; 15662306a36Sopenharmony_ci struct device *dev; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!drv || !drv->p) 15962306a36Sopenharmony_ci return NULL; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci klist_iter_init_node(&drv->p->klist_devices, &i, 16262306a36Sopenharmony_ci (start ? &start->p->knode_driver : NULL)); 16362306a36Sopenharmony_ci while ((dev = next_device(&i))) 16462306a36Sopenharmony_ci if (match(dev, data) && get_device(dev)) 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci klist_iter_exit(&i); 16762306a36Sopenharmony_ci return dev; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_find_device); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * driver_create_file - create sysfs file for driver. 17362306a36Sopenharmony_ci * @drv: driver. 17462306a36Sopenharmony_ci * @attr: driver attribute descriptor. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ciint driver_create_file(struct device_driver *drv, 17762306a36Sopenharmony_ci const struct driver_attribute *attr) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci int error; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (drv) 18262306a36Sopenharmony_ci error = sysfs_create_file(&drv->p->kobj, &attr->attr); 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci error = -EINVAL; 18562306a36Sopenharmony_ci return error; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_create_file); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * driver_remove_file - remove sysfs file for driver. 19162306a36Sopenharmony_ci * @drv: driver. 19262306a36Sopenharmony_ci * @attr: driver attribute descriptor. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_civoid driver_remove_file(struct device_driver *drv, 19562306a36Sopenharmony_ci const struct driver_attribute *attr) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci if (drv) 19862306a36Sopenharmony_ci sysfs_remove_file(&drv->p->kobj, &attr->attr); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_remove_file); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciint driver_add_groups(struct device_driver *drv, 20362306a36Sopenharmony_ci const struct attribute_group **groups) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci return sysfs_create_groups(&drv->p->kobj, groups); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_civoid driver_remove_groups(struct device_driver *drv, 20962306a36Sopenharmony_ci const struct attribute_group **groups) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci sysfs_remove_groups(&drv->p->kobj, groups); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * driver_register - register driver with bus 21662306a36Sopenharmony_ci * @drv: driver to register 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * We pass off most of the work to the bus_add_driver() call, 21962306a36Sopenharmony_ci * since most of the things we have to do deal with the bus 22062306a36Sopenharmony_ci * structures. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ciint driver_register(struct device_driver *drv) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int ret; 22562306a36Sopenharmony_ci struct device_driver *other; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!bus_is_registered(drv->bus)) { 22862306a36Sopenharmony_ci pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", 22962306a36Sopenharmony_ci drv->name, drv->bus->name); 23062306a36Sopenharmony_ci return -EINVAL; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if ((drv->bus->probe && drv->probe) || 23462306a36Sopenharmony_ci (drv->bus->remove && drv->remove) || 23562306a36Sopenharmony_ci (drv->bus->shutdown && drv->shutdown)) 23662306a36Sopenharmony_ci pr_warn("Driver '%s' needs updating - please use " 23762306a36Sopenharmony_ci "bus_type methods\n", drv->name); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci other = driver_find(drv->name, drv->bus); 24062306a36Sopenharmony_ci if (other) { 24162306a36Sopenharmony_ci pr_err("Error: Driver '%s' is already registered, " 24262306a36Sopenharmony_ci "aborting...\n", drv->name); 24362306a36Sopenharmony_ci return -EBUSY; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ret = bus_add_driver(drv); 24762306a36Sopenharmony_ci if (ret) 24862306a36Sopenharmony_ci return ret; 24962306a36Sopenharmony_ci ret = driver_add_groups(drv, drv->groups); 25062306a36Sopenharmony_ci if (ret) { 25162306a36Sopenharmony_ci bus_remove_driver(drv); 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci kobject_uevent(&drv->p->kobj, KOBJ_ADD); 25562306a36Sopenharmony_ci deferred_probe_extend_timeout(); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_register); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/** 26262306a36Sopenharmony_ci * driver_unregister - remove driver from system. 26362306a36Sopenharmony_ci * @drv: driver. 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * Again, we pass off most of the work to the bus-level call. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_civoid driver_unregister(struct device_driver *drv) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci if (!drv || !drv->p) { 27062306a36Sopenharmony_ci WARN(1, "Unexpected driver unregister!\n"); 27162306a36Sopenharmony_ci return; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci driver_remove_groups(drv, drv->groups); 27462306a36Sopenharmony_ci bus_remove_driver(drv); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(driver_unregister); 277