xref: /linux-6.15/drivers/base/driver.c (revision 767b74e0)
1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * driver.c - centralized device driver management
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 2002-3 Patrick Mochel
61da177e4SLinus Torvalds  * Copyright (c) 2002-3 Open Source Development Labs
7e5dd1278SGreg Kroah-Hartman  * Copyright (c) 2007 Greg Kroah-Hartman <[email protected]>
8e5dd1278SGreg Kroah-Hartman  * Copyright (c) 2007 Novell Inc.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
114c002c97SGreg Kroah-Hartman #include <linux/device/driver.h>
121da177e4SLinus Torvalds #include <linux/device.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/errno.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
161da177e4SLinus Torvalds #include <linux/string.h>
1763967685SGreg Kroah-Hartman #include <linux/sysfs.h>
181da177e4SLinus Torvalds #include "base.h"
191da177e4SLinus Torvalds 
next_device(struct klist_iter * i)2094e7b1c5S[email protected] static struct device *next_device(struct klist_iter *i)
2194e7b1c5S[email protected] {
2294e7b1c5S[email protected] 	struct klist_node *n = klist_next(i);
238940b4f3SGreg Kroah-Hartman 	struct device *dev = NULL;
248940b4f3SGreg Kroah-Hartman 	struct device_private *dev_prv;
258940b4f3SGreg Kroah-Hartman 
268940b4f3SGreg Kroah-Hartman 	if (n) {
278940b4f3SGreg Kroah-Hartman 		dev_prv = to_device_private_driver(n);
288940b4f3SGreg Kroah-Hartman 		dev = dev_prv->device;
298940b4f3SGreg Kroah-Hartman 	}
308940b4f3SGreg Kroah-Hartman 	return dev;
3194e7b1c5S[email protected] }
3294e7b1c5S[email protected] 
33fae3cd00S[email protected] /**
346c2f4211SKrzysztof Kozlowski  * driver_set_override() - Helper to set or clear driver override.
356c2f4211SKrzysztof Kozlowski  * @dev: Device to change
366c2f4211SKrzysztof Kozlowski  * @override: Address of string to change (e.g. &device->driver_override);
376c2f4211SKrzysztof Kozlowski  *            The contents will be freed and hold newly allocated override.
386c2f4211SKrzysztof Kozlowski  * @s: NUL-terminated string, new driver name to force a match, pass empty
396c2f4211SKrzysztof Kozlowski  *     string to clear it ("" or "\n", where the latter is only for sysfs
406c2f4211SKrzysztof Kozlowski  *     interface).
416c2f4211SKrzysztof Kozlowski  * @len: length of @s
426c2f4211SKrzysztof Kozlowski  *
436c2f4211SKrzysztof Kozlowski  * Helper to set or clear driver override in a device, intended for the cases
446c2f4211SKrzysztof Kozlowski  * when the driver_override field is allocated by driver/bus code.
456c2f4211SKrzysztof Kozlowski  *
466c2f4211SKrzysztof Kozlowski  * Returns: 0 on success or a negative error code on failure.
476c2f4211SKrzysztof Kozlowski  */
driver_set_override(struct device * dev,const char ** override,const char * s,size_t len)486c2f4211SKrzysztof Kozlowski int driver_set_override(struct device *dev, const char **override,
496c2f4211SKrzysztof Kozlowski 			const char *s, size_t len)
506c2f4211SKrzysztof Kozlowski {
516c2f4211SKrzysztof Kozlowski 	const char *new, *old;
526c2f4211SKrzysztof Kozlowski 	char *cp;
536c2f4211SKrzysztof Kozlowski 
546c2f4211SKrzysztof Kozlowski 	if (!override || !s)
556c2f4211SKrzysztof Kozlowski 		return -EINVAL;
566c2f4211SKrzysztof Kozlowski 
576c2f4211SKrzysztof Kozlowski 	/*
586c2f4211SKrzysztof Kozlowski 	 * The stored value will be used in sysfs show callback (sysfs_emit()),
596c2f4211SKrzysztof Kozlowski 	 * which has a length limit of PAGE_SIZE and adds a trailing newline.
606c2f4211SKrzysztof Kozlowski 	 * Thus we can store one character less to avoid truncation during sysfs
616c2f4211SKrzysztof Kozlowski 	 * show.
626c2f4211SKrzysztof Kozlowski 	 */
636c2f4211SKrzysztof Kozlowski 	if (len >= (PAGE_SIZE - 1))
646c2f4211SKrzysztof Kozlowski 		return -EINVAL;
656c2f4211SKrzysztof Kozlowski 
665666a274SGreg Kroah-Hartman 	/*
675666a274SGreg Kroah-Hartman 	 * Compute the real length of the string in case userspace sends us a
685666a274SGreg Kroah-Hartman 	 * bunch of \0 characters like python likes to do.
695666a274SGreg Kroah-Hartman 	 */
705666a274SGreg Kroah-Hartman 	len = strlen(s);
715666a274SGreg Kroah-Hartman 
726c2f4211SKrzysztof Kozlowski 	if (!len) {
736c2f4211SKrzysztof Kozlowski 		/* Empty string passed - clear override */
746c2f4211SKrzysztof Kozlowski 		device_lock(dev);
756c2f4211SKrzysztof Kozlowski 		old = *override;
766c2f4211SKrzysztof Kozlowski 		*override = NULL;
776c2f4211SKrzysztof Kozlowski 		device_unlock(dev);
786c2f4211SKrzysztof Kozlowski 		kfree(old);
796c2f4211SKrzysztof Kozlowski 
806c2f4211SKrzysztof Kozlowski 		return 0;
816c2f4211SKrzysztof Kozlowski 	}
826c2f4211SKrzysztof Kozlowski 
836c2f4211SKrzysztof Kozlowski 	cp = strnchr(s, len, '\n');
846c2f4211SKrzysztof Kozlowski 	if (cp)
856c2f4211SKrzysztof Kozlowski 		len = cp - s;
866c2f4211SKrzysztof Kozlowski 
876c2f4211SKrzysztof Kozlowski 	new = kstrndup(s, len, GFP_KERNEL);
886c2f4211SKrzysztof Kozlowski 	if (!new)
896c2f4211SKrzysztof Kozlowski 		return -ENOMEM;
906c2f4211SKrzysztof Kozlowski 
916c2f4211SKrzysztof Kozlowski 	device_lock(dev);
926c2f4211SKrzysztof Kozlowski 	old = *override;
936c2f4211SKrzysztof Kozlowski 	if (cp != s) {
946c2f4211SKrzysztof Kozlowski 		*override = new;
956c2f4211SKrzysztof Kozlowski 	} else {
966c2f4211SKrzysztof Kozlowski 		/* "\n" passed - clear override */
976c2f4211SKrzysztof Kozlowski 		kfree(new);
986c2f4211SKrzysztof Kozlowski 		*override = NULL;
996c2f4211SKrzysztof Kozlowski 	}
1006c2f4211SKrzysztof Kozlowski 	device_unlock(dev);
1016c2f4211SKrzysztof Kozlowski 
1026c2f4211SKrzysztof Kozlowski 	kfree(old);
1036c2f4211SKrzysztof Kozlowski 
1046c2f4211SKrzysztof Kozlowski 	return 0;
1056c2f4211SKrzysztof Kozlowski }
1066c2f4211SKrzysztof Kozlowski EXPORT_SYMBOL_GPL(driver_set_override);
1076c2f4211SKrzysztof Kozlowski 
1086c2f4211SKrzysztof Kozlowski /**
109fae3cd00S[email protected]  * driver_for_each_device - Iterator for devices bound to a driver.
110fae3cd00S[email protected]  * @drv: Driver we're iterating.
111c41455fbSRandy Dunlap  * @start: Device to begin with
112fae3cd00S[email protected]  * @data: Data to pass to the callback.
113fae3cd00S[email protected]  * @fn: Function to call for each device.
114fae3cd00S[email protected]  *
1154d12d2d9S[email protected]  * Iterate over the @drv's list of devices calling @fn for each one.
116fae3cd00S[email protected]  */
driver_for_each_device(struct device_driver * drv,struct device * start,void * data,device_iter_t fn)117fae3cd00S[email protected] int driver_for_each_device(struct device_driver *drv, struct device *start,
118*767b74e0SZijun Hu 			   void *data, device_iter_t fn)
119fae3cd00S[email protected] {
12094e7b1c5S[email protected] 	struct klist_iter i;
121fae3cd00S[email protected] 	struct device *dev;
122fae3cd00S[email protected] 	int error = 0;
123fae3cd00S[email protected] 
12494e7b1c5S[email protected] 	if (!drv)
12594e7b1c5S[email protected] 		return -EINVAL;
12694e7b1c5S[email protected] 
1277cd9c9bbSGreg Kroah-Hartman 	klist_iter_init_node(&drv->p->klist_devices, &i,
1288940b4f3SGreg Kroah-Hartman 			     start ? &start->p->knode_driver : NULL);
12993ead7c9SGimcuan Hui 	while (!error && (dev = next_device(&i)))
130fae3cd00S[email protected] 		error = fn(dev, data);
13194e7b1c5S[email protected] 	klist_iter_exit(&i);
132fae3cd00S[email protected] 	return error;
133fae3cd00S[email protected] }
134126eddfbS[email protected] EXPORT_SYMBOL_GPL(driver_for_each_device);
135fae3cd00S[email protected] 
1361da177e4SLinus Torvalds /**
1370edb5860SCornelia Huck  * driver_find_device - device iterator for locating a particular device.
138c41455fbSRandy Dunlap  * @drv: The device's driver
1390edb5860SCornelia Huck  * @start: Device to begin with
1400edb5860SCornelia Huck  * @data: Data to pass to match function
1410edb5860SCornelia Huck  * @match: Callback function to check device
1420edb5860SCornelia Huck  *
1430edb5860SCornelia Huck  * This is similar to the driver_for_each_device() function above, but
1440edb5860SCornelia Huck  * it returns a reference to a device that is 'found' for later use, as
1450edb5860SCornelia Huck  * determined by the @match callback.
1460edb5860SCornelia Huck  *
1470edb5860SCornelia Huck  * The callback should return 0 if the device doesn't match and non-zero
1480edb5860SCornelia Huck  * if it does.  If the callback returns non-zero, this function will
1490edb5860SCornelia Huck  * return to the caller and not iterate over any more devices.
1500edb5860SCornelia Huck  */
driver_find_device(const struct device_driver * drv,struct device * start,const void * data,device_match_t match)151f8fb4691SGreg Kroah-Hartman struct device *driver_find_device(const struct device_driver *drv,
15292ce7e83SSuzuki K Poulose 				  struct device *start, const void *data,
153b45ed06fSZijun Hu 				  device_match_t match)
1540edb5860SCornelia Huck {
1550edb5860SCornelia Huck 	struct klist_iter i;
1560edb5860SCornelia Huck 	struct device *dev;
1570edb5860SCornelia Huck 
158094e47e9SHiroshi DOYU 	if (!drv || !drv->p)
1590edb5860SCornelia Huck 		return NULL;
1600edb5860SCornelia Huck 
1617cd9c9bbSGreg Kroah-Hartman 	klist_iter_init_node(&drv->p->klist_devices, &i,
1627cd9c9bbSGreg Kroah-Hartman 			     (start ? &start->p->knode_driver : NULL));
1633f58ee54SZijun Hu 	while ((dev = next_device(&i))) {
1643f58ee54SZijun Hu 		if (match(dev, data)) {
1653f58ee54SZijun Hu 			get_device(dev);
1660edb5860SCornelia Huck 			break;
1673f58ee54SZijun Hu 		}
1683f58ee54SZijun Hu 	}
1690edb5860SCornelia Huck 	klist_iter_exit(&i);
1700edb5860SCornelia Huck 	return dev;
1710edb5860SCornelia Huck }
1720edb5860SCornelia Huck EXPORT_SYMBOL_GPL(driver_find_device);
1730edb5860SCornelia Huck 
1740edb5860SCornelia Huck /**
1751da177e4SLinus Torvalds  * driver_create_file - create sysfs file for driver.
1761da177e4SLinus Torvalds  * @drv: driver.
1771da177e4SLinus Torvalds  * @attr: driver attribute descriptor.
1781da177e4SLinus Torvalds  */
driver_create_file(const struct device_driver * drv,const struct driver_attribute * attr)179ab7a8802SGreg Kroah-Hartman int driver_create_file(const struct device_driver *drv,
180099c2f21SPhil Carmody 		       const struct driver_attribute *attr)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	int error;
18374642c6cSLavinia Tache 
1840c98b19fSCornelia Huck 	if (drv)
185e5dd1278SGreg Kroah-Hartman 		error = sysfs_create_file(&drv->p->kobj, &attr->attr);
1860c98b19fSCornelia Huck 	else
1871da177e4SLinus Torvalds 		error = -EINVAL;
1881da177e4SLinus Torvalds 	return error;
1891da177e4SLinus Torvalds }
1904a3ad20cSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(driver_create_file);
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds /**
1931da177e4SLinus Torvalds  * driver_remove_file - remove sysfs file for driver.
1941da177e4SLinus Torvalds  * @drv: driver.
1951da177e4SLinus Torvalds  * @attr: driver attribute descriptor.
1961da177e4SLinus Torvalds  */
driver_remove_file(const struct device_driver * drv,const struct driver_attribute * attr)197ab7a8802SGreg Kroah-Hartman void driver_remove_file(const struct device_driver *drv,
198099c2f21SPhil Carmody 			const struct driver_attribute *attr)
1991da177e4SLinus Torvalds {
2000c98b19fSCornelia Huck 	if (drv)
201e5dd1278SGreg Kroah-Hartman 		sysfs_remove_file(&drv->p->kobj, &attr->attr);
2021da177e4SLinus Torvalds }
2034a3ad20cSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(driver_remove_file);
2041da177e4SLinus Torvalds 
driver_add_groups(const struct device_driver * drv,const struct attribute_group ** groups)2050725e8f9SGreg Kroah-Hartman int driver_add_groups(const struct device_driver *drv,
206a4dbd674SDavid Brownell 		      const struct attribute_group **groups)
20757c74534SCornelia Huck {
2083e9b2baeSGreg Kroah-Hartman 	return sysfs_create_groups(&drv->p->kobj, groups);
20957c74534SCornelia Huck }
21057c74534SCornelia Huck 
driver_remove_groups(const struct device_driver * drv,const struct attribute_group ** groups)2110725e8f9SGreg Kroah-Hartman void driver_remove_groups(const struct device_driver *drv,
212a4dbd674SDavid Brownell 			  const struct attribute_group **groups)
21357c74534SCornelia Huck {
2143e9b2baeSGreg Kroah-Hartman 	sysfs_remove_groups(&drv->p->kobj, groups);
21557c74534SCornelia Huck }
21657c74534SCornelia Huck 
2171da177e4SLinus Torvalds /**
2181da177e4SLinus Torvalds  * driver_register - register driver with bus
2191da177e4SLinus Torvalds  * @drv: driver to register
2201da177e4SLinus Torvalds  *
2211da177e4SLinus Torvalds  * We pass off most of the work to the bus_add_driver() call,
2221da177e4SLinus Torvalds  * since most of the things we have to do deal with the bus
2231da177e4SLinus Torvalds  * structures.
2241da177e4SLinus Torvalds  */
driver_register(struct device_driver * drv)2251da177e4SLinus Torvalds int driver_register(struct device_driver *drv)
2261da177e4SLinus Torvalds {
22757c74534SCornelia Huck 	int ret;
22816dc42e0SStas Sergeev 	struct device_driver *other;
22957c74534SCornelia Huck 
23063b823d7SGreg Kroah-Hartman 	if (!bus_is_registered(drv->bus)) {
2310dda2bb6SFlorian Schmaus 		pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
2320dda2bb6SFlorian Schmaus 			   drv->name, drv->bus->name);
2330dda2bb6SFlorian Schmaus 		return -EINVAL;
2340dda2bb6SFlorian Schmaus 	}
235f48f3febSDave Young 
236594c8281SRussell King 	if ((drv->bus->probe && drv->probe) ||
237594c8281SRussell King 	    (drv->bus->remove && drv->remove) ||
2384a3ad20cSGreg Kroah-Hartman 	    (drv->bus->shutdown && drv->shutdown))
2395962b8b2SMatthias Brugger 		pr_warn("Driver '%s' needs updating - please use "
2404a3ad20cSGreg Kroah-Hartman 			"bus_type methods\n", drv->name);
24116dc42e0SStas Sergeev 
24216dc42e0SStas Sergeev 	other = driver_find(drv->name, drv->bus);
24316dc42e0SStas Sergeev 	if (other) {
2445962b8b2SMatthias Brugger 		pr_err("Error: Driver '%s' is already registered, "
24516dc42e0SStas Sergeev 			"aborting...\n", drv->name);
24639acbc12SStas Sergeev 		return -EBUSY;
24716dc42e0SStas Sergeev 	}
24816dc42e0SStas Sergeev 
24957c74534SCornelia Huck 	ret = bus_add_driver(drv);
25057c74534SCornelia Huck 	if (ret)
25157c74534SCornelia Huck 		return ret;
25257c74534SCornelia Huck 	ret = driver_add_groups(drv, drv->groups);
253a14af325SSebastian Ott 	if (ret) {
25457c74534SCornelia Huck 		bus_remove_driver(drv);
255a14af325SSebastian Ott 		return ret;
256a14af325SSebastian Ott 	}
2575a7689fdSSebastian Ott 	kobject_uevent(&drv->p->kobj, KOBJ_ADD);
2582b28a1a8SSaravana Kannan 	deferred_probe_extend_timeout();
2595a7689fdSSebastian Ott 
26057c74534SCornelia Huck 	return ret;
2611da177e4SLinus Torvalds }
2624a3ad20cSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(driver_register);
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds /**
2651da177e4SLinus Torvalds  * driver_unregister - remove driver from system.
2661da177e4SLinus Torvalds  * @drv: driver.
2671da177e4SLinus Torvalds  *
2681da177e4SLinus Torvalds  * Again, we pass off most of the work to the bus-level call.
2691da177e4SLinus Torvalds  */
driver_unregister(struct device_driver * drv)2701da177e4SLinus Torvalds void driver_unregister(struct device_driver *drv)
2711da177e4SLinus Torvalds {
2725c8563d7SKay Sievers 	if (!drv || !drv->p) {
2735c8563d7SKay Sievers 		WARN(1, "Unexpected driver unregister!\n");
2745c8563d7SKay Sievers 		return;
2755c8563d7SKay Sievers 	}
27657c74534SCornelia Huck 	driver_remove_groups(drv, drv->groups);
2771da177e4SLinus Torvalds 	bus_remove_driver(drv);
2781da177e4SLinus Torvalds }
2794a3ad20cSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(driver_unregister);
280