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