From: Hasso Tepper Date: Tue, 30 Sep 2008 12:20:29 +0000 (+0000) Subject: The devinfo(3) library provides userspace access to the internal device X-Git-Tag: v2.1.1~293 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/0010e23a7baba5424287f42a17c943471435ac39?hp=c0e34fb14b4033abadac79cc4361fc4e2bfe7852 The devinfo(3) library provides userspace access to the internal device hierarchy. The devinfo(8) utility can be used to view that information. Ported by Sascha Wildner. Obtained-from: FreeBSD --- diff --git a/gnu/usr.bin/groff/tmac/mdoc.local b/gnu/usr.bin/groff/tmac/mdoc.local index 9e95f56f50..424fa905ee 100644 --- a/gnu/usr.bin/groff/tmac/mdoc.local +++ b/gnu/usr.bin/groff/tmac/mdoc.local @@ -23,7 +23,7 @@ .\" SUCH DAMAGE. .\" .\" $FreeBSD: src/gnu/usr.bin/groff/tmac/mdoc.local,v 1.2.2.19 2003/03/25 10:20:12 murray Exp $ -.\" $DragonFly: src/gnu/usr.bin/groff/tmac/mdoc.local,v 1.25 2008/09/14 20:03:06 swildner Exp $ +.\" $DragonFly: src/gnu/usr.bin/groff/tmac/mdoc.local,v 1.26 2008/09/30 12:20:29 hasso Exp $ .\" .\" %beginstrip% . @@ -45,6 +45,7 @@ .ds doc-str-Lb-libcam Common Access Method User Library (libcam, \-lcam) .ds doc-str-Lb-libcaps CAPS IPC Library (libcaps, \-lcaps) .ds doc-str-Lb-libcipher FreeSec Crypt Library (libcipher, \-lcipher) +.ds doc-str-Lb-libdevinfo Device and Resource Information Utility Library (libdevinfo, \-ldevinfo) .ds doc-str-Lb-libdevstat Device Statistics Library (libdevstat, \-ldevstat) .ds doc-str-Lb-libfetch File Transfer Library (libfetch, \-lfetch) .ds doc-str-Lb-libftpio FTP Connection Management Library (libftpio, \-lftpio) diff --git a/lib/Makefile b/lib/Makefile index 632533d870..eacd8e1fb0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,6 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD: src/lib/Makefile,v 1.107.2.16 2002/10/10 19:24:35 kbyanc Exp $ -# $DragonFly: src/lib/Makefile,v 1.34 2008/07/23 14:09:05 swildner Exp $ +# $DragonFly: src/lib/Makefile,v 1.35 2008/09/30 12:20:29 hasso Exp $ # To satisfy shared library or ELF linkage when only the libraries being # built are visible: @@ -23,7 +23,7 @@ SUBDIR= libarchive libbluetooth libcom_err libcrypt libm libmd \ libncurses libradius libskey libtacplus libutil libsbuf \ libalias libatm ${_libbind} ${_libbind9} libbz2 libc ${_libc_r} \ - libcalendar libcam libcompat libdevstat libedit libevent libfetch \ + libcalendar libcam libcompat libdevinfo libdevstat libedit libevent libfetch \ libftpio libipsec libipx libisc libkcore libkinfo libkvm libmagic \ ${_libmilter} ${_libncp} libnetgraph libopie libpam \ libpcap libposix1e libsdp libthread_xu libpthread librpcsvc ${_libsm} \ diff --git a/lib/libdevinfo/Makefile b/lib/libdevinfo/Makefile new file mode 100644 index 0000000000..607ab119da --- /dev/null +++ b/lib/libdevinfo/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD: src/lib/libdevinfo/Makefile,v 1.4 2002/05/13 12:11:54 ru Exp $ +# $DragonFly: src/lib/libdevinfo/Makefile,v 1.1 2008/09/30 12:20:29 hasso Exp $ + +LIB= devinfo +SRCS= devinfo.c +INCS= devinfo.h +MAN= devinfo.3 + +.include diff --git a/lib/libdevinfo/devinfo.3 b/lib/libdevinfo/devinfo.3 new file mode 100644 index 0000000000..99b45ab96c --- /dev/null +++ b/lib/libdevinfo/devinfo.3 @@ -0,0 +1,250 @@ +.\" +.\" Copyright (c) 2001 Michael Smith +.\" 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: src/lib/libdevinfo/devinfo.3,v 1.11 2006/09/17 21:27:35 ru Exp $ +.\" $DragonFly: src/lib/libdevinfo/devinfo.3,v 1.1 2008/09/30 12:20:29 hasso Exp $ +.\" +.Dd September 30, 2008 +.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 +and was imported into +.Dx 1.11 . +.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 0000000000..ffcc2bb473 --- /dev/null +++ b/lib/libdevinfo/devinfo.c @@ -0,0 +1,503 @@ +/*- + * 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: src/lib/libdevinfo/devinfo.c,v 1.9 2006/07/17 09:33:24 stefanf Exp $ + * $DragonFly: src/lib/libdevinfo/devinfo.c,v 1.1 2008/09/30 12:20:29 hasso Exp $ + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#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(...) do { \ + fprintf(stderr, "%s:", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) +#else +# define debug(...) +#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 0000000000..8caf544629 --- /dev/null +++ b/lib/libdevinfo/devinfo.h @@ -0,0 +1,148 @@ +/*- + * 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: src/lib/libdevinfo/devinfo.h,v 1.5 2005/08/31 14:57:39 rodrigc Exp $ + * $DragonFly: src/lib/libdevinfo/devinfo.h,v 1.1 2008/09/30 12:20:29 hasso Exp $ + */ + +#ifndef _DEVINFO_H_INCLUDED +#define _DEVINFO_H_INCLUDED + +#include +#include + +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 0000000000..5189d12bb7 --- /dev/null +++ b/lib/libdevinfo/devinfo_var.h @@ -0,0 +1,73 @@ +/*- + * 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: src/lib/libdevinfo/devinfo_var.h,v 1.3 2003/02/17 18:56:00 imp Exp $ + * $DragonFly: src/lib/libdevinfo/devinfo_var.h,v 1.1 2008/09/30 12:20:29 hasso Exp $ + */ + +#define _KERNEL_STRUCTURES + +#include +#include + +/* + * 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; +}; diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 0cfe755092..cc308362cb 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/subr_bus.c,v 1.54.2.9 2002/10/10 15:13:32 jhb Exp $ - * $DragonFly: src/sys/kern/subr_bus.c,v 1.44 2008/09/29 06:59:45 hasso Exp $ + * $DragonFly: src/sys/kern/subr_bus.c,v 1.45 2008/09/30 12:20:29 hasso Exp $ */ #include "opt_bus.h" @@ -34,11 +34,9 @@ #include #include #include -#ifdef DEVICE_SYSCTLS -#include -#endif #include #include +#include #include #include #include @@ -47,6 +45,8 @@ #include +SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); + MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); #ifdef BUS_DEBUG @@ -92,10 +92,6 @@ void print_devclass_list(void); #define print_devclass_list() /* nop */ #endif -#ifdef DEVICE_SYSCTLS -static void device_register_oids(device_t dev); -static void device_unregister_oids(device_t dev); -#endif static void device_attach_async(device_t dev); static void device_attach_thread(void *arg); static int device_doattach(device_t dev); @@ -104,6 +100,9 @@ static int do_async_attach = 0; static int numasyncthreads; TUNABLE_INT("kern.do_async_attach", &do_async_attach); +TAILQ_HEAD(,device) bus_data_devices; +static int bus_data_generation = 1; + kobj_method_t null_methods[] = { { 0, 0 } }; @@ -143,6 +142,9 @@ devclass_find_internal(const char *classname, const char *parentname, dc->maxunit = 0; TAILQ_INIT(&dc->drivers); TAILQ_INSERT_TAIL(&devclasses, dc, link); + + bus_data_generation_update(); + } if (parentname && dc && !dc->parent) dc->parent = devclass_find_internal(parentname, NULL, FALSE); @@ -217,6 +219,7 @@ devclass_add_driver(devclass_t dc, driver_t *driver) } } + bus_data_generation_update(); return(0); } @@ -272,6 +275,7 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver) kobj_class_uninstantiate(driver); + bus_data_generation_update(); return(0); } @@ -505,10 +509,6 @@ devclass_add_device(devclass_t dc, device_t dev) dev->devclass = dc; ksnprintf(dev->nameunit, buflen, "%s%d", dc->name, dev->unit); -#ifdef DEVICE_SYSCTLS - device_register_oids(dev); -#endif - return(0); } @@ -529,10 +529,6 @@ devclass_delete_device(devclass_t dc, device_t dev) kfree(dev->nameunit, M_BUS); dev->nameunit = NULL; -#ifdef DEVICE_SYSCTLS - device_unregister_oids(dev); -#endif - return(0); } @@ -583,6 +579,9 @@ make_device(device_t parent, const char *name, int unit) dev->state = DS_NOTPRESENT; + TAILQ_INSERT_TAIL(&bus_data_devices, dev, devlink); + bus_data_generation_update(); + return(dev); } @@ -637,6 +636,7 @@ device_add_child_ordered(device_t dev, int order, const char *name, int unit) TAILQ_INSERT_TAIL(&dev->children, child, link); } + bus_data_generation_update(); return(child); } @@ -660,9 +660,11 @@ device_delete_child(device_t dev, device_t child) if (child->devclass) devclass_delete_device(child->devclass, child); TAILQ_REMOVE(&dev->children, child, link); + TAILQ_REMOVE(&bus_data_devices, child, devlink); device_set_desc(child, NULL); kobj_delete((kobj_t)child, M_BUS); + bus_data_generation_update(); return(0); } @@ -805,6 +807,8 @@ device_probe_child(device_t dev, device_t child) */ DEVICE_PROBE(child); } + + bus_data_generation_update(); child->state = DS_ALIVE; return(0); } @@ -928,17 +932,12 @@ device_set_desc_internal(device_t dev, const char* desc, int copy) strcpy(dev->desc, desc); dev->flags |= DF_DESCMALLOCED; } - } else + } else { /* Avoid a -Wcast-qual warning */ dev->desc = (char *)(uintptr_t) desc; - -#ifdef DEVICE_SYSCTLS - { - struct sysctl_oid *oid = &dev->oid[1]; - oid->oid_arg1 = dev->desc ? dev->desc : ""; - oid->oid_arg2 = dev->desc ? strlen(dev->desc) : 0; } -#endif + + bus_data_generation_update(); } void @@ -1089,6 +1088,7 @@ int device_set_devclass(device_t dev, const char *classname) { devclass_t dc; + int error; if (!classname) { if (dev->devclass) @@ -1105,7 +1105,10 @@ device_set_devclass(device_t dev, const char *classname) if (!dc) return(ENOMEM); - return(devclass_add_device(dc, dev)); + error = devclass_add_device(dc, dev); + + bus_data_generation_update(); + return(error); } int @@ -1135,8 +1138,11 @@ device_set_driver(device_t dev, driver_t *driver) return(ENOMEM); } } - } else + } else { kobj_init((kobj_t) dev, &null_class); + } + + bus_data_generation_update(); return(0); } @@ -1294,129 +1300,13 @@ device_set_unit(device_t dev, int unit) return(err); dev->unit = unit; err = devclass_add_device(dc, dev); - return(err); -} - -#ifdef DEVICE_SYSCTLS - -/* - * Sysctl nodes for devices. - */ - -SYSCTL_NODE(_hw, OID_AUTO, devices, CTLFLAG_RW, 0, "A list of all devices"); - -static int -sysctl_handle_children(SYSCTL_HANDLER_ARGS) -{ - device_t dev = arg1; - device_t child; - int first = 1, error = 0; - - TAILQ_FOREACH(child, &dev->children, link) - if (child->nameunit) { - if (!first) { - error = SYSCTL_OUT(req, ",", 1); - if (error) - return error; - } else - first = 0; - error = SYSCTL_OUT(req, child->nameunit, - strlen(child->nameunit)); - if (error) - return(error); - } - - error = SYSCTL_OUT(req, "", 1); - - return(error); -} - -static int -sysctl_handle_state(SYSCTL_HANDLER_ARGS) -{ - device_t dev = arg1; - - switch (dev->state) { - case DS_NOTPRESENT: - return SYSCTL_OUT(req, "notpresent", sizeof("notpresent")); - case DS_ALIVE: - return SYSCTL_OUT(req, "alive", sizeof("alive")); - case DS_INPROGRESS: - return SYSCTL_OUT(req, "in-progress", sizeof("in-progress")); - case DS_ATTACHED: - return SYSCTL_OUT(req, "attached", sizeof("attached")); - case DS_BUSY: - return SYSCTL_OUT(req, "busy", sizeof("busy")); - default: - return (0); - } -} - -static void -device_register_oids(device_t dev) -{ - struct sysctl_oid* oid; - - oid = &dev->oid[0]; - bzero(oid, sizeof(*oid)); - oid->oid_parent = &sysctl__hw_devices_children; - oid->oid_number = OID_AUTO; - oid->oid_kind = CTLTYPE_NODE | CTLFLAG_RW; - oid->oid_arg1 = &dev->oidlist[0]; - oid->oid_arg2 = 0; - oid->oid_name = dev->nameunit; - oid->oid_handler = 0; - oid->oid_fmt = "N"; - SLIST_INIT(&dev->oidlist[0]); - sysctl_register_oid(oid); - - oid = &dev->oid[1]; - bzero(oid, sizeof(*oid)); - oid->oid_parent = &dev->oidlist[0]; - oid->oid_number = OID_AUTO; - oid->oid_kind = CTLTYPE_STRING | CTLFLAG_RD; - oid->oid_arg1 = dev->desc ? dev->desc : ""; - oid->oid_arg2 = dev->desc ? strlen(dev->desc) : 0; - oid->oid_name = "desc"; - oid->oid_handler = sysctl_handle_string; - oid->oid_fmt = "A"; - sysctl_register_oid(oid); - - oid = &dev->oid[2]; - bzero(oid, sizeof(*oid)); - oid->oid_parent = &dev->oidlist[0]; - oid->oid_number = OID_AUTO; - oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD; - oid->oid_arg1 = dev; - oid->oid_arg2 = 0; - oid->oid_name = "children"; - oid->oid_handler = sysctl_handle_children; - oid->oid_fmt = "A"; - sysctl_register_oid(oid); - - oid = &dev->oid[3]; - bzero(oid, sizeof(*oid)); - oid->oid_parent = &dev->oidlist[0]; - oid->oid_number = OID_AUTO; - oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD; - oid->oid_arg1 = dev; - oid->oid_arg2 = 0; - oid->oid_name = "state"; - oid->oid_handler = sysctl_handle_state; - oid->oid_fmt = "A"; - sysctl_register_oid(oid); -} + if (err) + return(err); -static void -device_unregister_oids(device_t dev) -{ - sysctl_unregister_oid(&dev->oid[0]); - sysctl_unregister_oid(&dev->oid[1]); - sysctl_unregister_oid(&dev->oid[2]); + bus_data_generation_update(); + return(0); } -#endif - /*======================================*/ /* * Access functions for device resources. @@ -1837,6 +1727,8 @@ resource_list_delete(struct resource_list *rl, struct resource_list_entry *rle = resource_list_find(rl, type, rid); if (rle) { + if (rle->res != NULL) + panic("resource_list_delete: resource has not been released"); SLIST_REMOVE(rl, rle, resource_list_entry, link); kfree(rle, M_BUS); } @@ -1863,6 +1755,7 @@ resource_list_alloc(struct resource_list *rl, if (!rle) return(0); /* no resource of that type/rid */ + if (rle->res) panic("resource_list_alloc: resource entry is busy"); @@ -2641,6 +2534,7 @@ root_bus_module_handler(module_t mod, int what, void* arg) { switch (what) { case MOD_LOAD: + TAILQ_INIT(&bus_data_devices); root_bus = make_device(NULL, "root", 0); root_bus->desc = "System root bus"; kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver); @@ -2930,3 +2824,99 @@ resource_disabled(const char *name, int unit) return(0); return(value); } + +/* + * User-space access to the device tree. + * + * We implement a small set of nodes: + * + * hw.bus Single integer read method to obtain the + * current generation count. + * hw.bus.devices Reads the entire device tree in flat space. + * hw.bus.rman Resource manager interface + * + * We might like to add the ability to scan devclasses and/or drivers to + * determine what else is currently loaded/available. + */ + +static int +sysctl_bus(SYSCTL_HANDLER_ARGS) +{ + struct u_businfo ubus; + + ubus.ub_version = BUS_USER_VERSION; + ubus.ub_generation = bus_data_generation; + + return (SYSCTL_OUT(req, &ubus, sizeof(ubus))); +} +SYSCTL_NODE(_hw_bus, OID_AUTO, info, CTLFLAG_RW, sysctl_bus, + "bus-related data"); + +static int +sysctl_devices(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *)arg1; + u_int namelen = arg2; + int index; + struct device *dev; + struct u_device udev; /* XXX this is a bit big */ + int error; + + if (namelen != 2) + return (EINVAL); + + if (bus_data_generation_check(name[0])) + return (EINVAL); + + index = name[1]; + + /* + * Scan the list of devices, looking for the requested index. + */ + TAILQ_FOREACH(dev, &bus_data_devices, devlink) { + if (index-- == 0) + break; + } + if (dev == NULL) + return (ENOENT); + + /* + * Populate the return array. + */ + bzero(&udev, sizeof(udev)); + udev.dv_handle = (uintptr_t)dev; + udev.dv_parent = (uintptr_t)dev->parent; + if (dev->nameunit != NULL) + strlcpy(udev.dv_name, dev->nameunit, sizeof(udev.dv_name)); + if (dev->desc != NULL) + strlcpy(udev.dv_desc, dev->desc, sizeof(udev.dv_desc)); + if (dev->driver != NULL && dev->driver->name != NULL) + strlcpy(udev.dv_drivername, dev->driver->name, + sizeof(udev.dv_drivername)); + bus_child_pnpinfo_str(dev, udev.dv_pnpinfo, sizeof(udev.dv_pnpinfo)); + bus_child_location_str(dev, udev.dv_location, sizeof(udev.dv_location)); + udev.dv_devflags = dev->devflags; + udev.dv_flags = dev->flags; + udev.dv_state = dev->state; + error = SYSCTL_OUT(req, &udev, sizeof(udev)); + return (error); +} + +SYSCTL_NODE(_hw_bus, OID_AUTO, devices, CTLFLAG_RD, sysctl_devices, + "system device tree"); + +int +bus_data_generation_check(int generation) +{ + if (generation != bus_data_generation) + return (1); + + /* XXX generate optimised lists here? */ + return (0); +} + +void +bus_data_generation_update(void) +{ + bus_data_generation++; +} diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c index 86d0aede55..933d134eda 100644 --- a/sys/kern/subr_rman.c +++ b/sys/kern/subr_rman.c @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/subr_rman.c,v 1.10.2.1 2001/06/05 08:06:08 imp Exp $ - * $DragonFly: src/sys/kern/subr_rman.c,v 1.14 2008/01/05 14:02:38 swildner Exp $ + * $DragonFly: src/sys/kern/subr_rman.c,v 1.15 2008/09/30 12:20:29 hasso Exp $ */ /* @@ -623,3 +623,89 @@ rman_make_alignment_flags(uint32_t size) return(RF_ALIGNMENT_LOG2(i)); } + +/* + * Sysctl interface for scanning the resource lists. + * + * We take two input parameters; the index into the list of resource + * managers, and the resource offset into the list. + */ +static int +sysctl_rman(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *)arg1; + u_int namelen = arg2; + int rman_idx, res_idx; + struct rman *rm; + struct resource *res; + struct u_rman urm; + struct u_resource ures; + int error; + + if (namelen != 3) + return (EINVAL); + + if (bus_data_generation_check(name[0])) + return (EINVAL); + rman_idx = name[1]; + res_idx = name[2]; + + /* + * Find the indexed resource manager + */ + TAILQ_FOREACH(rm, &rman_head, rm_link) { + if (rman_idx-- == 0) + break; + } + if (rm == NULL) + return (ENOENT); + + /* + * If the resource index is -1, we want details on the + * resource manager. + */ + if (res_idx == -1) { + urm.rm_handle = (uintptr_t)rm; + strlcpy(urm.rm_descr, rm->rm_descr, RM_TEXTLEN); + urm.rm_start = rm->rm_start; + urm.rm_size = rm->rm_end - rm->rm_start + 1; + urm.rm_type = rm->rm_type; + + error = SYSCTL_OUT(req, &urm, sizeof(urm)); + return (error); + } + + /* + * Find the indexed resource and return it. + */ + CIRCLEQ_FOREACH(res, &rm->rm_list, r_link) { + if (res_idx-- == 0) { + ures.r_handle = (uintptr_t)res; + ures.r_parent = (uintptr_t)res->r_rm; + ures.r_device = (uintptr_t)res->r_dev; + if (res->r_dev != NULL) { + if (device_get_name(res->r_dev) != NULL) { + ksnprintf(ures.r_devname, RM_TEXTLEN, + "%s%d", + device_get_name(res->r_dev), + device_get_unit(res->r_dev)); + } else { + strlcpy(ures.r_devname, "nomatch", + RM_TEXTLEN); + } + } else { + ures.r_devname[0] = '\0'; + } + ures.r_start = res->r_start; + ures.r_size = res->r_end - res->r_start + 1; + ures.r_flags = res->r_flags; + + error = SYSCTL_OUT(req, &ures, sizeof(ures)); + return (error); + } + } + return (ENOENT); +} + +SYSCTL_NODE(_hw_bus, OID_AUTO, rman, CTLFLAG_RD, sysctl_rman, + "kernel resource manager"); diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 5e7369c432..01b0eae61d 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/sys/bus.h,v 1.30.2.5 2004/03/17 17:54:25 njl Exp $ - * $DragonFly: src/sys/sys/bus.h,v 1.29 2008/09/29 06:59:45 hasso Exp $ + * $DragonFly: src/sys/sys/bus.h,v 1.30 2008/09/30 12:20:29 hasso Exp $ */ #ifndef _SYS_BUS_H_ @@ -61,6 +61,44 @@ typedef struct devclass *devclass_t; typedef void driver_intr_t(void*); +/* + * Interface information structure. + */ +struct u_businfo { + int ub_version; /* interface version */ +#define BUS_USER_VERSION 1 + int ub_generation; /* generation count */ +}; + +/* + * State of the device. + */ +typedef enum device_state { + DS_NOTPRESENT, /* not probed or probe failed */ + DS_ALIVE, /* probe succeeded */ + DS_INPROGRESS, /* attach in progress */ + DS_ATTACHED, /* attach method called */ + DS_BUSY /* device is open */ +} device_state_t; + +/* + * Device information exported to userspace. + */ +struct u_device { + uintptr_t dv_handle; + uintptr_t dv_parent; + + char dv_name[32]; /* Name of device in tree. */ + char dv_desc[32]; /* Driver description */ + char dv_drivername[32]; /* Driver name */ + char dv_pnpinfo[128]; /* Plug and play info */ + char dv_location[128]; /* Where is the device? */ + uint32_t dv_devflags; /* API Flags for device */ + uint16_t dv_flags; /* flags for dev date */ + device_state_t dv_state; /* State of attachment */ + /* XXX more driver info? */ +}; + /* * Interrupt features mask. Note that DragonFly no longer implements * INTR_TYPE_* flags. @@ -85,14 +123,6 @@ enum intr_polarity { typedef int (*devop_t)(void); -typedef enum device_state { - DS_NOTPRESENT, /* not probed or probe failed */ - DS_ALIVE, /* probe succeeded */ - DS_INPROGRESS, /* attach in progress */ - DS_ATTACHED, /* attach method called */ - DS_BUSY /* device is open */ -} device_state_t; - /* * Definitions for drivers which need to keep simple lists of resources * for their child devices. @@ -381,6 +411,13 @@ int resource_set_string(const char *name, int unit, const char *resname, const char *value); int resource_count(void); +/* + * Functions for maintaining and checking consistency of + * bus information exported to userspace. + */ +int bus_data_generation_check(int generation); +void bus_data_generation_update(void); + /** * Some convenience defines for probe routines to return. These are just * suggested values, and there's nothing magical about them. diff --git a/sys/sys/bus_private.h b/sys/sys/bus_private.h index c20be86b31..dd407ba930 100644 --- a/sys/sys/bus_private.h +++ b/sys/sys/bus_private.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/sys/bus_private.h,v 1.11.2.2 2000/08/03 00:25:22 peter Exp $ - * $DragonFly: src/sys/sys/bus_private.h,v 1.9 2007/05/01 00:05:18 dillon Exp $ + * $DragonFly: src/sys/sys/bus_private.h,v 1.10 2008/09/30 12:20:29 hasso Exp $ */ #ifndef _SYS_BUS_PRIVATE_H_ @@ -103,6 +103,7 @@ struct device { * Device hierarchy. */ TAILQ_ENTRY(device) link; /* list of devices in parent */ + TAILQ_ENTRY(device) devlink; /* global device list membership */ device_t parent; device_list_t children; /* list of subordinate devices */ @@ -128,10 +129,6 @@ struct device { #define DF_ASYNCPROBE 0x0080 /* can be probed with its own thread */ u_char order; /* order from device_add_child_ordered() */ u_char pad; -#ifdef DEVICE_SYSCTLS - struct sysctl_oid oid[4]; - struct sysctl_oid_list oidlist[1]; -#endif void *ivars; void *softc; }; diff --git a/sys/sys/rman.h b/sys/sys/rman.h index d02d54d723..67ba8b5e81 100644 --- a/sys/sys/rman.h +++ b/sys/sys/rman.h @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/sys/rman.h,v 1.5.2.1 2001/06/05 08:06:07 imp Exp $ - * $DragonFly: src/sys/sys/rman.h,v 1.10 2006/10/25 20:56:03 dillon Exp $ + * $DragonFly: src/sys/sys/rman.h,v 1.11 2008/09/30 12:20:29 hasso Exp $ */ #ifndef _SYS_RMAN_H_ @@ -43,6 +43,52 @@ #include /* bus_space_tag_t */ #endif +#define RF_ALLOCATED 0x0001 /* resource has been reserved */ +#define RF_ACTIVE 0x0002 /* resource allocation has been activated */ +#define RF_SHAREABLE 0x0004 /* resource permits contemporaneous sharing */ +#define RF_TIMESHARE 0x0008 /* resource permits time-division sharing */ +#define RF_WANTED 0x0010 /* somebody is waiting for this resource */ +#define RF_FIRSTSHARE 0x0020 /* first in sharing list */ +#define RF_PREFETCHABLE 0x0040 /* resource is prefetchable */ +#define RF_OPTIONAL 0x0080 /* for bus_alloc_resources() */ + +#define RF_ALIGNMENT_SHIFT 10 /* alignment size bit starts bit 10 */ +#define RF_ALIGNMENT_MASK (0x003F << RF_ALIGNMENT_SHIFT) + /* resource address alignemnt size bit mask */ +#define RF_ALIGNMENT_LOG2(x) ((x) << RF_ALIGNMENT_SHIFT) +#define RF_ALIGNMENT(x) (((x) & RF_ALIGNMENT_MASK) >> RF_ALIGNMENT_SHIFT) + +enum rman_type { RMAN_UNINIT = 0, RMAN_GAUGE, RMAN_ARRAY }; + +/* + * String length exported to userspace for resource names, etc. + */ +#define RM_TEXTLEN 32 + +/* + * Userspace-exported structures. + */ +struct u_resource { + uintptr_t r_handle; /* resource uniquifier */ + uintptr_t r_parent; /* parent rman */ + uintptr_t r_device; /* device owning this resource */ + char r_devname[RM_TEXTLEN]; /* device name XXX obsolete */ + + u_long r_start; /* offset in resource space */ + u_long r_size; /* size in resource space */ + u_int r_flags; /* RF_* flags */ +}; + +struct u_rman { + uintptr_t rm_handle; /* rman uniquifier */ + char rm_descr[RM_TEXTLEN]; /* rman description */ + + u_long rm_start; /* base of managed region */ + u_long rm_size; /* size of managed region */ + enum rman_type rm_type; /* region type */ +}; + +#ifdef _KERNEL /* * We use a linked list rather than a bitmap because we need to be able to * represent potentially huge objects (like all of a processor's physical @@ -64,22 +110,6 @@ struct resource { struct rman *r_rm; /* resource manager from whence this came */ }; -#define RF_ALLOCATED 0x0001 /* resource has been reserved */ -#define RF_ACTIVE 0x0002 /* resource allocation has been activated */ -#define RF_SHAREABLE 0x0004 /* resource permits contemporaneous sharing */ -#define RF_TIMESHARE 0x0008 /* resource permits time-division sharing */ -#define RF_WANTED 0x0010 /* somebody is waiting for this resource */ -#define RF_FIRSTSHARE 0x0020 /* first in sharing list */ -#define RF_PREFETCHABLE 0x0040 /* resource is prefetchable */ - -#define RF_ALIGNMENT_SHIFT 10 /* alignment size bit starts bit 10 */ -#define RF_ALIGNMENT_MASK (0x003F << RF_ALIGNMENT_SHIFT) - /* resource address alignemnt size bit mask */ -#define RF_ALIGNMENT_LOG2(x) ((x) << RF_ALIGNMENT_SHIFT) -#define RF_ALIGNMENT(x) (((x) & RF_ALIGNMENT_MASK) >> RF_ALIGNMENT_SHIFT) - -enum rman_type { RMAN_UNINIT = 0, RMAN_GAUGE, RMAN_ARRAY }; - struct lwkt_token; struct lwkt_tokref; @@ -94,8 +124,6 @@ struct rman { }; TAILQ_HEAD(rman_head, rman); -#ifdef _KERNEL - int rman_activate_resource(struct resource *r); int rman_await_resource(struct resource *r, struct lwkt_tokref *ilock, int slpflags, int timo); int rman_deactivate_resource(struct resource *r); diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 7147496c7a..72375bae44 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -35,7 +35,7 @@ * * @(#)sysctl.h 8.1 (Berkeley) 6/2/93 * $FreeBSD: src/sys/sys/sysctl.h,v 1.81.2.10 2003/05/01 22:48:09 trhodes Exp $ - * $DragonFly: src/sys/sys/sysctl.h,v 1.28 2008/08/03 11:00:32 sephe Exp $ + * $DragonFly: src/sys/sys/sysctl.h,v 1.29 2008/09/30 12:20:29 hasso Exp $ */ #ifndef _SYS_SYSCTL_H_ @@ -602,6 +602,7 @@ SYSCTL_DECL(_net); SYSCTL_DECL(_debug); SYSCTL_DECL(_debug_sizeof); SYSCTL_DECL(_hw); +SYSCTL_DECL(_hw_bus); SYSCTL_DECL(_machdep); SYSCTL_DECL(_user); SYSCTL_DECL(_compat); diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index e49032eae9..e54205c1ba 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,6 +1,6 @@ # From: @(#)Makefile 5.20 (Berkeley) 6/12/93 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $ -# $DragonFly: src/usr.sbin/Makefile,v 1.48 2008/08/30 16:07:59 hasso Exp $ +# $DragonFly: src/usr.sbin/Makefile,v 1.49 2008/09/30 12:20:29 hasso Exp $ .include "../sys/platform/${MACHINE_PLATFORM}/Makefile.inc" @@ -32,6 +32,7 @@ SUBDIR= 802_11 \ crunch \ daemon \ dconschat \ + devinfo \ dev_mkdb \ dntpd \ edquota \ diff --git a/usr.sbin/devinfo/Makefile b/usr.sbin/devinfo/Makefile new file mode 100644 index 0000000000..fb16c7b2ba --- /dev/null +++ b/usr.sbin/devinfo/Makefile @@ -0,0 +1,12 @@ +# $FreeBSD: src/usr.sbin/devinfo/Makefile,v 1.6 2002/05/12 14:23:15 rwatson Exp $ +# $DragonFly: src/usr.sbin/devinfo/Makefile,v 1.1 2008/09/30 12:20:29 hasso Exp $ + +PROG= devinfo +MAN= devinfo.8 + +WARNS?= 2 + +DPADD= ${LIBDEVINFO} +LDADD= -ldevinfo + +.include diff --git a/usr.sbin/devinfo/devinfo.8 b/usr.sbin/devinfo/devinfo.8 new file mode 100644 index 0000000000..d30a04d391 --- /dev/null +++ b/usr.sbin/devinfo/devinfo.8 @@ -0,0 +1,76 @@ +.\" +.\" Copyright (c) 2002 Hiten Pandya +.\" Copyright (c) 2002 Robert N. M. Watson +.\" +.\" 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 AUTHORS ``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 AUTHORS 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: src/usr.sbin/devinfo/devinfo.8,v 1.9 2006/09/29 16:46:01 ru Exp $ +.\" $DragonFly: src/usr.sbin/devinfo/devinfo.8,v 1.1 2008/09/30 12:20:29 hasso Exp $ +.\" +.Dd September 30, 2008 +.Os +.Dt DEVINFO 8 +.Sh NAME +.Nm devinfo +.Nd print information about system device configuration +.Sh SYNOPSIS +.Nm +.Op Fl rv +.Nm +.Fl u +.Sh DESCRIPTION +The +.Nm +utility, without any arguments, shows the hierarchy of devices available +in the system, starting from the +.Dq nexus +device. +.Pp +The following options are accepted. +.Bl -tag -width indent +.It Fl r +Causes hardware resource information (such as IRQ, I/O ports, I/O memory +addresses) to be also listed, under each device that has reserved those resources. +.It Fl u +Displays the same information as with +.Fl r +but sorts by resource type rather than by device, allowing to review the +set of system resources by usage and available resources. +I.e., it lists all +the IRQ consumers together. +.It Fl v +Display all devices in the driver tree, not just those that are attached or +busy. +Without this flag, only those devices that have attached are reported. +.El +.Sh SEE ALSO +.Xr systat 1 , +.Xr devinfo 3 , +.Xr iostat 8 , +.Xr pciconf 8 , +.Xr pnpinfo 8 , +.Xr vmstat 8 , +.Xr devclass 9 , +.Xr device 9 +.Sh AUTHORS +.An Mike Smith Aq msmith@FreeBSD.org diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c new file mode 100644 index 0000000000..f5f9c36ecf --- /dev/null +++ b/usr.sbin/devinfo/devinfo.c @@ -0,0 +1,233 @@ +/*- + * Copyright (c) 2000, 2001 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: src/usr.sbin/devinfo/devinfo.c,v 1.7 2007/10/27 13:06:15 jhb Exp $ + * $DragonFly: src/usr.sbin/devinfo/devinfo.c,v 1.1 2008/09/30 12:20:29 hasso Exp $ + */ + +/* + * Print information about system device configuration. + */ + +#include +#include +#include +#include +#include +#include "devinfo.h" + +int rflag; +int vflag; + +static void print_resource(struct devinfo_res *); +static int print_device_matching_resource(struct devinfo_res *, void *); +static int print_device_rman_resources(struct devinfo_rman *, void *); +static int print_device(struct devinfo_dev *, void *); +static int print_rman_resource(struct devinfo_res *, void *); +static int print_rman(struct devinfo_rman *, void *); + +struct indent_arg +{ + int indent; + void *arg; +}; + +/* + * Print a resource. + */ +void +print_resource(struct devinfo_res *res) +{ + struct devinfo_rman *rman; + int hexmode; + + rman = devinfo_handle_to_rman(res->dr_rman); + hexmode = (rman->dm_size > 1000) || (rman->dm_size == 0); + printf(hexmode ? "0x%lx" : "%lu", res->dr_start); + if (res->dr_size > 1) + printf(hexmode ? "-0x%lx" : "-%lu", + res->dr_start + res->dr_size - 1); +} + +/* + * Print resource information if this resource matches the + * given device. + * + * If the given indent is 0, return an indicator that a matching + * resource exists. + */ +int +print_device_matching_resource(struct devinfo_res *res, void *arg) +{ + struct indent_arg *ia = (struct indent_arg *)arg; + struct devinfo_dev *dev = (struct devinfo_dev *)ia->arg; + int i; + + if (devinfo_handle_to_device(res->dr_device) == dev) { + /* in 'detect' mode, found a match */ + if (ia->indent == 0) + return(1); + for (i = 0; i < ia->indent; i++) + printf(" "); + print_resource(res); + printf("\n"); + } + return(0); +} + +/* + * Print resource information for this device and resource manager. + */ +int +print_device_rman_resources(struct devinfo_rman *rman, void *arg) +{ + struct indent_arg *ia = (struct indent_arg *)arg; + int indent, i; + + indent = ia->indent; + + /* check whether there are any resources matching this device */ + ia->indent = 0; + if (devinfo_foreach_rman_resource(rman, + print_device_matching_resource, ia) != 0) { + + /* there are, print header */ + for (i = 0; i < indent; i++) + printf(" "); + printf("%s:\n", rman->dm_desc); + + /* print resources */ + ia->indent = indent + 4; + devinfo_foreach_rman_resource(rman, + print_device_matching_resource, ia); + } + ia->indent = indent; + return(0); +} + +/* + * Print information about a device. + */ +int +print_device(struct devinfo_dev *dev, void *arg) +{ + struct indent_arg ia; + int i, indent; + + if (vflag || (dev->dd_name[0] != 0 && dev->dd_state >= DIS_ATTACHED)) { + indent = (int)(intptr_t)arg; + for (i = 0; i < indent; i++) + printf(" "); + printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown"); + if (vflag && *dev->dd_pnpinfo) + printf(" pnpinfo %s", dev->dd_pnpinfo); + if (vflag && *dev->dd_location) + printf(" at %s", dev->dd_location); + printf("\n"); + if (rflag) { + ia.indent = indent + 4; + ia.arg = dev; + devinfo_foreach_rman(print_device_rman_resources, + (void *)&ia); + } + } + + return(devinfo_foreach_device_child(dev, print_device, + (void *)((char *)arg + 2))); +} + +/* + * Print information about a resource under a resource manager. + */ +int +print_rman_resource(struct devinfo_res *res, void *arg __unused) +{ + struct devinfo_dev *dev; + + printf(" "); + print_resource(res); + dev = devinfo_handle_to_device(res->dr_device); + if ((dev != NULL) && (dev->dd_name[0] != 0)) { + printf(" (%s)", dev->dd_name); + } else { + printf(" ----"); + } + printf("\n"); + return(0); +} + +/* + * Print information about a resource manager. + */ +int +print_rman(struct devinfo_rman *rman, void *arg __unused) +{ + printf("%s:\n", rman->dm_desc); + devinfo_foreach_rman_resource(rman, print_rman_resource, 0); + return(0); +} + +int +main(int argc, char *argv[]) +{ + struct devinfo_dev *root; + int c, uflag; + + uflag = 0; + while ((c = getopt(argc, argv, "ruv")) != -1) { + switch(c) { + case 'r': + rflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + default: + fprintf(stderr, "%s\n%s\n", + "usage: devinfo [-rv]", + " devinfo -u"); + exit(1); + } + } + + if (devinfo_init()) + err(1, "devinfo_init"); + + if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL) + errx(1, "can't find root device"); + + /* print resource usage? */ + if (uflag) { + devinfo_foreach_rman(print_rman, NULL); + } else { + /* print device hierarchy */ + devinfo_foreach_device_child(root, print_device, (void *)0); + } + return(0); +} diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8 index 0fc2865a46..ad4e1e4b99 100644 --- a/usr.sbin/pciconf/pciconf.8 +++ b/usr.sbin/pciconf/pciconf.8 @@ -1,5 +1,5 @@ .\" $FreeBSD: src/usr.sbin/pciconf/pciconf.8,v 1.8.2.9 2003/03/11 22:31:30 trhodes Exp $ -.\" $DragonFly: src/usr.sbin/pciconf/pciconf.8,v 1.3 2008/07/23 14:14:44 swildner Exp $ +.\" $DragonFly: src/usr.sbin/pciconf/pciconf.8,v 1.4 2008/09/30 12:20:29 hasso Exp $ .\" Copyright (c) 1997 .\" Stefan Esser . All rights reserved. .\" @@ -178,6 +178,7 @@ This path can be overridden by setting the environment variable .Sh SEE ALSO .Xr ioctl 2 , .Xr pci 4 , +.Xr devinfo 8 , .Xr kldload 8 .Sh HISTORY The