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