at v5.2 5.9 kB view raw
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.h> 12#include <linux/module.h> 13#include <linux/errno.h> 14#include <linux/slab.h> 15#include <linux/string.h> 16#include <linux/sysfs.h> 17#include "base.h" 18 19static struct device *next_device(struct klist_iter *i) 20{ 21 struct klist_node *n = klist_next(i); 22 struct device *dev = NULL; 23 struct device_private *dev_prv; 24 25 if (n) { 26 dev_prv = to_device_private_driver(n); 27 dev = dev_prv->device; 28 } 29 return dev; 30} 31 32/** 33 * driver_for_each_device - Iterator for devices bound to a driver. 34 * @drv: Driver we're iterating. 35 * @start: Device to begin with 36 * @data: Data to pass to the callback. 37 * @fn: Function to call for each device. 38 * 39 * Iterate over the @drv's list of devices calling @fn for each one. 40 */ 41int driver_for_each_device(struct device_driver *drv, struct device *start, 42 void *data, int (*fn)(struct device *, void *)) 43{ 44 struct klist_iter i; 45 struct device *dev; 46 int error = 0; 47 48 if (!drv) 49 return -EINVAL; 50 51 klist_iter_init_node(&drv->p->klist_devices, &i, 52 start ? &start->p->knode_driver : NULL); 53 while (!error && (dev = next_device(&i))) 54 error = fn(dev, data); 55 klist_iter_exit(&i); 56 return error; 57} 58EXPORT_SYMBOL_GPL(driver_for_each_device); 59 60/** 61 * driver_find_device - device iterator for locating a particular device. 62 * @drv: The device's driver 63 * @start: Device to begin with 64 * @data: Data to pass to match function 65 * @match: Callback function to check device 66 * 67 * This is similar to the driver_for_each_device() function above, but 68 * it returns a reference to a device that is 'found' for later use, as 69 * determined by the @match callback. 70 * 71 * The callback should return 0 if the device doesn't match and non-zero 72 * if it does. If the callback returns non-zero, this function will 73 * return to the caller and not iterate over any more devices. 74 */ 75struct device *driver_find_device(struct device_driver *drv, 76 struct device *start, void *data, 77 int (*match)(struct device *dev, void *data)) 78{ 79 struct klist_iter i; 80 struct device *dev; 81 82 if (!drv || !drv->p) 83 return NULL; 84 85 klist_iter_init_node(&drv->p->klist_devices, &i, 86 (start ? &start->p->knode_driver : NULL)); 87 while ((dev = next_device(&i))) 88 if (match(dev, data) && get_device(dev)) 89 break; 90 klist_iter_exit(&i); 91 return dev; 92} 93EXPORT_SYMBOL_GPL(driver_find_device); 94 95/** 96 * driver_create_file - create sysfs file for driver. 97 * @drv: driver. 98 * @attr: driver attribute descriptor. 99 */ 100int driver_create_file(struct device_driver *drv, 101 const struct driver_attribute *attr) 102{ 103 int error; 104 105 if (drv) 106 error = sysfs_create_file(&drv->p->kobj, &attr->attr); 107 else 108 error = -EINVAL; 109 return error; 110} 111EXPORT_SYMBOL_GPL(driver_create_file); 112 113/** 114 * driver_remove_file - remove sysfs file for driver. 115 * @drv: driver. 116 * @attr: driver attribute descriptor. 117 */ 118void driver_remove_file(struct device_driver *drv, 119 const struct driver_attribute *attr) 120{ 121 if (drv) 122 sysfs_remove_file(&drv->p->kobj, &attr->attr); 123} 124EXPORT_SYMBOL_GPL(driver_remove_file); 125 126int driver_add_groups(struct device_driver *drv, 127 const struct attribute_group **groups) 128{ 129 return sysfs_create_groups(&drv->p->kobj, groups); 130} 131 132void driver_remove_groups(struct device_driver *drv, 133 const struct attribute_group **groups) 134{ 135 sysfs_remove_groups(&drv->p->kobj, groups); 136} 137 138/** 139 * driver_register - register driver with bus 140 * @drv: driver to register 141 * 142 * We pass off most of the work to the bus_add_driver() call, 143 * since most of the things we have to do deal with the bus 144 * structures. 145 */ 146int driver_register(struct device_driver *drv) 147{ 148 int ret; 149 struct device_driver *other; 150 151 if (!drv->bus->p) { 152 pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", 153 drv->name, drv->bus->name); 154 return -EINVAL; 155 } 156 157 if ((drv->bus->probe && drv->probe) || 158 (drv->bus->remove && drv->remove) || 159 (drv->bus->shutdown && drv->shutdown)) 160 printk(KERN_WARNING "Driver '%s' needs updating - please use " 161 "bus_type methods\n", drv->name); 162 163 other = driver_find(drv->name, drv->bus); 164 if (other) { 165 printk(KERN_ERR "Error: Driver '%s' is already registered, " 166 "aborting...\n", drv->name); 167 return -EBUSY; 168 } 169 170 ret = bus_add_driver(drv); 171 if (ret) 172 return ret; 173 ret = driver_add_groups(drv, drv->groups); 174 if (ret) { 175 bus_remove_driver(drv); 176 return ret; 177 } 178 kobject_uevent(&drv->p->kobj, KOBJ_ADD); 179 180 return ret; 181} 182EXPORT_SYMBOL_GPL(driver_register); 183 184/** 185 * driver_unregister - remove driver from system. 186 * @drv: driver. 187 * 188 * Again, we pass off most of the work to the bus-level call. 189 */ 190void driver_unregister(struct device_driver *drv) 191{ 192 if (!drv || !drv->p) { 193 WARN(1, "Unexpected driver unregister!\n"); 194 return; 195 } 196 driver_remove_groups(drv, drv->groups); 197 bus_remove_driver(drv); 198} 199EXPORT_SYMBOL_GPL(driver_unregister); 200 201/** 202 * driver_find - locate driver on a bus by its name. 203 * @name: name of the driver. 204 * @bus: bus to scan for the driver. 205 * 206 * Call kset_find_obj() to iterate over list of drivers on 207 * a bus to find driver by name. Return driver if found. 208 * 209 * This routine provides no locking to prevent the driver it returns 210 * from being unregistered or unloaded while the caller is using it. 211 * The caller is responsible for preventing this. 212 */ 213struct device_driver *driver_find(const char *name, struct bus_type *bus) 214{ 215 struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); 216 struct driver_private *priv; 217 218 if (k) { 219 /* Drop reference added by kset_find_obj() */ 220 kobject_put(k); 221 priv = to_driver(k); 222 return priv->driver; 223 } 224 return NULL; 225} 226EXPORT_SYMBOL_GPL(driver_find);