File Index
Files and directories
Sign in
FILE

driver.c

File preview with syntax highlighting.

linux-6.19.14/drivers/base/driver.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * driver.c - centralized device driver management
  4 *
  5 * Copyright (c) 2002-3 Patrick Mochel
  6 * Copyright (c) 2002-3 Open Source Development Labs
  7 * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
  8 * Copyright (c) 2007 Novell Inc.
  9 */
 10
 11#include <linux/device/driver.h>
 12#include <linux/device.h>
 13#include <linux/module.h>
 14#include <linux/errno.h>
 15#include <linux/slab.h>
 16#include <linux/string.h>
 17#include <linux/sysfs.h>
 18#include "base.h"
 19
 20static struct device *next_device(struct klist_iter *i)
 21{
 22	struct klist_node *n = klist_next(i);
 23	struct device *dev = NULL;
 24	struct device_private *dev_prv;
 25
 26	if (n) {
 27		dev_prv = to_device_private_driver(n);
 28		dev = dev_prv->device;
 29	}
 30	return dev;
 31}
 32
 33/**
 34 * driver_set_override() - Helper to set or clear driver override.
 35 * @dev: Device to change
 36 * @override: Address of string to change (e.g. &device->driver_override);
 37 *            The contents will be freed and hold newly allocated override.
 38 * @s: NUL-terminated string, new driver name to force a match, pass empty
 39 *     string to clear it ("" or "\n", where the latter is only for sysfs
 40 *     interface).
 41 * @len: length of @s
 42 *
 43 * Helper to set or clear driver override in a device, intended for the cases
 44 * when the driver_override field is allocated by driver/bus code.
 45 *
 46 * Returns: 0 on success or a negative error code on failure.
 47 */
 48int driver_set_override(struct device *dev, const char **override,
 49			const char *s, size_t len)
 50{
 51	const char *new, *old;
 52	char *cp;
 53
 54	if (!override || !s)
 55		return -EINVAL;
 56
 57	/*
 58	 * The stored value will be used in sysfs show callback (sysfs_emit()),
 59	 * which has a length limit of PAGE_SIZE and adds a trailing newline.
 60	 * Thus we can store one character less to avoid truncation during sysfs
 61	 * show.
 62	 */
 63	if (len >= (PAGE_SIZE - 1))
 64		return -EINVAL;
 65
 66	/*
 67	 * Compute the real length of the string in case userspace sends us a
 68	 * bunch of \0 characters like python likes to do.
 69	 */
 70	len = strlen(s);
 71
 72	if (!len) {
 73		/* Empty string passed - clear override */
 74		device_lock(dev);
 75		old = *override;
 76		*override = NULL;
 77		device_unlock(dev);
 78		kfree(old);
 79
 80		return 0;
 81	}
 82
 83	cp = strnchr(s, len, '\n');
 84	if (cp)
 85		len = cp - s;
 86
 87	new = kstrndup(s, len, GFP_KERNEL);
 88	if (!new)
 89		return -ENOMEM;
 90
 91	device_lock(dev);
 92	old = *override;
 93	if (cp != s) {
 94		*override = new;
 95	} else {
 96		/* "\n" passed - clear override */
 97		kfree(new);
 98		*override = NULL;
 99	}
100	device_unlock(dev);
101
102	kfree(old);
103
104	return 0;
105}
106EXPORT_SYMBOL_GPL(driver_set_override);
107
108/**
109 * driver_for_each_device - Iterator for devices bound to a driver.
110 * @drv: Driver we're iterating.
111 * @start: Device to begin with
112 * @data: Data to pass to the callback.
113 * @fn: Function to call for each device.
114 *
115 * Iterate over the @drv's list of devices calling @fn for each one.
116 */
117int driver_for_each_device(struct device_driver *drv, struct device *start,
118			   void *data, device_iter_t fn)
119{
120	struct klist_iter i;
121	struct device *dev;
122	int error = 0;
123
124	if (!drv)
125		return -EINVAL;
126
127	klist_iter_init_node(&drv->p->klist_devices, &i,
128			     start ? &start->p->knode_driver : NULL);
129	while (!error && (dev = next_device(&i)))
130		error = fn(dev, data);
131	klist_iter_exit(&i);
132	return error;
133}
134EXPORT_SYMBOL_GPL(driver_for_each_device);
135
136/**
137 * driver_find_device - device iterator for locating a particular device.
138 * @drv: The device's driver
139 * @start: Device to begin with
140 * @data: Data to pass to match function
141 * @match: Callback function to check device
142 *
143 * This is similar to the driver_for_each_device() function above, but
144 * it returns a reference to a device that is 'found' for later use, as
145 * determined by the @match callback.
146 *
147 * The callback should return 0 if the device doesn't match and non-zero
148 * if it does.  If the callback returns non-zero, this function will
149 * return to the caller and not iterate over any more devices.
150 */
151struct device *driver_find_device(const struct device_driver *drv,
152				  struct device *start, const void *data,
153				  device_match_t match)
154{
155	struct klist_iter i;
156	struct device *dev;
157
158	if (!drv || !drv->p)
159		return NULL;
160
161	klist_iter_init_node(&drv->p->klist_devices, &i,
162			     (start ? &start->p->knode_driver : NULL));
163	while ((dev = next_device(&i))) {
164		if (match(dev, data)) {
165			get_device(dev);
166			break;
167		}
168	}
169	klist_iter_exit(&i);
170	return dev;
171}
172EXPORT_SYMBOL_GPL(driver_find_device);
173
174/**
175 * driver_create_file - create sysfs file for driver.
176 * @drv: driver.
177 * @attr: driver attribute descriptor.
178 */
179int driver_create_file(const struct device_driver *drv,
180		       const struct driver_attribute *attr)
181{
182	int error;
183
184	if (drv)
185		error = sysfs_create_file(&drv->p->kobj, &attr->attr);
186	else
187		error = -EINVAL;
188	return error;
189}
190EXPORT_SYMBOL_GPL(driver_create_file);
191
192/**
193 * driver_remove_file - remove sysfs file for driver.
194 * @drv: driver.
195 * @attr: driver attribute descriptor.
196 */
197void driver_remove_file(const struct device_driver *drv,
198			const struct driver_attribute *attr)
199{
200	if (drv)
201		sysfs_remove_file(&drv->p->kobj, &attr->attr);
202}
203EXPORT_SYMBOL_GPL(driver_remove_file);
204
205int driver_add_groups(const struct device_driver *drv,
206		      const struct attribute_group **groups)
207{
208	return sysfs_create_groups(&drv->p->kobj, groups);
209}
210
211void driver_remove_groups(const struct device_driver *drv,
212			  const struct attribute_group **groups)
213{
214	sysfs_remove_groups(&drv->p->kobj, groups);
215}
216
217/**
218 * driver_register - register driver with bus
219 * @drv: driver to register
220 *
221 * We pass off most of the work to the bus_add_driver() call,
222 * since most of the things we have to do deal with the bus
223 * structures.
224 */
225int driver_register(struct device_driver *drv)
226{
227	int ret;
228	struct device_driver *other;
229
230	if (!bus_is_registered(drv->bus)) {
231		pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
232			   drv->name, drv->bus->name);
233		return -EINVAL;
234	}
235
236	if ((drv->bus->probe && drv->probe) ||
237	    (drv->bus->remove && drv->remove) ||
238	    (drv->bus->shutdown && drv->shutdown))
239		pr_warn("Driver '%s' needs updating - please use "
240			"bus_type methods\n", drv->name);
241
242	other = driver_find(drv->name, drv->bus);
243	if (other) {
244		pr_err("Error: Driver '%s' is already registered, "
245			"aborting...\n", drv->name);
246		return -EBUSY;
247	}
248
249	ret = bus_add_driver(drv);
250	if (ret)
251		return ret;
252	ret = driver_add_groups(drv, drv->groups);
253	if (ret) {
254		bus_remove_driver(drv);
255		return ret;
256	}
257	kobject_uevent(&drv->p->kobj, KOBJ_ADD);
258	deferred_probe_extend_timeout();
259
260	return ret;
261}
262EXPORT_SYMBOL_GPL(driver_register);
263
264/**
265 * driver_unregister - remove driver from system.
266 * @drv: driver.
267 *
268 * Again, we pass off most of the work to the bus-level call.
269 */
270void driver_unregister(struct device_driver *drv)
271{
272	if (!drv || !drv->p) {
273		WARN(1, "Unexpected driver unregister!\n");
274		return;
275	}
276	driver_remove_groups(drv, drv->groups);
277	bus_remove_driver(drv);
278}
279EXPORT_SYMBOL_GPL(driver_unregister);
~/ Read-only file preview.