Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 265 lines 7.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2025 Greg Kroah-Hartman <gregkh@linuxfoundation.org> 4 * Copyright (c) 2025 The Linux Foundation 5 * 6 * A "simple" faux bus that allows devices to be created and added 7 * automatically to it. This is to be used whenever you need to create a 8 * device that is not associated with any "real" system resources, and do 9 * not want to have to deal with a bus/driver binding logic. It is 10 * intended to be very simple, with only a create and a destroy function 11 * available. 12 */ 13#include <linux/err.h> 14#include <linux/init.h> 15#include <linux/slab.h> 16#include <linux/string.h> 17#include <linux/container_of.h> 18#include <linux/device/faux.h> 19#include "base.h" 20 21/* 22 * Internal wrapper structure so we can hold a pointer to the 23 * faux_device_ops for this device. 24 */ 25struct faux_object { 26 struct faux_device faux_dev; 27 const struct faux_device_ops *faux_ops; 28 const struct attribute_group **groups; 29}; 30#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev) 31 32static struct device *faux_bus_root; 33 34static int faux_match(struct device *dev, const struct device_driver *drv) 35{ 36 /* Match always succeeds, we only have one driver */ 37 return 1; 38} 39 40static int faux_probe(struct device *dev) 41{ 42 struct faux_object *faux_obj = to_faux_object(dev); 43 struct faux_device *faux_dev = &faux_obj->faux_dev; 44 const struct faux_device_ops *faux_ops = faux_obj->faux_ops; 45 int ret; 46 47 if (faux_ops && faux_ops->probe) { 48 ret = faux_ops->probe(faux_dev); 49 if (ret) 50 return ret; 51 } 52 53 /* 54 * Add groups after the probe succeeds to ensure resources are 55 * initialized correctly 56 */ 57 ret = device_add_groups(dev, faux_obj->groups); 58 if (ret && faux_ops && faux_ops->remove) 59 faux_ops->remove(faux_dev); 60 61 return ret; 62} 63 64static void faux_remove(struct device *dev) 65{ 66 struct faux_object *faux_obj = to_faux_object(dev); 67 struct faux_device *faux_dev = &faux_obj->faux_dev; 68 const struct faux_device_ops *faux_ops = faux_obj->faux_ops; 69 70 device_remove_groups(dev, faux_obj->groups); 71 72 if (faux_ops && faux_ops->remove) 73 faux_ops->remove(faux_dev); 74} 75 76static const struct bus_type faux_bus_type = { 77 .name = "faux", 78 .match = faux_match, 79 .probe = faux_probe, 80 .remove = faux_remove, 81}; 82 83static struct device_driver faux_driver = { 84 .name = "faux_driver", 85 .bus = &faux_bus_type, 86 .probe_type = PROBE_FORCE_SYNCHRONOUS, 87 .suppress_bind_attrs = true, 88}; 89 90static void faux_device_release(struct device *dev) 91{ 92 struct faux_object *faux_obj = to_faux_object(dev); 93 94 kfree(faux_obj); 95} 96 97/** 98 * faux_device_create_with_groups - Create and register with the driver 99 * core a faux device and populate the device with an initial 100 * set of sysfs attributes. 101 * @name: The name of the device we are adding, must be unique for 102 * all faux devices. 103 * @parent: Pointer to a potential parent struct device. If set to 104 * NULL, the device will be created in the "root" of the faux 105 * device tree in sysfs. 106 * @faux_ops: struct faux_device_ops that the new device will call back 107 * into, can be NULL. 108 * @groups: The set of sysfs attributes that will be created for this 109 * device when it is registered with the driver core. 110 * 111 * Create a new faux device and register it in the driver core properly. 112 * If present, callbacks in @faux_ops will be called with the device that 113 * for the caller to do something with at the proper time given the 114 * device's lifecycle. 115 * 116 * Note, when this function is called, the functions specified in struct 117 * faux_ops can be called before the function returns, so be prepared for 118 * everything to be properly initialized before that point in time. If the 119 * probe callback (if one is present) does NOT succeed, the creation of the 120 * device will fail and NULL will be returned. 121 * 122 * Return: 123 * * NULL if an error happened with creating the device 124 * * pointer to a valid struct faux_device that is registered with sysfs 125 */ 126struct faux_device *faux_device_create_with_groups(const char *name, 127 struct device *parent, 128 const struct faux_device_ops *faux_ops, 129 const struct attribute_group **groups) 130{ 131 struct faux_object *faux_obj; 132 struct faux_device *faux_dev; 133 struct device *dev; 134 int ret; 135 136 faux_obj = kzalloc_obj(*faux_obj); 137 if (!faux_obj) 138 return NULL; 139 140 /* Save off the callbacks and groups so we can use them in the future */ 141 faux_obj->faux_ops = faux_ops; 142 faux_obj->groups = groups; 143 144 /* Initialize the device portion and register it with the driver core */ 145 faux_dev = &faux_obj->faux_dev; 146 dev = &faux_dev->dev; 147 148 device_initialize(dev); 149 dev->release = faux_device_release; 150 if (parent) 151 dev->parent = parent; 152 else 153 dev->parent = faux_bus_root; 154 dev->bus = &faux_bus_type; 155 dev_set_name(dev, "%s", name); 156 device_set_pm_not_required(dev); 157 158 ret = device_add(dev); 159 if (ret) { 160 pr_err("%s: device_add for faux device '%s' failed with %d\n", 161 __func__, name, ret); 162 put_device(dev); 163 return NULL; 164 } 165 166 /* 167 * Verify that we did bind the driver to the device (i.e. probe worked), 168 * if not, let's fail the creation as trying to guess if probe was 169 * successful is almost impossible to determine by the caller. 170 */ 171 if (!dev->driver) { 172 dev_dbg(dev, "probe did not succeed, tearing down the device\n"); 173 faux_device_destroy(faux_dev); 174 faux_dev = NULL; 175 } 176 177 return faux_dev; 178} 179EXPORT_SYMBOL_GPL(faux_device_create_with_groups); 180 181/** 182 * faux_device_create - create and register with the driver core a faux device 183 * @name: The name of the device we are adding, must be unique for all 184 * faux devices. 185 * @parent: Pointer to a potential parent struct device. If set to 186 * NULL, the device will be created in the "root" of the faux 187 * device tree in sysfs. 188 * @faux_ops: struct faux_device_ops that the new device will call back 189 * into, can be NULL. 190 * 191 * Create a new faux device and register it in the driver core properly. 192 * If present, callbacks in @faux_ops will be called with the device that 193 * for the caller to do something with at the proper time given the 194 * device's lifecycle. 195 * 196 * Note, when this function is called, the functions specified in struct 197 * faux_ops can be called before the function returns, so be prepared for 198 * everything to be properly initialized before that point in time. 199 * 200 * Return: 201 * * NULL if an error happened with creating the device 202 * * pointer to a valid struct faux_device that is registered with sysfs 203 */ 204struct faux_device *faux_device_create(const char *name, 205 struct device *parent, 206 const struct faux_device_ops *faux_ops) 207{ 208 return faux_device_create_with_groups(name, parent, faux_ops, NULL); 209} 210EXPORT_SYMBOL_GPL(faux_device_create); 211 212/** 213 * faux_device_destroy - destroy a faux device 214 * @faux_dev: faux device to destroy 215 * 216 * Unregisters and cleans up a device that was created with a call to 217 * faux_device_create() 218 */ 219void faux_device_destroy(struct faux_device *faux_dev) 220{ 221 struct device *dev = &faux_dev->dev; 222 223 if (!faux_dev) 224 return; 225 226 device_del(dev); 227 228 /* The final put_device() will clean up the memory we allocated for this device. */ 229 put_device(dev); 230} 231EXPORT_SYMBOL_GPL(faux_device_destroy); 232 233int __init faux_bus_init(void) 234{ 235 int ret; 236 237 faux_bus_root = kzalloc_obj(*faux_bus_root); 238 if (!faux_bus_root) 239 return -ENOMEM; 240 241 dev_set_name(faux_bus_root, "faux"); 242 243 ret = device_register(faux_bus_root); 244 if (ret) { 245 put_device(faux_bus_root); 246 return ret; 247 } 248 249 ret = bus_register(&faux_bus_type); 250 if (ret) 251 goto error_bus; 252 253 ret = driver_register(&faux_driver); 254 if (ret) 255 goto error_driver; 256 257 return ret; 258 259error_driver: 260 bus_unregister(&faux_bus_type); 261 262error_bus: 263 device_unregister(faux_bus_root); 264 return ret; 265}