diff options
Diffstat (limited to 'lib/libdevinfo')
-rw-r--r-- | lib/libdevinfo/Makefile | 8 | ||||
-rw-r--r-- | lib/libdevinfo/devinfo.3 | 247 | ||||
-rw-r--r-- | lib/libdevinfo/devinfo.c | 500 | ||||
-rw-r--r-- | lib/libdevinfo/devinfo.h | 147 | ||||
-rw-r--r-- | lib/libdevinfo/devinfo_var.h | 70 |
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; +}; |