The branch stable/14 has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2cda5031841fa3745486a0f5c08981d266742569

commit 2cda5031841fa3745486a0f5c08981d266742569
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2024-09-08 04:40:41 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2024-10-24 02:44:40 +0000

    device: add generic named per-device property
    
    (cherry picked from commit cb83af64f161b228171d6fb4f36d22493cefaa7f)
---
 sys/kern/subr_bus.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/sys/bus.h       |   7 +++
 2 files changed, 127 insertions(+)

diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 5965b8941b54..9e6973f6174c 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -105,6 +105,16 @@ struct devclass {
        struct sysctl_oid *sysctl_tree;
 };
 
+struct device_prop_elm {
+       const char *name;
+       void *val;
+       void *dtr_ctx;
+       device_prop_dtr_t dtr;
+       LIST_ENTRY(device_prop_elm) link;
+};
+
+static void device_destroy_props(device_t dev);
+
 /**
  * @brief Implementation of _device.
  *
@@ -141,6 +151,7 @@ struct _device {
        u_int   order;                  /**< order from 
device_add_child_ordered() */
        void    *ivars;                 /**< instance variables  */
        void    *softc;                 /**< current driver's variables  */
+       LIST_HEAD(, device_prop_elm) props;
 
        struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables  */
        struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */
@@ -1350,6 +1361,7 @@ make_device(device_t parent, const char *name, int unit)
                dev->flags |= DF_QUIET | DF_QUIET_CHILDREN;
        dev->ivars = NULL;
        dev->softc = NULL;
+       LIST_INIT(&dev->props);
 
        dev->state = DS_NOTPRESENT;
 
@@ -1489,6 +1501,7 @@ device_delete_child(device_t dev, device_t child)
                        return (error);
        }
 
+       device_destroy_props(dev);
        if (child->devclass)
                devclass_delete_device(child->devclass, child);
        if (child->parent)
@@ -5990,6 +6003,113 @@ dev_wired_cache_match(device_location_cache_t *dcp, 
device_t dev,
        return (strcmp(res->dln_path, cp) == 0);
 }
 
+static struct device_prop_elm *
+device_prop_find(device_t dev, const char *name)
+{
+       struct device_prop_elm *e;
+
+       bus_topo_assert();
+
+       LIST_FOREACH(e, &dev->props, link) {
+               if (strcmp(name, e->name) == 0)
+                       return (e);
+       }
+       return (NULL);
+}
+
+int
+device_set_prop(device_t dev, const char *name, void *val,
+    device_prop_dtr_t dtr, void *dtr_ctx)
+{
+       struct device_prop_elm *e, *e1;
+
+       bus_topo_assert();
+
+       e = device_prop_find(dev, name);
+       if (e != NULL)
+               goto found;
+
+       e1 = malloc(sizeof(*e), M_BUS, M_WAITOK);
+       e = device_prop_find(dev, name);
+       if (e != NULL) {
+               free(e1, M_BUS);
+               goto found;
+       }
+
+       e1->name = name;
+       e1->val = val;
+       e1->dtr = dtr;
+       e1->dtr_ctx = dtr_ctx;
+       LIST_INSERT_HEAD(&dev->props, e1, link);
+       return (0);
+
+found:
+       LIST_REMOVE(e, link);
+       if (e->dtr != NULL)
+               e->dtr(dev, name, e->val, e->dtr_ctx);
+       e->val = val;
+       e->dtr = dtr;
+       e->dtr_ctx = dtr_ctx;
+       LIST_INSERT_HEAD(&dev->props, e, link);
+       return (EEXIST);
+}
+
+int
+device_get_prop(device_t dev, const char *name, void **valp)
+{
+       struct device_prop_elm *e;
+
+       bus_topo_assert();
+
+       e = device_prop_find(dev, name);
+       if (e == NULL)
+               return (ENOENT);
+       *valp = e->val;
+       return (0);
+}
+
+int
+device_clear_prop(device_t dev, const char *name)
+{
+       struct device_prop_elm *e;
+
+       bus_topo_assert();
+
+       e = device_prop_find(dev, name);
+       if (e == NULL)
+               return (ENOENT);
+       LIST_REMOVE(e, link);
+       if (e->dtr != NULL)
+               e->dtr(dev, e->name, e->val, e->dtr_ctx);
+       free(e, M_BUS);
+       return (0);
+}
+
+static void
+device_destroy_props(device_t dev)
+{
+       struct device_prop_elm *e;
+
+       bus_topo_assert();
+
+       while ((e = LIST_FIRST(&dev->props)) != NULL) {
+               LIST_REMOVE_HEAD(&dev->props, link);
+               if (e->dtr != NULL)
+                       e->dtr(dev, e->name, e->val, e->dtr_ctx);
+               free(e, M_BUS);
+       }
+}
+
+void
+device_clear_prop_alldev(const char *name)
+{
+       device_t dev;
+
+       TAILQ_FOREACH(dev, &bus_data_devices, devlink) {
+               device_clear_prop(dev, name);
+       }
+}
+
 /*
  * APIs to manage deprecation and obsolescence.
  */
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index 581e81352be4..eecff0c7c03e 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -889,6 +889,13 @@ device_location_cache_t *dev_wired_cache_init(void);
 void dev_wired_cache_fini(device_location_cache_t *dcp);
 bool dev_wired_cache_match(device_location_cache_t *dcp, device_t dev, const 
char *at);
 
+typedef void (*device_prop_dtr_t)(device_t dev, const char *name, void *val,
+    void *dtr_ctx);
+int device_set_prop(device_t dev, const char *name, void *val,
+    device_prop_dtr_t dtr, void *dtr_ctx);
+int device_get_prop(device_t dev, const char *name, void **valp);
+int device_clear_prop(device_t dev, const char *name);
+void device_clear_prop_alldev(const char *name);
 
 /**
  * Shorthand macros, taking resource argument

Reply via email to