summaryrefslogtreecommitdiffstats
path: root/lib/libdevinfo
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libdevinfo')
-rw-r--r--lib/libdevinfo/Makefile8
-rw-r--r--lib/libdevinfo/devinfo.3247
-rw-r--r--lib/libdevinfo/devinfo.c500
-rw-r--r--lib/libdevinfo/devinfo.h147
-rw-r--r--lib/libdevinfo/devinfo_var.h70
5 files changed, 972 insertions, 0 deletions
diff --git a/lib/libdevinfo/Makefile b/lib/libdevinfo/Makefile
new file mode 100644
index 0000000..0615195
--- /dev/null
+++ b/lib/libdevinfo/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+LIB= devinfo
+SRCS= devinfo.c
+INCS= devinfo.h
+MAN= devinfo.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libdevinfo/devinfo.3 b/lib/libdevinfo/devinfo.3
new file mode 100644
index 0000000..49516cc
--- /dev/null
+++ b/lib/libdevinfo/devinfo.3
@@ -0,0 +1,247 @@
+.\"
+.\" Copyright (c) 2001 Michael Smith <msmith@FreeBSD.org>
+.\" 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 AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 19, 2001
+.Dt DEVINFO 3
+.Os
+.Sh NAME
+.Nm devinfo ,
+.Nm devinfo_init ,
+.Nm devinfo_free ,
+.Nm devinfo_handle_to_device ,
+.Nm devinfo_handle_to_resource ,
+.Nm devinfo_handle_to_rman ,
+.Nm devinfo_foreach_device_child ,
+.Nm devinfo_foreach_device_resource ,
+.Nm devinfo_foreach_rman_resource ,
+.Nm devinfo_foreach_rman
+.Nd device and resource information utility library
+.Sh LIBRARY
+.Lb libdevinfo
+.Sh SYNOPSIS
+.In devinfo.h
+.Ft int
+.Fn devinfo_init "void"
+.Ft void
+.Fn devinfo_free "void"
+.Ft struct devinfo_dev *
+.Fn devinfo_handle_to_device "devinfo_handle_t handle"
+.Ft struct devinfo_res *
+.Fn devinfo_handle_to_resource "devinfo_handle_t handle"
+.Ft struct devinfo_rman *
+.Fn devinfo_handle_to_rman "devinfo_handle_t handle"
+.Ft int
+.Fo devinfo_foreach_device_child
+.Fa "struct devinfo_dev *parent"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *child, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_device_resource
+.Fa "struct devinfo_dev *dev"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_dev *dev, struct devinfo_res *res, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_rman_resource
+.Fa "struct devinfo_rman *rman"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_res *res, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Ft int
+.Fo devinfo_foreach_rman
+.Fa "int \*[lp]*fn\*[rp]\*[lp]struct devinfo_rman *rman, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+library provides access to the kernel's internal device hierarchy
+and to the I/O resource manager.
+The library uses a
+.Xr sysctl 3
+interface to obtain a snapshot of the kernel's state,
+which is then made available to the application.
+.Pp
+Due to the fact that the information may be logically arranged
+in a number of different fashions,
+the library does not attempt to impose any structure on the data.
+.Pp
+Device, resource, and resource manager information is returned in
+data structures defined in
+.In devinfo.h :
+.Bd -literal -offset indent
+struct devinfo_dev {
+ devinfo_handle_t dd_handle; /* device handle */
+ devinfo_handle_t dd_parent; /* parent handle */
+ char *dd_name; /* name of device */
+ char *dd_desc; /* device description */
+ char *dd_drivername; /* name of attached driver */
+ char *dd_pnpinfo; /* pnp info from parent bus */
+ char *dd_location; /* Where bus thinks dev at */
+ uint32_t dd_devflags; /* API flags */
+ uint16_t dd_flags; /* internal dev flags */
+ device_state_t dd_state; /* attachment state of dev */
+};
+
+struct devinfo_rman {
+ devinfo_handle_t dm_handle; /* resource manager handle */
+ u_long dm_start; /* resource start */
+ u_long dm_size; /* resource size */
+ char *dm_desc; /* resource description */
+};
+
+struct devinfo_res {
+ devinfo_handle_t dr_handle; /* resource handle */
+ devinfo_handle_t dr_rman; /* resource manager handle */
+ devinfo_handle_t dr_device; /* owning device */
+ u_long dr_start; /* region start */
+ u_long dr_size; /* region size */
+};
+.Ed
+.Pp
+The
+.Vt devinfo_handle_t
+values can be used to look up the correspondingly referenced structures.
+.Pp
+.Fn devinfo_init
+takes a snapshot of the kernel's internal device and resource state.
+It returns nonzero
+if after a number of retries a consistent snapshot cannot be obtained.
+.Fn devinfo_init
+must be called before any other functions can be used.
+.Pp
+.Fn devinfo_free
+releases the memory associated with the snapshot.
+Any pointers returned by other functions are invalidated by this,
+and
+.Fn devinfo_init
+must be called again before using any other functions.
+.Pp
+.Fn devinfo_handle_to_device ,
+.Fn devinfo_handle_to_resource
+and
+.Fn devinfo_handle_to_rman
+return pointers to
+.Vt devinfo_dev ,
+.Vt devinfo_res
+and
+.Vt devinfo_rman
+structures respectively based on the
+.Vt devinfo_handle_t
+passed to them.
+These functions can be used to traverse the tree from any node to any
+other node.
+If
+.Fn devinfo_handle_to_device
+is passed the constant
+.Dv DEVINFO_ROOT_DEVICE
+it will return the handle to the root of the device tree.
+.Pp
+.Fn devinfo_foreach_device_child
+invokes its callback argument
+.Fa fn
+on every device which is an immediate child of
+.Fa device .
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_device_child
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_device_resource
+invokes its callback argument
+.Fa fn
+on every resource which is owned by
+.Fa device .
+The
+.Fa fn
+function is also passed
+.Fa device
+and
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_device_resource
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_rman_resource
+invokes its callback argument
+.Fa fn
+on every resource within the resource manager
+.Fa rman .
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_rman_resource
+returns the error value to its caller.
+.Pp
+.Fn devinfo_foreach_rman
+invokes its callback argument
+.Fa fn
+on every resource manager.
+The
+.Fa fn
+function is also passed
+.Fa arg ,
+allowing state to be passed to the callback function.
+If
+.Fa fn
+returns a nonzero error value the traversal is halted,
+and
+.Fn devinfo_foreach_rman
+returns the error value to its caller.
+.Sh SEE ALSO
+.Xr devstat 3
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Michael Smith Aq msmith@FreeBSD.org
+.Sh BUGS
+This is the first implementation of the library,
+and the interface is still subject to refinement.
+.Pp
+The interface does not report device classes or drivers,
+making it hard to sort by class or driver.
diff --git a/lib/libdevinfo/devinfo.c b/lib/libdevinfo/devinfo.c
new file mode 100644
index 0000000..5ad68c3
--- /dev/null
+++ b/lib/libdevinfo/devinfo.c
@@ -0,0 +1,500 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * An interface to the FreeBSD kernel's bus/device information interface.
+ *
+ * This interface is implemented with the
+ *
+ * hw.bus
+ * hw.bus.devices
+ * hw.bus.rman
+ *
+ * sysctls. The interface is not meant for general user application
+ * consumption.
+ *
+ * Device information is obtained by scanning a linear list of all devices
+ * maintained by the kernel. The actual device structure pointers are
+ * handed out as opaque handles in order to allow reconstruction of the
+ * logical toplogy in user space.
+ *
+ * Resource information is obtained by scanning the kernel's resource
+ * managers and fetching their contents. Ownership of resources is
+ * tracked using the device's structure pointer again as a handle.
+ *
+ * In order to ensure coherency of the library's picture of the kernel,
+ * a generation count is maintained by the kernel. The initial generation
+ * count is obtained (along with the interface version) from the hw.bus
+ * sysctl, and must be passed in with every request. If the generation
+ * number supplied by the library does not match the kernel's current
+ * generation number, the request is failed and the library must discard
+ * the data it has received and rescan.
+ *
+ * The information obtained from the kernel is exported to consumers of
+ * this library through a variety of interfaces.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "devinfo.h"
+#include "devinfo_var.h"
+
+static int devinfo_init_devices(int generation);
+static int devinfo_init_resources(int generation);
+
+TAILQ_HEAD(,devinfo_i_dev) devinfo_dev;
+TAILQ_HEAD(,devinfo_i_rman) devinfo_rman;
+TAILQ_HEAD(,devinfo_i_res) devinfo_res;
+
+static int devinfo_initted = 0;
+static int devinfo_generation = 0;
+
+#if 0
+# define debug(fmt, args...) \
+ fprintf(stderr, "%s:" fmt "\n", __func__ , ##args)
+#else
+# define debug(fmt, args...)
+#endif
+
+/*
+ * Initialise our local database with the contents of the kernel's
+ * tables.
+ */
+int
+devinfo_init(void)
+{
+ struct u_businfo ubus;
+ size_t ub_size;
+ int error, retries;
+
+ if (!devinfo_initted) {
+ TAILQ_INIT(&devinfo_dev);
+ TAILQ_INIT(&devinfo_rman);
+ TAILQ_INIT(&devinfo_res);
+ }
+
+ /*
+ * Get the generation count and interface version, verify that we
+ * are compatible with the kernel.
+ */
+ for (retries = 0; retries < 10; retries++) {
+ debug("get interface version");
+ ub_size = sizeof(ubus);
+ if (sysctlbyname("hw.bus.info", &ubus,
+ &ub_size, NULL, 0) != 0) {
+ warn("sysctlbyname(\"hw.bus.info\", ...) failed");
+ return(EINVAL);
+ }
+ if ((ub_size != sizeof(ubus)) ||
+ (ubus.ub_version != BUS_USER_VERSION)) {
+ warn("kernel bus interface version mismatch");
+ return(EINVAL);
+ }
+ debug("generation count is %d", ubus.ub_generation);
+
+ /*
+ * Don't rescan if the generation count hasn't changed.
+ */
+ if (ubus.ub_generation == devinfo_generation)
+ return(0);
+
+ /*
+ * Generation count changed, rescan
+ */
+ devinfo_free();
+ devinfo_initted = 0;
+ devinfo_generation = 0;
+
+ if ((error = devinfo_init_devices(ubus.ub_generation)) != 0) {
+ devinfo_free();
+ if (error == EINVAL)
+ continue;
+ break;
+ }
+ if ((error = devinfo_init_resources(ubus.ub_generation)) != 0) {
+ devinfo_free();
+ if (error == EINVAL)
+ continue;
+ break;
+ }
+ devinfo_initted = 1;
+ devinfo_generation = ubus.ub_generation;
+ return(0);
+ }
+ debug("scan failed after %d retries", retries);
+ errno = error;
+ return(1);
+}
+
+static int
+devinfo_init_devices(int generation)
+{
+ struct u_device udev;
+ struct devinfo_i_dev *dd;
+ int dev_idx;
+ int dev_ptr;
+ int name2oid[2];
+ int oid[CTL_MAXNAME + 12];
+ size_t oidlen, rlen;
+ char *name;
+ int error;
+
+ /*
+ * Find the OID for the rman interface node.
+ * This is just the usual evil, undocumented sysctl juju.
+ */
+ name2oid[0] = 0;
+ name2oid[1] = 3;
+ oidlen = sizeof(oid);
+ name = "hw.bus.devices";
+ error = sysctl(name2oid, 2, oid, &oidlen, name, strlen(name));
+ if (error < 0) {
+ warnx("can't find hw.bus.devices sysctl node");
+ return(ENOENT);
+ }
+ oidlen /= sizeof(int);
+ if (oidlen > CTL_MAXNAME) {
+ warnx("hw.bus.devices oid is too large");
+ return(EINVAL);
+ }
+ oid[oidlen++] = generation;
+ dev_ptr = oidlen++;
+
+ /*
+ * Scan devices.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (dev_idx = 0; dev_idx < 1000; dev_idx++) {
+
+ /*
+ * Get the device information.
+ */
+ oid[dev_ptr] = dev_idx;
+ rlen = sizeof(udev);
+ error = sysctl(oid, oidlen, &udev, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip, restart */
+ warn("sysctl hw.bus.devices.%d", dev_idx);
+ return(errno);
+ }
+ if ((dd = malloc(sizeof(*dd))) == NULL)
+ return(ENOMEM);
+ dd->dd_dev.dd_handle = udev.dv_handle;
+ dd->dd_dev.dd_parent = udev.dv_parent;
+ snprintf(dd->dd_name, sizeof(dd->dd_name), "%s", udev.dv_name);
+ dd->dd_dev.dd_name = &dd->dd_name[0];
+ snprintf(dd->dd_desc, sizeof(dd->dd_desc), "%s", udev.dv_desc);
+ dd->dd_dev.dd_desc = &dd->dd_desc[0];
+ snprintf(dd->dd_drivername, sizeof(dd->dd_drivername), "%s",
+ udev.dv_drivername);
+ dd->dd_dev.dd_drivername = &dd->dd_drivername[0];
+ snprintf(dd->dd_pnpinfo, sizeof(dd->dd_pnpinfo), "%s",
+ udev.dv_pnpinfo);
+ dd->dd_dev.dd_pnpinfo = &dd->dd_pnpinfo[0];
+ snprintf(dd->dd_location, sizeof(dd->dd_location), "%s",
+ udev.dv_location);
+ dd->dd_dev.dd_location = &dd->dd_location[0];
+ dd->dd_dev.dd_devflags = udev.dv_devflags;
+ dd->dd_dev.dd_flags = udev.dv_flags;
+ dd->dd_dev.dd_state = udev.dv_state;
+ TAILQ_INSERT_TAIL(&devinfo_dev, dd, dd_link);
+ }
+ debug("fetched %d devices", dev_idx);
+ return(0);
+}
+
+static int
+devinfo_init_resources(int generation)
+{
+ struct u_rman urman;
+ struct devinfo_i_rman *dm;
+ struct u_resource ures;
+ struct devinfo_i_res *dr;
+ int rman_idx, res_idx;
+ int rman_ptr, res_ptr;
+ int name2oid[2];
+ int oid[CTL_MAXNAME + 12];
+ size_t oidlen, rlen;
+ char *name;
+ int error;
+
+ /*
+ * Find the OID for the rman interface node.
+ * This is just the usual evil, undocumented sysctl juju.
+ */
+ name2oid[0] = 0;
+ name2oid[1] = 3;
+ oidlen = sizeof(oid);
+ name = "hw.bus.rman";
+ error = sysctl(name2oid, 2, oid, &oidlen, name, strlen(name));
+ if (error < 0) {
+ warnx("can't find hw.bus.rman sysctl node");
+ return(ENOENT);
+ }
+ oidlen /= sizeof(int);
+ if (oidlen > CTL_MAXNAME) {
+ warnx("hw.bus.rman oid is too large");
+ return(EINVAL);
+ }
+ oid[oidlen++] = generation;
+ rman_ptr = oidlen++;
+ res_ptr = oidlen++;
+
+ /*
+ * Scan resource managers.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (rman_idx = 0; rman_idx < 255; rman_idx++) {
+
+ /*
+ * Get the resource manager information.
+ */
+ oid[rman_ptr] = rman_idx;
+ oid[res_ptr] = -1;
+ rlen = sizeof(urman);
+ error = sysctl(oid, oidlen, &urman, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip, restart */
+ warn("sysctl hw.bus.rman.%d", rman_idx);
+ return(errno);
+ }
+ if ((dm = malloc(sizeof(*dm))) == NULL)
+ return(ENOMEM);
+ dm->dm_rman.dm_handle = urman.rm_handle;
+ dm->dm_rman.dm_start = urman.rm_start;
+ dm->dm_rman.dm_size = urman.rm_size;
+ snprintf(dm->dm_desc, DEVINFO_STRLEN, "%s", urman.rm_descr);
+ dm->dm_rman.dm_desc = &dm->dm_desc[0];
+ TAILQ_INSERT_TAIL(&devinfo_rman, dm, dm_link);
+
+ /*
+ * Scan resources on this resource manager.
+ *
+ * Stop after a fairly insane number to avoid death in the case
+ * of kernel corruption.
+ */
+ for (res_idx = 0; res_idx < 1000; res_idx++) {
+ /*
+ * Get the resource information.
+ */
+ oid[res_ptr] = res_idx;
+ rlen = sizeof(ures);
+ error = sysctl(oid, oidlen, &ures, &rlen, NULL, 0);
+ if (error < 0) {
+ if (errno == ENOENT) /* end of list */
+ break;
+ if (errno != EINVAL) /* gen count skip */
+ warn("sysctl hw.bus.rman.%d.%d",
+ rman_idx, res_idx);
+ return(errno);
+ }
+ if ((dr = malloc(sizeof(*dr))) == NULL)
+ return(ENOMEM);
+ dr->dr_res.dr_handle = ures.r_handle;
+ dr->dr_res.dr_rman = ures.r_parent;
+ dr->dr_res.dr_device = ures.r_device;
+ dr->dr_res.dr_start = ures.r_start;
+ dr->dr_res.dr_size = ures.r_size;
+ TAILQ_INSERT_TAIL(&devinfo_res, dr, dr_link);
+ }
+ debug("fetched %d resources", res_idx);
+ }
+ debug("scanned %d resource managers", rman_idx);
+ return(0);
+}
+
+/*
+ * Free the list contents.
+ */
+void
+devinfo_free(void)
+{
+ struct devinfo_i_dev *dd;
+ struct devinfo_i_rman *dm;
+ struct devinfo_i_res *dr;
+
+ while ((dd = TAILQ_FIRST(&devinfo_dev)) != NULL) {
+ TAILQ_REMOVE(&devinfo_dev, dd, dd_link);
+ free(dd);
+ }
+ while ((dm = TAILQ_FIRST(&devinfo_rman)) != NULL) {
+ TAILQ_REMOVE(&devinfo_rman, dm, dm_link);
+ free(dm);
+ }
+ while ((dr = TAILQ_FIRST(&devinfo_res)) != NULL) {
+ TAILQ_REMOVE(&devinfo_res, dr, dr_link);
+ free(dr);
+ }
+ devinfo_initted = 0;
+ devinfo_generation = 0;
+}
+
+/*
+ * Find a device by its handle.
+ */
+struct devinfo_dev *
+devinfo_handle_to_device(devinfo_handle_t handle)
+{
+ struct devinfo_i_dev *dd;
+
+ /*
+ * Find the root device, whose parent is NULL
+ */
+ if (handle == DEVINFO_ROOT_DEVICE) {
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_parent == DEVINFO_ROOT_DEVICE)
+ return(&dd->dd_dev);
+ return(NULL);
+ }
+
+ /*
+ * Scan for the device
+ */
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_handle == handle)
+ return(&dd->dd_dev);
+ return(NULL);
+}
+
+/*
+ * Find a resource by its handle.
+ */
+struct devinfo_res *
+devinfo_handle_to_resource(devinfo_handle_t handle)
+{
+ struct devinfo_i_res *dr;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_handle == handle)
+ return(&dr->dr_res);
+ return(NULL);
+}
+
+/*
+ * Find a resource manager by its handle.
+ */
+struct devinfo_rman *
+devinfo_handle_to_rman(devinfo_handle_t handle)
+{
+ struct devinfo_i_rman *dm;
+
+ TAILQ_FOREACH(dm, &devinfo_rman, dm_link)
+ if (dm->dm_rman.dm_handle == handle)
+ return(&dm->dm_rman);
+ return(NULL);
+}
+
+/*
+ * Iterate over the children of a device, calling (fn) on each. If
+ * (fn) returns nonzero, abort the scan and return.
+ */
+int
+devinfo_foreach_device_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg)
+{
+ struct devinfo_i_dev *dd;
+ int error;
+
+ TAILQ_FOREACH(dd, &devinfo_dev, dd_link)
+ if (dd->dd_dev.dd_parent == parent->dd_handle)
+ if ((error = fn(&dd->dd_dev, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resources owned by a device, calling (fn) on each.
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+int
+devinfo_foreach_device_resource(struct devinfo_dev *dev,
+ int (* fn)(struct devinfo_dev *dev, struct devinfo_res *res, void *arg),
+ void *arg)
+{
+ struct devinfo_i_res *dr;
+ int error;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_device == dev->dd_handle)
+ if ((error = fn(dev, &dr->dr_res, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resources owned by a resource manager, calling (fn)
+ * on each. If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+devinfo_foreach_rman_resource(struct devinfo_rman *rman,
+ int (* fn)(struct devinfo_res *res, void *arg),
+ void *arg)
+{
+ struct devinfo_i_res *dr;
+ int error;
+
+ TAILQ_FOREACH(dr, &devinfo_res, dr_link)
+ if (dr->dr_res.dr_rman == rman->dm_handle)
+ if ((error = fn(&dr->dr_res, arg)) != 0)
+ return(error);
+ return(0);
+}
+
+/*
+ * Iterate over all the resource managers, calling (fn) on each. If (fn)
+ * returns nonzero, abort the scan and return.
+ */
+extern int
+devinfo_foreach_rman(int (* fn)(struct devinfo_rman *rman, void *arg),
+ void *arg)
+{
+ struct devinfo_i_rman *dm;
+ int error;
+
+ TAILQ_FOREACH(dm, &devinfo_rman, dm_link)
+ if ((error = fn(&dm->dm_rman, arg)) != 0)
+ return(error);
+ return(0);
+}
diff --git a/lib/libdevinfo/devinfo.h b/lib/libdevinfo/devinfo.h
new file mode 100644
index 0000000..91930a4
--- /dev/null
+++ b/lib/libdevinfo/devinfo.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEVINFO_H_INCLUDED
+#define _DEVINFO_H_INCLUDED
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+typedef __uintptr_t devinfo_handle_t;
+#define DEVINFO_ROOT_DEVICE ((devinfo_handle_t)0)
+
+/*
+ * State of the device.
+ */
+/* XXX not sure if I want a copy here, or expose sys/bus.h */
+typedef enum devinfo_state {
+ DIS_NOTPRESENT, /* not probed or probe failed */
+ DIS_ALIVE, /* probe succeeded */
+ DIS_ATTACHED, /* attach method called */
+ DIS_BUSY /* device is open */
+} devinfo_state_t;
+
+struct devinfo_dev {
+ devinfo_handle_t dd_handle; /* device handle */
+ devinfo_handle_t dd_parent; /* parent handle */
+
+ char *dd_name; /* name of device */
+ char *dd_desc; /* device description */
+ char *dd_drivername; /* name of attached driver*/
+ char *dd_pnpinfo; /* pnp info from parent bus */
+ char *dd_location; /* Where bus thinks dev at */
+ uint32_t dd_devflags; /* API flags */
+ uint16_t dd_flags; /* internal dev flags */
+ devinfo_state_t dd_state; /* attacement state of dev */
+};
+
+struct devinfo_rman {
+ devinfo_handle_t dm_handle; /* resource manager handle */
+
+ unsigned long dm_start; /* resource start */
+ unsigned long dm_size; /* resource size */
+
+ char *dm_desc; /* resource description */
+};
+
+struct devinfo_res {
+ devinfo_handle_t dr_handle; /* resource handle */
+ devinfo_handle_t dr_rman; /* resource manager handle */
+ devinfo_handle_t dr_device; /* owning device */
+
+ unsigned long dr_start; /* region start */
+ unsigned long dr_size; /* region size */
+ /* XXX add flags */
+};
+
+__BEGIN_DECLS
+
+/*
+ * Acquire a coherent copy of the kernel's device and resource tables.
+ * This must return success (zero) before any other interfaces will
+ * function. Sets errno on failure.
+ */
+extern int devinfo_init(void);
+
+/*
+ * Release the storage associated with the internal copy of the device
+ * and resource tables. devinfo_init must be called before any attempt
+ * is made to use any other interfaces.
+ */
+extern void devinfo_free(void);
+
+/*
+ * Find a device/resource/resource manager by its handle.
+ */
+extern struct devinfo_dev
+ *devinfo_handle_to_device(devinfo_handle_t handle);
+extern struct devinfo_res
+ *devinfo_handle_to_resource(devinfo_handle_t handle);
+extern struct devinfo_rman
+ *devinfo_handle_to_rman(devinfo_handle_t handle);
+
+/*
+ * Iterate over the children of a device, calling (fn) on each. If
+ * (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_device_child(struct devinfo_dev *parent,
+ int (* fn)(struct devinfo_dev *child, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resources owned by a device, calling (fn) on each.
+ * If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_device_resource(struct devinfo_dev *dev,
+ int (* fn)(struct devinfo_dev *dev,
+ struct devinfo_res *res, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resources owned by a resource manager, calling (fn)
+ * on each. If (fn) returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_rman_resource(struct devinfo_rman *rman,
+ int (* fn)(struct devinfo_res *res, void *arg),
+ void *arg);
+
+/*
+ * Iterate over all the resource managers, calling (fn) on each. If (fn)
+ * returns nonzero, abort the scan and return.
+ */
+extern int
+ devinfo_foreach_rman(int (* fn)(struct devinfo_rman *rman, void *arg),
+ void *arg);
+
+__END_DECLS
+
+#endif /* ! _DEVINFO_H_INCLUDED */
diff --git a/lib/libdevinfo/devinfo_var.h b/lib/libdevinfo/devinfo_var.h
new file mode 100644
index 0000000..b409671
--- /dev/null
+++ b/lib/libdevinfo/devinfo_var.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/rman.h>
+#include <sys/bus.h>
+
+/*
+ * This is defined by the version 1 interface.
+ */
+#define DEVINFO_STRLEN 32
+
+/*
+ * Devices.
+ *
+ * Internal structure contains string buffers and list linkage;
+ */
+struct devinfo_i_dev {
+ struct devinfo_dev dd_dev;
+ char dd_name[DEVINFO_STRLEN];
+ char dd_desc[DEVINFO_STRLEN];
+ char dd_drivername[DEVINFO_STRLEN];
+ char dd_pnpinfo[DEVINFO_STRLEN * 4];
+ char dd_location[DEVINFO_STRLEN * 4];
+ uint32_t dd_devflags;
+ uint16_t dd_flags;
+ device_state_t dd_state;
+ TAILQ_ENTRY(devinfo_i_dev) dd_link;
+};
+
+/*
+ * Resources.
+ *
+ * Internal structures contain string buffers and list linkage;
+ */
+struct devinfo_i_rman {
+ struct devinfo_rman dm_rman;
+ char dm_desc[32];
+ TAILQ_ENTRY(devinfo_i_rman) dm_link;
+};
+
+struct devinfo_i_res {
+ struct devinfo_res dr_res;
+ TAILQ_ENTRY(devinfo_i_res) dr_link;
+};
OpenPOWER on IntegriCloud