Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3249,6 +3249,7 @@ kern/subr_devstat.c standard kern/subr_disk.c standard kern/subr_eventhandler.c standard +kern/subr_extres.c standard kern/subr_fattime.c standard kern/subr_firmware.c optional firmware kern/subr_hash.c standard Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -131,6 +132,7 @@ u_int order; /**< order from device_add_child_ordered() */ void *ivars; /**< instance variables */ void *softc; /**< current driver's variables */ + struct extres_list extres_list; /**< list of extended resources */ struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ @@ -1776,6 +1778,7 @@ dev->devflags = 0; dev->flags = DF_ENABLED; dev->order = 0; + TAILQ_INIT(&dev->extres_list); if (unit == -1) dev->flags |= DF_WILDCARD; if (name) { @@ -2208,6 +2211,16 @@ } /** + * @brief Return list of extended resources. + */ +struct extres_list * +device_get_extres_list(device_t dev) +{ + + return (&dev->extres_list); +} + +/** * @brief Return the parent of a device */ device_t @@ -2925,6 +2938,7 @@ if (dev->state != DS_ATTACHED) return (0); + extres_detach(dev); if ((error = DEVICE_DETACH(dev)) != 0) return (error); devremoved(dev); Index: sys/kern/subr_extres.c =================================================================== --- /dev/null +++ sys/kern/subr_extres.c @@ -0,0 +1,130 @@ +/*- + * Copyright 2015 Michal Meloun + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +/* + * For now, use one global lock protect extended resource list for all + * devices. It can be fine grained by using per device mutex, if any + * contention is found. + */ +static struct mtx extres_mtx; +MTX_SYSINIT(extres_mtx, &extres_mtx, "extres mutex", MTX_DEF); + +static char * +extres_get_name(struct extres_node *extres_node) +{ + if (extres_node->descr->get_name == NULL) + return "Unknown"; + return (extres_node->descr->get_name(extres_node->fnc_arg)); +} + +static void +extres_release(struct extres_node *extres_node, + struct extres_list *extres_list) +{ + int rv; + + if (extres_node->descr->release == NULL) + return; +#ifdef DEBUG_EXTRES + printf("Releasing %s: %s\n", extres_node->descr->name, + extres_get_name(extres_node)); +#endif + rv = extres_node->descr->release(extres_node->fnc_arg); + if (rv != 0) { + device_printf(extres_node->cdev, + "Releasing resource '%s' failed: %d\n", + extres_get_name(extres_node), rv); + } +} + +/* Enlist resource to consumer device. */ +void +extres_register(struct extres_node *extres_node, device_t cdev, + struct extres_type_descr *descr, void *arg) +{ + struct extres_list *extres_list; + + extres_list = device_get_extres_list(cdev); + extres_node->descr = descr; + extres_node->cdev = cdev; + extres_node->fnc_arg = arg; +#ifdef DEBUG_EXTRES + printf("Registering %s: %s\n", extres_node->descr->name, + extres_get_name(extres_node)); +#endif + mtx_lock(&extres_mtx); + TAILQ_INSERT_TAIL(extres_list, extres_node, extres_e); + mtx_unlock(&extres_mtx); +} + +/* Delist resource from consumer device. */ +void +extres_deregister(struct extres_node *extres_node) +{ + struct extres_list *extres_list; + + extres_list = device_get_extres_list(extres_node->cdev); + mtx_lock(&extres_mtx); + TAILQ_REMOVE(extres_list, extres_node, extres_e); + mtx_unlock(&extres_mtx); +#ifdef DEBUG_EXTRES + printf("Deregistering %s: %s\n", extres_node->descr->name, + extres_get_name(extres_node)); +#endif + +} + +/* Release all already enlisted resources. */ +void +extres_detach(device_t cdev) +{ + struct extres_list *extres_list; + struct extres_node *extres_node; + + extres_list = device_get_extres_list(cdev); + + mtx_lock(&extres_mtx); + while (!TAILQ_EMPTY(extres_list)) { + extres_node = TAILQ_LAST(extres_list, extres_list); + TAILQ_REMOVE(extres_list, extres_node, extres_e); + mtx_unlock(&extres_mtx); + extres_release(extres_node, extres_list); + mtx_lock(&extres_mtx); + + } + mtx_unlock(&extres_mtx); +} Index: sys/sys/bus.h =================================================================== --- sys/sys/bus.h +++ sys/sys/bus.h @@ -31,6 +31,7 @@ #include #include +#include #include /** @@ -497,6 +498,7 @@ driver_t *device_get_driver(device_t dev); u_int32_t device_get_flags(device_t dev); device_t device_get_parent(device_t dev); +struct extres_list *device_get_extres_list(device_t dev); int device_get_children(device_t dev, device_t **listp, int *countp); void *device_get_ivars(device_t dev); void device_set_ivars(device_t dev, void *ivars); Index: sys/sys/extres.h =================================================================== --- /dev/null +++ sys/sys/extres.h @@ -0,0 +1,57 @@ +/*- + * Copyright 2015 Michal Meloun + * 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 + +#ifndef _EXTRES_H_ +#define _EXTRES_H_ + +/* Per resource type description */ +typedef int (*extres_release_t)(void *arg); +typedef char *(*extres_get_name_t)(void *arg); +struct extres_type_descr { + const char *name; + int (*release)(void *arg); + char *(*get_name)(void *arg); +}; + +TAILQ_HEAD(extres_list, extres_node); + +struct extres_node { + struct extres_type_descr *descr; /* resource type description */ + device_t cdev; /* consumer device */ + void *fnc_arg; /* function argument */ + TAILQ_ENTRY(extres_node) extres_e; /* children list entry */ +}; + +void extres_register(struct extres_node *extres, device_t cdev, + struct extres_type_descr *descr, void *arg); +void extres_deregister(struct extres_node *extres); +void extres_detach(device_t cdev); + +#endif /*_EXTRES_H_*/