From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: "Rafael J. Wysocki" <rafael@kernel.org>,
Danilo Krummrich <dakr@kernel.org>, Lyude Paul <lyude@redhat.com>
Cc: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Alexander Lobakin" <aleksander.lobakin@intel.com>,
"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Jonathan Cameron" <Jonathan.Cameron@huawei.com>,
"Liam Girdwood" <lgirdwood@gmail.com>,
"Lukas Wunner" <lukas@wunner.de>,
"Mark Brown" <broonie@kernel.org>,
"Maíra Canal" <mairacanal@riseup.net>,
"Robin Murphy" <robin.murphy@arm.com>,
"Simona Vetter" <simona.vetter@ffwll.ch>,
"Zijun Hu" <quic_zijuhu@quicinc.com>,
linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
rust-for-linux@vger.kernel.org
Subject: [PATCH 1/3] driver core: add a faux bus for use when a simple device/bus is needed
Date: Mon, 3 Feb 2025 15:25:17 +0100 [thread overview]
Message-ID: <2025020326-backer-vendetta-7094@gregkh> (raw)
In-Reply-To: <2025020324-thermal-quilt-1bae@gregkh>
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.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/base/Makefile | 2 +-
drivers/base/base.h | 1 +
drivers/base/faux.c | 189 ++++++++++++++++++++++++++++++++++++
drivers/base/init.c | 1 +
include/linux/device/faux.h | 33 +++++++
5 files changed, 225 insertions(+), 1 deletion(-)
create mode 100644 drivers/base/faux.c
create mode 100644 include/linux/device/faux.h
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7fb21768ca36..8074a10183dc 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
topology.o container.o property.o cacheinfo.o \
- swnode.o
+ swnode.o faux.o
obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-y += power/
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 8cf04a557bdb..0042e4774b0c 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -137,6 +137,7 @@ int hypervisor_init(void);
static inline int hypervisor_init(void) { return 0; }
#endif
int platform_bus_init(void);
+int faux_bus_init(void);
void cpu_dev_init(void);
void container_dev_init(void);
#ifdef CONFIG_AUXILIARY_BUS
diff --git a/drivers/base/faux.c b/drivers/base/faux.c
new file mode 100644
index 000000000000..0eba89a5cd57
--- /dev/null
+++ b/drivers/base/faux.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (c) 2025 The Linux Foundation
+ *
+ * A "simple" faux bus that allows devices to be created and added
+ * automatically to it. Whenever you need a device that is not "real",
+ * use this interface instead of even thinking of using a platform device.
+ *
+ */
+#include <linux/device/faux.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "base.h"
+
+/*
+ * Internal wrapper structure so we can hold the memory
+ * for the driver and the name string of the faux device.
+ */
+struct faux_object {
+ struct faux_device faux_dev;
+ struct device_driver driver;
+ const struct faux_driver_ops *faux_ops;
+ char name[];
+};
+#define to_faux_object(x) container_of_const(dev, struct faux_object, faux_dev.dev);
+
+static struct device faux_bus_root = {
+ .init_name = "faux_bus",
+};
+
+static int faux_match(struct device *dev, const struct device_driver *drv)
+{
+ struct faux_object *faux_obj = to_faux_object(dev);
+
+ /* Match is simple, strcmp()! */
+ return (strcmp(faux_obj->name, drv->name) == 0);
+}
+
+static int faux_probe(struct device *dev)
+{
+ struct faux_object *faux_obj = to_faux_object(dev);
+ struct faux_device *faux_dev = &faux_obj->faux_dev;
+ const struct faux_driver_ops *faux_ops = faux_obj->faux_ops;
+ int ret = 0;
+
+ if (faux_ops && faux_ops->probe)
+ ret = faux_ops->probe(faux_dev);
+
+ return ret;
+}
+
+static void faux_remove(struct device *dev)
+{
+ struct faux_object *faux_obj = to_faux_object(dev);
+ struct faux_device *faux_dev = &faux_obj->faux_dev;
+ const struct faux_driver_ops *faux_ops = faux_obj->faux_ops;
+
+ if (faux_ops && faux_ops->remove)
+ faux_ops->remove(faux_dev);
+}
+
+static const struct bus_type faux_bus_type = {
+ .name = "faux_bus",
+ .match = faux_match,
+ .probe = faux_probe,
+ .remove = faux_remove,
+};
+
+static void faux_device_release(struct device *dev)
+{
+ struct faux_object *faux_obj = to_faux_object(dev);
+ struct device_driver *drv = &faux_obj->driver;
+
+ /*
+ * Now that the device is going away, it has been unbound from the
+ * driver we created for it, so it is safe to unregister the driver from
+ * the system.
+ */
+ driver_unregister(drv);
+
+ kfree(faux_obj);
+}
+
+/**
+ * __faux_device_create - create and register a faux device and driver
+ * @name: name of the device and driver we are adding
+ * @faux_ops: struct faux_driver_ops that the new device will call back into, can be NULL
+ * @owner: module owner of the device/driver
+ *
+ * Create a new faux device and driver, both with the same name, and register
+ * them in the driver core properly. The probe() callback of @faux_ops will be
+ * called with the new device that is created for the caller to do something
+ * with.
+ */
+struct faux_device *__faux_device_create(const char *name,
+ struct faux_driver_ops *faux_ops,
+ struct module *owner)
+{
+ struct device_driver *drv;
+ struct device *dev;
+ struct faux_object *faux_obj;
+ struct faux_device *faux_dev;
+ int ret;
+
+ faux_obj = kzalloc(sizeof(*faux_obj) + strlen(name) + 1, GFP_KERNEL);
+ if (!faux_obj)
+ return NULL;
+
+ /* Save off the name of the object into local memory */
+ strcpy(faux_obj->name, name);
+
+ /* Initialize the driver portion and register it with the driver core */
+ faux_obj->faux_ops = faux_ops;
+ drv = &faux_obj->driver;
+
+ drv->owner = owner;
+ drv->name = faux_obj->name;
+ drv->bus = &faux_bus_type;
+ drv->probe_type = PROBE_PREFER_ASYNCHRONOUS;
+
+ ret = driver_register(drv);
+ if (ret) {
+ pr_err("%s: driver_register for %s faux driver failed with %d\n",
+ __func__, name, ret);
+ kfree(faux_obj);
+ return NULL;
+ }
+
+ /* Initialize the device portion and register it with the driver core */
+ faux_dev = &faux_obj->faux_dev;
+ dev = &faux_dev->dev;
+
+ device_initialize(dev);
+ dev->release = faux_device_release;
+ dev->parent = &faux_bus_root;
+ dev->bus = &faux_bus_type;
+ dev_set_name(dev, "%s", name);
+
+ ret = device_add(dev);
+ if (ret) {
+ pr_err("%s: device_add for %s faux device failed with %d\n",
+ __func__, name, ret);
+ put_device(dev);
+ return NULL;
+ }
+
+ return faux_dev;
+}
+EXPORT_SYMBOL_GPL(__faux_device_create);
+
+/**
+ * faux_device_destroy - destroy a faux device
+ * @faux_dev: faux device to destroy
+ *
+ * Unregister and free all memory associated with a faux device.
+ */
+void faux_device_destroy(struct faux_device *faux_dev)
+{
+ struct device *dev = &faux_dev->dev;
+
+ if (IS_ERR_OR_NULL(faux_dev))
+ return;
+
+ device_del(dev);
+
+ /* The final put_device() will clean up the driver we created for this device. */
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(faux_device_destroy);
+
+int __init faux_bus_init(void)
+{
+ int error;
+
+ error = device_register(&faux_bus_root);
+ if (error) {
+ put_device(&faux_bus_root);
+ return error;
+ }
+
+ error = bus_register(&faux_bus_type);
+ if (error)
+ device_unregister(&faux_bus_root);
+
+ return error;
+}
diff --git a/drivers/base/init.c b/drivers/base/init.c
index c4954835128c..9d2b06d65dfc 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -32,6 +32,7 @@ void __init driver_init(void)
/* These are also core pieces, but must come after the
* core core pieces.
*/
+ faux_bus_init();
of_core_init();
platform_bus_init();
auxiliary_bus_init();
diff --git a/include/linux/device/faux.h b/include/linux/device/faux.h
new file mode 100644
index 000000000000..b1a51fbb6f39
--- /dev/null
+++ b/include/linux/device/faux.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (c) 2025 The Linux Foundation
+ *
+ * A "simple" faux bus that allows devices to be created and added
+ * automatically to it. Whenever you need a device that is not "real",
+ * use this interface instead of even thinking of using a platform device.
+ *
+ */
+#ifndef _FAUX_DEVICE_H_
+#define _FAUX_DEVICE_H_
+
+#include <linux/module.h>
+#include <linux/device.h>
+
+struct faux_device {
+ struct device dev;
+};
+#define to_faux_device(x) container_of_const((x), struct faux_device, dev)
+
+struct faux_driver_ops {
+ int (*probe)(struct faux_device *faux_dev);
+ void (*remove)(struct faux_device *faux_dev);
+};
+
+#define faux_device_create(name, faux_ops) __faux_device_create(name, faux_ops, THIS_MODULE)
+struct faux_device *__faux_device_create(const char *name,
+ struct faux_driver_ops *faux_ops,
+ struct module *module);
+void faux_device_destroy(struct faux_device *faux_dev);
+
+#endif /* _FAUX_DEVICE_H_ */
--
2.48.1
next prev parent reply other threads:[~2025-02-03 14:25 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-03 14:25 [PATCH 0/3] Driver core: faux bus Greg Kroah-Hartman
2025-02-03 14:25 ` Greg Kroah-Hartman [this message]
2025-02-03 15:11 ` [PATCH 1/3] driver core: add a faux bus for use when a simple device/bus is needed Andy Shevchenko
2025-02-03 15:13 ` Andy Shevchenko
2025-02-03 15:35 ` Greg Kroah-Hartman
2025-02-03 15:46 ` Greg Kroah-Hartman
2025-02-03 16:05 ` Andy Shevchenko
2025-02-03 16:05 ` Andy Shevchenko
2025-02-03 16:10 ` Andy Shevchenko
2025-02-03 16:13 ` Greg Kroah-Hartman
2025-02-03 16:22 ` Andy Shevchenko
2025-02-04 9:25 ` Jonathan Cameron
2025-02-04 10:14 ` Greg Kroah-Hartman
2025-02-04 10:08 ` Thomas Weißschuh
2025-02-04 10:20 ` Greg Kroah-Hartman
2025-02-04 10:44 ` Thomas Weißschuh
2025-02-04 10:49 ` Greg Kroah-Hartman
2025-02-03 14:25 ` [PATCH 2/3] regulator: dummy: convert to use the faux bus Greg Kroah-Hartman
2025-02-03 15:39 ` Mark Brown
2025-02-03 15:46 ` Greg Kroah-Hartman
2025-02-03 16:11 ` Mark Brown
2025-02-03 14:25 ` [PATCH 3/3] USB: phy: convert usb_phy_generic logic to use a faux device Greg Kroah-Hartman
2025-02-03 15:15 ` Andy Shevchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2025020326-backer-vendetta-7094@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=Jonathan.Cameron@huawei.com \
--cc=aleksander.lobakin@intel.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=bhelgaas@google.com \
--cc=broonie@kernel.org \
--cc=dakr@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=lyude@redhat.com \
--cc=mairacanal@riseup.net \
--cc=quic_zijuhu@quicinc.com \
--cc=rafael@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona.vetter@ffwll.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.