at v4.16 222 lines 5.7 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 BUG_ON(!drv->bus->p); 152 153 if ((drv->bus->probe && drv->probe) || 154 (drv->bus->remove && drv->remove) || 155 (drv->bus->shutdown && drv->shutdown)) 156 printk(KERN_WARNING "Driver '%s' needs updating - please use " 157 "bus_type methods\n", drv->name); 158 159 other = driver_find(drv->name, drv->bus); 160 if (other) { 161 printk(KERN_ERR "Error: Driver '%s' is already registered, " 162 "aborting...\n", drv->name); 163 return -EBUSY; 164 } 165 166 ret = bus_add_driver(drv); 167 if (ret) 168 return ret; 169 ret = driver_add_groups(drv, drv->groups); 170 if (ret) { 171 bus_remove_driver(drv); 172 return ret; 173 } 174 kobject_uevent(&drv->p->kobj, KOBJ_ADD); 175 176 return ret; 177} 178EXPORT_SYMBOL_GPL(driver_register); 179 180/** 181 * driver_unregister - remove driver from system. 182 * @drv: driver. 183 * 184 * Again, we pass off most of the work to the bus-level call. 185 */ 186void driver_unregister(struct device_driver *drv) 187{ 188 if (!drv || !drv->p) { 189 WARN(1, "Unexpected driver unregister!\n"); 190 return; 191 } 192 driver_remove_groups(drv, drv->groups); 193 bus_remove_driver(drv); 194} 195EXPORT_SYMBOL_GPL(driver_unregister); 196 197/** 198 * driver_find - locate driver on a bus by its name. 199 * @name: name of the driver. 200 * @bus: bus to scan for the driver. 201 * 202 * Call kset_find_obj() to iterate over list of drivers on 203 * a bus to find driver by name. Return driver if found. 204 * 205 * This routine provides no locking to prevent the driver it returns 206 * from being unregistered or unloaded while the caller is using it. 207 * The caller is responsible for preventing this. 208 */ 209struct device_driver *driver_find(const char *name, struct bus_type *bus) 210{ 211 struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); 212 struct driver_private *priv; 213 214 if (k) { 215 /* Drop reference added by kset_find_obj() */ 216 kobject_put(k); 217 priv = to_driver(k); 218 return priv->driver; 219 } 220 return NULL; 221} 222EXPORT_SYMBOL_GPL(driver_find);