This is the Device Information Library, libdevinfo.
The devinfo library provides access to the kernel's internal device hierarchy and to the I/O resource manager. The library uses a sysctl(9) interface to obtain a snapshot of the kernel's state which is then made available to the application.
This commit is contained in:
parent
f444a4c57a
commit
a2e6df2951
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=75726
9
lib/libdevinfo/Makefile
Normal file
9
lib/libdevinfo/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
LIB= devinfo
|
||||||
|
SRCS= devinfo.c
|
||||||
|
INCS= devinfo.h devinfo_var.h
|
||||||
|
|
||||||
|
NOMAN= yes
|
||||||
|
|
||||||
|
.include <bsd.lib.mk>
|
488
lib/libdevinfo/devinfo.c
Normal file
488
lib/libdevinfo/devinfo.c
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
/*-
|
||||||
|
* 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An interface to the FreeBSD kernel's bus/devce 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 "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", __FUNCTION__ , ##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, *np, *fmt;
|
||||||
|
int error, hexmode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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, DEVINFO_STRLEN, "%s", udev.dv_name);
|
||||||
|
dd->dd_dev.dd_name = &dd->dd_name[0];
|
||||||
|
snprintf(dd->dd_desc, DEVINFO_STRLEN, "%s", udev.dv_desc);
|
||||||
|
dd->dd_dev.dd_desc = &dd->dd_desc[0];
|
||||||
|
snprintf(dd->dd_drivername, DEVINFO_STRLEN, "%s",
|
||||||
|
udev.dv_drivername);
|
||||||
|
dd->dd_dev.dd_drivername = &dd->dd_drivername[0];
|
||||||
|
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, *np, *fmt;
|
||||||
|
int error, hexmode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
119
lib/libdevinfo/devinfo.h
Normal file
119
lib/libdevinfo/devinfo.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*-
|
||||||
|
* 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uintptr_t devinfo_handle_t;
|
||||||
|
#define DEVINFO_ROOT_DEVICE (devinfo_handle_t)0
|
||||||
|
|
||||||
|
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*/
|
||||||
|
};
|
||||||
|
|
||||||
|
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 */
|
||||||
|
/* XXX add flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
65
lib/libdevinfo/devinfo_var.h
Normal file
65
lib/libdevinfo/devinfo_var.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*-
|
||||||
|
* 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[32];
|
||||||
|
char dd_desc[32];
|
||||||
|
char dd_drivername[32];
|
||||||
|
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;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user