Home | History | Annotate | Line # | Download | only in kern
subr_autoconf.c revision 1.163.4.2.4.1
      1  1.163.4.2.4.1     cliff /* $NetBSD: subr_autoconf.c,v 1.163.4.2.4.1 2011/02/05 06:00:14 cliff Exp $ */
      2           1.53       cgd 
      3           1.53       cgd /*
      4           1.53       cgd  * Copyright (c) 1996, 2000 Christopher G. Demetriou
      5           1.53       cgd  * All rights reserved.
      6           1.93     perry  *
      7           1.53       cgd  * Redistribution and use in source and binary forms, with or without
      8           1.53       cgd  * modification, are permitted provided that the following conditions
      9           1.53       cgd  * are met:
     10           1.53       cgd  * 1. Redistributions of source code must retain the above copyright
     11           1.53       cgd  *    notice, this list of conditions and the following disclaimer.
     12           1.53       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13           1.53       cgd  *    notice, this list of conditions and the following disclaimer in the
     14           1.53       cgd  *    documentation and/or other materials provided with the distribution.
     15           1.53       cgd  * 3. All advertising materials mentioning features or use of this software
     16           1.53       cgd  *    must display the following acknowledgement:
     17           1.54       cgd  *          This product includes software developed for the
     18           1.88    keihan  *          NetBSD Project.  See http://www.NetBSD.org/ for
     19           1.54       cgd  *          information about NetBSD.
     20           1.53       cgd  * 4. The name of the author may not be used to endorse or promote products
     21           1.54       cgd  *    derived from this software without specific prior written permission.
     22           1.93     perry  *
     23           1.53       cgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24           1.53       cgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25           1.53       cgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26           1.53       cgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27           1.53       cgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28           1.53       cgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29           1.53       cgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30           1.53       cgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31           1.53       cgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     32           1.53       cgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33           1.93     perry  *
     34           1.54       cgd  * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
     35           1.53       cgd  */
     36            1.9       cgd 
     37            1.1     glass /*
     38            1.7     glass  * Copyright (c) 1992, 1993
     39            1.7     glass  *	The Regents of the University of California.  All rights reserved.
     40            1.1     glass  *
     41            1.1     glass  * This software was developed by the Computer Systems Engineering group
     42            1.1     glass  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     43            1.1     glass  * contributed to Berkeley.
     44            1.1     glass  *
     45            1.1     glass  * All advertising materials mentioning features or use of this software
     46            1.1     glass  * must display the following acknowledgement:
     47            1.1     glass  *	This product includes software developed by the University of
     48            1.1     glass  *	California, Lawrence Berkeley Laboratories.
     49            1.1     glass  *
     50            1.7     glass  * Redistribution and use in source and binary forms, with or without
     51            1.7     glass  * modification, are permitted provided that the following conditions
     52            1.7     glass  * are met:
     53            1.7     glass  * 1. Redistributions of source code must retain the above copyright
     54            1.7     glass  *    notice, this list of conditions and the following disclaimer.
     55            1.7     glass  * 2. Redistributions in binary form must reproduce the above copyright
     56            1.7     glass  *    notice, this list of conditions and the following disclaimer in the
     57            1.7     glass  *    documentation and/or other materials provided with the distribution.
     58           1.87       agc  * 3. Neither the name of the University nor the names of its contributors
     59            1.7     glass  *    may be used to endorse or promote products derived from this software
     60            1.7     glass  *    without specific prior written permission.
     61            1.1     glass  *
     62            1.7     glass  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     63            1.7     glass  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     64            1.7     glass  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     65            1.7     glass  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     66            1.7     glass  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     67            1.7     glass  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     68            1.7     glass  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     69            1.7     glass  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     70            1.7     glass  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     71            1.7     glass  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     72            1.7     glass  * SUCH DAMAGE.
     73            1.1     glass  *
     74            1.8       cgd  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
     75            1.9       cgd  *
     76           1.28      fvdl  *	@(#)subr_autoconf.c	8.3 (Berkeley) 5/17/94
     77            1.1     glass  */
     78            1.1     glass 
     79           1.51       cgd #include <sys/cdefs.h>
     80  1.163.4.2.4.1     cliff __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.163.4.2.4.1 2011/02/05 06:00:14 cliff Exp $");
     81           1.62    simonb 
     82  1.163.4.2.4.1     cliff #include "opt_multiprocessor.h"
     83           1.62    simonb #include "opt_ddb.h"
     84          1.149  jmcneill #include "drvctl.h"
     85           1.51       cgd 
     86            1.4   mycroft #include <sys/param.h>
     87            1.4   mycroft #include <sys/device.h>
     88          1.118    dyoung #include <sys/disklabel.h>
     89          1.118    dyoung #include <sys/conf.h>
     90          1.118    dyoung #include <sys/kauth.h>
     91            1.4   mycroft #include <sys/malloc.h>
     92          1.159      matt #include <sys/kmem.h>
     93           1.17  christos #include <sys/systm.h>
     94           1.43   thorpej #include <sys/kernel.h>
     95           1.33   thorpej #include <sys/errno.h>
     96           1.47   thorpej #include <sys/proc.h>
     97           1.82       mrg #include <sys/reboot.h>
     98          1.142        ad #include <sys/kthread.h>
     99          1.118    dyoung #include <sys/buf.h>
    100          1.118    dyoung #include <sys/dirent.h>
    101          1.118    dyoung #include <sys/vnode.h>
    102          1.118    dyoung #include <sys/mount.h>
    103          1.118    dyoung #include <sys/namei.h>
    104          1.118    dyoung #include <sys/unistd.h>
    105          1.118    dyoung #include <sys/fcntl.h>
    106          1.118    dyoung #include <sys/lockf.h>
    107          1.124  jmcneill #include <sys/callout.h>
    108          1.136    dyoung #include <sys/mutex.h>
    109          1.136    dyoung #include <sys/condvar.h>
    110          1.149  jmcneill #include <sys/devmon.h>
    111          1.153    cegger #include <sys/cpu.h>
    112          1.118    dyoung 
    113          1.118    dyoung #include <sys/disk.h>
    114          1.118    dyoung 
    115           1.16   mycroft #include <machine/limits.h>
    116            1.1     glass 
    117           1.57  gmcgarry #include "opt_userconf.h"
    118           1.57  gmcgarry #ifdef USERCONF
    119           1.57  gmcgarry #include <sys/userconf.h>
    120           1.57  gmcgarry #endif
    121           1.57  gmcgarry 
    122          1.106    martin #ifdef __i386__
    123          1.105  jmcneill #include "opt_splash.h"
    124          1.105  jmcneill #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
    125          1.105  jmcneill #include <dev/splash/splash.h>
    126          1.105  jmcneill extern struct splash_progress *splash_progress_state;
    127          1.105  jmcneill #endif
    128          1.106    martin #endif
    129          1.105  jmcneill 
    130            1.1     glass /*
    131            1.1     glass  * Autoconfiguration subroutines.
    132            1.1     glass  */
    133            1.1     glass 
    134          1.139    dyoung typedef struct pmf_private {
    135          1.139    dyoung 	int		pp_nwait;
    136          1.139    dyoung 	int		pp_nlock;
    137          1.139    dyoung 	lwp_t		*pp_holder;
    138          1.139    dyoung 	kmutex_t	pp_mtx;
    139          1.139    dyoung 	kcondvar_t	pp_cv;
    140          1.139    dyoung } pmf_private_t;
    141          1.139    dyoung 
    142            1.1     glass /*
    143            1.1     glass  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
    144            1.1     glass  * devices and drivers are found via these tables.
    145            1.1     glass  */
    146            1.1     glass extern struct cfdata cfdata[];
    147           1.84      matt extern const short cfroots[];
    148            1.1     glass 
    149           1.65   thorpej /*
    150           1.67   thorpej  * List of all cfdriver structures.  We use this to detect duplicates
    151           1.67   thorpej  * when other cfdrivers are loaded.
    152           1.67   thorpej  */
    153           1.69   thorpej struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
    154           1.69   thorpej extern struct cfdriver * const cfdriver_list_initial[];
    155           1.67   thorpej 
    156           1.67   thorpej /*
    157           1.76   thorpej  * Initial list of cfattach's.
    158           1.76   thorpej  */
    159           1.76   thorpej extern const struct cfattachinit cfattachinit[];
    160           1.76   thorpej 
    161           1.76   thorpej /*
    162           1.65   thorpej  * List of cfdata tables.  We always have one such list -- the one
    163           1.65   thorpej  * built statically when the kernel was configured.
    164           1.65   thorpej  */
    165          1.121      matt struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
    166           1.65   thorpej static struct cftable initcftable;
    167           1.65   thorpej 
    168          1.102   thorpej #define	ROOT ((device_t)NULL)
    169            1.1     glass 
    170           1.16   mycroft struct matchinfo {
    171           1.99  drochner 	cfsubmatch_t fn;
    172           1.16   mycroft 	struct	device *parent;
    173           1.99  drochner 	const int *locs;
    174           1.25       cgd 	void	*aux;
    175           1.25       cgd 	struct	cfdata *match;
    176           1.25       cgd 	int	pri;
    177           1.16   mycroft };
    178           1.17  christos 
    179           1.51       cgd static char *number(char *, int);
    180          1.102   thorpej static void mapply(struct matchinfo *, cfdata_t);
    181          1.117  drochner static device_t config_devalloc(const device_t, const cfdata_t, const int *);
    182          1.117  drochner static void config_devdealloc(device_t);
    183          1.117  drochner static void config_makeroom(int, struct cfdriver *);
    184          1.117  drochner static void config_devlink(device_t);
    185          1.117  drochner static void config_devunlink(device_t);
    186           1.16   mycroft 
    187          1.139    dyoung static void pmflock_debug(device_t, const char *, int);
    188          1.139    dyoung static void pmflock_debug_with_flags(device_t, const char *, int PMF_FN_PROTO);
    189          1.139    dyoung 
    190          1.136    dyoung static device_t deviter_next1(deviter_t *);
    191          1.136    dyoung static void deviter_reinit(deviter_t *);
    192          1.136    dyoung 
    193           1.29   thorpej struct deferred_config {
    194           1.29   thorpej 	TAILQ_ENTRY(deferred_config) dc_queue;
    195          1.102   thorpej 	device_t dc_dev;
    196          1.102   thorpej 	void (*dc_func)(device_t);
    197           1.29   thorpej };
    198           1.29   thorpej 
    199           1.42   thorpej TAILQ_HEAD(deferred_config_head, deferred_config);
    200           1.29   thorpej 
    201          1.121      matt struct deferred_config_head deferred_config_queue =
    202          1.121      matt 	TAILQ_HEAD_INITIALIZER(deferred_config_queue);
    203          1.121      matt struct deferred_config_head interrupt_config_queue =
    204          1.121      matt 	TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
    205          1.142        ad int interrupt_config_threads = 8;
    206           1.42   thorpej 
    207          1.102   thorpej static void config_process_deferred(struct deferred_config_head *, device_t);
    208           1.29   thorpej 
    209           1.75   thorpej /* Hooks to finalize configuration once all real devices have been found. */
    210           1.75   thorpej struct finalize_hook {
    211           1.75   thorpej 	TAILQ_ENTRY(finalize_hook) f_list;
    212          1.102   thorpej 	int (*f_func)(device_t);
    213          1.102   thorpej 	device_t f_dev;
    214           1.75   thorpej };
    215          1.121      matt static TAILQ_HEAD(, finalize_hook) config_finalize_list =
    216          1.121      matt 	TAILQ_HEAD_INITIALIZER(config_finalize_list);
    217           1.75   thorpej static int config_finalize_done;
    218           1.75   thorpej 
    219           1.56   thorpej /* list of all devices */
    220          1.121      matt struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
    221          1.136    dyoung kcondvar_t alldevs_cv;
    222          1.136    dyoung kmutex_t alldevs_mtx;
    223          1.136    dyoung static int alldevs_nread = 0;
    224          1.136    dyoung static int alldevs_nwrite = 0;
    225          1.136    dyoung static lwp_t *alldevs_writer = NULL;
    226           1.56   thorpej 
    227          1.151        ad static int config_pending;		/* semaphore for mountroot */
    228          1.151        ad static kmutex_t config_misc_lock;
    229          1.151        ad static kcondvar_t config_misc_cv;
    230           1.47   thorpej 
    231           1.67   thorpej #define	STREQ(s1, s2)			\
    232           1.70   thorpej 	(*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
    233           1.67   thorpej 
    234           1.74   thorpej static int config_initialized;		/* config_init() has been called. */
    235           1.74   thorpej 
    236           1.80   thorpej static int config_do_twiddle;
    237           1.80   thorpej 
    238          1.118    dyoung struct vnode *
    239          1.118    dyoung opendisk(struct device *dv)
    240          1.118    dyoung {
    241          1.118    dyoung 	int bmajor, bminor;
    242          1.118    dyoung 	struct vnode *tmpvn;
    243          1.118    dyoung 	int error;
    244          1.118    dyoung 	dev_t dev;
    245          1.118    dyoung 
    246          1.118    dyoung 	/*
    247          1.118    dyoung 	 * Lookup major number for disk block device.
    248          1.118    dyoung 	 */
    249          1.118    dyoung 	bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
    250          1.118    dyoung 	if (bmajor == -1)
    251          1.118    dyoung 		return NULL;
    252          1.118    dyoung 
    253          1.118    dyoung 	bminor = minor(device_unit(dv));
    254          1.118    dyoung 	/*
    255          1.118    dyoung 	 * Fake a temporary vnode for the disk, open it, and read
    256          1.118    dyoung 	 * and hash the sectors.
    257          1.118    dyoung 	 */
    258          1.118    dyoung 	dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
    259          1.118    dyoung 	    MAKEDISKDEV(bmajor, bminor, RAW_PART);
    260          1.118    dyoung 	if (bdevvp(dev, &tmpvn))
    261          1.118    dyoung 		panic("%s: can't alloc vnode for %s", __func__,
    262          1.118    dyoung 		    device_xname(dv));
    263          1.123     pooka 	error = VOP_OPEN(tmpvn, FREAD, NOCRED);
    264          1.118    dyoung 	if (error) {
    265          1.118    dyoung #ifndef DEBUG
    266          1.118    dyoung 		/*
    267          1.118    dyoung 		 * Ignore errors caused by missing device, partition,
    268          1.118    dyoung 		 * or medium.
    269          1.118    dyoung 		 */
    270          1.118    dyoung 		if (error != ENXIO && error != ENODEV)
    271          1.118    dyoung #endif
    272          1.118    dyoung 			printf("%s: can't open dev %s (%d)\n",
    273          1.118    dyoung 			    __func__, device_xname(dv), error);
    274          1.118    dyoung 		vput(tmpvn);
    275          1.118    dyoung 		return NULL;
    276          1.118    dyoung 	}
    277          1.118    dyoung 
    278          1.118    dyoung 	return tmpvn;
    279          1.118    dyoung }
    280          1.118    dyoung 
    281          1.118    dyoung int
    282          1.118    dyoung config_handle_wedges(struct device *dv, int par)
    283          1.118    dyoung {
    284          1.118    dyoung 	struct dkwedge_list wl;
    285          1.118    dyoung 	struct dkwedge_info *wi;
    286          1.118    dyoung 	struct vnode *vn;
    287          1.118    dyoung 	char diskname[16];
    288          1.118    dyoung 	int i, error;
    289          1.118    dyoung 
    290          1.118    dyoung 	if ((vn = opendisk(dv)) == NULL)
    291          1.118    dyoung 		return -1;
    292          1.118    dyoung 
    293          1.118    dyoung 	wl.dkwl_bufsize = sizeof(*wi) * 16;
    294          1.118    dyoung 	wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
    295          1.118    dyoung 
    296          1.123     pooka 	error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED);
    297          1.123     pooka 	VOP_CLOSE(vn, FREAD, NOCRED);
    298          1.118    dyoung 	vput(vn);
    299          1.118    dyoung 	if (error) {
    300          1.118    dyoung #ifdef DEBUG_WEDGE
    301          1.118    dyoung 		printf("%s: List wedges returned %d\n",
    302          1.118    dyoung 		    device_xname(dv), error);
    303          1.118    dyoung #endif
    304          1.118    dyoung 		free(wi, M_TEMP);
    305          1.118    dyoung 		return -1;
    306          1.118    dyoung 	}
    307          1.118    dyoung 
    308          1.118    dyoung #ifdef DEBUG_WEDGE
    309          1.118    dyoung 	printf("%s: Returned %u(%u) wedges\n", device_xname(dv),
    310          1.118    dyoung 	    wl.dkwl_nwedges, wl.dkwl_ncopied);
    311          1.118    dyoung #endif
    312          1.118    dyoung 	snprintf(diskname, sizeof(diskname), "%s%c", device_xname(dv),
    313          1.118    dyoung 	    par + 'a');
    314          1.118    dyoung 
    315          1.118    dyoung 	for (i = 0; i < wl.dkwl_ncopied; i++) {
    316          1.118    dyoung #ifdef DEBUG_WEDGE
    317          1.118    dyoung 		printf("%s: Looking for %s in %s\n",
    318          1.118    dyoung 		    device_xname(dv), diskname, wi[i].dkw_wname);
    319          1.118    dyoung #endif
    320          1.118    dyoung 		if (strcmp(wi[i].dkw_wname, diskname) == 0)
    321          1.118    dyoung 			break;
    322          1.118    dyoung 	}
    323          1.118    dyoung 
    324          1.118    dyoung 	if (i == wl.dkwl_ncopied) {
    325          1.118    dyoung #ifdef DEBUG_WEDGE
    326          1.118    dyoung 		printf("%s: Cannot find wedge with parent %s\n",
    327          1.118    dyoung 		    device_xname(dv), diskname);
    328          1.118    dyoung #endif
    329          1.118    dyoung 		free(wi, M_TEMP);
    330          1.118    dyoung 		return -1;
    331          1.118    dyoung 	}
    332          1.118    dyoung 
    333          1.118    dyoung #ifdef DEBUG_WEDGE
    334          1.118    dyoung 	printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
    335          1.118    dyoung 		device_xname(dv), wi[i].dkw_devname, wi[i].dkw_wname,
    336          1.118    dyoung 		(unsigned long long)wi[i].dkw_offset,
    337          1.118    dyoung 		(unsigned long long)wi[i].dkw_size);
    338          1.118    dyoung #endif
    339          1.118    dyoung 	dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
    340          1.118    dyoung 	free(wi, M_TEMP);
    341          1.118    dyoung 	return 0;
    342          1.118    dyoung }
    343          1.118    dyoung 
    344           1.20       cgd /*
    345           1.74   thorpej  * Initialize the autoconfiguration data structures.  Normally this
    346           1.74   thorpej  * is done by configure(), but some platforms need to do this very
    347           1.74   thorpej  * early (to e.g. initialize the console).
    348           1.20       cgd  */
    349           1.20       cgd void
    350           1.74   thorpej config_init(void)
    351           1.20       cgd {
    352           1.76   thorpej 	const struct cfattachinit *cfai;
    353           1.76   thorpej 	int i, j;
    354           1.67   thorpej 
    355           1.74   thorpej 	if (config_initialized)
    356           1.74   thorpej 		return;
    357           1.74   thorpej 
    358          1.136    dyoung 	mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE);
    359          1.136    dyoung 	cv_init(&alldevs_cv, "alldevs");
    360          1.136    dyoung 
    361          1.151        ad 	mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
    362          1.151        ad 	cv_init(&config_misc_cv, "cfgmisc");
    363          1.151        ad 
    364           1.69   thorpej 	/* allcfdrivers is statically initialized. */
    365           1.76   thorpej 	for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
    366           1.67   thorpej 		if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
    367           1.67   thorpej 			panic("configure: duplicate `%s' drivers",
    368           1.67   thorpej 			    cfdriver_list_initial[i]->cd_name);
    369           1.76   thorpej 	}
    370           1.76   thorpej 
    371           1.76   thorpej 	for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
    372           1.76   thorpej 		for (j = 0; cfai->cfai_list[j] != NULL; j++) {
    373           1.76   thorpej 			if (config_cfattach_attach(cfai->cfai_name,
    374           1.76   thorpej 						   cfai->cfai_list[j]) != 0)
    375           1.76   thorpej 				panic("configure: duplicate `%s' attachment "
    376           1.76   thorpej 				    "of `%s' driver",
    377           1.76   thorpej 				    cfai->cfai_list[j]->ca_name,
    378           1.76   thorpej 				    cfai->cfai_name);
    379           1.76   thorpej 		}
    380           1.76   thorpej 	}
    381           1.20       cgd 
    382           1.65   thorpej 	initcftable.ct_cfdata = cfdata;
    383           1.65   thorpej 	TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
    384           1.65   thorpej 
    385           1.74   thorpej 	config_initialized = 1;
    386           1.74   thorpej }
    387           1.74   thorpej 
    388          1.126    dyoung void
    389          1.126    dyoung config_deferred(device_t dev)
    390          1.126    dyoung {
    391          1.126    dyoung 	config_process_deferred(&deferred_config_queue, dev);
    392          1.126    dyoung 	config_process_deferred(&interrupt_config_queue, dev);
    393          1.126    dyoung }
    394          1.126    dyoung 
    395          1.142        ad static void
    396          1.142        ad config_interrupts_thread(void *cookie)
    397          1.142        ad {
    398          1.142        ad 	struct deferred_config *dc;
    399          1.142        ad 
    400          1.142        ad 	while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
    401          1.142        ad 		TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
    402          1.142        ad 		(*dc->dc_func)(dc->dc_dev);
    403          1.159      matt 		kmem_free(dc, sizeof(*dc));
    404          1.142        ad 		config_pending_decr();
    405          1.142        ad 	}
    406          1.142        ad 	kthread_exit(0);
    407          1.142        ad }
    408          1.142        ad 
    409           1.74   thorpej /*
    410           1.74   thorpej  * Configure the system's hardware.
    411           1.74   thorpej  */
    412           1.74   thorpej void
    413           1.74   thorpej configure(void)
    414           1.74   thorpej {
    415           1.74   thorpej 	/* Initialize data structures. */
    416           1.74   thorpej 	config_init();
    417          1.124  jmcneill 	pmf_init();
    418          1.149  jmcneill #if NDRVCTL > 0
    419          1.149  jmcneill 	drvctl_init();
    420          1.149  jmcneill #endif
    421           1.86   thorpej 
    422           1.57  gmcgarry #ifdef USERCONF
    423           1.57  gmcgarry 	if (boothowto & RB_USERCONF)
    424           1.57  gmcgarry 		user_config();
    425           1.57  gmcgarry #endif
    426           1.41   thorpej 
    427           1.80   thorpej 	if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
    428           1.80   thorpej 		config_do_twiddle = 1;
    429           1.80   thorpej 		printf_nolog("Detecting hardware...");
    430           1.80   thorpej 	}
    431           1.80   thorpej 
    432           1.41   thorpej 	/*
    433           1.41   thorpej 	 * Do the machine-dependent portion of autoconfiguration.  This
    434           1.41   thorpej 	 * sets the configuration machinery here in motion by "finding"
    435           1.41   thorpej 	 * the root bus.  When this function returns, we expect interrupts
    436           1.41   thorpej 	 * to be enabled.
    437           1.41   thorpej 	 */
    438           1.41   thorpej 	cpu_configure();
    439      1.163.4.2       snj }
    440           1.43   thorpej 
    441      1.163.4.2       snj void
    442      1.163.4.2       snj configure2(void)
    443      1.163.4.2       snj {
    444      1.163.4.2       snj 	CPU_INFO_ITERATOR cii;
    445      1.163.4.2       snj 	struct cpu_info *ci;
    446      1.163.4.2       snj 	int i, s;
    447          1.144        ad 
    448           1.43   thorpej 	/*
    449           1.43   thorpej 	 * Now that we've found all the hardware, start the real time
    450           1.43   thorpej 	 * and statistics clocks.
    451           1.43   thorpej 	 */
    452           1.43   thorpej 	initclocks();
    453           1.43   thorpej 
    454           1.43   thorpej 	cold = 0;	/* clocks are running, we're warm now! */
    455          1.146        ad 	s = splsched();
    456          1.146        ad 	curcpu()->ci_schedstate.spc_flags |= SPCF_RUNNING;
    457          1.146        ad 	splx(s);
    458           1.42   thorpej 
    459          1.129      yamt 	/* Boot the secondary processors. */
    460          1.152        ad 	for (CPU_INFO_FOREACH(cii, ci)) {
    461          1.152        ad 		uvm_cpu_attach(ci);
    462          1.152        ad 	}
    463          1.129      yamt 	mp_online = true;
    464          1.122        ad #if defined(MULTIPROCESSOR)
    465          1.122        ad 	cpu_boot_secondary_processors();
    466          1.122        ad #endif
    467          1.122        ad 
    468          1.147     rmind 	/* Setup the runqueues and scheduler. */
    469          1.147     rmind 	runq_init();
    470          1.142        ad 	sched_init();
    471          1.142        ad 
    472           1.42   thorpej 	/*
    473          1.142        ad 	 * Create threads to call back and finish configuration for
    474          1.142        ad 	 * devices that want interrupts enabled.
    475           1.42   thorpej 	 */
    476          1.142        ad 	for (i = 0; i < interrupt_config_threads; i++) {
    477          1.142        ad 		(void)kthread_create(PRI_NONE, 0, NULL,
    478          1.142        ad 		    config_interrupts_thread, NULL, NULL, "config");
    479          1.142        ad 	}
    480           1.80   thorpej 
    481          1.142        ad 	/* Get the threads going and into any sleeps before continuing. */
    482          1.142        ad 	yield();
    483           1.20       cgd }
    484           1.20       cgd 
    485            1.1     glass /*
    486          1.149  jmcneill  * Announce device attach/detach to userland listeners.
    487          1.149  jmcneill  */
    488          1.149  jmcneill static void
    489          1.149  jmcneill devmon_report_device(device_t dev, bool isattach)
    490          1.149  jmcneill {
    491          1.149  jmcneill #if NDRVCTL > 0
    492          1.149  jmcneill 	prop_dictionary_t ev;
    493          1.149  jmcneill 	const char *parent;
    494          1.149  jmcneill 	const char *what;
    495          1.149  jmcneill 	device_t pdev = device_parent(dev);
    496          1.149  jmcneill 
    497          1.149  jmcneill 	ev = prop_dictionary_create();
    498          1.149  jmcneill 	if (ev == NULL)
    499          1.149  jmcneill 		return;
    500          1.149  jmcneill 
    501          1.149  jmcneill 	what = (isattach ? "device-attach" : "device-detach");
    502          1.149  jmcneill 	parent = (pdev == NULL ? "root" : device_xname(pdev));
    503          1.149  jmcneill 	if (!prop_dictionary_set_cstring(ev, "device", device_xname(dev)) ||
    504          1.149  jmcneill 	    !prop_dictionary_set_cstring(ev, "parent", parent)) {
    505          1.149  jmcneill 		prop_object_release(ev);
    506          1.149  jmcneill 		return;
    507          1.149  jmcneill 	}
    508          1.149  jmcneill 
    509          1.149  jmcneill 	devmon_insert(what, ev);
    510          1.149  jmcneill #endif
    511          1.149  jmcneill }
    512          1.149  jmcneill 
    513          1.149  jmcneill /*
    514           1.67   thorpej  * Add a cfdriver to the system.
    515           1.67   thorpej  */
    516           1.67   thorpej int
    517           1.67   thorpej config_cfdriver_attach(struct cfdriver *cd)
    518           1.67   thorpej {
    519           1.67   thorpej 	struct cfdriver *lcd;
    520           1.67   thorpej 
    521           1.67   thorpej 	/* Make sure this driver isn't already in the system. */
    522           1.67   thorpej 	LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
    523           1.67   thorpej 		if (STREQ(lcd->cd_name, cd->cd_name))
    524           1.67   thorpej 			return (EEXIST);
    525           1.67   thorpej 	}
    526           1.67   thorpej 
    527           1.76   thorpej 	LIST_INIT(&cd->cd_attach);
    528           1.67   thorpej 	LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
    529           1.67   thorpej 
    530           1.67   thorpej 	return (0);
    531           1.67   thorpej }
    532           1.67   thorpej 
    533           1.67   thorpej /*
    534           1.67   thorpej  * Remove a cfdriver from the system.
    535           1.67   thorpej  */
    536           1.67   thorpej int
    537           1.67   thorpej config_cfdriver_detach(struct cfdriver *cd)
    538           1.67   thorpej {
    539           1.67   thorpej 	int i;
    540           1.67   thorpej 
    541           1.67   thorpej 	/* Make sure there are no active instances. */
    542           1.67   thorpej 	for (i = 0; i < cd->cd_ndevs; i++) {
    543           1.67   thorpej 		if (cd->cd_devs[i] != NULL)
    544           1.67   thorpej 			return (EBUSY);
    545           1.67   thorpej 	}
    546           1.67   thorpej 
    547           1.76   thorpej 	/* ...and no attachments loaded. */
    548           1.76   thorpej 	if (LIST_EMPTY(&cd->cd_attach) == 0)
    549           1.76   thorpej 		return (EBUSY);
    550           1.76   thorpej 
    551           1.67   thorpej 	LIST_REMOVE(cd, cd_list);
    552           1.67   thorpej 
    553           1.67   thorpej 	KASSERT(cd->cd_devs == NULL);
    554           1.67   thorpej 
    555           1.67   thorpej 	return (0);
    556           1.67   thorpej }
    557           1.67   thorpej 
    558           1.67   thorpej /*
    559           1.67   thorpej  * Look up a cfdriver by name.
    560           1.67   thorpej  */
    561           1.78     isaki struct cfdriver *
    562           1.67   thorpej config_cfdriver_lookup(const char *name)
    563           1.67   thorpej {
    564           1.67   thorpej 	struct cfdriver *cd;
    565           1.69   thorpej 
    566           1.67   thorpej 	LIST_FOREACH(cd, &allcfdrivers, cd_list) {
    567           1.67   thorpej 		if (STREQ(cd->cd_name, name))
    568           1.67   thorpej 			return (cd);
    569           1.67   thorpej 	}
    570           1.67   thorpej 
    571           1.67   thorpej 	return (NULL);
    572           1.67   thorpej }
    573           1.67   thorpej 
    574           1.67   thorpej /*
    575           1.76   thorpej  * Add a cfattach to the specified driver.
    576           1.76   thorpej  */
    577           1.76   thorpej int
    578           1.76   thorpej config_cfattach_attach(const char *driver, struct cfattach *ca)
    579           1.76   thorpej {
    580           1.76   thorpej 	struct cfattach *lca;
    581           1.76   thorpej 	struct cfdriver *cd;
    582           1.76   thorpej 
    583           1.76   thorpej 	cd = config_cfdriver_lookup(driver);
    584           1.76   thorpej 	if (cd == NULL)
    585           1.76   thorpej 		return (ESRCH);
    586           1.76   thorpej 
    587           1.76   thorpej 	/* Make sure this attachment isn't already on this driver. */
    588           1.76   thorpej 	LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
    589           1.76   thorpej 		if (STREQ(lca->ca_name, ca->ca_name))
    590           1.76   thorpej 			return (EEXIST);
    591           1.76   thorpej 	}
    592           1.76   thorpej 
    593           1.76   thorpej 	LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
    594           1.76   thorpej 
    595           1.76   thorpej 	return (0);
    596           1.76   thorpej }
    597           1.76   thorpej 
    598           1.76   thorpej /*
    599           1.76   thorpej  * Remove a cfattach from the specified driver.
    600           1.76   thorpej  */
    601           1.76   thorpej int
    602           1.76   thorpej config_cfattach_detach(const char *driver, struct cfattach *ca)
    603           1.76   thorpej {
    604           1.76   thorpej 	struct cfdriver *cd;
    605          1.102   thorpej 	device_t dev;
    606           1.76   thorpej 	int i;
    607           1.76   thorpej 
    608           1.76   thorpej 	cd = config_cfdriver_lookup(driver);
    609           1.76   thorpej 	if (cd == NULL)
    610           1.76   thorpej 		return (ESRCH);
    611           1.76   thorpej 
    612           1.76   thorpej 	/* Make sure there are no active instances. */
    613           1.76   thorpej 	for (i = 0; i < cd->cd_ndevs; i++) {
    614           1.76   thorpej 		if ((dev = cd->cd_devs[i]) == NULL)
    615           1.76   thorpej 			continue;
    616           1.77   thorpej 		if (dev->dv_cfattach == ca)
    617           1.76   thorpej 			return (EBUSY);
    618           1.76   thorpej 	}
    619           1.76   thorpej 
    620           1.76   thorpej 	LIST_REMOVE(ca, ca_list);
    621           1.76   thorpej 
    622           1.76   thorpej 	return (0);
    623           1.76   thorpej }
    624           1.76   thorpej 
    625           1.76   thorpej /*
    626           1.76   thorpej  * Look up a cfattach by name.
    627           1.76   thorpej  */
    628           1.76   thorpej static struct cfattach *
    629           1.76   thorpej config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
    630           1.76   thorpej {
    631           1.76   thorpej 	struct cfattach *ca;
    632           1.76   thorpej 
    633           1.76   thorpej 	LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
    634           1.76   thorpej 		if (STREQ(ca->ca_name, atname))
    635           1.76   thorpej 			return (ca);
    636           1.76   thorpej 	}
    637           1.76   thorpej 
    638           1.76   thorpej 	return (NULL);
    639           1.76   thorpej }
    640           1.76   thorpej 
    641           1.76   thorpej /*
    642           1.76   thorpej  * Look up a cfattach by driver/attachment name.
    643           1.76   thorpej  */
    644           1.76   thorpej struct cfattach *
    645           1.76   thorpej config_cfattach_lookup(const char *name, const char *atname)
    646           1.76   thorpej {
    647           1.76   thorpej 	struct cfdriver *cd;
    648           1.76   thorpej 
    649           1.76   thorpej 	cd = config_cfdriver_lookup(name);
    650           1.76   thorpej 	if (cd == NULL)
    651           1.76   thorpej 		return (NULL);
    652           1.76   thorpej 
    653           1.76   thorpej 	return (config_cfattach_lookup_cd(cd, atname));
    654           1.76   thorpej }
    655           1.76   thorpej 
    656           1.76   thorpej /*
    657            1.1     glass  * Apply the matching function and choose the best.  This is used
    658            1.1     glass  * a few times and we want to keep the code small.
    659            1.1     glass  */
    660           1.16   mycroft static void
    661          1.102   thorpej mapply(struct matchinfo *m, cfdata_t cf)
    662            1.1     glass {
    663           1.50  augustss 	int pri;
    664            1.1     glass 
    665           1.99  drochner 	if (m->fn != NULL) {
    666           1.99  drochner 		pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
    667           1.90  drochner 	} else {
    668          1.100  drochner 		pri = config_match(m->parent, cf, m->aux);
    669            1.3     glass 	}
    670            1.1     glass 	if (pri > m->pri) {
    671           1.25       cgd 		m->match = cf;
    672            1.1     glass 		m->pri = pri;
    673            1.1     glass 	}
    674            1.1     glass }
    675            1.1     glass 
    676           1.98  drochner int
    677          1.102   thorpej config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
    678           1.98  drochner {
    679           1.98  drochner 	const struct cfiattrdata *ci;
    680           1.98  drochner 	const struct cflocdesc *cl;
    681           1.98  drochner 	int nlocs, i;
    682           1.98  drochner 
    683           1.98  drochner 	ci = cfiattr_lookup(cf->cf_pspec->cfp_iattr, parent->dv_cfdriver);
    684           1.98  drochner 	KASSERT(ci);
    685           1.98  drochner 	nlocs = ci->ci_loclen;
    686          1.154  drochner 	KASSERT(!nlocs || locs);
    687           1.98  drochner 	for (i = 0; i < nlocs; i++) {
    688           1.98  drochner 		cl = &ci->ci_locdesc[i];
    689           1.98  drochner 		/* !cld_defaultstr means no default value */
    690           1.98  drochner 		if ((!(cl->cld_defaultstr)
    691           1.98  drochner 		     || (cf->cf_loc[i] != cl->cld_default))
    692           1.98  drochner 		    && cf->cf_loc[i] != locs[i])
    693           1.98  drochner 			return (0);
    694           1.98  drochner 	}
    695           1.98  drochner 
    696           1.98  drochner 	return (config_match(parent, cf, aux));
    697           1.98  drochner }
    698           1.98  drochner 
    699            1.1     glass /*
    700           1.96  drochner  * Helper function: check whether the driver supports the interface attribute
    701           1.96  drochner  * and return its descriptor structure.
    702           1.91  drochner  */
    703           1.96  drochner static const struct cfiattrdata *
    704           1.96  drochner cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
    705           1.91  drochner {
    706           1.96  drochner 	const struct cfiattrdata * const *cpp;
    707           1.91  drochner 
    708           1.91  drochner 	if (cd->cd_attrs == NULL)
    709           1.91  drochner 		return (0);
    710           1.91  drochner 
    711           1.91  drochner 	for (cpp = cd->cd_attrs; *cpp; cpp++) {
    712           1.96  drochner 		if (STREQ((*cpp)->ci_name, ia)) {
    713           1.91  drochner 			/* Match. */
    714           1.96  drochner 			return (*cpp);
    715           1.91  drochner 		}
    716           1.91  drochner 	}
    717           1.91  drochner 	return (0);
    718           1.91  drochner }
    719           1.91  drochner 
    720           1.91  drochner /*
    721           1.96  drochner  * Lookup an interface attribute description by name.
    722           1.96  drochner  * If the driver is given, consider only its supported attributes.
    723           1.96  drochner  */
    724           1.96  drochner const struct cfiattrdata *
    725           1.96  drochner cfiattr_lookup(const char *name, const struct cfdriver *cd)
    726           1.96  drochner {
    727           1.96  drochner 	const struct cfdriver *d;
    728           1.96  drochner 	const struct cfiattrdata *ia;
    729           1.96  drochner 
    730           1.96  drochner 	if (cd)
    731           1.96  drochner 		return (cfdriver_get_iattr(cd, name));
    732           1.96  drochner 
    733           1.96  drochner 	LIST_FOREACH(d, &allcfdrivers, cd_list) {
    734           1.96  drochner 		ia = cfdriver_get_iattr(d, name);
    735           1.96  drochner 		if (ia)
    736           1.96  drochner 			return (ia);
    737           1.96  drochner 	}
    738           1.96  drochner 	return (0);
    739           1.96  drochner }
    740           1.96  drochner 
    741           1.96  drochner /*
    742           1.66   thorpej  * Determine if `parent' is a potential parent for a device spec based
    743           1.66   thorpej  * on `cfp'.
    744           1.66   thorpej  */
    745           1.66   thorpej static int
    746          1.102   thorpej cfparent_match(const device_t parent, const struct cfparent *cfp)
    747           1.66   thorpej {
    748           1.67   thorpej 	struct cfdriver *pcd;
    749           1.70   thorpej 
    750           1.70   thorpej 	/* We don't match root nodes here. */
    751           1.70   thorpej 	if (cfp == NULL)
    752           1.70   thorpej 		return (0);
    753           1.66   thorpej 
    754           1.77   thorpej 	pcd = parent->dv_cfdriver;
    755           1.67   thorpej 	KASSERT(pcd != NULL);
    756           1.67   thorpej 
    757           1.66   thorpej 	/*
    758           1.66   thorpej 	 * First, ensure this parent has the correct interface
    759           1.66   thorpej 	 * attribute.
    760           1.66   thorpej 	 */
    761           1.96  drochner 	if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
    762           1.91  drochner 		return (0);
    763           1.66   thorpej 
    764           1.66   thorpej 	/*
    765           1.66   thorpej 	 * If no specific parent device instance was specified (i.e.
    766           1.66   thorpej 	 * we're attaching to the attribute only), we're done!
    767           1.66   thorpej 	 */
    768           1.66   thorpej 	if (cfp->cfp_parent == NULL)
    769           1.66   thorpej 		return (1);
    770           1.66   thorpej 
    771           1.66   thorpej 	/*
    772           1.66   thorpej 	 * Check the parent device's name.
    773           1.66   thorpej 	 */
    774           1.71   thorpej 	if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
    775           1.66   thorpej 		return (0);	/* not the same parent */
    776           1.66   thorpej 
    777           1.66   thorpej 	/*
    778           1.66   thorpej 	 * Make sure the unit number matches.
    779           1.66   thorpej 	 */
    780           1.77   thorpej 	if (cfp->cfp_unit == DVUNIT_ANY ||	/* wildcard */
    781           1.66   thorpej 	    cfp->cfp_unit == parent->dv_unit)
    782           1.66   thorpej 		return (1);
    783           1.66   thorpej 
    784           1.66   thorpej 	/* Unit numbers don't match. */
    785           1.66   thorpej 	return (0);
    786           1.68   thorpej }
    787           1.68   thorpej 
    788           1.68   thorpej /*
    789           1.90  drochner  * Helper for config_cfdata_attach(): check all devices whether it could be
    790           1.90  drochner  * parent any attachment in the config data table passed, and rescan.
    791           1.90  drochner  */
    792           1.90  drochner static void
    793           1.90  drochner rescan_with_cfdata(const struct cfdata *cf)
    794           1.90  drochner {
    795          1.102   thorpej 	device_t d;
    796           1.90  drochner 	const struct cfdata *cf1;
    797          1.136    dyoung 	deviter_t di;
    798          1.136    dyoung 
    799           1.90  drochner 
    800           1.90  drochner 	/*
    801           1.90  drochner 	 * "alldevs" is likely longer than an LKM's cfdata, so make it
    802           1.90  drochner 	 * the outer loop.
    803           1.90  drochner 	 */
    804          1.136    dyoung 	for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) {
    805           1.90  drochner 
    806           1.90  drochner 		if (!(d->dv_cfattach->ca_rescan))
    807           1.90  drochner 			continue;
    808           1.90  drochner 
    809           1.90  drochner 		for (cf1 = cf; cf1->cf_name; cf1++) {
    810           1.90  drochner 
    811           1.90  drochner 			if (!cfparent_match(d, cf1->cf_pspec))
    812           1.90  drochner 				continue;
    813           1.90  drochner 
    814           1.90  drochner 			(*d->dv_cfattach->ca_rescan)(d,
    815           1.90  drochner 				cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
    816           1.90  drochner 		}
    817           1.90  drochner 	}
    818          1.136    dyoung 	deviter_release(&di);
    819           1.90  drochner }
    820           1.90  drochner 
    821           1.90  drochner /*
    822           1.90  drochner  * Attach a supplemental config data table and rescan potential
    823           1.90  drochner  * parent devices if required.
    824           1.90  drochner  */
    825           1.90  drochner int
    826          1.102   thorpej config_cfdata_attach(cfdata_t cf, int scannow)
    827           1.90  drochner {
    828           1.90  drochner 	struct cftable *ct;
    829           1.90  drochner 
    830          1.159      matt 	ct = kmem_alloc(sizeof(*ct), KM_SLEEP);
    831           1.90  drochner 	ct->ct_cfdata = cf;
    832           1.90  drochner 	TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
    833           1.90  drochner 
    834           1.90  drochner 	if (scannow)
    835           1.90  drochner 		rescan_with_cfdata(cf);
    836           1.90  drochner 
    837           1.90  drochner 	return (0);
    838           1.90  drochner }
    839           1.90  drochner 
    840           1.90  drochner /*
    841           1.90  drochner  * Helper for config_cfdata_detach: check whether a device is
    842           1.90  drochner  * found through any attachment in the config data table.
    843           1.90  drochner  */
    844           1.90  drochner static int
    845           1.90  drochner dev_in_cfdata(const struct device *d, const struct cfdata *cf)
    846           1.90  drochner {
    847           1.90  drochner 	const struct cfdata *cf1;
    848           1.90  drochner 
    849           1.90  drochner 	for (cf1 = cf; cf1->cf_name; cf1++)
    850           1.90  drochner 		if (d->dv_cfdata == cf1)
    851           1.90  drochner 			return (1);
    852           1.90  drochner 
    853           1.90  drochner 	return (0);
    854           1.90  drochner }
    855           1.90  drochner 
    856           1.90  drochner /*
    857           1.90  drochner  * Detach a supplemental config data table. Detach all devices found
    858           1.90  drochner  * through that table (and thus keeping references to it) before.
    859           1.90  drochner  */
    860           1.90  drochner int
    861          1.102   thorpej config_cfdata_detach(cfdata_t cf)
    862           1.90  drochner {
    863          1.102   thorpej 	device_t d;
    864          1.136    dyoung 	int error = 0;
    865           1.90  drochner 	struct cftable *ct;
    866          1.136    dyoung 	deviter_t di;
    867           1.90  drochner 
    868          1.136    dyoung 	for (d = deviter_first(&di, DEVITER_F_RW); d != NULL;
    869          1.136    dyoung 	     d = deviter_next(&di)) {
    870          1.136    dyoung 		if (!dev_in_cfdata(d, cf))
    871          1.136    dyoung 			continue;
    872          1.136    dyoung 		if ((error = config_detach(d, 0)) != 0)
    873          1.136    dyoung 			break;
    874          1.136    dyoung 	}
    875          1.136    dyoung 	deviter_release(&di);
    876          1.136    dyoung 	if (error) {
    877          1.136    dyoung 		aprint_error_dev(d, "unable to detach instance\n");
    878          1.136    dyoung 		return error;
    879           1.90  drochner 	}
    880           1.90  drochner 
    881           1.90  drochner 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
    882           1.90  drochner 		if (ct->ct_cfdata == cf) {
    883           1.90  drochner 			TAILQ_REMOVE(&allcftables, ct, ct_list);
    884          1.159      matt 			kmem_free(ct, sizeof(*ct));
    885           1.90  drochner 			return (0);
    886           1.90  drochner 		}
    887           1.90  drochner 	}
    888           1.90  drochner 
    889           1.90  drochner 	/* not found -- shouldn't happen */
    890           1.90  drochner 	return (EINVAL);
    891           1.90  drochner }
    892           1.90  drochner 
    893           1.90  drochner /*
    894           1.68   thorpej  * Invoke the "match" routine for a cfdata entry on behalf of
    895           1.68   thorpej  * an external caller, usually a "submatch" routine.
    896           1.68   thorpej  */
    897           1.68   thorpej int
    898          1.102   thorpej config_match(device_t parent, cfdata_t cf, void *aux)
    899           1.68   thorpej {
    900           1.76   thorpej 	struct cfattach *ca;
    901           1.76   thorpej 
    902           1.76   thorpej 	ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
    903           1.76   thorpej 	if (ca == NULL) {
    904           1.76   thorpej 		/* No attachment for this entry, oh well. */
    905           1.76   thorpej 		return (0);
    906           1.76   thorpej 	}
    907           1.68   thorpej 
    908           1.76   thorpej 	return ((*ca->ca_match)(parent, cf, aux));
    909           1.66   thorpej }
    910           1.66   thorpej 
    911           1.66   thorpej /*
    912            1.1     glass  * Iterate over all potential children of some device, calling the given
    913            1.1     glass  * function (default being the child's match function) for each one.
    914            1.1     glass  * Nonzero returns are matches; the highest value returned is considered
    915            1.1     glass  * the best match.  Return the `found child' if we got a match, or NULL
    916            1.1     glass  * otherwise.  The `aux' pointer is simply passed on through.
    917            1.1     glass  *
    918            1.1     glass  * Note that this function is designed so that it can be used to apply
    919            1.1     glass  * an arbitrary function to all potential children (its return value
    920            1.1     glass  * can be ignored).
    921            1.1     glass  */
    922          1.102   thorpej cfdata_t
    923          1.102   thorpej config_search_loc(cfsubmatch_t fn, device_t parent,
    924           1.99  drochner 		  const char *ifattr, const int *locs, void *aux)
    925           1.90  drochner {
    926           1.90  drochner 	struct cftable *ct;
    927          1.102   thorpej 	cfdata_t cf;
    928           1.90  drochner 	struct matchinfo m;
    929           1.90  drochner 
    930           1.90  drochner 	KASSERT(config_initialized);
    931           1.96  drochner 	KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
    932           1.90  drochner 
    933           1.99  drochner 	m.fn = fn;
    934            1.1     glass 	m.parent = parent;
    935           1.99  drochner 	m.locs = locs;
    936           1.25       cgd 	m.aux = aux;
    937           1.14   mycroft 	m.match = NULL;
    938            1.1     glass 	m.pri = 0;
    939           1.65   thorpej 
    940           1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
    941           1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
    942           1.90  drochner 
    943           1.90  drochner 			/* We don't match root nodes here. */
    944           1.90  drochner 			if (!cf->cf_pspec)
    945           1.90  drochner 				continue;
    946           1.90  drochner 
    947           1.65   thorpej 			/*
    948           1.65   thorpej 			 * Skip cf if no longer eligible, otherwise scan
    949           1.65   thorpej 			 * through parents for one matching `parent', and
    950           1.65   thorpej 			 * try match function.
    951           1.65   thorpej 			 */
    952           1.65   thorpej 			if (cf->cf_fstate == FSTATE_FOUND)
    953           1.65   thorpej 				continue;
    954           1.65   thorpej 			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
    955           1.65   thorpej 			    cf->cf_fstate == FSTATE_DSTAR)
    956           1.65   thorpej 				continue;
    957           1.90  drochner 
    958           1.90  drochner 			/*
    959           1.90  drochner 			 * If an interface attribute was specified,
    960           1.90  drochner 			 * consider only children which attach to
    961           1.90  drochner 			 * that attribute.
    962           1.90  drochner 			 */
    963           1.90  drochner 			if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
    964           1.90  drochner 				continue;
    965           1.90  drochner 
    966           1.66   thorpej 			if (cfparent_match(parent, cf->cf_pspec))
    967           1.66   thorpej 				mapply(&m, cf);
    968           1.65   thorpej 		}
    969            1.1     glass 	}
    970            1.1     glass 	return (m.match);
    971            1.1     glass }
    972            1.1     glass 
    973          1.102   thorpej cfdata_t
    974          1.102   thorpej config_search_ia(cfsubmatch_t fn, device_t parent, const char *ifattr,
    975          1.102   thorpej     void *aux)
    976          1.102   thorpej {
    977          1.102   thorpej 
    978          1.102   thorpej 	return (config_search_loc(fn, parent, ifattr, NULL, aux));
    979          1.102   thorpej }
    980          1.102   thorpej 
    981           1.16   mycroft /*
    982            1.1     glass  * Find the given root device.
    983            1.1     glass  * This is much like config_search, but there is no parent.
    984           1.65   thorpej  * Don't bother with multiple cfdata tables; the root node
    985           1.65   thorpej  * must always be in the initial table.
    986            1.1     glass  */
    987          1.102   thorpej cfdata_t
    988           1.95  drochner config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
    989            1.1     glass {
    990          1.102   thorpej 	cfdata_t cf;
    991           1.84      matt 	const short *p;
    992            1.1     glass 	struct matchinfo m;
    993            1.1     glass 
    994           1.99  drochner 	m.fn = fn;
    995            1.1     glass 	m.parent = ROOT;
    996           1.25       cgd 	m.aux = aux;
    997           1.14   mycroft 	m.match = NULL;
    998            1.1     glass 	m.pri = 0;
    999          1.114  christos 	m.locs = 0;
   1000            1.1     glass 	/*
   1001            1.1     glass 	 * Look at root entries for matching name.  We do not bother
   1002            1.1     glass 	 * with found-state here since only one root should ever be
   1003            1.1     glass 	 * searched (and it must be done first).
   1004            1.1     glass 	 */
   1005            1.1     glass 	for (p = cfroots; *p >= 0; p++) {
   1006            1.1     glass 		cf = &cfdata[*p];
   1007           1.67   thorpej 		if (strcmp(cf->cf_name, rootname) == 0)
   1008           1.16   mycroft 			mapply(&m, cf);
   1009            1.1     glass 	}
   1010            1.1     glass 	return (m.match);
   1011            1.1     glass }
   1012            1.1     glass 
   1013           1.83  jdolecek static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
   1014            1.1     glass 
   1015            1.1     glass /*
   1016            1.1     glass  * The given `aux' argument describes a device that has been found
   1017            1.1     glass  * on the given parent, but not necessarily configured.  Locate the
   1018           1.18       cgd  * configuration data for that device (using the submatch function
   1019           1.18       cgd  * provided, or using candidates' cd_match configuration driver
   1020           1.18       cgd  * functions) and attach it, and return true.  If the device was
   1021            1.1     glass  * not configured, call the given `print' function and return 0.
   1022            1.1     glass  */
   1023          1.102   thorpej device_t
   1024          1.102   thorpej config_found_sm_loc(device_t parent,
   1025           1.99  drochner 		const char *ifattr, const int *locs, void *aux,
   1026           1.95  drochner 		cfprint_t print, cfsubmatch_t submatch)
   1027           1.90  drochner {
   1028          1.102   thorpej 	cfdata_t cf;
   1029           1.90  drochner 
   1030          1.105  jmcneill #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
   1031          1.105  jmcneill 	if (splash_progress_state)
   1032          1.105  jmcneill 		splash_progress_update(splash_progress_state);
   1033          1.105  jmcneill #endif
   1034          1.105  jmcneill 
   1035           1.99  drochner 	if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux)))
   1036           1.99  drochner 		return(config_attach_loc(parent, cf, locs, aux, print));
   1037           1.90  drochner 	if (print) {
   1038           1.90  drochner 		if (config_do_twiddle)
   1039           1.90  drochner 			twiddle();
   1040          1.143    cegger 		aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]);
   1041           1.90  drochner 	}
   1042          1.105  jmcneill 
   1043          1.105  jmcneill #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
   1044          1.105  jmcneill 	if (splash_progress_state)
   1045          1.105  jmcneill 		splash_progress_update(splash_progress_state);
   1046          1.105  jmcneill #endif
   1047          1.105  jmcneill 
   1048           1.90  drochner 	return (NULL);
   1049           1.90  drochner }
   1050           1.90  drochner 
   1051          1.102   thorpej device_t
   1052          1.102   thorpej config_found_ia(device_t parent, const char *ifattr, void *aux,
   1053          1.102   thorpej     cfprint_t print)
   1054          1.102   thorpej {
   1055          1.102   thorpej 
   1056          1.102   thorpej 	return (config_found_sm_loc(parent, ifattr, NULL, aux, print, NULL));
   1057          1.102   thorpej }
   1058          1.102   thorpej 
   1059          1.102   thorpej device_t
   1060          1.102   thorpej config_found(device_t parent, void *aux, cfprint_t print)
   1061          1.102   thorpej {
   1062          1.102   thorpej 
   1063          1.102   thorpej 	return (config_found_sm_loc(parent, NULL, NULL, aux, print, NULL));
   1064          1.102   thorpej }
   1065          1.102   thorpej 
   1066            1.1     glass /*
   1067            1.1     glass  * As above, but for root devices.
   1068            1.1     glass  */
   1069          1.102   thorpej device_t
   1070           1.52       cgd config_rootfound(const char *rootname, void *aux)
   1071            1.1     glass {
   1072          1.102   thorpej 	cfdata_t cf;
   1073           1.25       cgd 
   1074           1.95  drochner 	if ((cf = config_rootsearch((cfsubmatch_t)NULL, rootname, aux)) != NULL)
   1075           1.25       cgd 		return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
   1076           1.80   thorpej 	aprint_error("root device %s not configured\n", rootname);
   1077           1.21       cgd 	return (NULL);
   1078            1.1     glass }
   1079            1.1     glass 
   1080            1.1     glass /* just like sprintf(buf, "%d") except that it works from the end */
   1081            1.1     glass static char *
   1082           1.51       cgd number(char *ep, int n)
   1083            1.1     glass {
   1084            1.1     glass 
   1085            1.1     glass 	*--ep = 0;
   1086            1.1     glass 	while (n >= 10) {
   1087            1.1     glass 		*--ep = (n % 10) + '0';
   1088            1.1     glass 		n /= 10;
   1089            1.1     glass 	}
   1090            1.1     glass 	*--ep = n + '0';
   1091            1.1     glass 	return (ep);
   1092            1.1     glass }
   1093            1.1     glass 
   1094            1.1     glass /*
   1095           1.59  augustss  * Expand the size of the cd_devs array if necessary.
   1096           1.59  augustss  */
   1097          1.117  drochner static void
   1098           1.59  augustss config_makeroom(int n, struct cfdriver *cd)
   1099           1.59  augustss {
   1100          1.159      matt 	const km_flag_t kmflags = (cold ? KM_NOSLEEP : KM_SLEEP);
   1101           1.59  augustss 	int old, new;
   1102          1.156  drochner 	device_t *nsp;
   1103           1.59  augustss 
   1104           1.59  augustss 	if (n < cd->cd_ndevs)
   1105           1.59  augustss 		return;
   1106           1.59  augustss 
   1107           1.59  augustss 	/*
   1108           1.59  augustss 	 * Need to expand the array.
   1109           1.59  augustss 	 */
   1110           1.59  augustss 	old = cd->cd_ndevs;
   1111           1.61   thorpej 	if (old == 0)
   1112          1.115       chs 		new = 4;
   1113           1.59  augustss 	else
   1114           1.59  augustss 		new = old * 2;
   1115           1.59  augustss 	while (new <= n)
   1116           1.59  augustss 		new *= 2;
   1117           1.59  augustss 	cd->cd_ndevs = new;
   1118          1.159      matt 	nsp = kmem_alloc(sizeof(device_t [new]), kmflags);
   1119           1.60  augustss 	if (nsp == NULL)
   1120           1.59  augustss 		panic("config_attach: %sing dev array",
   1121           1.59  augustss 		    old != 0 ? "expand" : "creat");
   1122          1.159      matt 	memset(nsp + old, 0, sizeof(device_t [new - old]));
   1123           1.61   thorpej 	if (old != 0) {
   1124          1.159      matt 		memcpy(nsp, cd->cd_devs, sizeof(device_t [old]));
   1125          1.159      matt 		kmem_free(cd->cd_devs, sizeof(device_t [old]));
   1126           1.59  augustss 	}
   1127           1.59  augustss 	cd->cd_devs = nsp;
   1128           1.59  augustss }
   1129           1.59  augustss 
   1130          1.117  drochner static void
   1131          1.117  drochner config_devlink(device_t dev)
   1132          1.117  drochner {
   1133          1.117  drochner 	struct cfdriver *cd = dev->dv_cfdriver;
   1134          1.117  drochner 
   1135          1.117  drochner 	/* put this device in the devices array */
   1136          1.117  drochner 	config_makeroom(dev->dv_unit, cd);
   1137          1.117  drochner 	if (cd->cd_devs[dev->dv_unit])
   1138          1.143    cegger 		panic("config_attach: duplicate %s", device_xname(dev));
   1139          1.117  drochner 	cd->cd_devs[dev->dv_unit] = dev;
   1140          1.117  drochner 
   1141          1.136    dyoung 	/* It is safe to add a device to the tail of the list while
   1142          1.136    dyoung 	 * readers are in the list, but not while a writer is in
   1143          1.136    dyoung 	 * the list.  Wait for any writer to complete.
   1144          1.136    dyoung 	 */
   1145          1.136    dyoung 	mutex_enter(&alldevs_mtx);
   1146          1.136    dyoung 	while (alldevs_nwrite != 0 && alldevs_writer != curlwp)
   1147          1.136    dyoung 		cv_wait(&alldevs_cv, &alldevs_mtx);
   1148          1.117  drochner 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);	/* link up */
   1149          1.136    dyoung 	cv_signal(&alldevs_cv);
   1150          1.136    dyoung 	mutex_exit(&alldevs_mtx);
   1151          1.117  drochner }
   1152          1.117  drochner 
   1153          1.117  drochner static void
   1154          1.117  drochner config_devunlink(device_t dev)
   1155          1.117  drochner {
   1156          1.117  drochner 	struct cfdriver *cd = dev->dv_cfdriver;
   1157          1.117  drochner 	int i;
   1158          1.117  drochner 
   1159          1.117  drochner 	/* Unlink from device list. */
   1160          1.117  drochner 	TAILQ_REMOVE(&alldevs, dev, dv_list);
   1161          1.117  drochner 
   1162          1.117  drochner 	/* Remove from cfdriver's array. */
   1163          1.117  drochner 	cd->cd_devs[dev->dv_unit] = NULL;
   1164          1.117  drochner 
   1165          1.117  drochner 	/*
   1166          1.117  drochner 	 * If the device now has no units in use, deallocate its softc array.
   1167          1.117  drochner 	 */
   1168          1.159      matt 	for (i = 0; i < cd->cd_ndevs; i++) {
   1169          1.117  drochner 		if (cd->cd_devs[i] != NULL)
   1170          1.159      matt 			return;
   1171          1.117  drochner 	}
   1172          1.159      matt 	/* nothing found; deallocate */
   1173          1.159      matt 	kmem_free(cd->cd_devs, sizeof(device_t [cd->cd_ndevs]));
   1174          1.159      matt 	cd->cd_devs = NULL;
   1175          1.159      matt 	cd->cd_ndevs = 0;
   1176          1.117  drochner }
   1177          1.117  drochner 
   1178          1.117  drochner static device_t
   1179          1.117  drochner config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
   1180           1.25       cgd {
   1181           1.50  augustss 	struct cfdriver *cd;
   1182           1.76   thorpej 	struct cfattach *ca;
   1183           1.50  augustss 	size_t lname, lunit;
   1184           1.52       cgd 	const char *xunit;
   1185           1.25       cgd 	int myunit;
   1186           1.25       cgd 	char num[10];
   1187          1.117  drochner 	device_t dev;
   1188          1.120     joerg 	void *dev_private;
   1189           1.96  drochner 	const struct cfiattrdata *ia;
   1190          1.159      matt 	const km_flag_t kmflags = (cold ? KM_NOSLEEP : KM_SLEEP);
   1191           1.25       cgd 
   1192           1.67   thorpej 	cd = config_cfdriver_lookup(cf->cf_name);
   1193          1.117  drochner 	if (cd == NULL)
   1194          1.117  drochner 		return (NULL);
   1195           1.76   thorpej 
   1196           1.76   thorpej 	ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
   1197          1.117  drochner 	if (ca == NULL)
   1198          1.117  drochner 		return (NULL);
   1199           1.76   thorpej 
   1200          1.120     joerg 	if ((ca->ca_flags & DVF_PRIV_ALLOC) == 0 &&
   1201          1.120     joerg 	    ca->ca_devsize < sizeof(struct device))
   1202          1.140      matt 		panic("config_devalloc: %s", cf->cf_atname);
   1203           1.66   thorpej 
   1204           1.46       cgd #ifndef __BROKEN_CONFIG_UNIT_USAGE
   1205           1.45       cgd 	if (cf->cf_fstate == FSTATE_STAR) {
   1206           1.45       cgd 		for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
   1207           1.45       cgd 			if (cd->cd_devs[myunit] == NULL)
   1208           1.45       cgd 				break;
   1209           1.45       cgd 		/*
   1210           1.45       cgd 		 * myunit is now the unit of the first NULL device pointer,
   1211           1.45       cgd 		 * or max(cd->cd_ndevs,cf->cf_unit).
   1212           1.45       cgd 		 */
   1213           1.45       cgd 	} else {
   1214           1.45       cgd 		myunit = cf->cf_unit;
   1215          1.117  drochner 		if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
   1216          1.117  drochner 			return (NULL);
   1217          1.117  drochner 	}
   1218           1.66   thorpej #else
   1219           1.46       cgd 	myunit = cf->cf_unit;
   1220           1.66   thorpej #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
   1221           1.25       cgd 
   1222           1.25       cgd 	/* compute length of name and decimal expansion of unit number */
   1223           1.25       cgd 	lname = strlen(cd->cd_name);
   1224           1.30     perry 	xunit = number(&num[sizeof(num)], myunit);
   1225           1.30     perry 	lunit = &num[sizeof(num)] - xunit;
   1226           1.64  drochner 	if (lname + lunit > sizeof(dev->dv_xname))
   1227          1.117  drochner 		panic("config_devalloc: device name too long");
   1228           1.25       cgd 
   1229           1.25       cgd 	/* get memory for all device vars */
   1230          1.132      matt 	KASSERT((ca->ca_flags & DVF_PRIV_ALLOC) || ca->ca_devsize >= sizeof(struct device));
   1231          1.132      matt 	if (ca->ca_devsize > 0) {
   1232          1.159      matt 		dev_private = kmem_zalloc(ca->ca_devsize, kmflags);
   1233          1.132      matt 		if (dev_private == NULL)
   1234          1.132      matt 			panic("config_devalloc: memory allocation for device softc failed");
   1235          1.132      matt 	} else {
   1236          1.132      matt 		KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
   1237          1.132      matt 		dev_private = NULL;
   1238          1.132      matt 	}
   1239          1.120     joerg 
   1240          1.120     joerg 	if ((ca->ca_flags & DVF_PRIV_ALLOC) != 0) {
   1241          1.159      matt 		dev = kmem_zalloc(sizeof(*dev), kmflags);
   1242          1.120     joerg 	} else {
   1243          1.120     joerg 		dev = dev_private;
   1244          1.120     joerg 	}
   1245          1.120     joerg 	if (dev == NULL)
   1246          1.120     joerg 		panic("config_devalloc: memory allocation for device_t failed");
   1247          1.124  jmcneill 
   1248           1.25       cgd 	dev->dv_class = cd->cd_class;
   1249           1.25       cgd 	dev->dv_cfdata = cf;
   1250           1.76   thorpej 	dev->dv_cfdriver = cd;
   1251           1.76   thorpej 	dev->dv_cfattach = ca;
   1252           1.25       cgd 	dev->dv_unit = myunit;
   1253          1.124  jmcneill 	dev->dv_activity_count = 0;
   1254          1.124  jmcneill 	dev->dv_activity_handlers = NULL;
   1255          1.120     joerg 	dev->dv_private = dev_private;
   1256           1.31     perry 	memcpy(dev->dv_xname, cd->cd_name, lname);
   1257           1.31     perry 	memcpy(dev->dv_xname + lname, xunit, lunit);
   1258           1.25       cgd 	dev->dv_parent = parent;
   1259          1.124  jmcneill 	if (parent != NULL)
   1260          1.124  jmcneill 		dev->dv_depth = parent->dv_depth + 1;
   1261          1.124  jmcneill 	else
   1262          1.124  jmcneill 		dev->dv_depth = 0;
   1263           1.33   thorpej 	dev->dv_flags = DVF_ACTIVE;	/* always initially active */
   1264          1.120     joerg 	dev->dv_flags |= ca->ca_flags;	/* inherit flags from class */
   1265           1.97  drochner 	if (locs) {
   1266           1.96  drochner 		KASSERT(parent); /* no locators at root */
   1267           1.96  drochner 		ia = cfiattr_lookup(cf->cf_pspec->cfp_iattr,
   1268           1.96  drochner 				    parent->dv_cfdriver);
   1269          1.159      matt 		dev->dv_locators =
   1270          1.159      matt 		    kmem_alloc(sizeof(int [ia->ci_loclen + 1]), kmflags);
   1271          1.159      matt 		*dev->dv_locators++ = sizeof(int [ia->ci_loclen + 1]);
   1272          1.159      matt 		memcpy(dev->dv_locators, locs, sizeof(int [ia->ci_loclen]));
   1273           1.90  drochner 	}
   1274          1.112   thorpej 	dev->dv_properties = prop_dictionary_create();
   1275          1.112   thorpej 	KASSERT(dev->dv_properties != NULL);
   1276           1.29   thorpej 
   1277          1.150  jmcneill 	prop_dictionary_set_cstring_nocopy(dev->dv_properties,
   1278          1.150  jmcneill 	    "device-driver", dev->dv_cfdriver->cd_name);
   1279          1.150  jmcneill 	prop_dictionary_set_uint16(dev->dv_properties,
   1280          1.150  jmcneill 	    "device-unit", dev->dv_unit);
   1281          1.150  jmcneill 
   1282          1.117  drochner 	return (dev);
   1283          1.117  drochner }
   1284          1.117  drochner 
   1285          1.117  drochner static void
   1286          1.117  drochner config_devdealloc(device_t dev)
   1287          1.117  drochner {
   1288          1.162  drochner 	int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
   1289          1.117  drochner 
   1290          1.117  drochner 	KASSERT(dev->dv_properties != NULL);
   1291          1.117  drochner 	prop_object_release(dev->dv_properties);
   1292          1.117  drochner 
   1293          1.124  jmcneill 	if (dev->dv_activity_handlers)
   1294          1.124  jmcneill 		panic("config_devdealloc with registered handlers");
   1295          1.124  jmcneill 
   1296          1.159      matt 	if (dev->dv_locators) {
   1297          1.159      matt 		size_t amount = *--dev->dv_locators;
   1298          1.159      matt 		kmem_free(dev->dv_locators, amount);
   1299          1.159      matt 	}
   1300          1.117  drochner 
   1301          1.162  drochner 	if (dev->dv_cfattach->ca_devsize > 0)
   1302          1.159      matt 		kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
   1303          1.162  drochner 	if (priv)
   1304          1.162  drochner 		kmem_free(dev, sizeof(*dev));
   1305          1.117  drochner }
   1306          1.117  drochner 
   1307          1.117  drochner /*
   1308          1.117  drochner  * Attach a found device.
   1309          1.117  drochner  */
   1310          1.117  drochner device_t
   1311          1.117  drochner config_attach_loc(device_t parent, cfdata_t cf,
   1312          1.117  drochner 	const int *locs, void *aux, cfprint_t print)
   1313          1.117  drochner {
   1314          1.117  drochner 	device_t dev;
   1315          1.117  drochner 	struct cftable *ct;
   1316          1.117  drochner 	const char *drvname;
   1317          1.117  drochner 
   1318          1.117  drochner #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
   1319          1.117  drochner 	if (splash_progress_state)
   1320          1.117  drochner 		splash_progress_update(splash_progress_state);
   1321          1.117  drochner #endif
   1322          1.117  drochner 
   1323          1.117  drochner 	dev = config_devalloc(parent, cf, locs);
   1324          1.117  drochner 	if (!dev)
   1325          1.117  drochner 		panic("config_attach: allocation of device softc failed");
   1326          1.117  drochner 
   1327          1.117  drochner 	/* XXX redundant - see below? */
   1328          1.117  drochner 	if (cf->cf_fstate != FSTATE_STAR) {
   1329          1.117  drochner 		KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
   1330          1.117  drochner 		cf->cf_fstate = FSTATE_FOUND;
   1331          1.117  drochner 	}
   1332          1.117  drochner #ifdef __BROKEN_CONFIG_UNIT_USAGE
   1333          1.117  drochner 	  else
   1334          1.117  drochner 		cf->cf_unit++;
   1335          1.117  drochner #endif
   1336          1.117  drochner 
   1337          1.117  drochner 	config_devlink(dev);
   1338          1.117  drochner 
   1339           1.80   thorpej 	if (config_do_twiddle)
   1340           1.80   thorpej 		twiddle();
   1341           1.80   thorpej 	else
   1342           1.80   thorpej 		aprint_naive("Found ");
   1343           1.80   thorpej 	/*
   1344           1.80   thorpej 	 * We want the next two printfs for normal, verbose, and quiet,
   1345           1.80   thorpej 	 * but not silent (in which case, we're twiddling, instead).
   1346           1.80   thorpej 	 */
   1347           1.80   thorpej 	if (parent == ROOT) {
   1348          1.143    cegger 		aprint_naive("%s (root)", device_xname(dev));
   1349          1.143    cegger 		aprint_normal("%s (root)", device_xname(dev));
   1350           1.80   thorpej 	} else {
   1351          1.143    cegger 		aprint_naive("%s at %s", device_xname(dev), device_xname(parent));
   1352          1.143    cegger 		aprint_normal("%s at %s", device_xname(dev), device_xname(parent));
   1353           1.25       cgd 		if (print)
   1354           1.52       cgd 			(void) (*print)(aux, NULL);
   1355           1.25       cgd 	}
   1356           1.25       cgd 
   1357           1.25       cgd 	/*
   1358           1.25       cgd 	 * Before attaching, clobber any unfound devices that are
   1359           1.45       cgd 	 * otherwise identical.
   1360          1.117  drochner 	 * XXX code above is redundant?
   1361           1.25       cgd 	 */
   1362          1.117  drochner 	drvname = dev->dv_cfdriver->cd_name;
   1363           1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
   1364           1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
   1365          1.117  drochner 			if (STREQ(cf->cf_name, drvname) &&
   1366           1.65   thorpej 			    cf->cf_unit == dev->dv_unit) {
   1367           1.65   thorpej 				if (cf->cf_fstate == FSTATE_NOTFOUND)
   1368           1.65   thorpej 					cf->cf_fstate = FSTATE_FOUND;
   1369           1.46       cgd #ifdef __BROKEN_CONFIG_UNIT_USAGE
   1370           1.66   thorpej 				/*
   1371           1.66   thorpej 				 * Bump the unit number on all starred cfdata
   1372           1.66   thorpej 				 * entries for this device.
   1373           1.66   thorpej 				 */
   1374           1.65   thorpej 				if (cf->cf_fstate == FSTATE_STAR)
   1375           1.65   thorpej 					cf->cf_unit++;
   1376           1.46       cgd #endif /* __BROKEN_CONFIG_UNIT_USAGE */
   1377           1.65   thorpej 			}
   1378           1.25       cgd 		}
   1379           1.65   thorpej 	}
   1380           1.49      danw #ifdef __HAVE_DEVICE_REGISTER
   1381           1.25       cgd 	device_register(dev, aux);
   1382           1.25       cgd #endif
   1383          1.124  jmcneill 
   1384          1.149  jmcneill 	/* Let userland know */
   1385          1.149  jmcneill 	devmon_report_device(dev, true);
   1386          1.149  jmcneill 
   1387          1.105  jmcneill #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
   1388          1.105  jmcneill 	if (splash_progress_state)
   1389          1.105  jmcneill 		splash_progress_update(splash_progress_state);
   1390          1.105  jmcneill #endif
   1391          1.117  drochner 	(*dev->dv_cfattach->ca_attach)(parent, dev, aux);
   1392          1.105  jmcneill #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
   1393          1.105  jmcneill 	if (splash_progress_state)
   1394          1.105  jmcneill 		splash_progress_update(splash_progress_state);
   1395          1.105  jmcneill #endif
   1396          1.124  jmcneill 
   1397          1.124  jmcneill 	if (!device_pmf_is_registered(dev))
   1398          1.125  jmcneill 		aprint_debug_dev(dev, "WARNING: power management not supported\n");
   1399          1.124  jmcneill 
   1400           1.42   thorpej 	config_process_deferred(&deferred_config_queue, dev);
   1401           1.25       cgd 	return (dev);
   1402           1.25       cgd }
   1403           1.29   thorpej 
   1404          1.102   thorpej device_t
   1405          1.102   thorpej config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print)
   1406          1.102   thorpej {
   1407          1.102   thorpej 
   1408          1.102   thorpej 	return (config_attach_loc(parent, cf, NULL, aux, print));
   1409          1.102   thorpej }
   1410          1.102   thorpej 
   1411           1.29   thorpej /*
   1412           1.77   thorpej  * As above, but for pseudo-devices.  Pseudo-devices attached in this
   1413           1.77   thorpej  * way are silently inserted into the device tree, and their children
   1414           1.77   thorpej  * attached.
   1415           1.77   thorpej  *
   1416           1.77   thorpej  * Note that because pseudo-devices are attached silently, any information
   1417           1.77   thorpej  * the attach routine wishes to print should be prefixed with the device
   1418           1.77   thorpej  * name by the attach routine.
   1419           1.77   thorpej  */
   1420          1.102   thorpej device_t
   1421          1.102   thorpej config_attach_pseudo(cfdata_t cf)
   1422           1.77   thorpej {
   1423          1.102   thorpej 	device_t dev;
   1424           1.77   thorpej 
   1425          1.117  drochner 	dev = config_devalloc(ROOT, cf, NULL);
   1426          1.117  drochner 	if (!dev)
   1427           1.77   thorpej 		return (NULL);
   1428           1.77   thorpej 
   1429          1.117  drochner 	/* XXX mark busy in cfdata */
   1430           1.77   thorpej 
   1431          1.117  drochner 	config_devlink(dev);
   1432           1.77   thorpej 
   1433           1.77   thorpej #if 0	/* XXXJRT not yet */
   1434           1.77   thorpej #ifdef __HAVE_DEVICE_REGISTER
   1435           1.77   thorpej 	device_register(dev, NULL);	/* like a root node */
   1436           1.77   thorpej #endif
   1437           1.77   thorpej #endif
   1438          1.117  drochner 	(*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
   1439           1.77   thorpej 	config_process_deferred(&deferred_config_queue, dev);
   1440           1.77   thorpej 	return (dev);
   1441           1.77   thorpej }
   1442           1.77   thorpej 
   1443           1.77   thorpej /*
   1444           1.33   thorpej  * Detach a device.  Optionally forced (e.g. because of hardware
   1445           1.33   thorpej  * removal) and quiet.  Returns zero if successful, non-zero
   1446           1.33   thorpej  * (an error code) otherwise.
   1447           1.33   thorpej  *
   1448           1.33   thorpej  * Note that this code wants to be run from a process context, so
   1449           1.33   thorpej  * that the detach can sleep to allow processes which have a device
   1450           1.33   thorpej  * open to run and unwind their stacks.
   1451           1.33   thorpej  */
   1452           1.33   thorpej int
   1453          1.102   thorpej config_detach(device_t dev, int flags)
   1454           1.33   thorpej {
   1455           1.65   thorpej 	struct cftable *ct;
   1456          1.102   thorpej 	cfdata_t cf;
   1457           1.73   thorpej 	const struct cfattach *ca;
   1458           1.33   thorpej 	struct cfdriver *cd;
   1459           1.33   thorpej #ifdef DIAGNOSTIC
   1460          1.102   thorpej 	device_t d;
   1461           1.33   thorpej #endif
   1462          1.117  drochner 	int rv = 0;
   1463           1.33   thorpej 
   1464           1.33   thorpej #ifdef DIAGNOSTIC
   1465          1.161  christos 	cf = dev->dv_cfdata;
   1466          1.161  christos 	if (cf != NULL && cf->cf_fstate != FSTATE_FOUND &&
   1467          1.161  christos 	    cf->cf_fstate != FSTATE_STAR)
   1468          1.161  christos 		panic("config_detach: %s: bad device fstate %d",
   1469          1.161  christos 		    device_xname(dev), cf ? cf->cf_fstate : -1);
   1470           1.33   thorpej #endif
   1471           1.77   thorpej 	cd = dev->dv_cfdriver;
   1472           1.67   thorpej 	KASSERT(cd != NULL);
   1473           1.76   thorpej 
   1474           1.77   thorpej 	ca = dev->dv_cfattach;
   1475           1.76   thorpej 	KASSERT(ca != NULL);
   1476           1.33   thorpej 
   1477          1.136    dyoung 	KASSERT(curlwp != NULL);
   1478          1.136    dyoung 	mutex_enter(&alldevs_mtx);
   1479          1.136    dyoung 	if (alldevs_nwrite > 0 && alldevs_writer == NULL)
   1480          1.136    dyoung 		;
   1481          1.136    dyoung 	else while (alldevs_nread != 0 ||
   1482          1.136    dyoung 	       (alldevs_nwrite != 0 && alldevs_writer != curlwp))
   1483          1.136    dyoung 		cv_wait(&alldevs_cv, &alldevs_mtx);
   1484          1.136    dyoung 	if (alldevs_nwrite++ == 0)
   1485          1.136    dyoung 		alldevs_writer = curlwp;
   1486          1.136    dyoung 	mutex_exit(&alldevs_mtx);
   1487          1.136    dyoung 
   1488           1.33   thorpej 	/*
   1489           1.33   thorpej 	 * Ensure the device is deactivated.  If the device doesn't
   1490           1.33   thorpej 	 * have an activation entry point, we allow DVF_ACTIVE to
   1491           1.33   thorpej 	 * remain set.  Otherwise, if DVF_ACTIVE is still set, the
   1492           1.33   thorpej 	 * device is busy, and the detach fails.
   1493           1.33   thorpej 	 */
   1494           1.35   thorpej 	if (ca->ca_activate != NULL)
   1495           1.35   thorpej 		rv = config_deactivate(dev);
   1496           1.33   thorpej 
   1497           1.33   thorpej 	/*
   1498           1.33   thorpej 	 * Try to detach the device.  If that's not possible, then
   1499           1.33   thorpej 	 * we either panic() (for the forced but failed case), or
   1500           1.33   thorpej 	 * return an error.
   1501           1.33   thorpej 	 */
   1502           1.33   thorpej 	if (rv == 0) {
   1503           1.33   thorpej 		if (ca->ca_detach != NULL)
   1504           1.33   thorpej 			rv = (*ca->ca_detach)(dev, flags);
   1505           1.33   thorpej 		else
   1506           1.33   thorpej 			rv = EOPNOTSUPP;
   1507           1.33   thorpej 	}
   1508           1.33   thorpej 	if (rv != 0) {
   1509           1.33   thorpej 		if ((flags & DETACH_FORCE) == 0)
   1510          1.136    dyoung 			goto out;
   1511           1.33   thorpej 		else
   1512           1.33   thorpej 			panic("config_detach: forced detach of %s failed (%d)",
   1513          1.143    cegger 			    device_xname(dev), rv);
   1514           1.33   thorpej 	}
   1515           1.33   thorpej 
   1516           1.33   thorpej 	/*
   1517           1.33   thorpej 	 * The device has now been successfully detached.
   1518           1.33   thorpej 	 */
   1519           1.33   thorpej 
   1520          1.149  jmcneill 	/* Let userland know */
   1521          1.149  jmcneill 	devmon_report_device(dev, false);
   1522          1.149  jmcneill 
   1523           1.33   thorpej #ifdef DIAGNOSTIC
   1524           1.33   thorpej 	/*
   1525           1.33   thorpej 	 * Sanity: If you're successfully detached, you should have no
   1526           1.33   thorpej 	 * children.  (Note that because children must be attached
   1527           1.33   thorpej 	 * after parents, we only need to search the latter part of
   1528           1.33   thorpej 	 * the list.)
   1529           1.33   thorpej 	 */
   1530           1.33   thorpej 	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
   1531           1.48     enami 	    d = TAILQ_NEXT(d, dv_list)) {
   1532           1.48     enami 		if (d->dv_parent == dev) {
   1533           1.48     enami 			printf("config_detach: detached device %s"
   1534          1.143    cegger 			    " has children %s\n", device_xname(dev), device_xname(d));
   1535           1.48     enami 			panic("config_detach");
   1536           1.48     enami 		}
   1537           1.33   thorpej 	}
   1538           1.33   thorpej #endif
   1539           1.33   thorpej 
   1540           1.90  drochner 	/* notify the parent that the child is gone */
   1541           1.90  drochner 	if (dev->dv_parent) {
   1542          1.102   thorpej 		device_t p = dev->dv_parent;
   1543           1.90  drochner 		if (p->dv_cfattach->ca_childdetached)
   1544           1.90  drochner 			(*p->dv_cfattach->ca_childdetached)(p, dev);
   1545           1.90  drochner 	}
   1546           1.90  drochner 
   1547           1.33   thorpej 	/*
   1548           1.33   thorpej 	 * Mark cfdata to show that the unit can be reused, if possible.
   1549           1.33   thorpej 	 */
   1550           1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
   1551           1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
   1552           1.67   thorpej 			if (STREQ(cf->cf_name, cd->cd_name)) {
   1553           1.65   thorpej 				if (cf->cf_fstate == FSTATE_FOUND &&
   1554           1.65   thorpej 				    cf->cf_unit == dev->dv_unit)
   1555           1.65   thorpej 					cf->cf_fstate = FSTATE_NOTFOUND;
   1556           1.46       cgd #ifdef __BROKEN_CONFIG_UNIT_USAGE
   1557           1.66   thorpej 				/*
   1558           1.66   thorpej 				 * Note that we can only re-use a starred
   1559           1.66   thorpej 				 * unit number if the unit being detached
   1560           1.66   thorpej 				 * had the last assigned unit number.
   1561           1.66   thorpej 				 */
   1562           1.65   thorpej 				if (cf->cf_fstate == FSTATE_STAR &&
   1563           1.65   thorpej 				    cf->cf_unit == dev->dv_unit + 1)
   1564           1.65   thorpej 					cf->cf_unit--;
   1565           1.46       cgd #endif /* __BROKEN_CONFIG_UNIT_USAGE */
   1566           1.65   thorpej 			}
   1567           1.33   thorpej 		}
   1568           1.33   thorpej 	}
   1569           1.33   thorpej 
   1570          1.117  drochner 	config_devunlink(dev);
   1571           1.33   thorpej 
   1572           1.77   thorpej 	if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
   1573          1.136    dyoung 		aprint_normal_dev(dev, "detached\n");
   1574           1.33   thorpej 
   1575          1.117  drochner 	config_devdealloc(dev);
   1576           1.33   thorpej 
   1577          1.136    dyoung out:
   1578          1.136    dyoung 	mutex_enter(&alldevs_mtx);
   1579          1.136    dyoung 	if (--alldevs_nwrite == 0)
   1580          1.136    dyoung 		alldevs_writer = NULL;
   1581          1.136    dyoung 	cv_signal(&alldevs_cv);
   1582          1.136    dyoung 	mutex_exit(&alldevs_mtx);
   1583          1.136    dyoung 	return rv;
   1584           1.33   thorpej }
   1585           1.33   thorpej 
   1586          1.126    dyoung int
   1587          1.126    dyoung config_detach_children(device_t parent, int flags)
   1588          1.126    dyoung {
   1589          1.130  drochner 	device_t dv;
   1590          1.136    dyoung 	deviter_t di;
   1591          1.136    dyoung 	int error = 0;
   1592          1.126    dyoung 
   1593          1.136    dyoung 	for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL;
   1594          1.136    dyoung 	     dv = deviter_next(&di)) {
   1595          1.136    dyoung 		if (device_parent(dv) != parent)
   1596          1.136    dyoung 			continue;
   1597          1.136    dyoung 		if ((error = config_detach(dv, flags)) != 0)
   1598          1.130  drochner 			break;
   1599          1.136    dyoung 	}
   1600          1.136    dyoung 	deviter_release(&di);
   1601          1.130  drochner 	return error;
   1602          1.126    dyoung }
   1603          1.126    dyoung 
   1604           1.33   thorpej int
   1605          1.102   thorpej config_activate(device_t dev)
   1606           1.33   thorpej {
   1607           1.76   thorpej 	const struct cfattach *ca = dev->dv_cfattach;
   1608           1.34   thorpej 	int rv = 0, oflags = dev->dv_flags;
   1609           1.33   thorpej 
   1610           1.33   thorpej 	if (ca->ca_activate == NULL)
   1611           1.33   thorpej 		return (EOPNOTSUPP);
   1612           1.33   thorpej 
   1613           1.33   thorpej 	if ((dev->dv_flags & DVF_ACTIVE) == 0) {
   1614           1.33   thorpej 		dev->dv_flags |= DVF_ACTIVE;
   1615           1.33   thorpej 		rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
   1616           1.34   thorpej 		if (rv)
   1617           1.34   thorpej 			dev->dv_flags = oflags;
   1618           1.33   thorpej 	}
   1619           1.33   thorpej 	return (rv);
   1620           1.33   thorpej }
   1621           1.33   thorpej 
   1622           1.33   thorpej int
   1623          1.102   thorpej config_deactivate(device_t dev)
   1624           1.33   thorpej {
   1625           1.76   thorpej 	const struct cfattach *ca = dev->dv_cfattach;
   1626           1.34   thorpej 	int rv = 0, oflags = dev->dv_flags;
   1627           1.33   thorpej 
   1628           1.33   thorpej 	if (ca->ca_activate == NULL)
   1629           1.33   thorpej 		return (EOPNOTSUPP);
   1630           1.33   thorpej 
   1631           1.33   thorpej 	if (dev->dv_flags & DVF_ACTIVE) {
   1632           1.33   thorpej 		dev->dv_flags &= ~DVF_ACTIVE;
   1633           1.33   thorpej 		rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
   1634           1.34   thorpej 		if (rv)
   1635           1.34   thorpej 			dev->dv_flags = oflags;
   1636           1.33   thorpej 	}
   1637           1.33   thorpej 	return (rv);
   1638           1.33   thorpej }
   1639           1.33   thorpej 
   1640           1.33   thorpej /*
   1641           1.29   thorpej  * Defer the configuration of the specified device until all
   1642           1.29   thorpej  * of its parent's devices have been attached.
   1643           1.29   thorpej  */
   1644           1.29   thorpej void
   1645          1.102   thorpej config_defer(device_t dev, void (*func)(device_t))
   1646           1.29   thorpej {
   1647          1.159      matt 	const km_flag_t kmflags = (cold ? KM_NOSLEEP : KM_SLEEP);
   1648           1.29   thorpej 	struct deferred_config *dc;
   1649           1.29   thorpej 
   1650           1.29   thorpej 	if (dev->dv_parent == NULL)
   1651           1.29   thorpej 		panic("config_defer: can't defer config of a root device");
   1652           1.29   thorpej 
   1653           1.29   thorpej #ifdef DIAGNOSTIC
   1654           1.29   thorpej 	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
   1655           1.29   thorpej 	     dc = TAILQ_NEXT(dc, dc_queue)) {
   1656           1.29   thorpej 		if (dc->dc_dev == dev)
   1657           1.29   thorpej 			panic("config_defer: deferred twice");
   1658           1.29   thorpej 	}
   1659           1.29   thorpej #endif
   1660           1.29   thorpej 
   1661          1.159      matt 	dc = kmem_alloc(sizeof(*dc), kmflags);
   1662           1.43   thorpej 	if (dc == NULL)
   1663           1.43   thorpej 		panic("config_defer: unable to allocate callback");
   1664           1.29   thorpej 
   1665           1.29   thorpej 	dc->dc_dev = dev;
   1666           1.29   thorpej 	dc->dc_func = func;
   1667           1.29   thorpej 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
   1668           1.47   thorpej 	config_pending_incr();
   1669           1.29   thorpej }
   1670           1.29   thorpej 
   1671           1.29   thorpej /*
   1672           1.42   thorpej  * Defer some autoconfiguration for a device until after interrupts
   1673           1.42   thorpej  * are enabled.
   1674           1.42   thorpej  */
   1675           1.42   thorpej void
   1676          1.102   thorpej config_interrupts(device_t dev, void (*func)(device_t))
   1677           1.42   thorpej {
   1678          1.159      matt 	const km_flag_t kmflags = (cold ? KM_NOSLEEP : KM_SLEEP);
   1679           1.42   thorpej 	struct deferred_config *dc;
   1680           1.42   thorpej 
   1681           1.42   thorpej 	/*
   1682           1.42   thorpej 	 * If interrupts are enabled, callback now.
   1683           1.42   thorpej 	 */
   1684           1.43   thorpej 	if (cold == 0) {
   1685           1.42   thorpej 		(*func)(dev);
   1686           1.42   thorpej 		return;
   1687           1.42   thorpej 	}
   1688           1.42   thorpej 
   1689           1.42   thorpej #ifdef DIAGNOSTIC
   1690           1.42   thorpej 	for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
   1691           1.42   thorpej 	     dc = TAILQ_NEXT(dc, dc_queue)) {
   1692           1.42   thorpej 		if (dc->dc_dev == dev)
   1693           1.42   thorpej 			panic("config_interrupts: deferred twice");
   1694           1.42   thorpej 	}
   1695           1.42   thorpej #endif
   1696           1.42   thorpej 
   1697          1.159      matt 	dc = kmem_alloc(sizeof(*dc), kmflags);
   1698           1.43   thorpej 	if (dc == NULL)
   1699           1.43   thorpej 		panic("config_interrupts: unable to allocate callback");
   1700           1.42   thorpej 
   1701           1.42   thorpej 	dc->dc_dev = dev;
   1702           1.42   thorpej 	dc->dc_func = func;
   1703           1.42   thorpej 	TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
   1704           1.47   thorpej 	config_pending_incr();
   1705           1.42   thorpej }
   1706           1.42   thorpej 
   1707           1.42   thorpej /*
   1708           1.42   thorpej  * Process a deferred configuration queue.
   1709           1.29   thorpej  */
   1710           1.29   thorpej static void
   1711           1.51       cgd config_process_deferred(struct deferred_config_head *queue,
   1712          1.102   thorpej     device_t parent)
   1713           1.29   thorpej {
   1714           1.29   thorpej 	struct deferred_config *dc, *ndc;
   1715           1.29   thorpej 
   1716           1.42   thorpej 	for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
   1717           1.29   thorpej 		ndc = TAILQ_NEXT(dc, dc_queue);
   1718           1.42   thorpej 		if (parent == NULL || dc->dc_dev->dv_parent == parent) {
   1719           1.42   thorpej 			TAILQ_REMOVE(queue, dc, dc_queue);
   1720           1.29   thorpej 			(*dc->dc_func)(dc->dc_dev);
   1721          1.159      matt 			kmem_free(dc, sizeof(*dc));
   1722           1.47   thorpej 			config_pending_decr();
   1723           1.29   thorpej 		}
   1724           1.29   thorpej 	}
   1725           1.47   thorpej }
   1726           1.47   thorpej 
   1727           1.47   thorpej /*
   1728           1.47   thorpej  * Manipulate the config_pending semaphore.
   1729           1.47   thorpej  */
   1730           1.47   thorpej void
   1731           1.51       cgd config_pending_incr(void)
   1732           1.47   thorpej {
   1733           1.47   thorpej 
   1734          1.151        ad 	mutex_enter(&config_misc_lock);
   1735           1.47   thorpej 	config_pending++;
   1736          1.151        ad 	mutex_exit(&config_misc_lock);
   1737           1.47   thorpej }
   1738           1.47   thorpej 
   1739           1.47   thorpej void
   1740           1.51       cgd config_pending_decr(void)
   1741           1.47   thorpej {
   1742           1.47   thorpej 
   1743           1.47   thorpej #ifdef DIAGNOSTIC
   1744           1.47   thorpej 	if (config_pending == 0)
   1745           1.47   thorpej 		panic("config_pending_decr: config_pending == 0");
   1746           1.47   thorpej #endif
   1747          1.151        ad 	mutex_enter(&config_misc_lock);
   1748           1.47   thorpej 	config_pending--;
   1749           1.47   thorpej 	if (config_pending == 0)
   1750          1.151        ad 		cv_broadcast(&config_misc_cv);
   1751          1.151        ad 	mutex_exit(&config_misc_lock);
   1752           1.75   thorpej }
   1753           1.75   thorpej 
   1754           1.75   thorpej /*
   1755           1.75   thorpej  * Register a "finalization" routine.  Finalization routines are
   1756           1.75   thorpej  * called iteratively once all real devices have been found during
   1757           1.75   thorpej  * autoconfiguration, for as long as any one finalizer has done
   1758           1.75   thorpej  * any work.
   1759           1.75   thorpej  */
   1760           1.75   thorpej int
   1761          1.102   thorpej config_finalize_register(device_t dev, int (*fn)(device_t))
   1762           1.75   thorpej {
   1763           1.75   thorpej 	struct finalize_hook *f;
   1764           1.75   thorpej 
   1765           1.75   thorpej 	/*
   1766           1.75   thorpej 	 * If finalization has already been done, invoke the
   1767           1.75   thorpej 	 * callback function now.
   1768           1.75   thorpej 	 */
   1769           1.75   thorpej 	if (config_finalize_done) {
   1770           1.75   thorpej 		while ((*fn)(dev) != 0)
   1771           1.75   thorpej 			/* loop */ ;
   1772           1.75   thorpej 	}
   1773           1.75   thorpej 
   1774           1.75   thorpej 	/* Ensure this isn't already on the list. */
   1775           1.75   thorpej 	TAILQ_FOREACH(f, &config_finalize_list, f_list) {
   1776           1.75   thorpej 		if (f->f_func == fn && f->f_dev == dev)
   1777           1.75   thorpej 			return (EEXIST);
   1778           1.75   thorpej 	}
   1779           1.75   thorpej 
   1780          1.159      matt 	f = kmem_alloc(sizeof(*f), KM_SLEEP);
   1781           1.75   thorpej 	f->f_func = fn;
   1782           1.75   thorpej 	f->f_dev = dev;
   1783           1.75   thorpej 	TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
   1784           1.75   thorpej 
   1785           1.75   thorpej 	return (0);
   1786           1.75   thorpej }
   1787           1.75   thorpej 
   1788           1.75   thorpej void
   1789           1.75   thorpej config_finalize(void)
   1790           1.75   thorpej {
   1791           1.75   thorpej 	struct finalize_hook *f;
   1792          1.142        ad 	struct pdevinit *pdev;
   1793          1.142        ad 	extern struct pdevinit pdevinit[];
   1794          1.142        ad 	int errcnt, rv;
   1795          1.142        ad 
   1796          1.142        ad 	/*
   1797          1.142        ad 	 * Now that device driver threads have been created, wait for
   1798          1.142        ad 	 * them to finish any deferred autoconfiguration.
   1799          1.142        ad 	 */
   1800          1.151        ad 	mutex_enter(&config_misc_lock);
   1801          1.151        ad 	while (config_pending != 0)
   1802          1.151        ad 		cv_wait(&config_misc_cv, &config_misc_lock);
   1803          1.151        ad 	mutex_exit(&config_misc_lock);
   1804          1.142        ad 
   1805      1.163.4.1       snj 	KERNEL_LOCK(1, NULL);
   1806      1.163.4.1       snj 
   1807          1.142        ad 	/* Attach pseudo-devices. */
   1808          1.142        ad 	for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
   1809          1.142        ad 		(*pdev->pdev_attach)(pdev->pdev_count);
   1810           1.75   thorpej 
   1811           1.75   thorpej 	/* Run the hooks until none of them does any work. */
   1812           1.75   thorpej 	do {
   1813           1.75   thorpej 		rv = 0;
   1814           1.75   thorpej 		TAILQ_FOREACH(f, &config_finalize_list, f_list)
   1815           1.75   thorpej 			rv |= (*f->f_func)(f->f_dev);
   1816           1.75   thorpej 	} while (rv != 0);
   1817           1.75   thorpej 
   1818           1.75   thorpej 	config_finalize_done = 1;
   1819           1.75   thorpej 
   1820           1.75   thorpej 	/* Now free all the hooks. */
   1821           1.75   thorpej 	while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
   1822           1.75   thorpej 		TAILQ_REMOVE(&config_finalize_list, f, f_list);
   1823          1.159      matt 		kmem_free(f, sizeof(*f));
   1824           1.79   thorpej 	}
   1825          1.142        ad 
   1826      1.163.4.1       snj 	KERNEL_UNLOCK_ONE(NULL);
   1827      1.163.4.1       snj 
   1828          1.142        ad 	errcnt = aprint_get_error_count();
   1829          1.142        ad 	if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
   1830          1.142        ad 	    (boothowto & AB_VERBOSE) == 0) {
   1831          1.142        ad 		if (config_do_twiddle) {
   1832          1.142        ad 			config_do_twiddle = 0;
   1833          1.142        ad 			printf_nolog("done.\n");
   1834          1.142        ad 		}
   1835          1.142        ad 		if (errcnt != 0) {
   1836          1.142        ad 			printf("WARNING: %d error%s while detecting hardware; "
   1837          1.142        ad 			    "check system log.\n", errcnt,
   1838          1.142        ad 			    errcnt == 1 ? "" : "s");
   1839          1.142        ad 		}
   1840          1.142        ad 	}
   1841           1.79   thorpej }
   1842           1.79   thorpej 
   1843          1.104   thorpej /*
   1844          1.107   thorpej  * device_lookup:
   1845          1.107   thorpej  *
   1846          1.107   thorpej  *	Look up a device instance for a given driver.
   1847          1.107   thorpej  */
   1848          1.156  drochner device_t
   1849          1.107   thorpej device_lookup(cfdriver_t cd, int unit)
   1850          1.107   thorpej {
   1851          1.107   thorpej 
   1852          1.107   thorpej 	if (unit < 0 || unit >= cd->cd_ndevs)
   1853          1.107   thorpej 		return (NULL);
   1854          1.107   thorpej 
   1855          1.107   thorpej 	return (cd->cd_devs[unit]);
   1856          1.107   thorpej }
   1857          1.107   thorpej 
   1858          1.107   thorpej /*
   1859          1.140      matt  * device_lookup:
   1860          1.140      matt  *
   1861          1.140      matt  *	Look up a device instance for a given driver.
   1862          1.140      matt  */
   1863          1.140      matt void *
   1864          1.140      matt device_lookup_private(cfdriver_t cd, int unit)
   1865          1.140      matt {
   1866          1.140      matt 	device_t dv;
   1867          1.140      matt 
   1868          1.140      matt 	if (unit < 0 || unit >= cd->cd_ndevs)
   1869          1.140      matt 		return NULL;
   1870          1.140      matt 
   1871          1.140      matt 	if ((dv = cd->cd_devs[unit]) == NULL)
   1872          1.140      matt 		return NULL;
   1873          1.140      matt 
   1874          1.140      matt 	return dv->dv_private;
   1875          1.140      matt }
   1876          1.140      matt 
   1877          1.140      matt /*
   1878          1.107   thorpej  * Accessor functions for the device_t type.
   1879          1.107   thorpej  */
   1880          1.107   thorpej devclass_t
   1881          1.107   thorpej device_class(device_t dev)
   1882          1.107   thorpej {
   1883          1.107   thorpej 
   1884          1.107   thorpej 	return (dev->dv_class);
   1885          1.107   thorpej }
   1886          1.107   thorpej 
   1887          1.107   thorpej cfdata_t
   1888          1.107   thorpej device_cfdata(device_t dev)
   1889          1.107   thorpej {
   1890          1.107   thorpej 
   1891          1.107   thorpej 	return (dev->dv_cfdata);
   1892          1.107   thorpej }
   1893          1.107   thorpej 
   1894          1.107   thorpej cfdriver_t
   1895          1.107   thorpej device_cfdriver(device_t dev)
   1896          1.107   thorpej {
   1897          1.107   thorpej 
   1898          1.107   thorpej 	return (dev->dv_cfdriver);
   1899          1.107   thorpej }
   1900          1.107   thorpej 
   1901          1.107   thorpej cfattach_t
   1902          1.107   thorpej device_cfattach(device_t dev)
   1903          1.107   thorpej {
   1904          1.107   thorpej 
   1905          1.107   thorpej 	return (dev->dv_cfattach);
   1906          1.107   thorpej }
   1907          1.107   thorpej 
   1908          1.107   thorpej int
   1909          1.107   thorpej device_unit(device_t dev)
   1910          1.107   thorpej {
   1911          1.107   thorpej 
   1912          1.107   thorpej 	return (dev->dv_unit);
   1913          1.107   thorpej }
   1914          1.107   thorpej 
   1915          1.107   thorpej const char *
   1916          1.107   thorpej device_xname(device_t dev)
   1917          1.107   thorpej {
   1918          1.107   thorpej 
   1919          1.107   thorpej 	return (dev->dv_xname);
   1920          1.107   thorpej }
   1921          1.107   thorpej 
   1922          1.107   thorpej device_t
   1923          1.107   thorpej device_parent(device_t dev)
   1924          1.107   thorpej {
   1925          1.107   thorpej 
   1926          1.107   thorpej 	return (dev->dv_parent);
   1927          1.107   thorpej }
   1928          1.107   thorpej 
   1929          1.116   thorpej bool
   1930          1.107   thorpej device_is_active(device_t dev)
   1931          1.107   thorpej {
   1932          1.124  jmcneill 	int active_flags;
   1933          1.124  jmcneill 
   1934          1.124  jmcneill 	active_flags = DVF_ACTIVE;
   1935          1.124  jmcneill 	active_flags |= DVF_CLASS_SUSPENDED;
   1936          1.124  jmcneill 	active_flags |= DVF_DRIVER_SUSPENDED;
   1937          1.124  jmcneill 	active_flags |= DVF_BUS_SUSPENDED;
   1938          1.124  jmcneill 
   1939          1.124  jmcneill 	return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
   1940          1.124  jmcneill }
   1941          1.124  jmcneill 
   1942          1.124  jmcneill bool
   1943          1.124  jmcneill device_is_enabled(device_t dev)
   1944          1.124  jmcneill {
   1945          1.124  jmcneill 	return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
   1946          1.124  jmcneill }
   1947          1.124  jmcneill 
   1948          1.124  jmcneill bool
   1949          1.124  jmcneill device_has_power(device_t dev)
   1950          1.124  jmcneill {
   1951          1.124  jmcneill 	int active_flags;
   1952          1.124  jmcneill 
   1953          1.124  jmcneill 	active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
   1954          1.107   thorpej 
   1955          1.124  jmcneill 	return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
   1956          1.107   thorpej }
   1957          1.107   thorpej 
   1958          1.109   thorpej int
   1959          1.111   thorpej device_locator(device_t dev, u_int locnum)
   1960          1.107   thorpej {
   1961          1.107   thorpej 
   1962          1.109   thorpej 	KASSERT(dev->dv_locators != NULL);
   1963          1.109   thorpej 	return (dev->dv_locators[locnum]);
   1964          1.107   thorpej }
   1965          1.108   thorpej 
   1966          1.110   thorpej void *
   1967          1.110   thorpej device_private(device_t dev)
   1968          1.110   thorpej {
   1969          1.110   thorpej 
   1970          1.134      cube 	/*
   1971          1.134      cube 	 * The reason why device_private(NULL) is allowed is to simplify the
   1972          1.134      cube 	 * work of a lot of userspace request handlers (i.e., c/bdev
   1973          1.134      cube 	 * handlers) which grab cfdriver_t->cd_units[n].
   1974          1.134      cube 	 * It avoids having them test for it to be NULL and only then calling
   1975          1.134      cube 	 * device_private.
   1976          1.134      cube 	 */
   1977          1.134      cube 	return dev == NULL ? NULL : dev->dv_private;
   1978          1.110   thorpej }
   1979          1.110   thorpej 
   1980          1.112   thorpej prop_dictionary_t
   1981          1.112   thorpej device_properties(device_t dev)
   1982          1.112   thorpej {
   1983          1.112   thorpej 
   1984          1.112   thorpej 	return (dev->dv_properties);
   1985          1.112   thorpej }
   1986          1.112   thorpej 
   1987          1.108   thorpej /*
   1988          1.108   thorpej  * device_is_a:
   1989          1.108   thorpej  *
   1990          1.108   thorpej  *	Returns true if the device is an instance of the specified
   1991          1.108   thorpej  *	driver.
   1992          1.108   thorpej  */
   1993          1.116   thorpej bool
   1994          1.108   thorpej device_is_a(device_t dev, const char *dname)
   1995          1.108   thorpej {
   1996          1.108   thorpej 
   1997          1.108   thorpej 	return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
   1998          1.108   thorpej }
   1999          1.124  jmcneill 
   2000          1.124  jmcneill /*
   2001          1.131     joerg  * device_find_by_xname:
   2002          1.131     joerg  *
   2003          1.131     joerg  *	Returns the device of the given name or NULL if it doesn't exist.
   2004          1.131     joerg  */
   2005          1.131     joerg device_t
   2006          1.131     joerg device_find_by_xname(const char *name)
   2007          1.131     joerg {
   2008          1.131     joerg 	device_t dv;
   2009          1.136    dyoung 	deviter_t di;
   2010          1.131     joerg 
   2011          1.136    dyoung 	for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) {
   2012          1.131     joerg 		if (strcmp(device_xname(dv), name) == 0)
   2013          1.131     joerg 			break;
   2014          1.131     joerg 	}
   2015          1.136    dyoung 	deviter_release(&di);
   2016          1.131     joerg 
   2017          1.131     joerg 	return dv;
   2018          1.131     joerg }
   2019          1.131     joerg 
   2020          1.131     joerg /*
   2021          1.131     joerg  * device_find_by_driver_unit:
   2022          1.131     joerg  *
   2023          1.131     joerg  *	Returns the device of the given driver name and unit or
   2024          1.131     joerg  *	NULL if it doesn't exist.
   2025          1.131     joerg  */
   2026          1.131     joerg device_t
   2027          1.131     joerg device_find_by_driver_unit(const char *name, int unit)
   2028          1.131     joerg {
   2029          1.131     joerg 	struct cfdriver *cd;
   2030          1.131     joerg 
   2031          1.131     joerg 	if ((cd = config_cfdriver_lookup(name)) == NULL)
   2032          1.131     joerg 		return NULL;
   2033          1.131     joerg 	return device_lookup(cd, unit);
   2034          1.131     joerg }
   2035          1.131     joerg 
   2036          1.131     joerg /*
   2037          1.124  jmcneill  * Power management related functions.
   2038          1.124  jmcneill  */
   2039          1.124  jmcneill 
   2040          1.124  jmcneill bool
   2041          1.124  jmcneill device_pmf_is_registered(device_t dev)
   2042          1.124  jmcneill {
   2043          1.124  jmcneill 	return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
   2044          1.124  jmcneill }
   2045          1.124  jmcneill 
   2046          1.124  jmcneill bool
   2047          1.135    dyoung device_pmf_driver_suspend(device_t dev PMF_FN_ARGS)
   2048          1.124  jmcneill {
   2049          1.124  jmcneill 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
   2050          1.124  jmcneill 		return true;
   2051          1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
   2052          1.124  jmcneill 		return false;
   2053          1.124  jmcneill 	if (*dev->dv_driver_suspend != NULL &&
   2054          1.135    dyoung 	    !(*dev->dv_driver_suspend)(dev PMF_FN_CALL))
   2055          1.124  jmcneill 		return false;
   2056          1.124  jmcneill 
   2057          1.124  jmcneill 	dev->dv_flags |= DVF_DRIVER_SUSPENDED;
   2058          1.124  jmcneill 	return true;
   2059          1.124  jmcneill }
   2060          1.124  jmcneill 
   2061          1.124  jmcneill bool
   2062          1.135    dyoung device_pmf_driver_resume(device_t dev PMF_FN_ARGS)
   2063          1.124  jmcneill {
   2064          1.124  jmcneill 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
   2065          1.124  jmcneill 		return true;
   2066          1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
   2067          1.124  jmcneill 		return false;
   2068          1.141    dyoung 	if ((flags & PMF_F_SELF) != 0 && !device_is_self_suspended(dev))
   2069          1.141    dyoung 		return false;
   2070          1.124  jmcneill 	if (*dev->dv_driver_resume != NULL &&
   2071          1.135    dyoung 	    !(*dev->dv_driver_resume)(dev PMF_FN_CALL))
   2072          1.124  jmcneill 		return false;
   2073          1.124  jmcneill 
   2074          1.124  jmcneill 	dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
   2075          1.124  jmcneill 	return true;
   2076          1.124  jmcneill }
   2077          1.124  jmcneill 
   2078          1.133  drochner bool
   2079          1.133  drochner device_pmf_driver_shutdown(device_t dev, int how)
   2080          1.133  drochner {
   2081          1.133  drochner 
   2082          1.133  drochner 	if (*dev->dv_driver_shutdown != NULL &&
   2083          1.133  drochner 	    !(*dev->dv_driver_shutdown)(dev, how))
   2084          1.133  drochner 		return false;
   2085          1.133  drochner 	return true;
   2086          1.133  drochner }
   2087          1.133  drochner 
   2088          1.135    dyoung bool
   2089          1.124  jmcneill device_pmf_driver_register(device_t dev,
   2090          1.135    dyoung     bool (*suspend)(device_t PMF_FN_PROTO),
   2091          1.135    dyoung     bool (*resume)(device_t PMF_FN_PROTO),
   2092          1.133  drochner     bool (*shutdown)(device_t, int))
   2093          1.124  jmcneill {
   2094          1.139    dyoung 	pmf_private_t *pp;
   2095          1.139    dyoung 
   2096          1.159      matt 	if ((pp = kmem_zalloc(sizeof(*pp), KM_NOSLEEP)) == NULL)
   2097          1.139    dyoung 		return false;
   2098          1.139    dyoung 	mutex_init(&pp->pp_mtx, MUTEX_DEFAULT, IPL_NONE);
   2099          1.139    dyoung 	cv_init(&pp->pp_cv, "pmfsusp");
   2100          1.139    dyoung 	dev->dv_pmf_private = pp;
   2101          1.139    dyoung 
   2102          1.124  jmcneill 	dev->dv_driver_suspend = suspend;
   2103          1.124  jmcneill 	dev->dv_driver_resume = resume;
   2104          1.133  drochner 	dev->dv_driver_shutdown = shutdown;
   2105          1.124  jmcneill 	dev->dv_flags |= DVF_POWER_HANDLERS;
   2106          1.135    dyoung 	return true;
   2107          1.124  jmcneill }
   2108          1.124  jmcneill 
   2109          1.139    dyoung static const char *
   2110          1.139    dyoung curlwp_name(void)
   2111          1.139    dyoung {
   2112          1.139    dyoung 	if (curlwp->l_name != NULL)
   2113          1.139    dyoung 		return curlwp->l_name;
   2114          1.139    dyoung 	else
   2115          1.139    dyoung 		return curlwp->l_proc->p_comm;
   2116          1.139    dyoung }
   2117          1.139    dyoung 
   2118          1.124  jmcneill void
   2119          1.124  jmcneill device_pmf_driver_deregister(device_t dev)
   2120          1.124  jmcneill {
   2121          1.139    dyoung 	pmf_private_t *pp = dev->dv_pmf_private;
   2122          1.139    dyoung 
   2123          1.157  drochner 	/* XXX avoid crash in case we are not initialized */
   2124          1.157  drochner 	if (!pp)
   2125          1.157  drochner 		return;
   2126          1.157  drochner 
   2127          1.124  jmcneill 	dev->dv_driver_suspend = NULL;
   2128          1.124  jmcneill 	dev->dv_driver_resume = NULL;
   2129          1.139    dyoung 
   2130          1.139    dyoung 	mutex_enter(&pp->pp_mtx);
   2131          1.124  jmcneill 	dev->dv_flags &= ~DVF_POWER_HANDLERS;
   2132          1.139    dyoung 	while (pp->pp_nlock > 0 || pp->pp_nwait > 0) {
   2133          1.139    dyoung 		/* Wake a thread that waits for the lock.  That
   2134          1.139    dyoung 		 * thread will fail to acquire the lock, and then
   2135          1.139    dyoung 		 * it will wake the next thread that waits for the
   2136          1.139    dyoung 		 * lock, or else it will wake us.
   2137          1.139    dyoung 		 */
   2138          1.139    dyoung 		cv_signal(&pp->pp_cv);
   2139          1.139    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2140          1.139    dyoung 		cv_wait(&pp->pp_cv, &pp->pp_mtx);
   2141          1.139    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2142          1.139    dyoung 	}
   2143          1.155    dyoung 	dev->dv_pmf_private = NULL;
   2144          1.139    dyoung 	mutex_exit(&pp->pp_mtx);
   2145          1.139    dyoung 
   2146          1.139    dyoung 	cv_destroy(&pp->pp_cv);
   2147          1.139    dyoung 	mutex_destroy(&pp->pp_mtx);
   2148          1.159      matt 	kmem_free(pp, sizeof(*pp));
   2149          1.124  jmcneill }
   2150          1.124  jmcneill 
   2151          1.124  jmcneill bool
   2152          1.124  jmcneill device_pmf_driver_child_register(device_t dev)
   2153          1.124  jmcneill {
   2154          1.124  jmcneill 	device_t parent = device_parent(dev);
   2155          1.124  jmcneill 
   2156          1.124  jmcneill 	if (parent == NULL || parent->dv_driver_child_register == NULL)
   2157          1.124  jmcneill 		return true;
   2158          1.124  jmcneill 	return (*parent->dv_driver_child_register)(dev);
   2159          1.124  jmcneill }
   2160          1.124  jmcneill 
   2161          1.124  jmcneill void
   2162          1.124  jmcneill device_pmf_driver_set_child_register(device_t dev,
   2163          1.124  jmcneill     bool (*child_register)(device_t))
   2164          1.124  jmcneill {
   2165          1.124  jmcneill 	dev->dv_driver_child_register = child_register;
   2166          1.124  jmcneill }
   2167          1.124  jmcneill 
   2168          1.141    dyoung void
   2169          1.141    dyoung device_pmf_self_resume(device_t dev PMF_FN_ARGS)
   2170          1.141    dyoung {
   2171          1.141    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2172          1.141    dyoung 	if ((dev->dv_flags & DVF_SELF_SUSPENDED) != 0)
   2173          1.141    dyoung 		dev->dv_flags &= ~DVF_SELF_SUSPENDED;
   2174          1.141    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2175          1.141    dyoung }
   2176          1.141    dyoung 
   2177          1.141    dyoung bool
   2178          1.141    dyoung device_is_self_suspended(device_t dev)
   2179          1.141    dyoung {
   2180          1.141    dyoung 	return (dev->dv_flags & DVF_SELF_SUSPENDED) != 0;
   2181          1.141    dyoung }
   2182          1.141    dyoung 
   2183          1.141    dyoung void
   2184          1.141    dyoung device_pmf_self_suspend(device_t dev PMF_FN_ARGS)
   2185          1.141    dyoung {
   2186          1.141    dyoung 	bool self = (flags & PMF_F_SELF) != 0;
   2187          1.141    dyoung 
   2188          1.141    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2189          1.141    dyoung 
   2190          1.141    dyoung 	if (!self)
   2191          1.141    dyoung 		dev->dv_flags &= ~DVF_SELF_SUSPENDED;
   2192          1.141    dyoung 	else if (device_is_active(dev))
   2193          1.141    dyoung 		dev->dv_flags |= DVF_SELF_SUSPENDED;
   2194          1.141    dyoung 
   2195          1.141    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2196          1.141    dyoung }
   2197          1.141    dyoung 
   2198          1.139    dyoung static void
   2199          1.139    dyoung pmflock_debug(device_t dev, const char *func, int line)
   2200          1.139    dyoung {
   2201          1.139    dyoung 	pmf_private_t *pp = device_pmf_private(dev);
   2202          1.139    dyoung 
   2203          1.139    dyoung 	aprint_debug_dev(dev, "%s.%d, %s pp_nlock %d pp_nwait %d dv_flags %x\n",
   2204          1.139    dyoung 	    func, line, curlwp_name(), pp->pp_nlock, pp->pp_nwait,
   2205          1.139    dyoung 	    dev->dv_flags);
   2206          1.139    dyoung }
   2207          1.139    dyoung 
   2208          1.139    dyoung static void
   2209          1.139    dyoung pmflock_debug_with_flags(device_t dev, const char *func, int line PMF_FN_ARGS)
   2210          1.139    dyoung {
   2211          1.139    dyoung 	pmf_private_t *pp = device_pmf_private(dev);
   2212          1.139    dyoung 
   2213          1.139    dyoung 	aprint_debug_dev(dev, "%s.%d, %s pp_nlock %d pp_nwait %d dv_flags %x "
   2214          1.139    dyoung 	    "flags " PMF_FLAGS_FMT "\n", func, line, curlwp_name(),
   2215          1.139    dyoung 	    pp->pp_nlock, pp->pp_nwait, dev->dv_flags PMF_FN_CALL);
   2216          1.139    dyoung }
   2217          1.139    dyoung 
   2218          1.139    dyoung static bool
   2219          1.139    dyoung device_pmf_lock1(device_t dev PMF_FN_ARGS)
   2220          1.139    dyoung {
   2221          1.139    dyoung 	pmf_private_t *pp = device_pmf_private(dev);
   2222          1.139    dyoung 
   2223          1.155    dyoung 	while (device_pmf_is_registered(dev) &&
   2224          1.155    dyoung 	    pp->pp_nlock > 0 && pp->pp_holder != curlwp) {
   2225          1.139    dyoung 		pp->pp_nwait++;
   2226          1.139    dyoung 		pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2227          1.139    dyoung 		cv_wait(&pp->pp_cv, &pp->pp_mtx);
   2228          1.139    dyoung 		pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2229          1.139    dyoung 		pp->pp_nwait--;
   2230          1.139    dyoung 	}
   2231          1.139    dyoung 	if (!device_pmf_is_registered(dev)) {
   2232          1.139    dyoung 		pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2233          1.139    dyoung 		/* We could not acquire the lock, but some other thread may
   2234          1.139    dyoung 		 * wait for it, also.  Wake that thread.
   2235          1.139    dyoung 		 */
   2236          1.139    dyoung 		cv_signal(&pp->pp_cv);
   2237          1.139    dyoung 		return false;
   2238          1.139    dyoung 	}
   2239          1.139    dyoung 	pp->pp_nlock++;
   2240          1.139    dyoung 	pp->pp_holder = curlwp;
   2241          1.139    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2242          1.139    dyoung 	return true;
   2243          1.139    dyoung }
   2244          1.139    dyoung 
   2245          1.139    dyoung bool
   2246          1.139    dyoung device_pmf_lock(device_t dev PMF_FN_ARGS)
   2247          1.139    dyoung {
   2248          1.139    dyoung 	bool rc;
   2249          1.139    dyoung 	pmf_private_t *pp = device_pmf_private(dev);
   2250          1.139    dyoung 
   2251          1.139    dyoung 	mutex_enter(&pp->pp_mtx);
   2252          1.139    dyoung 	rc = device_pmf_lock1(dev PMF_FN_CALL);
   2253          1.139    dyoung 	mutex_exit(&pp->pp_mtx);
   2254          1.139    dyoung 
   2255          1.139    dyoung 	return rc;
   2256          1.139    dyoung }
   2257          1.139    dyoung 
   2258          1.139    dyoung void
   2259          1.139    dyoung device_pmf_unlock(device_t dev PMF_FN_ARGS)
   2260          1.139    dyoung {
   2261          1.139    dyoung 	pmf_private_t *pp = device_pmf_private(dev);
   2262          1.139    dyoung 
   2263          1.139    dyoung 	KASSERT(pp->pp_nlock > 0);
   2264          1.139    dyoung 	mutex_enter(&pp->pp_mtx);
   2265          1.139    dyoung 	if (--pp->pp_nlock == 0)
   2266          1.139    dyoung 		pp->pp_holder = NULL;
   2267          1.139    dyoung 	cv_signal(&pp->pp_cv);
   2268          1.139    dyoung 	pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
   2269          1.139    dyoung 	mutex_exit(&pp->pp_mtx);
   2270          1.139    dyoung }
   2271          1.139    dyoung 
   2272          1.139    dyoung void *
   2273          1.139    dyoung device_pmf_private(device_t dev)
   2274          1.139    dyoung {
   2275          1.139    dyoung 	return dev->dv_pmf_private;
   2276          1.139    dyoung }
   2277          1.139    dyoung 
   2278          1.124  jmcneill void *
   2279          1.124  jmcneill device_pmf_bus_private(device_t dev)
   2280          1.124  jmcneill {
   2281          1.124  jmcneill 	return dev->dv_bus_private;
   2282          1.124  jmcneill }
   2283          1.124  jmcneill 
   2284          1.124  jmcneill bool
   2285          1.135    dyoung device_pmf_bus_suspend(device_t dev PMF_FN_ARGS)
   2286          1.124  jmcneill {
   2287          1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
   2288          1.124  jmcneill 		return true;
   2289          1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
   2290          1.124  jmcneill 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
   2291          1.124  jmcneill 		return false;
   2292          1.124  jmcneill 	if (*dev->dv_bus_suspend != NULL &&
   2293          1.135    dyoung 	    !(*dev->dv_bus_suspend)(dev PMF_FN_CALL))
   2294          1.124  jmcneill 		return false;
   2295          1.124  jmcneill 
   2296          1.124  jmcneill 	dev->dv_flags |= DVF_BUS_SUSPENDED;
   2297          1.124  jmcneill 	return true;
   2298          1.124  jmcneill }
   2299          1.124  jmcneill 
   2300          1.124  jmcneill bool
   2301          1.135    dyoung device_pmf_bus_resume(device_t dev PMF_FN_ARGS)
   2302          1.124  jmcneill {
   2303          1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
   2304          1.124  jmcneill 		return true;
   2305          1.141    dyoung 	if ((flags & PMF_F_SELF) != 0 && !device_is_self_suspended(dev))
   2306          1.141    dyoung 		return false;
   2307          1.124  jmcneill 	if (*dev->dv_bus_resume != NULL &&
   2308          1.135    dyoung 	    !(*dev->dv_bus_resume)(dev PMF_FN_CALL))
   2309          1.124  jmcneill 		return false;
   2310          1.124  jmcneill 
   2311          1.124  jmcneill 	dev->dv_flags &= ~DVF_BUS_SUSPENDED;
   2312          1.124  jmcneill 	return true;
   2313          1.124  jmcneill }
   2314          1.124  jmcneill 
   2315          1.133  drochner bool
   2316          1.133  drochner device_pmf_bus_shutdown(device_t dev, int how)
   2317          1.133  drochner {
   2318          1.133  drochner 
   2319          1.133  drochner 	if (*dev->dv_bus_shutdown != NULL &&
   2320          1.133  drochner 	    !(*dev->dv_bus_shutdown)(dev, how))
   2321          1.133  drochner 		return false;
   2322          1.133  drochner 	return true;
   2323          1.133  drochner }
   2324          1.133  drochner 
   2325          1.124  jmcneill void
   2326          1.124  jmcneill device_pmf_bus_register(device_t dev, void *priv,
   2327          1.135    dyoung     bool (*suspend)(device_t PMF_FN_PROTO),
   2328          1.135    dyoung     bool (*resume)(device_t PMF_FN_PROTO),
   2329          1.133  drochner     bool (*shutdown)(device_t, int), void (*deregister)(device_t))
   2330          1.124  jmcneill {
   2331          1.124  jmcneill 	dev->dv_bus_private = priv;
   2332          1.124  jmcneill 	dev->dv_bus_resume = resume;
   2333          1.124  jmcneill 	dev->dv_bus_suspend = suspend;
   2334          1.133  drochner 	dev->dv_bus_shutdown = shutdown;
   2335          1.124  jmcneill 	dev->dv_bus_deregister = deregister;
   2336          1.124  jmcneill }
   2337          1.124  jmcneill 
   2338          1.124  jmcneill void
   2339          1.124  jmcneill device_pmf_bus_deregister(device_t dev)
   2340          1.124  jmcneill {
   2341          1.124  jmcneill 	if (dev->dv_bus_deregister == NULL)
   2342          1.124  jmcneill 		return;
   2343          1.124  jmcneill 	(*dev->dv_bus_deregister)(dev);
   2344          1.124  jmcneill 	dev->dv_bus_private = NULL;
   2345          1.124  jmcneill 	dev->dv_bus_suspend = NULL;
   2346          1.124  jmcneill 	dev->dv_bus_resume = NULL;
   2347          1.124  jmcneill 	dev->dv_bus_deregister = NULL;
   2348          1.124  jmcneill }
   2349          1.124  jmcneill 
   2350          1.124  jmcneill void *
   2351          1.124  jmcneill device_pmf_class_private(device_t dev)
   2352          1.124  jmcneill {
   2353          1.124  jmcneill 	return dev->dv_class_private;
   2354          1.124  jmcneill }
   2355          1.124  jmcneill 
   2356          1.124  jmcneill bool
   2357          1.135    dyoung device_pmf_class_suspend(device_t dev PMF_FN_ARGS)
   2358          1.124  jmcneill {
   2359          1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
   2360          1.124  jmcneill 		return true;
   2361          1.124  jmcneill 	if (*dev->dv_class_suspend != NULL &&
   2362          1.135    dyoung 	    !(*dev->dv_class_suspend)(dev PMF_FN_CALL))
   2363          1.124  jmcneill 		return false;
   2364          1.124  jmcneill 
   2365          1.124  jmcneill 	dev->dv_flags |= DVF_CLASS_SUSPENDED;
   2366          1.124  jmcneill 	return true;
   2367          1.124  jmcneill }
   2368          1.124  jmcneill 
   2369          1.124  jmcneill bool
   2370          1.135    dyoung device_pmf_class_resume(device_t dev PMF_FN_ARGS)
   2371          1.124  jmcneill {
   2372          1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
   2373          1.124  jmcneill 		return true;
   2374          1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
   2375          1.124  jmcneill 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
   2376          1.124  jmcneill 		return false;
   2377          1.124  jmcneill 	if (*dev->dv_class_resume != NULL &&
   2378          1.135    dyoung 	    !(*dev->dv_class_resume)(dev PMF_FN_CALL))
   2379          1.124  jmcneill 		return false;
   2380          1.124  jmcneill 
   2381          1.124  jmcneill 	dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
   2382          1.124  jmcneill 	return true;
   2383          1.124  jmcneill }
   2384          1.124  jmcneill 
   2385          1.124  jmcneill void
   2386          1.124  jmcneill device_pmf_class_register(device_t dev, void *priv,
   2387          1.135    dyoung     bool (*suspend)(device_t PMF_FN_PROTO),
   2388          1.135    dyoung     bool (*resume)(device_t PMF_FN_PROTO),
   2389          1.124  jmcneill     void (*deregister)(device_t))
   2390          1.124  jmcneill {
   2391          1.124  jmcneill 	dev->dv_class_private = priv;
   2392          1.124  jmcneill 	dev->dv_class_suspend = suspend;
   2393          1.124  jmcneill 	dev->dv_class_resume = resume;
   2394          1.124  jmcneill 	dev->dv_class_deregister = deregister;
   2395          1.124  jmcneill }
   2396          1.124  jmcneill 
   2397          1.124  jmcneill void
   2398          1.124  jmcneill device_pmf_class_deregister(device_t dev)
   2399          1.124  jmcneill {
   2400          1.124  jmcneill 	if (dev->dv_class_deregister == NULL)
   2401          1.124  jmcneill 		return;
   2402          1.124  jmcneill 	(*dev->dv_class_deregister)(dev);
   2403          1.124  jmcneill 	dev->dv_class_private = NULL;
   2404          1.124  jmcneill 	dev->dv_class_suspend = NULL;
   2405          1.124  jmcneill 	dev->dv_class_resume = NULL;
   2406          1.124  jmcneill 	dev->dv_class_deregister = NULL;
   2407          1.124  jmcneill }
   2408          1.124  jmcneill 
   2409          1.124  jmcneill bool
   2410          1.124  jmcneill device_active(device_t dev, devactive_t type)
   2411          1.124  jmcneill {
   2412          1.124  jmcneill 	size_t i;
   2413          1.124  jmcneill 
   2414          1.124  jmcneill 	if (dev->dv_activity_count == 0)
   2415          1.124  jmcneill 		return false;
   2416          1.124  jmcneill 
   2417          1.160      matt 	for (i = 0; i < dev->dv_activity_count; ++i) {
   2418          1.160      matt 		if (dev->dv_activity_handlers[i] == NULL)
   2419          1.160      matt 			break;
   2420          1.124  jmcneill 		(*dev->dv_activity_handlers[i])(dev, type);
   2421          1.160      matt 	}
   2422          1.124  jmcneill 
   2423          1.124  jmcneill 	return true;
   2424          1.124  jmcneill }
   2425          1.124  jmcneill 
   2426          1.124  jmcneill bool
   2427          1.124  jmcneill device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
   2428          1.124  jmcneill {
   2429          1.124  jmcneill 	void (**new_handlers)(device_t, devactive_t);
   2430          1.124  jmcneill 	void (**old_handlers)(device_t, devactive_t);
   2431          1.159      matt 	size_t i, old_size, new_size;
   2432          1.124  jmcneill 	int s;
   2433          1.124  jmcneill 
   2434          1.124  jmcneill 	old_handlers = dev->dv_activity_handlers;
   2435          1.159      matt 	old_size = dev->dv_activity_count;
   2436          1.124  jmcneill 
   2437          1.159      matt 	for (i = 0; i < old_size; ++i) {
   2438          1.159      matt 		KASSERT(old_handlers[i] != handler);
   2439          1.159      matt 		if (old_handlers[i] == NULL) {
   2440          1.159      matt 			old_handlers[i] = handler;
   2441          1.159      matt 			return true;
   2442          1.159      matt 		}
   2443          1.124  jmcneill 	}
   2444          1.124  jmcneill 
   2445          1.159      matt 	new_size = old_size + 4;
   2446          1.159      matt 	new_handlers = kmem_alloc(sizeof(void *[new_size]), KM_SLEEP);
   2447          1.124  jmcneill 
   2448          1.159      matt 	memcpy(new_handlers, old_handlers, sizeof(void *[old_size]));
   2449          1.159      matt 	new_handlers[old_size] = handler;
   2450          1.159      matt 	memset(new_handlers + old_size + 1, 0,
   2451          1.159      matt 	    sizeof(int [new_size - (old_size+1)]));
   2452          1.124  jmcneill 
   2453          1.124  jmcneill 	s = splhigh();
   2454          1.124  jmcneill 	dev->dv_activity_count = new_size;
   2455          1.124  jmcneill 	dev->dv_activity_handlers = new_handlers;
   2456          1.124  jmcneill 	splx(s);
   2457          1.124  jmcneill 
   2458          1.124  jmcneill 	if (old_handlers != NULL)
   2459          1.159      matt 		kmem_free(old_handlers, sizeof(int [old_size]));
   2460          1.124  jmcneill 
   2461          1.124  jmcneill 	return true;
   2462          1.124  jmcneill }
   2463          1.124  jmcneill 
   2464          1.124  jmcneill void
   2465          1.124  jmcneill device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
   2466          1.124  jmcneill {
   2467          1.124  jmcneill 	void (**old_handlers)(device_t, devactive_t);
   2468          1.159      matt 	size_t i, old_size;
   2469          1.124  jmcneill 	int s;
   2470          1.124  jmcneill 
   2471          1.124  jmcneill 	old_handlers = dev->dv_activity_handlers;
   2472          1.159      matt 	old_size = dev->dv_activity_count;
   2473          1.124  jmcneill 
   2474          1.159      matt 	for (i = 0; i < old_size; ++i) {
   2475          1.124  jmcneill 		if (old_handlers[i] == handler)
   2476          1.124  jmcneill 			break;
   2477          1.159      matt 		if (old_handlers[i] == NULL)
   2478          1.159      matt 			return; /* XXX panic? */
   2479          1.124  jmcneill 	}
   2480          1.124  jmcneill 
   2481          1.159      matt 	if (i == old_size)
   2482          1.124  jmcneill 		return; /* XXX panic? */
   2483          1.124  jmcneill 
   2484          1.159      matt 	for (; i < old_size - 1; ++i) {
   2485          1.159      matt 		if ((old_handlers[i] = old_handlers[i + 1]) != NULL)
   2486          1.159      matt 			continue;
   2487          1.124  jmcneill 
   2488          1.159      matt 		if (i == 0) {
   2489          1.159      matt 			s = splhigh();
   2490          1.159      matt 			dev->dv_activity_count = 0;
   2491          1.159      matt 			dev->dv_activity_handlers = NULL;
   2492          1.159      matt 			splx(s);
   2493          1.159      matt 			kmem_free(old_handlers, sizeof(void *[old_size]));
   2494          1.159      matt 		}
   2495          1.159      matt 		return;
   2496          1.124  jmcneill 	}
   2497          1.159      matt 	old_handlers[i] = NULL;
   2498          1.124  jmcneill }
   2499          1.136    dyoung 
   2500          1.136    dyoung /*
   2501          1.136    dyoung  * Device Iteration
   2502          1.136    dyoung  *
   2503          1.136    dyoung  * deviter_t: a device iterator.  Holds state for a "walk" visiting
   2504          1.136    dyoung  *     each device_t's in the device tree.
   2505          1.136    dyoung  *
   2506          1.136    dyoung  * deviter_init(di, flags): initialize the device iterator `di'
   2507          1.136    dyoung  *     to "walk" the device tree.  deviter_next(di) will return
   2508          1.136    dyoung  *     the first device_t in the device tree, or NULL if there are
   2509          1.136    dyoung  *     no devices.
   2510          1.136    dyoung  *
   2511          1.136    dyoung  *     `flags' is one or more of DEVITER_F_RW, indicating that the
   2512          1.136    dyoung  *     caller intends to modify the device tree by calling
   2513          1.136    dyoung  *     config_detach(9) on devices in the order that the iterator
   2514          1.136    dyoung  *     returns them; DEVITER_F_ROOT_FIRST, asking for the devices
   2515          1.136    dyoung  *     nearest the "root" of the device tree to be returned, first;
   2516          1.136    dyoung  *     DEVITER_F_LEAVES_FIRST, asking for the devices furthest from
   2517          1.136    dyoung  *     the root of the device tree, first; and DEVITER_F_SHUTDOWN,
   2518          1.136    dyoung  *     indicating both that deviter_init() should not respect any
   2519          1.136    dyoung  *     locks on the device tree, and that deviter_next(di) may run
   2520          1.136    dyoung  *     in more than one LWP before the walk has finished.
   2521          1.136    dyoung  *
   2522          1.136    dyoung  *     Only one DEVITER_F_RW iterator may be in the device tree at
   2523          1.136    dyoung  *     once.
   2524          1.136    dyoung  *
   2525          1.136    dyoung  *     DEVITER_F_SHUTDOWN implies DEVITER_F_RW.
   2526          1.136    dyoung  *
   2527          1.136    dyoung  *     Results are undefined if the flags DEVITER_F_ROOT_FIRST and
   2528          1.136    dyoung  *     DEVITER_F_LEAVES_FIRST are used in combination.
   2529          1.136    dyoung  *
   2530          1.136    dyoung  * deviter_first(di, flags): initialize the device iterator `di'
   2531          1.136    dyoung  *     and return the first device_t in the device tree, or NULL
   2532          1.136    dyoung  *     if there are no devices.  The statement
   2533          1.136    dyoung  *
   2534          1.136    dyoung  *         dv = deviter_first(di);
   2535          1.136    dyoung  *
   2536          1.136    dyoung  *     is shorthand for
   2537          1.136    dyoung  *
   2538          1.136    dyoung  *         deviter_init(di);
   2539          1.136    dyoung  *         dv = deviter_next(di);
   2540          1.136    dyoung  *
   2541          1.136    dyoung  * deviter_next(di): return the next device_t in the device tree,
   2542          1.136    dyoung  *     or NULL if there are no more devices.  deviter_next(di)
   2543          1.136    dyoung  *     is undefined if `di' was not initialized with deviter_init() or
   2544          1.136    dyoung  *     deviter_first().
   2545          1.136    dyoung  *
   2546          1.136    dyoung  * deviter_release(di): stops iteration (subsequent calls to
   2547          1.136    dyoung  *     deviter_next() will return NULL), releases any locks and
   2548          1.136    dyoung  *     resources held by the device iterator.
   2549          1.136    dyoung  *
   2550          1.136    dyoung  * Device iteration does not return device_t's in any particular
   2551          1.136    dyoung  * order.  An iterator will never return the same device_t twice.
   2552          1.136    dyoung  * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
   2553          1.136    dyoung  * is called repeatedly on the same `di', it will eventually return
   2554          1.136    dyoung  * NULL.  It is ok to attach/detach devices during device iteration.
   2555          1.136    dyoung  */
   2556          1.136    dyoung void
   2557          1.136    dyoung deviter_init(deviter_t *di, deviter_flags_t flags)
   2558          1.136    dyoung {
   2559          1.136    dyoung 	device_t dv;
   2560          1.136    dyoung 	bool rw;
   2561          1.136    dyoung 
   2562          1.136    dyoung 	mutex_enter(&alldevs_mtx);
   2563          1.136    dyoung 	if ((flags & DEVITER_F_SHUTDOWN) != 0) {
   2564          1.136    dyoung 		flags |= DEVITER_F_RW;
   2565          1.136    dyoung 		alldevs_nwrite++;
   2566          1.136    dyoung 		alldevs_writer = NULL;
   2567          1.136    dyoung 		alldevs_nread = 0;
   2568          1.136    dyoung 	} else {
   2569          1.136    dyoung 		rw = (flags & DEVITER_F_RW) != 0;
   2570          1.136    dyoung 
   2571          1.136    dyoung 		if (alldevs_nwrite > 0 && alldevs_writer == NULL)
   2572          1.136    dyoung 			;
   2573          1.136    dyoung 		else while ((alldevs_nwrite != 0 && alldevs_writer != curlwp) ||
   2574          1.136    dyoung 		       (rw && alldevs_nread != 0))
   2575          1.136    dyoung 			cv_wait(&alldevs_cv, &alldevs_mtx);
   2576          1.136    dyoung 
   2577          1.136    dyoung 		if (rw) {
   2578          1.136    dyoung 			if (alldevs_nwrite++ == 0)
   2579          1.136    dyoung 				alldevs_writer = curlwp;
   2580          1.136    dyoung 		} else
   2581          1.136    dyoung 			alldevs_nread++;
   2582          1.136    dyoung 	}
   2583          1.136    dyoung 	mutex_exit(&alldevs_mtx);
   2584          1.136    dyoung 
   2585          1.136    dyoung 	memset(di, 0, sizeof(*di));
   2586          1.136    dyoung 
   2587          1.136    dyoung 	di->di_flags = flags;
   2588          1.136    dyoung 
   2589          1.136    dyoung 	switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
   2590          1.136    dyoung 	case DEVITER_F_LEAVES_FIRST:
   2591          1.136    dyoung 		TAILQ_FOREACH(dv, &alldevs, dv_list)
   2592          1.136    dyoung 			di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
   2593          1.136    dyoung 		break;
   2594          1.136    dyoung 	case DEVITER_F_ROOT_FIRST:
   2595          1.136    dyoung 		TAILQ_FOREACH(dv, &alldevs, dv_list)
   2596          1.136    dyoung 			di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
   2597          1.136    dyoung 		break;
   2598          1.136    dyoung 	default:
   2599          1.136    dyoung 		break;
   2600          1.136    dyoung 	}
   2601          1.136    dyoung 
   2602          1.136    dyoung 	deviter_reinit(di);
   2603          1.136    dyoung }
   2604          1.136    dyoung 
   2605          1.136    dyoung static void
   2606          1.136    dyoung deviter_reinit(deviter_t *di)
   2607          1.136    dyoung {
   2608          1.136    dyoung 	if ((di->di_flags & DEVITER_F_RW) != 0)
   2609          1.136    dyoung 		di->di_prev = TAILQ_LAST(&alldevs, devicelist);
   2610          1.136    dyoung 	else
   2611          1.136    dyoung 		di->di_prev = TAILQ_FIRST(&alldevs);
   2612          1.136    dyoung }
   2613          1.136    dyoung 
   2614          1.136    dyoung device_t
   2615          1.136    dyoung deviter_first(deviter_t *di, deviter_flags_t flags)
   2616          1.136    dyoung {
   2617          1.136    dyoung 	deviter_init(di, flags);
   2618          1.136    dyoung 	return deviter_next(di);
   2619          1.136    dyoung }
   2620          1.136    dyoung 
   2621          1.136    dyoung static device_t
   2622          1.136    dyoung deviter_next1(deviter_t *di)
   2623          1.136    dyoung {
   2624          1.136    dyoung 	device_t dv;
   2625          1.136    dyoung 
   2626          1.136    dyoung 	dv = di->di_prev;
   2627          1.136    dyoung 
   2628          1.136    dyoung 	if (dv == NULL)
   2629          1.136    dyoung 		;
   2630          1.136    dyoung 	else if ((di->di_flags & DEVITER_F_RW) != 0)
   2631          1.136    dyoung 		di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
   2632          1.136    dyoung 	else
   2633          1.136    dyoung 		di->di_prev = TAILQ_NEXT(dv, dv_list);
   2634          1.136    dyoung 
   2635          1.136    dyoung 	return dv;
   2636          1.136    dyoung }
   2637          1.136    dyoung 
   2638          1.136    dyoung device_t
   2639          1.136    dyoung deviter_next(deviter_t *di)
   2640          1.136    dyoung {
   2641          1.136    dyoung 	device_t dv = NULL;
   2642          1.136    dyoung 
   2643          1.136    dyoung 	switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
   2644          1.136    dyoung 	case 0:
   2645          1.136    dyoung 		return deviter_next1(di);
   2646          1.136    dyoung 	case DEVITER_F_LEAVES_FIRST:
   2647          1.136    dyoung 		while (di->di_curdepth >= 0) {
   2648          1.136    dyoung 			if ((dv = deviter_next1(di)) == NULL) {
   2649          1.136    dyoung 				di->di_curdepth--;
   2650          1.136    dyoung 				deviter_reinit(di);
   2651          1.136    dyoung 			} else if (dv->dv_depth == di->di_curdepth)
   2652          1.136    dyoung 				break;
   2653          1.136    dyoung 		}
   2654          1.136    dyoung 		return dv;
   2655          1.136    dyoung 	case DEVITER_F_ROOT_FIRST:
   2656          1.136    dyoung 		while (di->di_curdepth <= di->di_maxdepth) {
   2657          1.136    dyoung 			if ((dv = deviter_next1(di)) == NULL) {
   2658          1.136    dyoung 				di->di_curdepth++;
   2659          1.136    dyoung 				deviter_reinit(di);
   2660          1.136    dyoung 			} else if (dv->dv_depth == di->di_curdepth)
   2661          1.136    dyoung 				break;
   2662          1.136    dyoung 		}
   2663          1.136    dyoung 		return dv;
   2664          1.136    dyoung 	default:
   2665          1.136    dyoung 		return NULL;
   2666          1.136    dyoung 	}
   2667          1.136    dyoung }
   2668          1.136    dyoung 
   2669          1.136    dyoung void
   2670          1.136    dyoung deviter_release(deviter_t *di)
   2671          1.136    dyoung {
   2672          1.136    dyoung 	bool rw = (di->di_flags & DEVITER_F_RW) != 0;
   2673          1.136    dyoung 
   2674          1.136    dyoung 	mutex_enter(&alldevs_mtx);
   2675          1.136    dyoung 	if (alldevs_nwrite > 0 && alldevs_writer == NULL)
   2676          1.136    dyoung 		--alldevs_nwrite;
   2677          1.136    dyoung 	else {
   2678          1.136    dyoung 
   2679          1.136    dyoung 		if (rw) {
   2680          1.136    dyoung 			if (--alldevs_nwrite == 0)
   2681          1.136    dyoung 				alldevs_writer = NULL;
   2682          1.136    dyoung 		} else
   2683          1.136    dyoung 			--alldevs_nread;
   2684          1.136    dyoung 
   2685          1.136    dyoung 		cv_signal(&alldevs_cv);
   2686          1.136    dyoung 	}
   2687          1.136    dyoung 	mutex_exit(&alldevs_mtx);
   2688          1.136    dyoung }
   2689