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.

driver core: add a faux bus for use when a simple device/bus is needed

Many drivers abuse the platform driver/bus system as it provides a
simple way to create and bind a device to a driver-specific set of
probe/release functions. Instead of doing that, and wasting all of the
memory associated with a platform device, here is a "faux" bus that
can be used instead.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Zijun Hu <quic_zijuhu@quicinc.com>
Link: https://lore.kernel.org/r/2025021026-atlantic-gibberish-3f0c@gregkh
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

+310 -1
+6
Documentation/driver-api/infrastructure.rst
··· 41 41 .. kernel-doc:: drivers/base/class.c 42 42 :export: 43 43 44 + .. kernel-doc:: include/linux/device/faux.h 45 + :internal: 46 + 47 + .. kernel-doc:: drivers/base/faux.c 48 + :export: 49 + 44 50 .. kernel-doc:: drivers/base/node.c 45 51 :internal: 46 52
+1 -1
drivers/base/Makefile
··· 6 6 cpu.o firmware.o init.o map.o devres.o \ 7 7 attribute_container.o transport_class.o \ 8 8 topology.o container.o property.o cacheinfo.o \ 9 - swnode.o 9 + swnode.o faux.o 10 10 obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o 11 11 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o 12 12 obj-y += power/
+1
drivers/base/base.h
··· 137 137 static inline int hypervisor_init(void) { return 0; } 138 138 #endif 139 139 int platform_bus_init(void); 140 + int faux_bus_init(void); 140 141 void cpu_dev_init(void); 141 142 void container_dev_init(void); 142 143 #ifdef CONFIG_AUXILIARY_BUS
+232
drivers/base/faux.c
··· 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 + }
+1
drivers/base/init.c
··· 32 32 /* These are also core pieces, but must come after the 33 33 * core core pieces. 34 34 */ 35 + faux_bus_init(); 35 36 of_core_init(); 36 37 platform_bus_init(); 37 38 auxiliary_bus_init();
+69
include/linux/device/faux.h
··· 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 + #ifndef _FAUX_DEVICE_H_ 14 + #define _FAUX_DEVICE_H_ 15 + 16 + #include <linux/container_of.h> 17 + #include <linux/device.h> 18 + 19 + /** 20 + * struct faux_device - a "faux" device 21 + * @dev: internal struct device of the object 22 + * 23 + * A simple faux device that can be created/destroyed. To be used when a 24 + * driver only needs to have a device to "hang" something off. This can be 25 + * used for downloading firmware or other basic tasks. Use this instead of 26 + * a struct platform_device if the device has no resources assigned to 27 + * it at all. 28 + */ 29 + struct faux_device { 30 + struct device dev; 31 + }; 32 + #define to_faux_device(x) container_of_const((x), struct faux_device, dev) 33 + 34 + /** 35 + * struct faux_device_ops - a set of callbacks for a struct faux_device 36 + * @probe: called when a faux device is probed by the driver core 37 + * before the device is fully bound to the internal faux bus 38 + * code. If probe succeeds, return 0, otherwise return a 39 + * negative error number to stop the probe sequence from 40 + * succeeding. 41 + * @remove: called when a faux device is removed from the system 42 + * 43 + * Both @probe and @remove are optional, if not needed, set to NULL. 44 + */ 45 + struct faux_device_ops { 46 + int (*probe)(struct faux_device *faux_dev); 47 + void (*remove)(struct faux_device *faux_dev); 48 + }; 49 + 50 + struct faux_device *faux_device_create(const char *name, 51 + struct device *parent, 52 + const struct faux_device_ops *faux_ops); 53 + struct faux_device *faux_device_create_with_groups(const char *name, 54 + struct device *parent, 55 + const struct faux_device_ops *faux_ops, 56 + const struct attribute_group **groups); 57 + void faux_device_destroy(struct faux_device *faux_dev); 58 + 59 + static inline void *faux_device_get_drvdata(const struct faux_device *faux_dev) 60 + { 61 + return dev_get_drvdata(&faux_dev->dev); 62 + } 63 + 64 + static inline void faux_device_set_drvdata(struct faux_device *faux_dev, void *data) 65 + { 66 + dev_set_drvdata(&faux_dev->dev, data); 67 + } 68 + 69 + #endif /* _FAUX_DEVICE_H_ */