summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/subr_autoconf.c69
-rw-r--r--sys/sys/device.h3
2 files changed, 67 insertions, 5 deletions
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c
index 866e1c9979a..93613bb63df 100644
--- a/sys/kern/subr_autoconf.c
+++ b/sys/kern/subr_autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_autoconf.c,v 1.23 1999/07/23 19:45:21 niklas Exp $ */
+/* $OpenBSD: subr_autoconf.c,v 1.24 1999/08/05 17:41:44 niklas Exp $ */
/* $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $ */
/*
@@ -95,6 +95,16 @@ int autoconf_verbose = AUTOCONF_VERBOSE; /* trace probe calls */
static char *number __P((char *, int));
static void mapply __P((struct matchinfo *, struct cfdata *));
+struct deferred_config {
+ TAILQ_ENTRY(deferred_config) dc_queue;
+ struct device *dc_dev;
+ void (*dc_func) __P((struct device *));
+};
+
+TAILQ_HEAD(, deferred_config) deferred_config_queue;
+
+void config_process_deferred_children __P((struct device *));
+
struct devicelist alldevs; /* list of all devices */
struct evcntlist allevents; /* list of all event counters */
@@ -106,7 +116,7 @@ struct evcntlist allevents; /* list of all event counters */
void
config_init()
{
-
+ TAILQ_INIT(&deferred_config_queue);
TAILQ_INIT(&alldevs);
TAILQ_INIT(&allevents);
TAILQ_INIT(&allcftables);
@@ -117,7 +127,7 @@ config_init()
* Apply the matching function and choose the best. This is used
* a few times and we want to keep the code small.
*/
-static void
+void
mapply(m, cf)
register struct matchinfo *m;
register struct cfdata *cf;
@@ -335,7 +345,7 @@ config_rootfound(rootname, aux)
}
/* just like sprintf(buf, "%d") except that it works from the end */
-static char *
+char *
number(ep, n)
register char *ep;
register int n;
@@ -418,6 +428,7 @@ config_attach(parent, match, aux, print)
device_register(dev, aux);
#endif
(*ca->ca_attach)(parent, dev, aux);
+ config_process_deferred_children(dev);
return (dev);
}
@@ -500,6 +511,56 @@ config_make_softc(parent, cf)
}
/*
+ * Defer the configuration of the specified device until all
+ * of its parent's devices have been attached.
+ */
+void
+config_defer(dev, func)
+ struct device *dev;
+ void (*func) __P((struct device *));
+{
+ struct deferred_config *dc;
+
+ if (dev->dv_parent == NULL)
+ panic("config_defer: can't defer config of a root device");
+
+#ifdef DIAGNOSTIC
+ for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
+ dc = TAILQ_NEXT(dc, dc_queue)) {
+ if (dc->dc_dev == dev)
+ panic("config_defer: deferred twice");
+ }
+#endif
+
+ if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
+ panic("config_defer: can't allocate defer structure");
+
+ dc->dc_dev = dev;
+ dc->dc_func = func;
+ TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
+}
+
+/*
+ * Process the deferred configuration queue for a device.
+ */
+void
+config_process_deferred_children(parent)
+ struct device *parent;
+{
+ struct deferred_config *dc, *ndc;
+
+ for (dc = TAILQ_FIRST(&deferred_config_queue);
+ dc != NULL; dc = ndc) {
+ ndc = TAILQ_NEXT(dc, dc_queue);
+ if (dc->dc_dev->dv_parent == parent) {
+ TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
+ (*dc->dc_func)(dc->dc_dev);
+ free(dc, M_DEVBUF);
+ }
+ }
+}
+
+/*
* Attach an event. These must come from initially-zero space (see
* commented-out assignments below), but that occurs naturally for
* device instance variables.
diff --git a/sys/sys/device.h b/sys/sys/device.h
index a7980629246..bb241eeba60 100644
--- a/sys/sys/device.h
+++ b/sys/sys/device.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: device.h,v 1.15 1999/07/23 19:45:20 niklas Exp $ */
+/* $OpenBSD: device.h,v 1.16 1999/08/05 17:41:43 niklas Exp $ */
/* $NetBSD: device.h,v 1.15 1996/04/09 20:55:24 cgd Exp $ */
/*
@@ -181,6 +181,7 @@ void config_scan __P((cfscan_t, struct device *));
struct device *config_attach __P((struct device *, void *, void *, cfprint_t));
struct device *config_make_softc __P((struct device *parent,
struct cfdata *cf));
+void config_defer __P((struct device *, void (*)(struct device *)));
void evcnt_attach __P((struct device *, const char *, struct evcnt *));
/* compatibility definitions */