Module Name:    src
Committed By:   thorpej
Date:           Fri Feb  5 17:03:35 UTC 2021

Modified Files:
        src/sys/kern: subr_device.c
        src/sys/sys: device.h param.h

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/kern/subr_device.c
cvs rdiff -u -r1.165 -r1.166 src/sys/sys/device.h
cvs rdiff -u -r1.683 -r1.684 src/sys/sys/param.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_device.c
diff -u src/sys/kern/subr_device.c:1.5 src/sys/kern/subr_device.c:1.6
--- src/sys/kern/subr_device.c:1.5	Thu Feb  4 23:29:16 2021
+++ src/sys/kern/subr_device.c	Fri Feb  5 17:03:35 2021
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: subr_device.
 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 @@ device_attached_to_iattr(device_t dev, c
 
 	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);
+}

Index: src/sys/sys/device.h
diff -u src/sys/sys/device.h:1.165 src/sys/sys/device.h:1.166
--- src/sys/sys/device.h:1.165	Thu Feb  4 23:29:16 2021
+++ src/sys/sys/device.h	Fri Feb  5 17:03:35 2021
@@ -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 @@ struct device_garbage {
 	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 @@ bool		device_has_power(device_t);
 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 @@ bool		device_attached_to_iattr(device_t,
 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 @@ void		device_pmf_class_deregister(device
 
 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 *);
+	void *	callback_arg;
+};
+
+int		device_call(device_t, const char *, void *);
+
 #endif /* _KERNEL */
 
 #endif /* !_SYS_DEVICE_H_ */

Index: src/sys/sys/param.h
diff -u src/sys/sys/param.h:1.683 src/sys/sys/param.h:1.684
--- src/sys/sys/param.h:1.683	Mon Jan 25 12:17:24 2021
+++ src/sys/sys/param.h	Fri Feb  5 17:03:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: param.h,v 1.683 2021/01/25 12:17:24 jmcneill Exp $	*/
+/*	$NetBSD: param.h,v 1.684 2021/02/05 17:03:35 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -67,7 +67,7 @@
  *	2.99.9		(299000900)
  */
 
-#define	__NetBSD_Version__	999007900	/* NetBSD 9.99.79 */
+#define	__NetBSD_Version__	999008000	/* NetBSD 9.99.80 */
 
 #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
     (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)

Reply via email to