Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Introduce a generalized "device handle", designed to abs...



details:   https://anonhg.NetBSD.org/src/rev/c63283819474
branches:  trunk
changeset: 951530:c63283819474
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Fri Feb 05 17:03:35 2021 +0000

description:
Introduce a generalized "device handle", designed to abstract the handles
used by platform description mechanisms like OpenFirmware, Device Tree,
and ACPI.  In addition to encapsulating the handle's opaque value, the
handle also contains a pointer to an "implementation", which can be used
to invoke methods on a device / device handle.

Device handles are designed to be passed around by-value.  It is expected
that any other memory objects they refer to will be durable.  They are an
aggregate type that consumes 2 pointers worth of storage space.

When device_t's are created, they initially have an invalid device handle.
It is currently the responsibility of platform-specific code to assign
device handles to device_t's.

When necessary, platform-specific code can override a handle's implementation
in a way that resembles sub-classing, such that specific methods can by
intercepted, but others simply passed through.  This also allows platforms
that do not otherwise have a platform description mechanism to provide
handle implementations in specific circumstances to describe the hardware
to platform-independent code.

A general device method calling infrastructure is provided.  Method names
that begin with "device-" are reserved for / defined by the autoconfiguration
subsystem.  Define the "device-enumerate-children" method.  Other subsystems
are free to define their own device method calls and bindings.

Welcome to NetBSD 9.99.80.

diffstat:

 sys/kern/subr_device.c |  112 +++++++++++++++++++++++++++++++++++++++-
 sys/sys/device.h       |  135 ++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/sys/param.h        |    4 +-
 3 files changed, 246 insertions(+), 5 deletions(-)

diffs (truncated from 326 to 300 lines):

diff -r 059688abe71b -r c63283819474 sys/kern/subr_device.c
--- a/sys/kern/subr_device.c    Fri Feb 05 16:06:24 2021 +0000
+++ b/sys/kern/subr_device.c    Fri Feb 05 17:03:35 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_device.c,v 1.5 2021/02/04 23:29:16 thorpej Exp $  */
+/*     $NetBSD: subr_device.c,v 1.6 2021/02/05 17:03:35 thorpej Exp $  */
 
 /*
  * Copyright (c) 2006, 2021 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_device.c,v 1.5 2021/02/04 23:29:16 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_device.c,v 1.6 2021/02/05 17:03:35 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -37,6 +37,75 @@
 device_t                       root_device;
 
 /*
+ * device_handle_t accessors / mutators.
+ */
+
+static bool
+devhandle_is_valid_internal(const devhandle_t * const handlep)
+{
+       if (handlep->impl == NULL) {
+               return false;
+       }
+       return handlep->impl->type != DEVHANDLE_TYPE_INVALID;
+}
+
+bool
+devhandle_is_valid(devhandle_t handle)
+{
+       return devhandle_is_valid_internal(&handle);
+}
+
+void
+devhandle_invalidate(devhandle_t * const handlep)
+{
+       handlep->impl = NULL;
+       handlep->uintptr = 0;
+}
+
+devhandle_type_t
+devhandle_type(devhandle_t handle)
+{
+       if (!devhandle_is_valid_internal(&handle)) {
+               return DEVHANDLE_TYPE_INVALID;
+       }
+
+       return handle.impl->type;
+}
+
+static device_call_t
+devhandle_lookup_device_call(devhandle_t handle, const char *name,
+    devhandle_t *call_handlep)
+{
+       const struct devhandle_impl *impl;
+       device_call_t call;
+
+       /*
+        * The back-end can override the handle to use for the call,
+        * if needed.
+        */
+       *call_handlep = handle;
+
+       for (impl = handle.impl; impl != NULL; impl = impl->super) {
+               if (impl->lookup_device_call != NULL) {
+                       call = impl->lookup_device_call(handle, name,
+                           call_handlep);
+                       if (call != NULL) {
+                               return call;
+                       }
+               }
+       }
+       return NULL;
+}
+
+void
+devhandle_impl_inherit(struct devhandle_impl *impl,
+    const struct devhandle_impl *super)
+{
+       memcpy(impl, super, sizeof(*impl));
+       impl->super = super;
+}
+
+/*
  * Accessor functions for the device_t type.
  */
 
@@ -202,3 +271,42 @@
 
        return strcmp(pspec->cfp_iattr, iattr) == 0;
 }
+
+void
+device_set_handle(device_t dev, devhandle_t handle)
+{
+       dev->dv_handle = handle;
+}
+
+devhandle_t
+device_handle(device_t dev)
+{
+       return dev->dv_handle;
+}
+
+int
+device_call(device_t dev, const char *name, void *arg)
+{
+       devhandle_t handle = device_handle(dev);
+       device_call_t call;
+       devhandle_t call_handle;
+
+       call = devhandle_lookup_device_call(handle, name, &call_handle);
+       if (call == NULL) {
+               return ENOTSUP;
+       }
+       return call(dev, call_handle, arg);
+}
+
+int
+device_enumerate_children(device_t dev,
+    bool (*callback)(device_t, devhandle_t, void *),
+    void *callback_arg)
+{
+       struct device_enumerate_children_args args = {
+               .callback = callback,
+               .callback_arg = callback_arg,
+       };
+
+       return device_call(dev, "device-enumerate-children", &args);
+}
diff -r 059688abe71b -r c63283819474 sys/sys/device.h
--- a/sys/sys/device.h  Fri Feb 05 16:06:24 2021 +0000
+++ b/sys/sys/device.h  Fri Feb 05 17:03:35 2021 +0000
@@ -1,4 +1,30 @@
-/* $NetBSD: device.h,v 1.165 2021/02/04 23:29:16 thorpej Exp $ */
+/* $NetBSD: device.h,v 1.166 2021/02/05 17:03:35 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /*
  * Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -156,7 +182,73 @@
        int             dg_ndevs;
 };
 
+/*
+ * devhandle_t --
+ *
+ *     This is an abstraction of the device handles used by ACPI,
+ *     OpenFirmware, and others, to support device enumeration and
+ *     device tree linkage.  A devhandle_t can be safely passed
+ *     by value.
+ */
+struct devhandle {
+       const struct devhandle_impl *   impl;
+       union {
+               /*
+                * Storage for the device handle.  Which storage field
+                * is used is at the sole discretion of the type
+                * implementation.
+                */
+               void *                  pointer;
+               const void *            const_pointer;
+               uintptr_t               uintptr;
+               int                     integer;
+       };
+};
+typedef struct devhandle devhandle_t;
+
+typedef enum {
+       /* Used to represent invalid states. */
+       DEVHANDLE_TYPE_INVALID          =       0,
+
+       /* ACPI */
+       DEVHANDLE_TYPE_ACPI             =       0x41435049,     /* 'ACPI' */
+
+       /* OpenFirmware, FDT */
+       DEVHANDLE_TYPE_OF               =       0x4f504657,     /* 'OPFW' */
+
+       /* Private (opaque data) */
+       DEVHANDLE_TYPE_PRIVATE          =       0x50525654,     /* 'PRVT' */
+
+       /* Max value. */
+       DEVHANDLE_TYPE_MAX              =       0xffffffff
+} devhandle_type_t;
+
+/* Device method call function signature. */
+typedef int (*device_call_t)(device_t, devhandle_t, void *);
+
+struct device_call_descriptor {
+       const char *name;
+       device_call_t call;
+};
+
+#define        _DEVICE_CALL_REGISTER(_g_, _c_)                                 \
+       __link_set_add_rodata(_g_, __CONCAT(_c_,_descriptor));
+#define        DEVICE_CALL_REGISTER(_g_, _n_, _c_)                             \
+static const struct device_call_descriptor __CONCAT(_c_,_descriptor) = {\
+       .name = (_n_), .call = (_c_)                                    \
+};                                                                     \
+_DEVICE_CALL_REGISTER(_g_, _c_)
+
+struct devhandle_impl {
+       devhandle_type_t                type;
+       const struct devhandle_impl *   super;
+       device_call_t                   (*lookup_device_call)(devhandle_t,
+                                           const char *, devhandle_t *);
+};
+
 struct device {
+       devhandle_t     dv_handle;      /* this device's handle;
+                                          new device_t's get INVALID */
        devclass_t      dv_class;       /* this device's classification */
        TAILQ_ENTRY(device) dv_list;    /* entry on list of all devices */
        cfdata_t        dv_cfdata;      /* config data that found us
@@ -531,6 +623,15 @@
 int            device_locator(device_t, u_int);
 void           *device_private(device_t);
 prop_dictionary_t device_properties(device_t);
+void           device_set_handle(device_t, devhandle_t);
+devhandle_t    device_handle(device_t);
+
+bool           devhandle_is_valid(devhandle_t);
+void           devhandle_invalidate(devhandle_t *);
+devhandle_type_t devhandle_type(devhandle_t);
+
+void           devhandle_impl_inherit(struct devhandle_impl *,
+                   const struct devhandle_impl *);
 
 device_t       deviter_first(deviter_t *, deviter_flags_t);
 void           deviter_init(deviter_t *, deviter_flags_t);
@@ -549,6 +650,9 @@
 device_t       device_find_by_xname(const char *);
 device_t       device_find_by_driver_unit(const char *, int);
 
+int            device_enumerate_children(device_t,
+                   bool (*)(device_t, devhandle_t, void *), void *);
+
 int            device_compatible_match(const char **, int,
                                const struct device_compatible_entry *);
 int            device_compatible_pmatch(const char **, int,
@@ -627,6 +731,35 @@
 
 device_t       shutdown_first(struct shutdown_state *);
 device_t       shutdown_next(struct shutdown_state *);
+
+/*
+ * device calls --
+ *
+ * This provides a generic mechanism for invoking special methods on
+ * devices, often dependent on the device tree implementation used
+ * by the platform.
+ *
+ * While individual subsystems may define their own device calls,
+ * the ones prefixed with "device-" are reserved, and defined by
+ * the device autoconfiguration subsystem.  It is the responsibility
+ * of each device tree back end to implement these calls.
+ *
+ * device-enumerate-children
+ *
+ *     Enumerates the direct children of a device, invoking the
+ *     callback for each one.  The callback is passed the devhandle_t
+ *     corresponding to the child device, as well as a user-supplied
+ *     argument.  If the callback returns true, then enumeration
+ *     continues.  If the callback returns false, enumeration is stopped.
+ */
+
+struct device_enumerate_children_args {
+       bool    (*callback)(device_t, devhandle_t, void *);



Home | Main Index | Thread Index | Old Index