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 <sys/param.h>
 #include <sys/conf.h>
+#include <sys/extres.h>
 #include <sys/filio.h>
 #include <sys/lock.h>
 #include <sys/kernel.h>
@@ -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 <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/extres.h>
+#include <sys/bus.h>
+#include <sys/extres.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+
+/*
+ * 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 <machine/_limits.h>
 #include <sys/_bus_dma.h>
+#include <sys/extres.h>
 #include <sys/ioccom.h>
 
 /**
@@ -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 <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+
+#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_*/