Home | History | Annotate | Line # | Download | only in kern
subr_autoconf.c revision 1.277.2.11
      1  1.277.2.11   thorpej /* $NetBSD: subr_autoconf.c,v 1.277.2.11 2021/04/04 19:12:27 thorpej 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.277.2.11   thorpej __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.277.2.11 2021/04/04 19:12:27 thorpej Exp $");
     81        1.62    simonb 
     82       1.180     pooka #ifdef _KERNEL_OPT
     83        1.62    simonb #include "opt_ddb.h"
     84       1.217  jmcneill #include "drvctl.h"
     85       1.180     pooka #endif
     86        1.51       cgd 
     87         1.4   mycroft #include <sys/param.h>
     88         1.4   mycroft #include <sys/device.h>
     89       1.118    dyoung #include <sys/disklabel.h>
     90       1.118    dyoung #include <sys/conf.h>
     91       1.118    dyoung #include <sys/kauth.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/mount.h>
    102       1.118    dyoung #include <sys/namei.h>
    103       1.118    dyoung #include <sys/unistd.h>
    104       1.118    dyoung #include <sys/fcntl.h>
    105       1.118    dyoung #include <sys/lockf.h>
    106       1.124  jmcneill #include <sys/callout.h>
    107       1.149  jmcneill #include <sys/devmon.h>
    108       1.153    cegger #include <sys/cpu.h>
    109       1.174    dyoung #include <sys/sysctl.h>
    110   1.277.2.1   thorpej #include <sys/stdarg.h>
    111       1.118    dyoung 
    112       1.118    dyoung #include <sys/disk.h>
    113       1.118    dyoung 
    114       1.235  riastrad #include <sys/rndsource.h>
    115       1.231       tls 
    116        1.16   mycroft #include <machine/limits.h>
    117         1.1     glass 
    118         1.1     glass /*
    119         1.1     glass  * Autoconfiguration subroutines.
    120         1.1     glass  */
    121         1.1     glass 
    122         1.1     glass /*
    123       1.231       tls  * Device autoconfiguration timings are mixed into the entropy pool.
    124       1.231       tls  */
    125       1.270  riastrad static krndsource_t rnd_autoconf_source;
    126       1.231       tls 
    127       1.231       tls /*
    128         1.1     glass  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
    129         1.1     glass  * devices and drivers are found via these tables.
    130         1.1     glass  */
    131         1.1     glass extern struct cfdata cfdata[];
    132        1.84      matt extern const short cfroots[];
    133         1.1     glass 
    134        1.65   thorpej /*
    135        1.67   thorpej  * List of all cfdriver structures.  We use this to detect duplicates
    136        1.67   thorpej  * when other cfdrivers are loaded.
    137        1.67   thorpej  */
    138        1.69   thorpej struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
    139        1.69   thorpej extern struct cfdriver * const cfdriver_list_initial[];
    140        1.67   thorpej 
    141        1.67   thorpej /*
    142        1.76   thorpej  * Initial list of cfattach's.
    143        1.76   thorpej  */
    144        1.76   thorpej extern const struct cfattachinit cfattachinit[];
    145        1.76   thorpej 
    146        1.76   thorpej /*
    147        1.65   thorpej  * List of cfdata tables.  We always have one such list -- the one
    148        1.65   thorpej  * built statically when the kernel was configured.
    149        1.65   thorpej  */
    150       1.121      matt struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
    151        1.65   thorpej static struct cftable initcftable;
    152        1.65   thorpej 
    153       1.102   thorpej #define	ROOT ((device_t)NULL)
    154         1.1     glass 
    155        1.16   mycroft struct matchinfo {
    156        1.99  drochner 	cfsubmatch_t fn;
    157       1.224       chs 	device_t parent;
    158        1.99  drochner 	const int *locs;
    159        1.25       cgd 	void	*aux;
    160        1.25       cgd 	struct	cfdata *match;
    161        1.25       cgd 	int	pri;
    162        1.16   mycroft };
    163        1.17  christos 
    164       1.198    dyoung struct alldevs_foray {
    165       1.198    dyoung 	int			af_s;
    166       1.198    dyoung 	struct devicelist	af_garbage;
    167       1.198    dyoung };
    168       1.198    dyoung 
    169        1.51       cgd static char *number(char *, int);
    170       1.102   thorpej static void mapply(struct matchinfo *, cfdata_t);
    171   1.277.2.9   thorpej static device_t config_vattach(device_t, cfdata_t, void *, cfprint_t, cfarg_t,
    172   1.277.2.9   thorpej 			       va_list);
    173       1.187    dyoung static void config_devdelete(device_t);
    174       1.190    dyoung static void config_devunlink(device_t, struct devicelist *);
    175       1.117  drochner static void config_makeroom(int, struct cfdriver *);
    176       1.117  drochner static void config_devlink(device_t);
    177       1.198    dyoung static void config_alldevs_enter(struct alldevs_foray *);
    178       1.198    dyoung static void config_alldevs_exit(struct alldevs_foray *);
    179       1.221  pgoyette static void config_add_attrib_dict(device_t);
    180       1.197     rmind 
    181       1.197     rmind static void config_collect_garbage(struct devicelist *);
    182       1.197     rmind static void config_dump_garbage(struct devicelist *);
    183       1.197     rmind 
    184       1.139    dyoung static void pmflock_debug(device_t, const char *, int);
    185       1.139    dyoung 
    186       1.136    dyoung static device_t deviter_next1(deviter_t *);
    187       1.136    dyoung static void deviter_reinit(deviter_t *);
    188       1.136    dyoung 
    189        1.29   thorpej struct deferred_config {
    190        1.29   thorpej 	TAILQ_ENTRY(deferred_config) dc_queue;
    191       1.102   thorpej 	device_t dc_dev;
    192       1.102   thorpej 	void (*dc_func)(device_t);
    193        1.29   thorpej };
    194        1.29   thorpej 
    195        1.42   thorpej TAILQ_HEAD(deferred_config_head, deferred_config);
    196        1.29   thorpej 
    197       1.263       mrg static struct deferred_config_head deferred_config_queue =
    198       1.121      matt 	TAILQ_HEAD_INITIALIZER(deferred_config_queue);
    199       1.263       mrg static struct deferred_config_head interrupt_config_queue =
    200       1.121      matt 	TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
    201       1.263       mrg static int interrupt_config_threads = 8;
    202       1.263       mrg static struct deferred_config_head mountroot_config_queue =
    203       1.207   tsutsui 	TAILQ_HEAD_INITIALIZER(mountroot_config_queue);
    204       1.263       mrg static int mountroot_config_threads = 2;
    205       1.234       mrg static lwp_t **mountroot_config_lwpids;
    206       1.234       mrg static size_t mountroot_config_lwpids_size;
    207       1.263       mrg bool root_is_mounted = false;
    208        1.42   thorpej 
    209       1.102   thorpej static void config_process_deferred(struct deferred_config_head *, device_t);
    210        1.29   thorpej 
    211        1.75   thorpej /* Hooks to finalize configuration once all real devices have been found. */
    212        1.75   thorpej struct finalize_hook {
    213        1.75   thorpej 	TAILQ_ENTRY(finalize_hook) f_list;
    214       1.102   thorpej 	int (*f_func)(device_t);
    215       1.102   thorpej 	device_t f_dev;
    216        1.75   thorpej };
    217       1.121      matt static TAILQ_HEAD(, finalize_hook) config_finalize_list =
    218       1.121      matt 	TAILQ_HEAD_INITIALIZER(config_finalize_list);
    219        1.75   thorpej static int config_finalize_done;
    220        1.75   thorpej 
    221        1.56   thorpej /* list of all devices */
    222       1.257   mlelstv static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
    223       1.257   mlelstv static kmutex_t alldevs_lock __cacheline_aligned;
    224       1.257   mlelstv static devgen_t alldevs_gen = 1;
    225       1.257   mlelstv static int alldevs_nread = 0;
    226       1.257   mlelstv static int alldevs_nwrite = 0;
    227       1.257   mlelstv static bool alldevs_garbage = false;
    228        1.56   thorpej 
    229       1.274  riastrad static struct devicelist config_pending =
    230       1.274  riastrad     TAILQ_HEAD_INITIALIZER(config_pending);
    231       1.151        ad static kmutex_t config_misc_lock;
    232       1.151        ad static kcondvar_t config_misc_cv;
    233        1.47   thorpej 
    234       1.210    martin static bool detachall = false;
    235       1.174    dyoung 
    236        1.67   thorpej #define	STREQ(s1, s2)			\
    237        1.70   thorpej 	(*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
    238        1.67   thorpej 
    239       1.185     pooka static bool config_initialized = false;	/* config_init() has been called. */
    240        1.74   thorpej 
    241        1.80   thorpej static int config_do_twiddle;
    242       1.176        ad static callout_t config_twiddle_ch;
    243        1.80   thorpej 
    244       1.182     pooka static void sysctl_detach_setup(struct sysctllog **);
    245       1.182     pooka 
    246       1.237  pgoyette int no_devmon_insert(const char *, prop_dictionary_t);
    247       1.237  pgoyette int (*devmon_insert_vec)(const char *, prop_dictionary_t) = no_devmon_insert;
    248       1.237  pgoyette 
    249       1.204     pooka typedef int (*cfdriver_fn)(struct cfdriver *);
    250       1.204     pooka static int
    251       1.204     pooka frob_cfdrivervec(struct cfdriver * const *cfdriverv,
    252       1.204     pooka 	cfdriver_fn drv_do, cfdriver_fn drv_undo,
    253       1.204     pooka 	const char *style, bool dopanic)
    254       1.204     pooka {
    255       1.226  christos 	void (*pr)(const char *, ...) __printflike(1, 2) =
    256       1.255     joerg 	    dopanic ? panic : printf;
    257       1.229    martin 	int i, error = 0, e2 __diagused;
    258       1.204     pooka 
    259       1.204     pooka 	for (i = 0; cfdriverv[i] != NULL; i++) {
    260       1.204     pooka 		if ((error = drv_do(cfdriverv[i])) != 0) {
    261       1.204     pooka 			pr("configure: `%s' driver %s failed: %d",
    262       1.204     pooka 			    cfdriverv[i]->cd_name, style, error);
    263       1.204     pooka 			goto bad;
    264       1.204     pooka 		}
    265       1.204     pooka 	}
    266       1.204     pooka 
    267       1.204     pooka 	KASSERT(error == 0);
    268       1.204     pooka 	return 0;
    269       1.204     pooka 
    270       1.204     pooka  bad:
    271       1.204     pooka 	printf("\n");
    272       1.204     pooka 	for (i--; i >= 0; i--) {
    273       1.204     pooka 		e2 = drv_undo(cfdriverv[i]);
    274       1.204     pooka 		KASSERT(e2 == 0);
    275       1.204     pooka 	}
    276       1.204     pooka 
    277       1.204     pooka 	return error;
    278       1.204     pooka }
    279       1.204     pooka 
    280       1.204     pooka typedef int (*cfattach_fn)(const char *, struct cfattach *);
    281       1.204     pooka static int
    282       1.204     pooka frob_cfattachvec(const struct cfattachinit *cfattachv,
    283       1.204     pooka 	cfattach_fn att_do, cfattach_fn att_undo,
    284       1.204     pooka 	const char *style, bool dopanic)
    285       1.204     pooka {
    286       1.204     pooka 	const struct cfattachinit *cfai = NULL;
    287       1.226  christos 	void (*pr)(const char *, ...) __printflike(1, 2) =
    288       1.255     joerg 	    dopanic ? panic : printf;
    289       1.229    martin 	int j = 0, error = 0, e2 __diagused;
    290       1.204     pooka 
    291       1.204     pooka 	for (cfai = &cfattachv[0]; cfai->cfai_name != NULL; cfai++) {
    292       1.204     pooka 		for (j = 0; cfai->cfai_list[j] != NULL; j++) {
    293       1.204     pooka 			if ((error = att_do(cfai->cfai_name,
    294       1.214   mbalmer 			    cfai->cfai_list[j])) != 0) {
    295       1.204     pooka 				pr("configure: attachment `%s' "
    296       1.204     pooka 				    "of `%s' driver %s failed: %d",
    297       1.204     pooka 				    cfai->cfai_list[j]->ca_name,
    298       1.204     pooka 				    cfai->cfai_name, style, error);
    299       1.204     pooka 				goto bad;
    300       1.204     pooka 			}
    301       1.204     pooka 		}
    302       1.204     pooka 	}
    303       1.204     pooka 
    304       1.204     pooka 	KASSERT(error == 0);
    305       1.204     pooka 	return 0;
    306       1.204     pooka 
    307       1.204     pooka  bad:
    308       1.204     pooka 	/*
    309       1.204     pooka 	 * Rollback in reverse order.  dunno if super-important, but
    310       1.204     pooka 	 * do that anyway.  Although the code looks a little like
    311       1.204     pooka 	 * someone did a little integration (in the math sense).
    312       1.204     pooka 	 */
    313       1.204     pooka 	printf("\n");
    314       1.204     pooka 	if (cfai) {
    315       1.204     pooka 		bool last;
    316       1.204     pooka 
    317       1.204     pooka 		for (last = false; last == false; ) {
    318       1.204     pooka 			if (cfai == &cfattachv[0])
    319       1.204     pooka 				last = true;
    320       1.204     pooka 			for (j--; j >= 0; j--) {
    321       1.204     pooka 				e2 = att_undo(cfai->cfai_name,
    322       1.204     pooka 				    cfai->cfai_list[j]);
    323       1.204     pooka 				KASSERT(e2 == 0);
    324       1.204     pooka 			}
    325       1.204     pooka 			if (!last) {
    326       1.204     pooka 				cfai--;
    327       1.204     pooka 				for (j = 0; cfai->cfai_list[j] != NULL; j++)
    328       1.204     pooka 					;
    329       1.204     pooka 			}
    330       1.204     pooka 		}
    331       1.204     pooka 	}
    332       1.204     pooka 
    333       1.204     pooka 	return error;
    334       1.204     pooka }
    335       1.204     pooka 
    336        1.20       cgd /*
    337        1.74   thorpej  * Initialize the autoconfiguration data structures.  Normally this
    338        1.74   thorpej  * is done by configure(), but some platforms need to do this very
    339        1.74   thorpej  * early (to e.g. initialize the console).
    340        1.20       cgd  */
    341        1.20       cgd void
    342        1.74   thorpej config_init(void)
    343        1.20       cgd {
    344        1.67   thorpej 
    345       1.185     pooka 	KASSERT(config_initialized == false);
    346        1.74   thorpej 
    347       1.257   mlelstv 	mutex_init(&alldevs_lock, MUTEX_DEFAULT, IPL_VM);
    348       1.136    dyoung 
    349       1.151        ad 	mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
    350       1.151        ad 	cv_init(&config_misc_cv, "cfgmisc");
    351       1.151        ad 
    352       1.176        ad 	callout_init(&config_twiddle_ch, CALLOUT_MPSAFE);
    353       1.176        ad 
    354       1.204     pooka 	frob_cfdrivervec(cfdriver_list_initial,
    355       1.204     pooka 	    config_cfdriver_attach, NULL, "bootstrap", true);
    356       1.204     pooka 	frob_cfattachvec(cfattachinit,
    357       1.204     pooka 	    config_cfattach_attach, NULL, "bootstrap", true);
    358        1.20       cgd 
    359        1.65   thorpej 	initcftable.ct_cfdata = cfdata;
    360        1.65   thorpej 	TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
    361       1.185     pooka 
    362       1.270  riastrad 	rnd_attach_source(&rnd_autoconf_source, "autoconf", RND_TYPE_UNKNOWN,
    363       1.270  riastrad 	    RND_FLAG_COLLECT_TIME);
    364       1.270  riastrad 
    365       1.185     pooka 	config_initialized = true;
    366       1.185     pooka }
    367       1.185     pooka 
    368       1.204     pooka /*
    369       1.204     pooka  * Init or fini drivers and attachments.  Either all or none
    370       1.204     pooka  * are processed (via rollback).  It would be nice if this were
    371       1.204     pooka  * atomic to outside consumers, but with the current state of
    372       1.204     pooka  * locking ...
    373       1.204     pooka  */
    374       1.204     pooka int
    375       1.204     pooka config_init_component(struct cfdriver * const *cfdriverv,
    376       1.204     pooka 	const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
    377       1.204     pooka {
    378       1.204     pooka 	int error;
    379       1.204     pooka 
    380       1.204     pooka 	if ((error = frob_cfdrivervec(cfdriverv,
    381       1.204     pooka 	    config_cfdriver_attach, config_cfdriver_detach, "init", false))!= 0)
    382       1.204     pooka 		return error;
    383       1.204     pooka 	if ((error = frob_cfattachvec(cfattachv,
    384       1.204     pooka 	    config_cfattach_attach, config_cfattach_detach,
    385       1.204     pooka 	    "init", false)) != 0) {
    386       1.204     pooka 		frob_cfdrivervec(cfdriverv,
    387       1.204     pooka 	            config_cfdriver_detach, NULL, "init rollback", true);
    388       1.204     pooka 		return error;
    389       1.204     pooka 	}
    390       1.204     pooka 	if ((error = config_cfdata_attach(cfdatav, 1)) != 0) {
    391       1.204     pooka 		frob_cfattachvec(cfattachv,
    392       1.204     pooka 		    config_cfattach_detach, NULL, "init rollback", true);
    393       1.204     pooka 		frob_cfdrivervec(cfdriverv,
    394       1.204     pooka 	            config_cfdriver_detach, NULL, "init rollback", true);
    395       1.204     pooka 		return error;
    396       1.204     pooka 	}
    397       1.204     pooka 
    398       1.204     pooka 	return 0;
    399       1.204     pooka }
    400       1.204     pooka 
    401       1.204     pooka int
    402       1.204     pooka config_fini_component(struct cfdriver * const *cfdriverv,
    403       1.204     pooka 	const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
    404       1.204     pooka {
    405       1.204     pooka 	int error;
    406       1.204     pooka 
    407       1.204     pooka 	if ((error = config_cfdata_detach(cfdatav)) != 0)
    408       1.204     pooka 		return error;
    409       1.204     pooka 	if ((error = frob_cfattachvec(cfattachv,
    410       1.204     pooka 	    config_cfattach_detach, config_cfattach_attach,
    411       1.204     pooka 	    "fini", false)) != 0) {
    412       1.204     pooka 		if (config_cfdata_attach(cfdatav, 0) != 0)
    413       1.204     pooka 			panic("config_cfdata fini rollback failed");
    414       1.204     pooka 		return error;
    415       1.204     pooka 	}
    416       1.204     pooka 	if ((error = frob_cfdrivervec(cfdriverv,
    417       1.204     pooka 	    config_cfdriver_detach, config_cfdriver_attach,
    418       1.204     pooka 	    "fini", false)) != 0) {
    419       1.204     pooka 		frob_cfattachvec(cfattachv,
    420       1.204     pooka 	            config_cfattach_attach, NULL, "fini rollback", true);
    421       1.204     pooka 		if (config_cfdata_attach(cfdatav, 0) != 0)
    422       1.204     pooka 			panic("config_cfdata fini rollback failed");
    423       1.204     pooka 		return error;
    424       1.204     pooka 	}
    425       1.204     pooka 
    426       1.204     pooka 	return 0;
    427       1.204     pooka }
    428       1.204     pooka 
    429       1.185     pooka void
    430       1.185     pooka config_init_mi(void)
    431       1.185     pooka {
    432       1.185     pooka 
    433       1.185     pooka 	if (!config_initialized)
    434       1.185     pooka 		config_init();
    435       1.185     pooka 
    436       1.182     pooka 	sysctl_detach_setup(NULL);
    437        1.74   thorpej }
    438        1.74   thorpej 
    439       1.126    dyoung void
    440       1.126    dyoung config_deferred(device_t dev)
    441       1.126    dyoung {
    442       1.126    dyoung 	config_process_deferred(&deferred_config_queue, dev);
    443       1.126    dyoung 	config_process_deferred(&interrupt_config_queue, dev);
    444       1.207   tsutsui 	config_process_deferred(&mountroot_config_queue, dev);
    445       1.126    dyoung }
    446       1.126    dyoung 
    447       1.142        ad static void
    448       1.142        ad config_interrupts_thread(void *cookie)
    449       1.142        ad {
    450       1.142        ad 	struct deferred_config *dc;
    451       1.267  jdolecek 	device_t dev;
    452       1.142        ad 
    453       1.266  jdolecek 	mutex_enter(&config_misc_lock);
    454       1.142        ad 	while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
    455       1.142        ad 		TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
    456       1.266  jdolecek 		mutex_exit(&config_misc_lock);
    457       1.266  jdolecek 
    458       1.267  jdolecek 		dev = dc->dc_dev;
    459       1.267  jdolecek 		(*dc->dc_func)(dev);
    460       1.267  jdolecek 		if (!device_pmf_is_registered(dev))
    461       1.267  jdolecek 			aprint_debug_dev(dev,
    462       1.265   msaitoh 			    "WARNING: power management not supported\n");
    463       1.267  jdolecek 		config_pending_decr(dev);
    464       1.159      matt 		kmem_free(dc, sizeof(*dc));
    465       1.266  jdolecek 
    466       1.266  jdolecek 		mutex_enter(&config_misc_lock);
    467       1.267  jdolecek 		dev->dv_flags &= ~DVF_ATTACH_INPROGRESS;
    468       1.142        ad 	}
    469       1.266  jdolecek 	mutex_exit(&config_misc_lock);
    470       1.266  jdolecek 
    471       1.142        ad 	kthread_exit(0);
    472       1.142        ad }
    473       1.142        ad 
    474        1.74   thorpej void
    475       1.222      matt config_create_interruptthreads(void)
    476        1.74   thorpej {
    477       1.180     pooka 	int i;
    478       1.144        ad 
    479       1.142        ad 	for (i = 0; i < interrupt_config_threads; i++) {
    480       1.266  jdolecek 		(void)kthread_create(PRI_NONE, 0/*XXXSMP */, NULL,
    481       1.223      matt 		    config_interrupts_thread, NULL, NULL, "configintr");
    482       1.142        ad 	}
    483        1.20       cgd }
    484        1.20       cgd 
    485       1.207   tsutsui static void
    486       1.207   tsutsui config_mountroot_thread(void *cookie)
    487       1.207   tsutsui {
    488       1.207   tsutsui 	struct deferred_config *dc;
    489       1.207   tsutsui 
    490       1.266  jdolecek 	mutex_enter(&config_misc_lock);
    491       1.207   tsutsui 	while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
    492       1.207   tsutsui 		TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
    493       1.266  jdolecek 		mutex_exit(&config_misc_lock);
    494       1.266  jdolecek 
    495       1.207   tsutsui 		(*dc->dc_func)(dc->dc_dev);
    496       1.207   tsutsui 		kmem_free(dc, sizeof(*dc));
    497       1.266  jdolecek 
    498       1.266  jdolecek 		mutex_enter(&config_misc_lock);
    499       1.207   tsutsui 	}
    500       1.266  jdolecek 	mutex_exit(&config_misc_lock);
    501       1.266  jdolecek 
    502       1.207   tsutsui 	kthread_exit(0);
    503       1.207   tsutsui }
    504       1.207   tsutsui 
    505       1.207   tsutsui void
    506       1.222      matt config_create_mountrootthreads(void)
    507       1.207   tsutsui {
    508       1.207   tsutsui 	int i;
    509       1.207   tsutsui 
    510       1.208   tsutsui 	if (!root_is_mounted)
    511       1.208   tsutsui 		root_is_mounted = true;
    512       1.208   tsutsui 
    513       1.234       mrg 	mountroot_config_lwpids_size = sizeof(mountroot_config_lwpids) *
    514       1.234       mrg 				       mountroot_config_threads;
    515       1.234       mrg 	mountroot_config_lwpids = kmem_alloc(mountroot_config_lwpids_size,
    516       1.234       mrg 					     KM_NOSLEEP);
    517       1.234       mrg 	KASSERT(mountroot_config_lwpids);
    518       1.207   tsutsui 	for (i = 0; i < mountroot_config_threads; i++) {
    519       1.234       mrg 		mountroot_config_lwpids[i] = 0;
    520       1.266  jdolecek 		(void)kthread_create(PRI_NONE, KTHREAD_MUSTJOIN/* XXXSMP */,
    521       1.266  jdolecek 				     NULL, config_mountroot_thread, NULL,
    522       1.234       mrg 				     &mountroot_config_lwpids[i],
    523       1.234       mrg 				     "configroot");
    524       1.234       mrg 	}
    525       1.234       mrg }
    526       1.234       mrg 
    527       1.234       mrg void
    528       1.234       mrg config_finalize_mountroot(void)
    529       1.234       mrg {
    530       1.234       mrg 	int i, error;
    531       1.234       mrg 
    532       1.234       mrg 	for (i = 0; i < mountroot_config_threads; i++) {
    533       1.234       mrg 		if (mountroot_config_lwpids[i] == 0)
    534       1.234       mrg 			continue;
    535       1.234       mrg 
    536       1.234       mrg 		error = kthread_join(mountroot_config_lwpids[i]);
    537       1.234       mrg 		if (error)
    538       1.234       mrg 			printf("%s: thread %x joined with error %d\n",
    539       1.234       mrg 			       __func__, i, error);
    540       1.207   tsutsui 	}
    541       1.234       mrg 	kmem_free(mountroot_config_lwpids, mountroot_config_lwpids_size);
    542       1.207   tsutsui }
    543       1.207   tsutsui 
    544         1.1     glass /*
    545       1.149  jmcneill  * Announce device attach/detach to userland listeners.
    546       1.149  jmcneill  */
    547       1.237  pgoyette 
    548       1.237  pgoyette int
    549       1.237  pgoyette no_devmon_insert(const char *name, prop_dictionary_t p)
    550       1.237  pgoyette {
    551       1.237  pgoyette 
    552       1.237  pgoyette 	return ENODEV;
    553       1.237  pgoyette }
    554       1.237  pgoyette 
    555       1.149  jmcneill static void
    556       1.149  jmcneill devmon_report_device(device_t dev, bool isattach)
    557       1.149  jmcneill {
    558       1.269  macallan 	prop_dictionary_t ev, dict = device_properties(dev);
    559       1.149  jmcneill 	const char *parent;
    560       1.149  jmcneill 	const char *what;
    561       1.269  macallan 	const char *where;
    562       1.149  jmcneill 	device_t pdev = device_parent(dev);
    563       1.149  jmcneill 
    564       1.237  pgoyette 	/* If currently no drvctl device, just return */
    565       1.237  pgoyette 	if (devmon_insert_vec == no_devmon_insert)
    566       1.237  pgoyette 		return;
    567       1.237  pgoyette 
    568       1.149  jmcneill 	ev = prop_dictionary_create();
    569       1.149  jmcneill 	if (ev == NULL)
    570       1.149  jmcneill 		return;
    571       1.149  jmcneill 
    572       1.149  jmcneill 	what = (isattach ? "device-attach" : "device-detach");
    573       1.149  jmcneill 	parent = (pdev == NULL ? "root" : device_xname(pdev));
    574       1.272  jmcneill 	if (prop_dictionary_get_string(dict, "location", &where)) {
    575       1.272  jmcneill 		prop_dictionary_set_string(ev, "location", where);
    576       1.269  macallan 		aprint_debug("ev: %s %s at %s in [%s]\n",
    577       1.269  macallan 		    what, device_xname(dev), parent, where);
    578       1.269  macallan 	}
    579       1.272  jmcneill 	if (!prop_dictionary_set_string(ev, "device", device_xname(dev)) ||
    580       1.272  jmcneill 	    !prop_dictionary_set_string(ev, "parent", parent)) {
    581       1.149  jmcneill 		prop_object_release(ev);
    582       1.149  jmcneill 		return;
    583       1.149  jmcneill 	}
    584       1.149  jmcneill 
    585       1.237  pgoyette 	if ((*devmon_insert_vec)(what, ev) != 0)
    586       1.237  pgoyette 		prop_object_release(ev);
    587       1.149  jmcneill }
    588       1.149  jmcneill 
    589       1.149  jmcneill /*
    590        1.67   thorpej  * Add a cfdriver to the system.
    591        1.67   thorpej  */
    592        1.67   thorpej int
    593        1.67   thorpej config_cfdriver_attach(struct cfdriver *cd)
    594        1.67   thorpej {
    595        1.67   thorpej 	struct cfdriver *lcd;
    596        1.67   thorpej 
    597        1.67   thorpej 	/* Make sure this driver isn't already in the system. */
    598        1.67   thorpej 	LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
    599        1.67   thorpej 		if (STREQ(lcd->cd_name, cd->cd_name))
    600       1.175    cegger 			return EEXIST;
    601        1.67   thorpej 	}
    602        1.67   thorpej 
    603        1.76   thorpej 	LIST_INIT(&cd->cd_attach);
    604        1.67   thorpej 	LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
    605        1.67   thorpej 
    606       1.175    cegger 	return 0;
    607        1.67   thorpej }
    608        1.67   thorpej 
    609        1.67   thorpej /*
    610        1.67   thorpej  * Remove a cfdriver from the system.
    611        1.67   thorpej  */
    612        1.67   thorpej int
    613        1.67   thorpej config_cfdriver_detach(struct cfdriver *cd)
    614        1.67   thorpej {
    615       1.198    dyoung 	struct alldevs_foray af;
    616       1.198    dyoung 	int i, rc = 0;
    617        1.67   thorpej 
    618       1.198    dyoung 	config_alldevs_enter(&af);
    619        1.67   thorpej 	/* Make sure there are no active instances. */
    620        1.67   thorpej 	for (i = 0; i < cd->cd_ndevs; i++) {
    621       1.187    dyoung 		if (cd->cd_devs[i] != NULL) {
    622       1.187    dyoung 			rc = EBUSY;
    623       1.187    dyoung 			break;
    624       1.187    dyoung 		}
    625        1.67   thorpej 	}
    626       1.198    dyoung 	config_alldevs_exit(&af);
    627       1.187    dyoung 
    628       1.187    dyoung 	if (rc != 0)
    629       1.187    dyoung 		return rc;
    630        1.67   thorpej 
    631        1.76   thorpej 	/* ...and no attachments loaded. */
    632        1.76   thorpej 	if (LIST_EMPTY(&cd->cd_attach) == 0)
    633       1.175    cegger 		return EBUSY;
    634        1.76   thorpej 
    635        1.67   thorpej 	LIST_REMOVE(cd, cd_list);
    636        1.67   thorpej 
    637        1.67   thorpej 	KASSERT(cd->cd_devs == NULL);
    638        1.67   thorpej 
    639       1.175    cegger 	return 0;
    640        1.67   thorpej }
    641        1.67   thorpej 
    642        1.67   thorpej /*
    643        1.67   thorpej  * Look up a cfdriver by name.
    644        1.67   thorpej  */
    645        1.78     isaki struct cfdriver *
    646        1.67   thorpej config_cfdriver_lookup(const char *name)
    647        1.67   thorpej {
    648        1.67   thorpej 	struct cfdriver *cd;
    649        1.69   thorpej 
    650        1.67   thorpej 	LIST_FOREACH(cd, &allcfdrivers, cd_list) {
    651        1.67   thorpej 		if (STREQ(cd->cd_name, name))
    652       1.175    cegger 			return cd;
    653        1.67   thorpej 	}
    654        1.67   thorpej 
    655       1.175    cegger 	return NULL;
    656        1.67   thorpej }
    657        1.67   thorpej 
    658        1.67   thorpej /*
    659        1.76   thorpej  * Add a cfattach to the specified driver.
    660        1.76   thorpej  */
    661        1.76   thorpej int
    662        1.76   thorpej config_cfattach_attach(const char *driver, struct cfattach *ca)
    663        1.76   thorpej {
    664        1.76   thorpej 	struct cfattach *lca;
    665        1.76   thorpej 	struct cfdriver *cd;
    666        1.76   thorpej 
    667        1.76   thorpej 	cd = config_cfdriver_lookup(driver);
    668        1.76   thorpej 	if (cd == NULL)
    669       1.175    cegger 		return ESRCH;
    670        1.76   thorpej 
    671        1.76   thorpej 	/* Make sure this attachment isn't already on this driver. */
    672        1.76   thorpej 	LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
    673        1.76   thorpej 		if (STREQ(lca->ca_name, ca->ca_name))
    674       1.175    cegger 			return EEXIST;
    675        1.76   thorpej 	}
    676        1.76   thorpej 
    677        1.76   thorpej 	LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
    678        1.76   thorpej 
    679       1.175    cegger 	return 0;
    680        1.76   thorpej }
    681        1.76   thorpej 
    682        1.76   thorpej /*
    683        1.76   thorpej  * Remove a cfattach from the specified driver.
    684        1.76   thorpej  */
    685        1.76   thorpej int
    686        1.76   thorpej config_cfattach_detach(const char *driver, struct cfattach *ca)
    687        1.76   thorpej {
    688       1.198    dyoung 	struct alldevs_foray af;
    689        1.76   thorpej 	struct cfdriver *cd;
    690       1.102   thorpej 	device_t dev;
    691       1.198    dyoung 	int i, rc = 0;
    692        1.76   thorpej 
    693        1.76   thorpej 	cd = config_cfdriver_lookup(driver);
    694        1.76   thorpej 	if (cd == NULL)
    695       1.175    cegger 		return ESRCH;
    696        1.76   thorpej 
    697       1.198    dyoung 	config_alldevs_enter(&af);
    698        1.76   thorpej 	/* Make sure there are no active instances. */
    699        1.76   thorpej 	for (i = 0; i < cd->cd_ndevs; i++) {
    700        1.76   thorpej 		if ((dev = cd->cd_devs[i]) == NULL)
    701        1.76   thorpej 			continue;
    702       1.187    dyoung 		if (dev->dv_cfattach == ca) {
    703       1.187    dyoung 			rc = EBUSY;
    704       1.187    dyoung 			break;
    705       1.187    dyoung 		}
    706        1.76   thorpej 	}
    707       1.198    dyoung 	config_alldevs_exit(&af);
    708       1.187    dyoung 
    709       1.187    dyoung 	if (rc != 0)
    710       1.187    dyoung 		return rc;
    711        1.76   thorpej 
    712        1.76   thorpej 	LIST_REMOVE(ca, ca_list);
    713        1.76   thorpej 
    714       1.175    cegger 	return 0;
    715        1.76   thorpej }
    716        1.76   thorpej 
    717        1.76   thorpej /*
    718        1.76   thorpej  * Look up a cfattach by name.
    719        1.76   thorpej  */
    720        1.76   thorpej static struct cfattach *
    721        1.76   thorpej config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
    722        1.76   thorpej {
    723        1.76   thorpej 	struct cfattach *ca;
    724        1.76   thorpej 
    725        1.76   thorpej 	LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
    726        1.76   thorpej 		if (STREQ(ca->ca_name, atname))
    727       1.175    cegger 			return ca;
    728        1.76   thorpej 	}
    729        1.76   thorpej 
    730       1.175    cegger 	return NULL;
    731        1.76   thorpej }
    732        1.76   thorpej 
    733        1.76   thorpej /*
    734        1.76   thorpej  * Look up a cfattach by driver/attachment name.
    735        1.76   thorpej  */
    736        1.76   thorpej struct cfattach *
    737        1.76   thorpej config_cfattach_lookup(const char *name, const char *atname)
    738        1.76   thorpej {
    739        1.76   thorpej 	struct cfdriver *cd;
    740        1.76   thorpej 
    741        1.76   thorpej 	cd = config_cfdriver_lookup(name);
    742        1.76   thorpej 	if (cd == NULL)
    743       1.175    cegger 		return NULL;
    744        1.76   thorpej 
    745       1.175    cegger 	return config_cfattach_lookup_cd(cd, atname);
    746        1.76   thorpej }
    747        1.76   thorpej 
    748        1.76   thorpej /*
    749         1.1     glass  * Apply the matching function and choose the best.  This is used
    750         1.1     glass  * a few times and we want to keep the code small.
    751         1.1     glass  */
    752        1.16   mycroft static void
    753       1.102   thorpej mapply(struct matchinfo *m, cfdata_t cf)
    754         1.1     glass {
    755        1.50  augustss 	int pri;
    756         1.1     glass 
    757        1.99  drochner 	if (m->fn != NULL) {
    758        1.99  drochner 		pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
    759        1.90  drochner 	} else {
    760       1.100  drochner 		pri = config_match(m->parent, cf, m->aux);
    761         1.3     glass 	}
    762         1.1     glass 	if (pri > m->pri) {
    763        1.25       cgd 		m->match = cf;
    764         1.1     glass 		m->pri = pri;
    765         1.1     glass 	}
    766         1.1     glass }
    767         1.1     glass 
    768        1.98  drochner int
    769       1.102   thorpej config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
    770        1.98  drochner {
    771        1.98  drochner 	const struct cfiattrdata *ci;
    772        1.98  drochner 	const struct cflocdesc *cl;
    773        1.98  drochner 	int nlocs, i;
    774        1.98  drochner 
    775       1.201    dyoung 	ci = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
    776        1.98  drochner 	KASSERT(ci);
    777        1.98  drochner 	nlocs = ci->ci_loclen;
    778       1.154  drochner 	KASSERT(!nlocs || locs);
    779        1.98  drochner 	for (i = 0; i < nlocs; i++) {
    780        1.98  drochner 		cl = &ci->ci_locdesc[i];
    781       1.233  uebayasi 		if (cl->cld_defaultstr != NULL &&
    782       1.233  uebayasi 		    cf->cf_loc[i] == cl->cld_default)
    783       1.233  uebayasi 			continue;
    784       1.233  uebayasi 		if (cf->cf_loc[i] == locs[i])
    785       1.233  uebayasi 			continue;
    786       1.233  uebayasi 		return 0;
    787        1.98  drochner 	}
    788        1.98  drochner 
    789       1.175    cegger 	return config_match(parent, cf, aux);
    790        1.98  drochner }
    791        1.98  drochner 
    792         1.1     glass /*
    793        1.96  drochner  * Helper function: check whether the driver supports the interface attribute
    794        1.96  drochner  * and return its descriptor structure.
    795        1.91  drochner  */
    796        1.96  drochner static const struct cfiattrdata *
    797        1.96  drochner cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
    798        1.91  drochner {
    799        1.96  drochner 	const struct cfiattrdata * const *cpp;
    800        1.91  drochner 
    801        1.91  drochner 	if (cd->cd_attrs == NULL)
    802       1.175    cegger 		return 0;
    803        1.91  drochner 
    804        1.91  drochner 	for (cpp = cd->cd_attrs; *cpp; cpp++) {
    805        1.96  drochner 		if (STREQ((*cpp)->ci_name, ia)) {
    806        1.91  drochner 			/* Match. */
    807       1.175    cegger 			return *cpp;
    808        1.91  drochner 		}
    809        1.91  drochner 	}
    810       1.175    cegger 	return 0;
    811        1.91  drochner }
    812        1.91  drochner 
    813   1.277.2.2   thorpej #if defined(DIAGNOSTIC)
    814   1.277.2.2   thorpej static int
    815   1.277.2.2   thorpej cfdriver_iattr_count(const struct cfdriver *cd)
    816   1.277.2.2   thorpej {
    817   1.277.2.2   thorpej 	const struct cfiattrdata * const *cpp;
    818   1.277.2.2   thorpej 	int i;
    819   1.277.2.2   thorpej 
    820   1.277.2.2   thorpej 	if (cd->cd_attrs == NULL)
    821   1.277.2.2   thorpej 		return 0;
    822   1.277.2.2   thorpej 
    823   1.277.2.2   thorpej 	for (i = 0, cpp = cd->cd_attrs; *cpp; cpp++) {
    824   1.277.2.2   thorpej 		i++;
    825   1.277.2.2   thorpej 	}
    826   1.277.2.2   thorpej 	return i;
    827   1.277.2.2   thorpej }
    828   1.277.2.2   thorpej #endif /* DIAGNOSTIC */
    829   1.277.2.2   thorpej 
    830        1.91  drochner /*
    831        1.96  drochner  * Lookup an interface attribute description by name.
    832        1.96  drochner  * If the driver is given, consider only its supported attributes.
    833        1.96  drochner  */
    834        1.96  drochner const struct cfiattrdata *
    835        1.96  drochner cfiattr_lookup(const char *name, const struct cfdriver *cd)
    836        1.96  drochner {
    837        1.96  drochner 	const struct cfdriver *d;
    838        1.96  drochner 	const struct cfiattrdata *ia;
    839        1.96  drochner 
    840        1.96  drochner 	if (cd)
    841       1.175    cegger 		return cfdriver_get_iattr(cd, name);
    842        1.96  drochner 
    843        1.96  drochner 	LIST_FOREACH(d, &allcfdrivers, cd_list) {
    844        1.96  drochner 		ia = cfdriver_get_iattr(d, name);
    845        1.96  drochner 		if (ia)
    846       1.175    cegger 			return ia;
    847        1.96  drochner 	}
    848       1.175    cegger 	return 0;
    849        1.96  drochner }
    850        1.96  drochner 
    851        1.96  drochner /*
    852        1.66   thorpej  * Determine if `parent' is a potential parent for a device spec based
    853        1.66   thorpej  * on `cfp'.
    854        1.66   thorpej  */
    855        1.66   thorpej static int
    856       1.102   thorpej cfparent_match(const device_t parent, const struct cfparent *cfp)
    857        1.66   thorpej {
    858        1.67   thorpej 	struct cfdriver *pcd;
    859        1.70   thorpej 
    860        1.70   thorpej 	/* We don't match root nodes here. */
    861        1.70   thorpej 	if (cfp == NULL)
    862       1.175    cegger 		return 0;
    863        1.66   thorpej 
    864        1.77   thorpej 	pcd = parent->dv_cfdriver;
    865        1.67   thorpej 	KASSERT(pcd != NULL);
    866        1.67   thorpej 
    867        1.66   thorpej 	/*
    868        1.66   thorpej 	 * First, ensure this parent has the correct interface
    869        1.66   thorpej 	 * attribute.
    870        1.66   thorpej 	 */
    871        1.96  drochner 	if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
    872       1.175    cegger 		return 0;
    873        1.66   thorpej 
    874        1.66   thorpej 	/*
    875        1.66   thorpej 	 * If no specific parent device instance was specified (i.e.
    876        1.66   thorpej 	 * we're attaching to the attribute only), we're done!
    877        1.66   thorpej 	 */
    878        1.66   thorpej 	if (cfp->cfp_parent == NULL)
    879       1.175    cegger 		return 1;
    880        1.66   thorpej 
    881        1.66   thorpej 	/*
    882        1.66   thorpej 	 * Check the parent device's name.
    883        1.66   thorpej 	 */
    884        1.71   thorpej 	if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
    885       1.175    cegger 		return 0;	/* not the same parent */
    886        1.66   thorpej 
    887        1.66   thorpej 	/*
    888        1.66   thorpej 	 * Make sure the unit number matches.
    889        1.66   thorpej 	 */
    890        1.77   thorpej 	if (cfp->cfp_unit == DVUNIT_ANY ||	/* wildcard */
    891        1.66   thorpej 	    cfp->cfp_unit == parent->dv_unit)
    892       1.175    cegger 		return 1;
    893        1.66   thorpej 
    894        1.66   thorpej 	/* Unit numbers don't match. */
    895       1.175    cegger 	return 0;
    896        1.68   thorpej }
    897        1.68   thorpej 
    898        1.68   thorpej /*
    899        1.90  drochner  * Helper for config_cfdata_attach(): check all devices whether it could be
    900        1.90  drochner  * parent any attachment in the config data table passed, and rescan.
    901        1.90  drochner  */
    902        1.90  drochner static void
    903        1.90  drochner rescan_with_cfdata(const struct cfdata *cf)
    904        1.90  drochner {
    905       1.102   thorpej 	device_t d;
    906        1.90  drochner 	const struct cfdata *cf1;
    907       1.136    dyoung 	deviter_t di;
    908       1.243   msaitoh 
    909        1.90  drochner 
    910        1.90  drochner 	/*
    911       1.164        ad 	 * "alldevs" is likely longer than a modules's cfdata, so make it
    912        1.90  drochner 	 * the outer loop.
    913        1.90  drochner 	 */
    914       1.136    dyoung 	for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) {
    915        1.90  drochner 
    916        1.90  drochner 		if (!(d->dv_cfattach->ca_rescan))
    917        1.90  drochner 			continue;
    918        1.90  drochner 
    919        1.90  drochner 		for (cf1 = cf; cf1->cf_name; cf1++) {
    920        1.90  drochner 
    921        1.90  drochner 			if (!cfparent_match(d, cf1->cf_pspec))
    922        1.90  drochner 				continue;
    923        1.90  drochner 
    924        1.90  drochner 			(*d->dv_cfattach->ca_rescan)(d,
    925       1.201    dyoung 				cfdata_ifattr(cf1), cf1->cf_loc);
    926       1.209    jruoho 
    927       1.209    jruoho 			config_deferred(d);
    928        1.90  drochner 		}
    929        1.90  drochner 	}
    930       1.136    dyoung 	deviter_release(&di);
    931        1.90  drochner }
    932        1.90  drochner 
    933        1.90  drochner /*
    934        1.90  drochner  * Attach a supplemental config data table and rescan potential
    935        1.90  drochner  * parent devices if required.
    936        1.90  drochner  */
    937        1.90  drochner int
    938       1.102   thorpej config_cfdata_attach(cfdata_t cf, int scannow)
    939        1.90  drochner {
    940        1.90  drochner 	struct cftable *ct;
    941        1.90  drochner 
    942       1.159      matt 	ct = kmem_alloc(sizeof(*ct), KM_SLEEP);
    943        1.90  drochner 	ct->ct_cfdata = cf;
    944        1.90  drochner 	TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
    945        1.90  drochner 
    946        1.90  drochner 	if (scannow)
    947        1.90  drochner 		rescan_with_cfdata(cf);
    948        1.90  drochner 
    949       1.175    cegger 	return 0;
    950        1.90  drochner }
    951        1.90  drochner 
    952        1.90  drochner /*
    953        1.90  drochner  * Helper for config_cfdata_detach: check whether a device is
    954        1.90  drochner  * found through any attachment in the config data table.
    955        1.90  drochner  */
    956        1.90  drochner static int
    957       1.224       chs dev_in_cfdata(device_t d, cfdata_t cf)
    958        1.90  drochner {
    959        1.90  drochner 	const struct cfdata *cf1;
    960        1.90  drochner 
    961        1.90  drochner 	for (cf1 = cf; cf1->cf_name; cf1++)
    962        1.90  drochner 		if (d->dv_cfdata == cf1)
    963       1.175    cegger 			return 1;
    964        1.90  drochner 
    965       1.175    cegger 	return 0;
    966        1.90  drochner }
    967        1.90  drochner 
    968        1.90  drochner /*
    969        1.90  drochner  * Detach a supplemental config data table. Detach all devices found
    970        1.90  drochner  * through that table (and thus keeping references to it) before.
    971        1.90  drochner  */
    972        1.90  drochner int
    973       1.102   thorpej config_cfdata_detach(cfdata_t cf)
    974        1.90  drochner {
    975       1.102   thorpej 	device_t d;
    976       1.136    dyoung 	int error = 0;
    977        1.90  drochner 	struct cftable *ct;
    978       1.136    dyoung 	deviter_t di;
    979        1.90  drochner 
    980       1.136    dyoung 	for (d = deviter_first(&di, DEVITER_F_RW); d != NULL;
    981       1.136    dyoung 	     d = deviter_next(&di)) {
    982       1.136    dyoung 		if (!dev_in_cfdata(d, cf))
    983       1.136    dyoung 			continue;
    984       1.136    dyoung 		if ((error = config_detach(d, 0)) != 0)
    985       1.136    dyoung 			break;
    986       1.136    dyoung 	}
    987       1.136    dyoung 	deviter_release(&di);
    988       1.136    dyoung 	if (error) {
    989       1.136    dyoung 		aprint_error_dev(d, "unable to detach instance\n");
    990       1.136    dyoung 		return error;
    991        1.90  drochner 	}
    992        1.90  drochner 
    993        1.90  drochner 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
    994        1.90  drochner 		if (ct->ct_cfdata == cf) {
    995        1.90  drochner 			TAILQ_REMOVE(&allcftables, ct, ct_list);
    996       1.159      matt 			kmem_free(ct, sizeof(*ct));
    997       1.175    cegger 			return 0;
    998        1.90  drochner 		}
    999        1.90  drochner 	}
   1000        1.90  drochner 
   1001        1.90  drochner 	/* not found -- shouldn't happen */
   1002       1.175    cegger 	return EINVAL;
   1003        1.90  drochner }
   1004        1.90  drochner 
   1005        1.90  drochner /*
   1006        1.68   thorpej  * Invoke the "match" routine for a cfdata entry on behalf of
   1007        1.68   thorpej  * an external caller, usually a "submatch" routine.
   1008        1.68   thorpej  */
   1009        1.68   thorpej int
   1010       1.102   thorpej config_match(device_t parent, cfdata_t cf, void *aux)
   1011        1.68   thorpej {
   1012        1.76   thorpej 	struct cfattach *ca;
   1013        1.76   thorpej 
   1014        1.76   thorpej 	ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
   1015        1.76   thorpej 	if (ca == NULL) {
   1016        1.76   thorpej 		/* No attachment for this entry, oh well. */
   1017       1.175    cegger 		return 0;
   1018        1.76   thorpej 	}
   1019        1.68   thorpej 
   1020       1.175    cegger 	return (*ca->ca_match)(parent, cf, aux);
   1021        1.66   thorpej }
   1022        1.66   thorpej 
   1023   1.277.2.1   thorpej static void
   1024   1.277.2.1   thorpej config_get_cfargs(cfarg_t tag,
   1025   1.277.2.1   thorpej 		  cfsubmatch_t *fnp,		/* output */
   1026   1.277.2.1   thorpej 		  const char **ifattrp,		/* output */
   1027   1.277.2.1   thorpej 		  const int **locsp,		/* output */
   1028  1.277.2.10   thorpej 		  devhandle_t *handlep,		/* output */
   1029   1.277.2.1   thorpej 		  va_list ap)
   1030   1.277.2.1   thorpej {
   1031   1.277.2.1   thorpej 	cfsubmatch_t fn = NULL;
   1032   1.277.2.1   thorpej 	const char *ifattr = NULL;
   1033   1.277.2.1   thorpej 	const int *locs = NULL;
   1034  1.277.2.10   thorpej 	devhandle_t handle;
   1035  1.277.2.10   thorpej 
   1036  1.277.2.10   thorpej 	devhandle_invalidate(&handle);
   1037   1.277.2.1   thorpej 
   1038   1.277.2.1   thorpej 	while (tag != CFARG_EOL) {
   1039   1.277.2.1   thorpej 		switch (tag) {
   1040  1.277.2.11   thorpej 		/*
   1041  1.277.2.11   thorpej 		 * CFARG_SUBMATCH and CFARG_SEARCH are synonyms, but this
   1042  1.277.2.11   thorpej 		 * is merely an implementation detail.  They are distinct
   1043  1.277.2.11   thorpej 		 * from the caller's point of view.
   1044  1.277.2.11   thorpej 		 */
   1045   1.277.2.1   thorpej 		case CFARG_SUBMATCH:
   1046  1.277.2.11   thorpej 		case CFARG_SEARCH:
   1047  1.277.2.11   thorpej 			/* Only allow one function to be specified. */
   1048  1.277.2.11   thorpej 			if (fn != NULL) {
   1049  1.277.2.11   thorpej 				panic("%s: caller specified both "
   1050  1.277.2.11   thorpej 				    "SUBMATCH and SEARCH", __func__);
   1051  1.277.2.11   thorpej 			}
   1052   1.277.2.1   thorpej 			fn = va_arg(ap, cfsubmatch_t);
   1053   1.277.2.1   thorpej 			break;
   1054   1.277.2.1   thorpej 
   1055   1.277.2.1   thorpej 		case CFARG_IATTR:
   1056   1.277.2.1   thorpej 			ifattr = va_arg(ap, const char *);
   1057   1.277.2.1   thorpej 			break;
   1058   1.277.2.1   thorpej 
   1059   1.277.2.1   thorpej 		case CFARG_LOCATORS:
   1060   1.277.2.1   thorpej 			locs = va_arg(ap, const int *);
   1061   1.277.2.1   thorpej 			break;
   1062   1.277.2.1   thorpej 
   1063  1.277.2.10   thorpej 		case CFARG_DEVHANDLE:
   1064  1.277.2.10   thorpej 			handle = va_arg(ap, devhandle_t);
   1065  1.277.2.10   thorpej 			break;
   1066  1.277.2.10   thorpej 
   1067   1.277.2.1   thorpej 		default:
   1068  1.277.2.11   thorpej 			panic("%s: unknown cfarg tag: %d\n",
   1069   1.277.2.1   thorpej 			    __func__, tag);
   1070   1.277.2.1   thorpej 		}
   1071   1.277.2.1   thorpej 		tag = va_arg(ap, cfarg_t);
   1072   1.277.2.1   thorpej 	}
   1073   1.277.2.1   thorpej 
   1074   1.277.2.1   thorpej 	if (fnp != NULL)
   1075   1.277.2.1   thorpej 		*fnp = fn;
   1076   1.277.2.1   thorpej 	if (ifattrp != NULL)
   1077   1.277.2.1   thorpej 		*ifattrp = ifattr;
   1078   1.277.2.1   thorpej 	if (locsp != NULL)
   1079   1.277.2.1   thorpej 		*locsp = locs;
   1080  1.277.2.10   thorpej 	if (handlep != NULL)
   1081  1.277.2.10   thorpej 		*handlep = handle;
   1082   1.277.2.1   thorpej }
   1083   1.277.2.1   thorpej 
   1084        1.66   thorpej /*
   1085         1.1     glass  * Iterate over all potential children of some device, calling the given
   1086         1.1     glass  * function (default being the child's match function) for each one.
   1087         1.1     glass  * Nonzero returns are matches; the highest value returned is considered
   1088         1.1     glass  * the best match.  Return the `found child' if we got a match, or NULL
   1089         1.1     glass  * otherwise.  The `aux' pointer is simply passed on through.
   1090         1.1     glass  *
   1091         1.1     glass  * Note that this function is designed so that it can be used to apply
   1092         1.1     glass  * an arbitrary function to all potential children (its return value
   1093         1.1     glass  * can be ignored).
   1094         1.1     glass  */
   1095   1.277.2.1   thorpej static cfdata_t
   1096   1.277.2.1   thorpej config_vsearch(device_t parent, void *aux, cfarg_t tag, va_list ap)
   1097        1.90  drochner {
   1098   1.277.2.1   thorpej 	cfsubmatch_t fn;
   1099   1.277.2.1   thorpej 	const char *ifattr;
   1100   1.277.2.1   thorpej 	const int *locs;
   1101        1.90  drochner 	struct cftable *ct;
   1102       1.102   thorpej 	cfdata_t cf;
   1103        1.90  drochner 	struct matchinfo m;
   1104        1.90  drochner 
   1105  1.277.2.10   thorpej 	config_get_cfargs(tag, &fn, &ifattr, &locs, NULL, ap);
   1106   1.277.2.1   thorpej 
   1107        1.90  drochner 	KASSERT(config_initialized);
   1108        1.96  drochner 	KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
   1109   1.277.2.2   thorpej 	KASSERT(ifattr || cfdriver_iattr_count(parent->dv_cfdriver) < 2);
   1110        1.90  drochner 
   1111        1.99  drochner 	m.fn = fn;
   1112         1.1     glass 	m.parent = parent;
   1113        1.99  drochner 	m.locs = locs;
   1114        1.25       cgd 	m.aux = aux;
   1115        1.14   mycroft 	m.match = NULL;
   1116         1.1     glass 	m.pri = 0;
   1117        1.65   thorpej 
   1118        1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
   1119        1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
   1120        1.90  drochner 
   1121        1.90  drochner 			/* We don't match root nodes here. */
   1122        1.90  drochner 			if (!cf->cf_pspec)
   1123        1.90  drochner 				continue;
   1124        1.90  drochner 
   1125        1.65   thorpej 			/*
   1126        1.65   thorpej 			 * Skip cf if no longer eligible, otherwise scan
   1127        1.65   thorpej 			 * through parents for one matching `parent', and
   1128        1.65   thorpej 			 * try match function.
   1129        1.65   thorpej 			 */
   1130        1.65   thorpej 			if (cf->cf_fstate == FSTATE_FOUND)
   1131        1.65   thorpej 				continue;
   1132        1.65   thorpej 			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
   1133        1.65   thorpej 			    cf->cf_fstate == FSTATE_DSTAR)
   1134        1.65   thorpej 				continue;
   1135        1.90  drochner 
   1136        1.90  drochner 			/*
   1137        1.90  drochner 			 * If an interface attribute was specified,
   1138        1.90  drochner 			 * consider only children which attach to
   1139        1.90  drochner 			 * that attribute.
   1140        1.90  drochner 			 */
   1141       1.201    dyoung 			if (ifattr && !STREQ(ifattr, cfdata_ifattr(cf)))
   1142        1.90  drochner 				continue;
   1143        1.90  drochner 
   1144        1.66   thorpej 			if (cfparent_match(parent, cf->cf_pspec))
   1145        1.66   thorpej 				mapply(&m, cf);
   1146        1.65   thorpej 		}
   1147         1.1     glass 	}
   1148       1.175    cegger 	return m.match;
   1149         1.1     glass }
   1150         1.1     glass 
   1151       1.102   thorpej cfdata_t
   1152   1.277.2.1   thorpej config_search(device_t parent, void *aux, cfarg_t tag, ...)
   1153       1.102   thorpej {
   1154   1.277.2.1   thorpej 	cfdata_t cf;
   1155   1.277.2.1   thorpej 	va_list ap;
   1156   1.277.2.1   thorpej 
   1157   1.277.2.1   thorpej 	va_start(ap, tag);
   1158   1.277.2.1   thorpej 	cf = config_vsearch(parent, aux, tag, ap);
   1159   1.277.2.1   thorpej 	va_end(ap);
   1160       1.102   thorpej 
   1161   1.277.2.1   thorpej 	return cf;
   1162       1.102   thorpej }
   1163       1.102   thorpej 
   1164        1.16   mycroft /*
   1165         1.1     glass  * Find the given root device.
   1166         1.1     glass  * This is much like config_search, but there is no parent.
   1167        1.65   thorpej  * Don't bother with multiple cfdata tables; the root node
   1168        1.65   thorpej  * must always be in the initial table.
   1169         1.1     glass  */
   1170       1.102   thorpej cfdata_t
   1171        1.95  drochner config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
   1172         1.1     glass {
   1173       1.102   thorpej 	cfdata_t cf;
   1174        1.84      matt 	const short *p;
   1175         1.1     glass 	struct matchinfo m;
   1176         1.1     glass 
   1177        1.99  drochner 	m.fn = fn;
   1178         1.1     glass 	m.parent = ROOT;
   1179        1.25       cgd 	m.aux = aux;
   1180        1.14   mycroft 	m.match = NULL;
   1181         1.1     glass 	m.pri = 0;
   1182       1.114  christos 	m.locs = 0;
   1183         1.1     glass 	/*
   1184         1.1     glass 	 * Look at root entries for matching name.  We do not bother
   1185         1.1     glass 	 * with found-state here since only one root should ever be
   1186         1.1     glass 	 * searched (and it must be done first).
   1187         1.1     glass 	 */
   1188         1.1     glass 	for (p = cfroots; *p >= 0; p++) {
   1189         1.1     glass 		cf = &cfdata[*p];
   1190        1.67   thorpej 		if (strcmp(cf->cf_name, rootname) == 0)
   1191        1.16   mycroft 			mapply(&m, cf);
   1192         1.1     glass 	}
   1193       1.175    cegger 	return m.match;
   1194         1.1     glass }
   1195         1.1     glass 
   1196        1.83  jdolecek static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
   1197         1.1     glass 
   1198         1.1     glass /*
   1199         1.1     glass  * The given `aux' argument describes a device that has been found
   1200         1.1     glass  * on the given parent, but not necessarily configured.  Locate the
   1201        1.18       cgd  * configuration data for that device (using the submatch function
   1202        1.18       cgd  * provided, or using candidates' cd_match configuration driver
   1203       1.218    dyoung  * functions) and attach it, and return its device_t.  If the device was
   1204       1.218    dyoung  * not configured, call the given `print' function and return NULL.
   1205         1.1     glass  */
   1206   1.277.2.3   thorpej static device_t
   1207   1.277.2.3   thorpej config_vfound(device_t parent, void *aux, cfprint_t print, cfarg_t tag,
   1208   1.277.2.3   thorpej     va_list ap)
   1209        1.90  drochner {
   1210       1.102   thorpej 	cfdata_t cf;
   1211   1.277.2.9   thorpej 	va_list nap;
   1212   1.277.2.9   thorpej 
   1213   1.277.2.9   thorpej 	va_copy(nap, ap);
   1214   1.277.2.9   thorpej 	cf = config_vsearch(parent, aux, tag, nap);
   1215   1.277.2.9   thorpej 	va_end(nap);
   1216        1.90  drochner 
   1217   1.277.2.9   thorpej 	if (cf != NULL) {
   1218   1.277.2.9   thorpej 		return config_vattach(parent, cf, aux, print, tag, ap);
   1219   1.277.2.9   thorpej 	}
   1220   1.277.2.3   thorpej 
   1221        1.90  drochner 	if (print) {
   1222       1.176        ad 		if (config_do_twiddle && cold)
   1223        1.90  drochner 			twiddle();
   1224       1.143    cegger 		aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]);
   1225        1.90  drochner 	}
   1226       1.105  jmcneill 
   1227       1.231       tls 	/*
   1228       1.231       tls 	 * This has the effect of mixing in a single timestamp to the
   1229       1.231       tls 	 * entropy pool.  Experiments indicate the estimator will almost
   1230       1.231       tls 	 * always attribute one bit of entropy to this sample; analysis
   1231       1.231       tls 	 * of device attach/detach timestamps on FreeBSD indicates 4
   1232       1.231       tls 	 * bits of entropy/sample so this seems appropriately conservative.
   1233       1.231       tls 	 */
   1234       1.231       tls 	rnd_add_uint32(&rnd_autoconf_source, 0);
   1235       1.175    cegger 	return NULL;
   1236        1.90  drochner }
   1237        1.90  drochner 
   1238       1.102   thorpej device_t
   1239   1.277.2.3   thorpej config_found(device_t parent, void *aux, cfprint_t print, cfarg_t tag, ...)
   1240       1.102   thorpej {
   1241   1.277.2.3   thorpej 	device_t dev;
   1242   1.277.2.3   thorpej 	va_list ap;
   1243       1.102   thorpej 
   1244   1.277.2.3   thorpej 	va_start(ap, tag);
   1245   1.277.2.3   thorpej 	dev = config_vfound(parent, aux, print, tag, ap);
   1246   1.277.2.3   thorpej 	va_end(ap);
   1247   1.277.2.3   thorpej 
   1248   1.277.2.3   thorpej 	return dev;
   1249       1.102   thorpej }
   1250       1.102   thorpej 
   1251         1.1     glass /*
   1252         1.1     glass  * As above, but for root devices.
   1253         1.1     glass  */
   1254       1.102   thorpej device_t
   1255        1.52       cgd config_rootfound(const char *rootname, void *aux)
   1256         1.1     glass {
   1257       1.102   thorpej 	cfdata_t cf;
   1258        1.25       cgd 
   1259       1.220    plunky 	if ((cf = config_rootsearch(NULL, rootname, aux)) != NULL)
   1260   1.277.2.7   thorpej 		return config_attach(ROOT, cf, aux, NULL, CFARG_EOL);
   1261        1.80   thorpej 	aprint_error("root device %s not configured\n", rootname);
   1262       1.175    cegger 	return NULL;
   1263         1.1     glass }
   1264         1.1     glass 
   1265         1.1     glass /* just like sprintf(buf, "%d") except that it works from the end */
   1266         1.1     glass static char *
   1267        1.51       cgd number(char *ep, int n)
   1268         1.1     glass {
   1269         1.1     glass 
   1270         1.1     glass 	*--ep = 0;
   1271         1.1     glass 	while (n >= 10) {
   1272         1.1     glass 		*--ep = (n % 10) + '0';
   1273         1.1     glass 		n /= 10;
   1274         1.1     glass 	}
   1275         1.1     glass 	*--ep = n + '0';
   1276       1.175    cegger 	return ep;
   1277         1.1     glass }
   1278         1.1     glass 
   1279         1.1     glass /*
   1280        1.59  augustss  * Expand the size of the cd_devs array if necessary.
   1281       1.187    dyoung  *
   1282       1.257   mlelstv  * The caller must hold alldevs_lock. config_makeroom() may release and
   1283       1.257   mlelstv  * re-acquire alldevs_lock, so callers should re-check conditions such
   1284       1.257   mlelstv  * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom()
   1285       1.187    dyoung  * returns.
   1286        1.59  augustss  */
   1287       1.117  drochner static void
   1288        1.59  augustss config_makeroom(int n, struct cfdriver *cd)
   1289        1.59  augustss {
   1290       1.232      matt 	int ondevs, nndevs;
   1291       1.190    dyoung 	device_t *osp, *nsp;
   1292        1.59  augustss 
   1293       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   1294       1.257   mlelstv 	alldevs_nwrite++;
   1295       1.187    dyoung 
   1296       1.232      matt 	for (nndevs = MAX(4, cd->cd_ndevs); nndevs <= n; nndevs += nndevs)
   1297       1.190    dyoung 		;
   1298       1.190    dyoung 
   1299       1.190    dyoung 	while (n >= cd->cd_ndevs) {
   1300       1.190    dyoung 		/*
   1301       1.190    dyoung 		 * Need to expand the array.
   1302       1.190    dyoung 		 */
   1303       1.232      matt 		ondevs = cd->cd_ndevs;
   1304       1.190    dyoung 		osp = cd->cd_devs;
   1305       1.190    dyoung 
   1306       1.251  riastrad 		/*
   1307       1.257   mlelstv 		 * Release alldevs_lock around allocation, which may
   1308       1.190    dyoung 		 * sleep.
   1309       1.190    dyoung 		 */
   1310       1.257   mlelstv 		mutex_exit(&alldevs_lock);
   1311       1.273  jdolecek 		nsp = kmem_alloc(sizeof(device_t) * nndevs, KM_SLEEP);
   1312       1.257   mlelstv 		mutex_enter(&alldevs_lock);
   1313       1.190    dyoung 
   1314       1.251  riastrad 		/*
   1315       1.251  riastrad 		 * If another thread moved the array while we did
   1316       1.257   mlelstv 		 * not hold alldevs_lock, try again.
   1317       1.190    dyoung 		 */
   1318       1.190    dyoung 		if (cd->cd_devs != osp) {
   1319       1.257   mlelstv 			mutex_exit(&alldevs_lock);
   1320       1.273  jdolecek 			kmem_free(nsp, sizeof(device_t) * nndevs);
   1321       1.257   mlelstv 			mutex_enter(&alldevs_lock);
   1322       1.190    dyoung 			continue;
   1323       1.190    dyoung 		}
   1324        1.59  augustss 
   1325       1.273  jdolecek 		memset(nsp + ondevs, 0, sizeof(device_t) * (nndevs - ondevs));
   1326       1.232      matt 		if (ondevs != 0)
   1327       1.273  jdolecek 			memcpy(nsp, cd->cd_devs, sizeof(device_t) * ondevs);
   1328       1.190    dyoung 
   1329       1.232      matt 		cd->cd_ndevs = nndevs;
   1330       1.190    dyoung 		cd->cd_devs = nsp;
   1331       1.232      matt 		if (ondevs != 0) {
   1332       1.257   mlelstv 			mutex_exit(&alldevs_lock);
   1333       1.273  jdolecek 			kmem_free(osp, sizeof(device_t) * ondevs);
   1334       1.257   mlelstv 			mutex_enter(&alldevs_lock);
   1335       1.206    dyoung 		}
   1336        1.59  augustss 	}
   1337       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   1338       1.257   mlelstv 	alldevs_nwrite--;
   1339        1.59  augustss }
   1340        1.59  augustss 
   1341       1.190    dyoung /*
   1342       1.190    dyoung  * Put dev into the devices list.
   1343       1.190    dyoung  */
   1344       1.117  drochner static void
   1345       1.117  drochner config_devlink(device_t dev)
   1346       1.117  drochner {
   1347       1.117  drochner 
   1348       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   1349       1.117  drochner 
   1350       1.190    dyoung 	KASSERT(device_cfdriver(dev)->cd_devs[dev->dv_unit] == dev);
   1351       1.190    dyoung 
   1352       1.257   mlelstv 	dev->dv_add_gen = alldevs_gen;
   1353       1.136    dyoung 	/* It is safe to add a device to the tail of the list while
   1354       1.187    dyoung 	 * readers and writers are in the list.
   1355       1.136    dyoung 	 */
   1356       1.257   mlelstv 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
   1357       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   1358       1.117  drochner }
   1359       1.117  drochner 
   1360       1.190    dyoung static void
   1361       1.190    dyoung config_devfree(device_t dev)
   1362       1.190    dyoung {
   1363       1.271   thorpej 	KASSERT(dev->dv_flags & DVF_PRIV_ALLOC);
   1364       1.190    dyoung 
   1365       1.190    dyoung 	if (dev->dv_cfattach->ca_devsize > 0)
   1366       1.190    dyoung 		kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
   1367       1.271   thorpej 	kmem_free(dev, sizeof(*dev));
   1368       1.190    dyoung }
   1369       1.190    dyoung 
   1370       1.187    dyoung /*
   1371       1.257   mlelstv  * Caller must hold alldevs_lock.
   1372       1.187    dyoung  */
   1373       1.117  drochner static void
   1374       1.190    dyoung config_devunlink(device_t dev, struct devicelist *garbage)
   1375       1.117  drochner {
   1376       1.190    dyoung 	struct device_garbage *dg = &dev->dv_garbage;
   1377       1.190    dyoung 	cfdriver_t cd = device_cfdriver(dev);
   1378       1.190    dyoung 	int i;
   1379       1.187    dyoung 
   1380       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   1381       1.117  drochner 
   1382       1.190    dyoung  	/* Unlink from device list.  Link to garbage list. */
   1383       1.257   mlelstv 	TAILQ_REMOVE(&alldevs, dev, dv_list);
   1384       1.190    dyoung 	TAILQ_INSERT_TAIL(garbage, dev, dv_list);
   1385       1.117  drochner 
   1386       1.117  drochner 	/* Remove from cfdriver's array. */
   1387       1.117  drochner 	cd->cd_devs[dev->dv_unit] = NULL;
   1388       1.117  drochner 
   1389       1.117  drochner 	/*
   1390       1.190    dyoung 	 * If the device now has no units in use, unlink its softc array.
   1391       1.117  drochner 	 */
   1392       1.159      matt 	for (i = 0; i < cd->cd_ndevs; i++) {
   1393       1.117  drochner 		if (cd->cd_devs[i] != NULL)
   1394       1.187    dyoung 			break;
   1395       1.187    dyoung 	}
   1396       1.190    dyoung 	/* Nothing found.  Unlink, now.  Deallocate, later. */
   1397       1.187    dyoung 	if (i == cd->cd_ndevs) {
   1398       1.190    dyoung 		dg->dg_ndevs = cd->cd_ndevs;
   1399       1.190    dyoung 		dg->dg_devs = cd->cd_devs;
   1400       1.187    dyoung 		cd->cd_devs = NULL;
   1401       1.187    dyoung 		cd->cd_ndevs = 0;
   1402       1.187    dyoung 	}
   1403       1.190    dyoung }
   1404       1.187    dyoung 
   1405       1.190    dyoung static void
   1406       1.190    dyoung config_devdelete(device_t dev)
   1407       1.190    dyoung {
   1408       1.190    dyoung 	struct device_garbage *dg = &dev->dv_garbage;
   1409       1.190    dyoung 	device_lock_t dvl = device_getlock(dev);
   1410       1.187    dyoung 
   1411       1.190    dyoung 	if (dg->dg_devs != NULL)
   1412       1.273  jdolecek 		kmem_free(dg->dg_devs, sizeof(device_t) * dg->dg_ndevs);
   1413       1.187    dyoung 
   1414       1.187    dyoung 	cv_destroy(&dvl->dvl_cv);
   1415       1.187    dyoung 	mutex_destroy(&dvl->dvl_mtx);
   1416       1.187    dyoung 
   1417       1.187    dyoung 	KASSERT(dev->dv_properties != NULL);
   1418       1.187    dyoung 	prop_object_release(dev->dv_properties);
   1419       1.187    dyoung 
   1420       1.197     rmind 	if (dev->dv_activity_handlers)
   1421       1.197     rmind 		panic("%s with registered handlers", __func__);
   1422       1.187    dyoung 
   1423       1.187    dyoung 	if (dev->dv_locators) {
   1424       1.187    dyoung 		size_t amount = *--dev->dv_locators;
   1425       1.187    dyoung 		kmem_free(dev->dv_locators, amount);
   1426       1.117  drochner 	}
   1427       1.197     rmind 
   1428       1.190    dyoung 	config_devfree(dev);
   1429       1.190    dyoung }
   1430       1.190    dyoung 
   1431       1.190    dyoung static int
   1432       1.190    dyoung config_unit_nextfree(cfdriver_t cd, cfdata_t cf)
   1433       1.190    dyoung {
   1434       1.190    dyoung 	int unit;
   1435       1.190    dyoung 
   1436       1.190    dyoung 	if (cf->cf_fstate == FSTATE_STAR) {
   1437       1.190    dyoung 		for (unit = cf->cf_unit; unit < cd->cd_ndevs; unit++)
   1438       1.190    dyoung 			if (cd->cd_devs[unit] == NULL)
   1439       1.190    dyoung 				break;
   1440       1.190    dyoung 		/*
   1441       1.190    dyoung 		 * unit is now the unit of the first NULL device pointer,
   1442       1.190    dyoung 		 * or max(cd->cd_ndevs,cf->cf_unit).
   1443       1.190    dyoung 		 */
   1444       1.190    dyoung 	} else {
   1445       1.190    dyoung 		unit = cf->cf_unit;
   1446       1.190    dyoung 		if (unit < cd->cd_ndevs && cd->cd_devs[unit] != NULL)
   1447       1.190    dyoung 			unit = -1;
   1448       1.190    dyoung 	}
   1449       1.190    dyoung 	return unit;
   1450       1.190    dyoung }
   1451       1.190    dyoung 
   1452       1.190    dyoung static int
   1453       1.190    dyoung config_unit_alloc(device_t dev, cfdriver_t cd, cfdata_t cf)
   1454       1.190    dyoung {
   1455       1.198    dyoung 	struct alldevs_foray af;
   1456       1.198    dyoung 	int unit;
   1457       1.187    dyoung 
   1458       1.198    dyoung 	config_alldevs_enter(&af);
   1459       1.190    dyoung 	for (;;) {
   1460       1.190    dyoung 		unit = config_unit_nextfree(cd, cf);
   1461       1.190    dyoung 		if (unit == -1)
   1462       1.190    dyoung 			break;
   1463       1.190    dyoung 		if (unit < cd->cd_ndevs) {
   1464       1.190    dyoung 			cd->cd_devs[unit] = dev;
   1465       1.190    dyoung 			dev->dv_unit = unit;
   1466       1.190    dyoung 			break;
   1467       1.190    dyoung 		}
   1468       1.190    dyoung 		config_makeroom(unit, cd);
   1469       1.190    dyoung 	}
   1470       1.198    dyoung 	config_alldevs_exit(&af);
   1471       1.187    dyoung 
   1472       1.190    dyoung 	return unit;
   1473       1.117  drochner }
   1474       1.187    dyoung 
   1475       1.117  drochner static device_t
   1476   1.277.2.9   thorpej config_vdevalloc(const device_t parent, const cfdata_t cf, cfarg_t tag,
   1477   1.277.2.9   thorpej     va_list ap)
   1478        1.25       cgd {
   1479       1.190    dyoung 	cfdriver_t cd;
   1480       1.190    dyoung 	cfattach_t ca;
   1481        1.50  augustss 	size_t lname, lunit;
   1482        1.52       cgd 	const char *xunit;
   1483       1.189     pooka 	int myunit;
   1484        1.25       cgd 	char num[10];
   1485       1.117  drochner 	device_t dev;
   1486       1.120     joerg 	void *dev_private;
   1487        1.96  drochner 	const struct cfiattrdata *ia;
   1488       1.174    dyoung 	device_lock_t dvl;
   1489   1.277.2.9   thorpej 	const int *locs;
   1490   1.277.2.9   thorpej 
   1491        1.67   thorpej 	cd = config_cfdriver_lookup(cf->cf_name);
   1492       1.117  drochner 	if (cd == NULL)
   1493       1.175    cegger 		return NULL;
   1494        1.76   thorpej 
   1495        1.76   thorpej 	ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
   1496       1.117  drochner 	if (ca == NULL)
   1497       1.175    cegger 		return NULL;
   1498        1.76   thorpej 
   1499        1.25       cgd 	/* get memory for all device vars */
   1500       1.271   thorpej 	KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
   1501       1.132      matt 	if (ca->ca_devsize > 0) {
   1502       1.166        ad 		dev_private = kmem_zalloc(ca->ca_devsize, KM_SLEEP);
   1503       1.132      matt 	} else {
   1504       1.132      matt 		dev_private = NULL;
   1505       1.132      matt 	}
   1506       1.271   thorpej 	dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
   1507       1.120     joerg 
   1508  1.277.2.10   thorpej 	/*
   1509  1.277.2.10   thorpej 	 * If a handle was supplied to config_attach(), we'll get it
   1510  1.277.2.10   thorpej 	 * assigned automatically here.  If not, then we'll get the
   1511  1.277.2.10   thorpej 	 * default invalid handle.
   1512  1.277.2.10   thorpej 	 */
   1513  1.277.2.10   thorpej 	config_get_cfargs(tag, NULL, NULL, &locs, &dev->dv_handle, ap);
   1514  1.277.2.10   thorpej 
   1515       1.202    dyoung 	dev->dv_class = cd->cd_class;
   1516       1.202    dyoung 	dev->dv_cfdata = cf;
   1517       1.202    dyoung 	dev->dv_cfdriver = cd;
   1518       1.202    dyoung 	dev->dv_cfattach = ca;
   1519       1.202    dyoung 	dev->dv_activity_count = 0;
   1520       1.202    dyoung 	dev->dv_activity_handlers = NULL;
   1521       1.202    dyoung 	dev->dv_private = dev_private;
   1522       1.202    dyoung 	dev->dv_flags = ca->ca_flags;	/* inherit flags from class */
   1523       1.202    dyoung 
   1524       1.190    dyoung 	myunit = config_unit_alloc(dev, cd, cf);
   1525       1.190    dyoung 	if (myunit == -1) {
   1526       1.190    dyoung 		config_devfree(dev);
   1527       1.190    dyoung 		return NULL;
   1528       1.190    dyoung 	}
   1529       1.190    dyoung 
   1530       1.190    dyoung 	/* compute length of name and decimal expansion of unit number */
   1531       1.190    dyoung 	lname = strlen(cd->cd_name);
   1532       1.190    dyoung 	xunit = number(&num[sizeof(num)], myunit);
   1533       1.190    dyoung 	lunit = &num[sizeof(num)] - xunit;
   1534       1.190    dyoung 	if (lname + lunit > sizeof(dev->dv_xname))
   1535   1.277.2.9   thorpej 		panic("config_vdevalloc: device name too long");
   1536       1.190    dyoung 
   1537       1.174    dyoung 	dvl = device_getlock(dev);
   1538       1.174    dyoung 
   1539       1.174    dyoung 	mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE);
   1540       1.174    dyoung 	cv_init(&dvl->dvl_cv, "pmfsusp");
   1541       1.174    dyoung 
   1542        1.31     perry 	memcpy(dev->dv_xname, cd->cd_name, lname);
   1543        1.31     perry 	memcpy(dev->dv_xname + lname, xunit, lunit);
   1544        1.25       cgd 	dev->dv_parent = parent;
   1545       1.124  jmcneill 	if (parent != NULL)
   1546       1.124  jmcneill 		dev->dv_depth = parent->dv_depth + 1;
   1547       1.124  jmcneill 	else
   1548       1.124  jmcneill 		dev->dv_depth = 0;
   1549       1.202    dyoung 	dev->dv_flags |= DVF_ACTIVE;	/* always initially active */
   1550        1.97  drochner 	if (locs) {
   1551        1.96  drochner 		KASSERT(parent); /* no locators at root */
   1552       1.201    dyoung 		ia = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
   1553       1.159      matt 		dev->dv_locators =
   1554       1.273  jdolecek 		    kmem_alloc(sizeof(int) * (ia->ci_loclen + 1), KM_SLEEP);
   1555       1.273  jdolecek 		*dev->dv_locators++ = sizeof(int) * (ia->ci_loclen + 1);
   1556       1.273  jdolecek 		memcpy(dev->dv_locators, locs, sizeof(int) * ia->ci_loclen);
   1557        1.90  drochner 	}
   1558       1.112   thorpej 	dev->dv_properties = prop_dictionary_create();
   1559       1.112   thorpej 	KASSERT(dev->dv_properties != NULL);
   1560        1.29   thorpej 
   1561       1.272  jmcneill 	prop_dictionary_set_string_nocopy(dev->dv_properties,
   1562       1.150  jmcneill 	    "device-driver", dev->dv_cfdriver->cd_name);
   1563       1.150  jmcneill 	prop_dictionary_set_uint16(dev->dv_properties,
   1564       1.150  jmcneill 	    "device-unit", dev->dv_unit);
   1565       1.236     joerg 	if (parent != NULL) {
   1566       1.272  jmcneill 		prop_dictionary_set_string(dev->dv_properties,
   1567       1.236     joerg 		    "device-parent", device_xname(parent));
   1568       1.236     joerg 	}
   1569       1.150  jmcneill 
   1570       1.221  pgoyette 	if (dev->dv_cfdriver->cd_attrs != NULL)
   1571       1.221  pgoyette 		config_add_attrib_dict(dev);
   1572       1.221  pgoyette 
   1573       1.175    cegger 	return dev;
   1574       1.117  drochner }
   1575       1.117  drochner 
   1576   1.277.2.9   thorpej static device_t
   1577   1.277.2.9   thorpej config_devalloc(const device_t parent, const cfdata_t cf, cfarg_t tag, ...)
   1578   1.277.2.9   thorpej {
   1579   1.277.2.9   thorpej 	device_t dev;
   1580   1.277.2.9   thorpej 	va_list ap;
   1581   1.277.2.9   thorpej 
   1582   1.277.2.9   thorpej 	va_start(ap, tag);
   1583   1.277.2.9   thorpej 	dev = config_vdevalloc(parent, cf, tag, ap);
   1584   1.277.2.9   thorpej 	va_end(ap);
   1585   1.277.2.9   thorpej 
   1586   1.277.2.9   thorpej 	return dev;
   1587   1.277.2.9   thorpej }
   1588   1.277.2.9   thorpej 
   1589       1.117  drochner /*
   1590       1.221  pgoyette  * Create an array of device attach attributes and add it
   1591       1.221  pgoyette  * to the device's dv_properties dictionary.
   1592       1.221  pgoyette  *
   1593       1.221  pgoyette  * <key>interface-attributes</key>
   1594       1.221  pgoyette  * <array>
   1595       1.221  pgoyette  *    <dict>
   1596       1.221  pgoyette  *       <key>attribute-name</key>
   1597       1.221  pgoyette  *       <string>foo</string>
   1598       1.221  pgoyette  *       <key>locators</key>
   1599       1.221  pgoyette  *       <array>
   1600       1.221  pgoyette  *          <dict>
   1601       1.221  pgoyette  *             <key>loc-name</key>
   1602       1.221  pgoyette  *             <string>foo-loc1</string>
   1603       1.221  pgoyette  *          </dict>
   1604       1.221  pgoyette  *          <dict>
   1605       1.221  pgoyette  *             <key>loc-name</key>
   1606       1.221  pgoyette  *             <string>foo-loc2</string>
   1607       1.221  pgoyette  *             <key>default</key>
   1608       1.221  pgoyette  *             <string>foo-loc2-default</string>
   1609       1.221  pgoyette  *          </dict>
   1610       1.221  pgoyette  *          ...
   1611       1.221  pgoyette  *       </array>
   1612       1.221  pgoyette  *    </dict>
   1613       1.221  pgoyette  *    ...
   1614       1.221  pgoyette  * </array>
   1615       1.221  pgoyette  */
   1616       1.221  pgoyette 
   1617       1.221  pgoyette static void
   1618       1.221  pgoyette config_add_attrib_dict(device_t dev)
   1619       1.221  pgoyette {
   1620       1.221  pgoyette 	int i, j;
   1621       1.221  pgoyette 	const struct cfiattrdata *ci;
   1622       1.221  pgoyette 	prop_dictionary_t attr_dict, loc_dict;
   1623       1.221  pgoyette 	prop_array_t attr_array, loc_array;
   1624       1.221  pgoyette 
   1625       1.221  pgoyette 	if ((attr_array = prop_array_create()) == NULL)
   1626       1.221  pgoyette 		return;
   1627       1.221  pgoyette 
   1628       1.221  pgoyette 	for (i = 0; ; i++) {
   1629       1.221  pgoyette 		if ((ci = dev->dv_cfdriver->cd_attrs[i]) == NULL)
   1630       1.221  pgoyette 			break;
   1631       1.221  pgoyette 		if ((attr_dict = prop_dictionary_create()) == NULL)
   1632       1.221  pgoyette 			break;
   1633       1.272  jmcneill 		prop_dictionary_set_string_nocopy(attr_dict, "attribute-name",
   1634       1.221  pgoyette 		    ci->ci_name);
   1635       1.221  pgoyette 
   1636       1.221  pgoyette 		/* Create an array of the locator names and defaults */
   1637       1.221  pgoyette 
   1638       1.221  pgoyette 		if (ci->ci_loclen != 0 &&
   1639       1.221  pgoyette 		    (loc_array = prop_array_create()) != NULL) {
   1640       1.221  pgoyette 			for (j = 0; j < ci->ci_loclen; j++) {
   1641       1.221  pgoyette 				loc_dict = prop_dictionary_create();
   1642       1.221  pgoyette 				if (loc_dict == NULL)
   1643       1.221  pgoyette 					continue;
   1644       1.272  jmcneill 				prop_dictionary_set_string_nocopy(loc_dict,
   1645       1.221  pgoyette 				    "loc-name", ci->ci_locdesc[j].cld_name);
   1646       1.221  pgoyette 				if (ci->ci_locdesc[j].cld_defaultstr != NULL)
   1647       1.272  jmcneill 					prop_dictionary_set_string_nocopy(
   1648       1.221  pgoyette 					    loc_dict, "default",
   1649       1.221  pgoyette 					    ci->ci_locdesc[j].cld_defaultstr);
   1650       1.221  pgoyette 				prop_array_set(loc_array, j, loc_dict);
   1651       1.221  pgoyette 				prop_object_release(loc_dict);
   1652       1.221  pgoyette 			}
   1653       1.221  pgoyette 			prop_dictionary_set_and_rel(attr_dict, "locators",
   1654       1.221  pgoyette 			    loc_array);
   1655       1.221  pgoyette 		}
   1656       1.221  pgoyette 		prop_array_add(attr_array, attr_dict);
   1657       1.221  pgoyette 		prop_object_release(attr_dict);
   1658       1.221  pgoyette 	}
   1659       1.221  pgoyette 	if (i == 0)
   1660       1.221  pgoyette 		prop_object_release(attr_array);
   1661       1.221  pgoyette 	else
   1662       1.221  pgoyette 		prop_dictionary_set_and_rel(dev->dv_properties,
   1663       1.221  pgoyette 		    "interface-attributes", attr_array);
   1664       1.221  pgoyette 
   1665       1.221  pgoyette 	return;
   1666       1.221  pgoyette }
   1667       1.221  pgoyette 
   1668       1.221  pgoyette /*
   1669       1.117  drochner  * Attach a found device.
   1670       1.117  drochner  */
   1671   1.277.2.7   thorpej static device_t
   1672   1.277.2.7   thorpej config_vattach(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
   1673   1.277.2.7   thorpej     cfarg_t tag, va_list ap)
   1674       1.117  drochner {
   1675       1.117  drochner 	device_t dev;
   1676       1.117  drochner 	struct cftable *ct;
   1677       1.117  drochner 	const char *drvname;
   1678       1.117  drochner 
   1679   1.277.2.9   thorpej 	dev = config_vdevalloc(parent, cf, tag, ap);
   1680       1.117  drochner 	if (!dev)
   1681       1.117  drochner 		panic("config_attach: allocation of device softc failed");
   1682       1.117  drochner 
   1683       1.117  drochner 	/* XXX redundant - see below? */
   1684       1.117  drochner 	if (cf->cf_fstate != FSTATE_STAR) {
   1685       1.117  drochner 		KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
   1686       1.117  drochner 		cf->cf_fstate = FSTATE_FOUND;
   1687       1.117  drochner 	}
   1688       1.117  drochner 
   1689       1.117  drochner 	config_devlink(dev);
   1690       1.117  drochner 
   1691       1.176        ad 	if (config_do_twiddle && cold)
   1692        1.80   thorpej 		twiddle();
   1693        1.80   thorpej 	else
   1694        1.80   thorpej 		aprint_naive("Found ");
   1695        1.80   thorpej 	/*
   1696        1.80   thorpej 	 * We want the next two printfs for normal, verbose, and quiet,
   1697        1.80   thorpej 	 * but not silent (in which case, we're twiddling, instead).
   1698        1.80   thorpej 	 */
   1699        1.80   thorpej 	if (parent == ROOT) {
   1700       1.143    cegger 		aprint_naive("%s (root)", device_xname(dev));
   1701       1.143    cegger 		aprint_normal("%s (root)", device_xname(dev));
   1702        1.80   thorpej 	} else {
   1703       1.243   msaitoh 		aprint_naive("%s at %s", device_xname(dev),
   1704       1.243   msaitoh 		    device_xname(parent));
   1705       1.243   msaitoh 		aprint_normal("%s at %s", device_xname(dev),
   1706       1.243   msaitoh 		    device_xname(parent));
   1707        1.25       cgd 		if (print)
   1708        1.52       cgd 			(void) (*print)(aux, NULL);
   1709        1.25       cgd 	}
   1710        1.25       cgd 
   1711        1.25       cgd 	/*
   1712        1.25       cgd 	 * Before attaching, clobber any unfound devices that are
   1713        1.45       cgd 	 * otherwise identical.
   1714       1.117  drochner 	 * XXX code above is redundant?
   1715        1.25       cgd 	 */
   1716       1.117  drochner 	drvname = dev->dv_cfdriver->cd_name;
   1717        1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
   1718        1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
   1719       1.117  drochner 			if (STREQ(cf->cf_name, drvname) &&
   1720        1.65   thorpej 			    cf->cf_unit == dev->dv_unit) {
   1721        1.65   thorpej 				if (cf->cf_fstate == FSTATE_NOTFOUND)
   1722        1.65   thorpej 					cf->cf_fstate = FSTATE_FOUND;
   1723        1.65   thorpej 			}
   1724        1.25       cgd 		}
   1725        1.65   thorpej 	}
   1726        1.25       cgd 	device_register(dev, aux);
   1727       1.124  jmcneill 
   1728       1.149  jmcneill 	/* Let userland know */
   1729       1.149  jmcneill 	devmon_report_device(dev, true);
   1730       1.149  jmcneill 
   1731       1.117  drochner 	(*dev->dv_cfattach->ca_attach)(parent, dev, aux);
   1732       1.124  jmcneill 
   1733       1.264   msaitoh 	if (((dev->dv_flags & DVF_ATTACH_INPROGRESS) == 0)
   1734       1.264   msaitoh 	    && !device_pmf_is_registered(dev))
   1735       1.264   msaitoh 		aprint_debug_dev(dev,
   1736       1.264   msaitoh 		    "WARNING: power management not supported\n");
   1737       1.124  jmcneill 
   1738        1.42   thorpej 	config_process_deferred(&deferred_config_queue, dev);
   1739       1.196    martin 
   1740       1.196    martin 	device_register_post_config(dev, aux);
   1741       1.175    cegger 	return dev;
   1742        1.25       cgd }
   1743        1.29   thorpej 
   1744       1.102   thorpej device_t
   1745   1.277.2.7   thorpej config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
   1746   1.277.2.7   thorpej     cfarg_t tag, ...)
   1747       1.102   thorpej {
   1748   1.277.2.7   thorpej 	device_t dev;
   1749   1.277.2.7   thorpej 	va_list ap;
   1750   1.277.2.7   thorpej 
   1751   1.277.2.7   thorpej 	va_start(ap, tag);
   1752   1.277.2.7   thorpej 	dev = config_vattach(parent, cf, aux, print, tag, ap);
   1753   1.277.2.7   thorpej 	va_end(ap);
   1754       1.102   thorpej 
   1755   1.277.2.7   thorpej 	return dev;
   1756   1.277.2.7   thorpej }
   1757   1.277.2.7   thorpej 
   1758        1.29   thorpej /*
   1759        1.77   thorpej  * As above, but for pseudo-devices.  Pseudo-devices attached in this
   1760        1.77   thorpej  * way are silently inserted into the device tree, and their children
   1761        1.77   thorpej  * attached.
   1762        1.77   thorpej  *
   1763        1.77   thorpej  * Note that because pseudo-devices are attached silently, any information
   1764        1.77   thorpej  * the attach routine wishes to print should be prefixed with the device
   1765        1.77   thorpej  * name by the attach routine.
   1766        1.77   thorpej  */
   1767       1.102   thorpej device_t
   1768       1.102   thorpej config_attach_pseudo(cfdata_t cf)
   1769        1.77   thorpej {
   1770       1.102   thorpej 	device_t dev;
   1771        1.77   thorpej 
   1772   1.277.2.9   thorpej 	dev = config_devalloc(ROOT, cf, CFARG_EOL);
   1773       1.117  drochner 	if (!dev)
   1774       1.175    cegger 		return NULL;
   1775        1.77   thorpej 
   1776       1.117  drochner 	/* XXX mark busy in cfdata */
   1777        1.77   thorpej 
   1778       1.170    dyoung 	if (cf->cf_fstate != FSTATE_STAR) {
   1779       1.170    dyoung 		KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
   1780       1.170    dyoung 		cf->cf_fstate = FSTATE_FOUND;
   1781       1.170    dyoung 	}
   1782       1.170    dyoung 
   1783       1.117  drochner 	config_devlink(dev);
   1784        1.77   thorpej 
   1785        1.77   thorpej #if 0	/* XXXJRT not yet */
   1786        1.77   thorpej 	device_register(dev, NULL);	/* like a root node */
   1787        1.77   thorpej #endif
   1788       1.225   mlelstv 
   1789       1.225   mlelstv 	/* Let userland know */
   1790       1.225   mlelstv 	devmon_report_device(dev, true);
   1791       1.225   mlelstv 
   1792       1.117  drochner 	(*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
   1793       1.225   mlelstv 
   1794        1.77   thorpej 	config_process_deferred(&deferred_config_queue, dev);
   1795       1.175    cegger 	return dev;
   1796        1.77   thorpej }
   1797        1.77   thorpej 
   1798        1.77   thorpej /*
   1799       1.257   mlelstv  * Caller must hold alldevs_lock.
   1800       1.197     rmind  */
   1801       1.197     rmind static void
   1802       1.197     rmind config_collect_garbage(struct devicelist *garbage)
   1803       1.197     rmind {
   1804       1.197     rmind 	device_t dv;
   1805       1.197     rmind 
   1806       1.197     rmind 	KASSERT(!cpu_intr_p());
   1807       1.197     rmind 	KASSERT(!cpu_softintr_p());
   1808       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   1809       1.197     rmind 
   1810       1.257   mlelstv 	while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) {
   1811       1.257   mlelstv 		TAILQ_FOREACH(dv, &alldevs, dv_list) {
   1812       1.197     rmind 			if (dv->dv_del_gen != 0)
   1813       1.197     rmind 				break;
   1814       1.197     rmind 		}
   1815       1.197     rmind 		if (dv == NULL) {
   1816       1.257   mlelstv 			alldevs_garbage = false;
   1817       1.197     rmind 			break;
   1818       1.197     rmind 		}
   1819       1.197     rmind 		config_devunlink(dv, garbage);
   1820       1.197     rmind 	}
   1821       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   1822       1.197     rmind }
   1823       1.197     rmind 
   1824       1.197     rmind static void
   1825       1.197     rmind config_dump_garbage(struct devicelist *garbage)
   1826       1.197     rmind {
   1827       1.197     rmind 	device_t dv;
   1828       1.197     rmind 
   1829       1.197     rmind 	while ((dv = TAILQ_FIRST(garbage)) != NULL) {
   1830       1.197     rmind 		TAILQ_REMOVE(garbage, dv, dv_list);
   1831       1.197     rmind 		config_devdelete(dv);
   1832       1.197     rmind 	}
   1833       1.197     rmind }
   1834       1.197     rmind 
   1835       1.197     rmind /*
   1836        1.33   thorpej  * Detach a device.  Optionally forced (e.g. because of hardware
   1837        1.33   thorpej  * removal) and quiet.  Returns zero if successful, non-zero
   1838        1.33   thorpej  * (an error code) otherwise.
   1839        1.33   thorpej  *
   1840        1.33   thorpej  * Note that this code wants to be run from a process context, so
   1841        1.33   thorpej  * that the detach can sleep to allow processes which have a device
   1842        1.33   thorpej  * open to run and unwind their stacks.
   1843        1.33   thorpej  */
   1844        1.33   thorpej int
   1845       1.102   thorpej config_detach(device_t dev, int flags)
   1846        1.33   thorpej {
   1847       1.198    dyoung 	struct alldevs_foray af;
   1848        1.65   thorpej 	struct cftable *ct;
   1849       1.102   thorpej 	cfdata_t cf;
   1850        1.73   thorpej 	const struct cfattach *ca;
   1851        1.33   thorpej 	struct cfdriver *cd;
   1852       1.252  riastrad 	device_t d __diagused;
   1853       1.241     skrll 	int rv = 0;
   1854        1.33   thorpej 
   1855       1.161  christos 	cf = dev->dv_cfdata;
   1856       1.252  riastrad 	KASSERTMSG((cf == NULL || cf->cf_fstate == FSTATE_FOUND ||
   1857       1.252  riastrad 		cf->cf_fstate == FSTATE_STAR),
   1858       1.252  riastrad 	    "config_detach: %s: bad device fstate: %d",
   1859       1.252  riastrad 	    device_xname(dev), cf ? cf->cf_fstate : -1);
   1860       1.252  riastrad 
   1861        1.77   thorpej 	cd = dev->dv_cfdriver;
   1862        1.67   thorpej 	KASSERT(cd != NULL);
   1863        1.76   thorpej 
   1864        1.77   thorpej 	ca = dev->dv_cfattach;
   1865        1.76   thorpej 	KASSERT(ca != NULL);
   1866        1.33   thorpej 
   1867       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   1868       1.187    dyoung 	if (dev->dv_del_gen != 0) {
   1869       1.257   mlelstv 		mutex_exit(&alldevs_lock);
   1870       1.187    dyoung #ifdef DIAGNOSTIC
   1871       1.187    dyoung 		printf("%s: %s is already detached\n", __func__,
   1872       1.187    dyoung 		    device_xname(dev));
   1873       1.187    dyoung #endif /* DIAGNOSTIC */
   1874       1.187    dyoung 		return ENOENT;
   1875       1.187    dyoung 	}
   1876       1.257   mlelstv 	alldevs_nwrite++;
   1877       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   1878       1.136    dyoung 
   1879       1.174    dyoung 	if (!detachall &&
   1880       1.174    dyoung 	    (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
   1881       1.174    dyoung 	    (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
   1882       1.183    dyoung 		rv = EOPNOTSUPP;
   1883       1.187    dyoung 	} else if (ca->ca_detach != NULL) {
   1884       1.187    dyoung 		rv = (*ca->ca_detach)(dev, flags);
   1885       1.187    dyoung 	} else
   1886       1.187    dyoung 		rv = EOPNOTSUPP;
   1887        1.33   thorpej 
   1888        1.33   thorpej 	/*
   1889       1.187    dyoung 	 * If it was not possible to detach the device, then we either
   1890       1.187    dyoung 	 * panic() (for the forced but failed case), or return an error.
   1891       1.187    dyoung 	 *
   1892       1.187    dyoung 	 * If it was possible to detach the device, ensure that the
   1893       1.187    dyoung 	 * device is deactivated.
   1894        1.33   thorpej 	 */
   1895       1.187    dyoung 	if (rv == 0)
   1896       1.187    dyoung 		dev->dv_flags &= ~DVF_ACTIVE;
   1897       1.187    dyoung 	else if ((flags & DETACH_FORCE) == 0)
   1898       1.187    dyoung 		goto out;
   1899       1.187    dyoung 	else {
   1900       1.187    dyoung 		panic("config_detach: forced detach of %s failed (%d)",
   1901       1.187    dyoung 		    device_xname(dev), rv);
   1902        1.33   thorpej 	}
   1903        1.33   thorpej 
   1904        1.33   thorpej 	/*
   1905        1.33   thorpej 	 * The device has now been successfully detached.
   1906        1.33   thorpej 	 */
   1907        1.33   thorpej 
   1908       1.149  jmcneill 	/* Let userland know */
   1909       1.149  jmcneill 	devmon_report_device(dev, false);
   1910       1.149  jmcneill 
   1911        1.33   thorpej #ifdef DIAGNOSTIC
   1912        1.33   thorpej 	/*
   1913        1.33   thorpej 	 * Sanity: If you're successfully detached, you should have no
   1914        1.33   thorpej 	 * children.  (Note that because children must be attached
   1915        1.33   thorpej 	 * after parents, we only need to search the latter part of
   1916        1.33   thorpej 	 * the list.)
   1917        1.33   thorpej 	 */
   1918        1.33   thorpej 	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
   1919        1.48     enami 	    d = TAILQ_NEXT(d, dv_list)) {
   1920       1.187    dyoung 		if (d->dv_parent == dev && d->dv_del_gen == 0) {
   1921        1.48     enami 			printf("config_detach: detached device %s"
   1922       1.243   msaitoh 			    " has children %s\n", device_xname(dev),
   1923       1.243   msaitoh 			    device_xname(d));
   1924        1.48     enami 			panic("config_detach");
   1925        1.48     enami 		}
   1926        1.33   thorpej 	}
   1927        1.33   thorpej #endif
   1928        1.33   thorpej 
   1929        1.90  drochner 	/* notify the parent that the child is gone */
   1930        1.90  drochner 	if (dev->dv_parent) {
   1931       1.102   thorpej 		device_t p = dev->dv_parent;
   1932        1.90  drochner 		if (p->dv_cfattach->ca_childdetached)
   1933        1.90  drochner 			(*p->dv_cfattach->ca_childdetached)(p, dev);
   1934        1.90  drochner 	}
   1935        1.90  drochner 
   1936        1.33   thorpej 	/*
   1937        1.33   thorpej 	 * Mark cfdata to show that the unit can be reused, if possible.
   1938        1.33   thorpej 	 */
   1939        1.65   thorpej 	TAILQ_FOREACH(ct, &allcftables, ct_list) {
   1940        1.67   thorpej 		for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
   1941        1.67   thorpej 			if (STREQ(cf->cf_name, cd->cd_name)) {
   1942        1.65   thorpej 				if (cf->cf_fstate == FSTATE_FOUND &&
   1943        1.65   thorpej 				    cf->cf_unit == dev->dv_unit)
   1944        1.65   thorpej 					cf->cf_fstate = FSTATE_NOTFOUND;
   1945        1.65   thorpej 			}
   1946        1.33   thorpej 		}
   1947        1.33   thorpej 	}
   1948        1.33   thorpej 
   1949        1.77   thorpej 	if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
   1950       1.136    dyoung 		aprint_normal_dev(dev, "detached\n");
   1951        1.33   thorpej 
   1952       1.136    dyoung out:
   1953       1.198    dyoung 	config_alldevs_enter(&af);
   1954       1.257   mlelstv 	KASSERT(alldevs_nwrite != 0);
   1955       1.257   mlelstv 	--alldevs_nwrite;
   1956       1.211    dyoung 	if (rv == 0 && dev->dv_del_gen == 0) {
   1957       1.257   mlelstv 		if (alldevs_nwrite == 0 && alldevs_nread == 0)
   1958       1.211    dyoung 			config_devunlink(dev, &af.af_garbage);
   1959       1.211    dyoung 		else {
   1960       1.257   mlelstv 			dev->dv_del_gen = alldevs_gen;
   1961       1.257   mlelstv 			alldevs_garbage = true;
   1962       1.211    dyoung 		}
   1963       1.211    dyoung 	}
   1964       1.198    dyoung 	config_alldevs_exit(&af);
   1965       1.187    dyoung 
   1966       1.136    dyoung 	return rv;
   1967        1.33   thorpej }
   1968        1.33   thorpej 
   1969       1.126    dyoung int
   1970       1.126    dyoung config_detach_children(device_t parent, int flags)
   1971       1.126    dyoung {
   1972       1.130  drochner 	device_t dv;
   1973       1.136    dyoung 	deviter_t di;
   1974       1.136    dyoung 	int error = 0;
   1975       1.126    dyoung 
   1976       1.136    dyoung 	for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL;
   1977       1.136    dyoung 	     dv = deviter_next(&di)) {
   1978       1.136    dyoung 		if (device_parent(dv) != parent)
   1979       1.136    dyoung 			continue;
   1980       1.136    dyoung 		if ((error = config_detach(dv, flags)) != 0)
   1981       1.130  drochner 			break;
   1982       1.136    dyoung 	}
   1983       1.136    dyoung 	deviter_release(&di);
   1984       1.130  drochner 	return error;
   1985       1.126    dyoung }
   1986       1.126    dyoung 
   1987       1.178    dyoung device_t
   1988       1.178    dyoung shutdown_first(struct shutdown_state *s)
   1989       1.178    dyoung {
   1990       1.178    dyoung 	if (!s->initialized) {
   1991       1.178    dyoung 		deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
   1992       1.178    dyoung 		s->initialized = true;
   1993       1.178    dyoung 	}
   1994       1.178    dyoung 	return shutdown_next(s);
   1995       1.178    dyoung }
   1996       1.178    dyoung 
   1997       1.178    dyoung device_t
   1998       1.178    dyoung shutdown_next(struct shutdown_state *s)
   1999       1.178    dyoung {
   2000       1.178    dyoung 	device_t dv;
   2001       1.178    dyoung 
   2002       1.178    dyoung 	while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
   2003       1.178    dyoung 		;
   2004       1.178    dyoung 
   2005       1.178    dyoung 	if (dv == NULL)
   2006       1.178    dyoung 		s->initialized = false;
   2007       1.178    dyoung 
   2008       1.178    dyoung 	return dv;
   2009       1.178    dyoung }
   2010       1.178    dyoung 
   2011       1.178    dyoung bool
   2012       1.178    dyoung config_detach_all(int how)
   2013       1.178    dyoung {
   2014       1.178    dyoung 	static struct shutdown_state s;
   2015       1.178    dyoung 	device_t curdev;
   2016       1.178    dyoung 	bool progress = false;
   2017       1.242    bouyer 	int flags;
   2018       1.178    dyoung 
   2019       1.239  christos 	if ((how & (RB_NOSYNC|RB_DUMP)) != 0)
   2020       1.178    dyoung 		return false;
   2021       1.178    dyoung 
   2022       1.242    bouyer 	if ((how & RB_POWERDOWN) == RB_POWERDOWN)
   2023       1.242    bouyer 		flags = DETACH_SHUTDOWN | DETACH_POWEROFF;
   2024       1.242    bouyer 	else
   2025       1.242    bouyer 		flags = DETACH_SHUTDOWN;
   2026       1.242    bouyer 
   2027       1.178    dyoung 	for (curdev = shutdown_first(&s); curdev != NULL;
   2028       1.178    dyoung 	     curdev = shutdown_next(&s)) {
   2029       1.178    dyoung 		aprint_debug(" detaching %s, ", device_xname(curdev));
   2030       1.242    bouyer 		if (config_detach(curdev, flags) == 0) {
   2031       1.178    dyoung 			progress = true;
   2032       1.178    dyoung 			aprint_debug("success.");
   2033       1.178    dyoung 		} else
   2034       1.178    dyoung 			aprint_debug("failed.");
   2035       1.178    dyoung 	}
   2036       1.178    dyoung 	return progress;
   2037       1.178    dyoung }
   2038       1.178    dyoung 
   2039       1.187    dyoung static bool
   2040       1.187    dyoung device_is_ancestor_of(device_t ancestor, device_t descendant)
   2041       1.187    dyoung {
   2042       1.187    dyoung 	device_t dv;
   2043       1.187    dyoung 
   2044       1.187    dyoung 	for (dv = descendant; dv != NULL; dv = device_parent(dv)) {
   2045       1.187    dyoung 		if (device_parent(dv) == ancestor)
   2046       1.187    dyoung 			return true;
   2047       1.187    dyoung 	}
   2048       1.187    dyoung 	return false;
   2049       1.187    dyoung }
   2050       1.187    dyoung 
   2051        1.33   thorpej int
   2052       1.102   thorpej config_deactivate(device_t dev)
   2053        1.33   thorpej {
   2054       1.187    dyoung 	deviter_t di;
   2055       1.187    dyoung 	const struct cfattach *ca;
   2056       1.187    dyoung 	device_t descendant;
   2057       1.187    dyoung 	int s, rv = 0, oflags;
   2058        1.33   thorpej 
   2059       1.187    dyoung 	for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST);
   2060       1.187    dyoung 	     descendant != NULL;
   2061       1.187    dyoung 	     descendant = deviter_next(&di)) {
   2062       1.187    dyoung 		if (dev != descendant &&
   2063       1.187    dyoung 		    !device_is_ancestor_of(dev, descendant))
   2064       1.187    dyoung 			continue;
   2065       1.187    dyoung 
   2066       1.187    dyoung 		if ((descendant->dv_flags & DVF_ACTIVE) == 0)
   2067       1.187    dyoung 			continue;
   2068        1.33   thorpej 
   2069       1.187    dyoung 		ca = descendant->dv_cfattach;
   2070       1.187    dyoung 		oflags = descendant->dv_flags;
   2071       1.187    dyoung 
   2072       1.187    dyoung 		descendant->dv_flags &= ~DVF_ACTIVE;
   2073       1.187    dyoung 		if (ca->ca_activate == NULL)
   2074       1.187    dyoung 			continue;
   2075       1.187    dyoung 		s = splhigh();
   2076       1.187    dyoung 		rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE);
   2077       1.187    dyoung 		splx(s);
   2078       1.187    dyoung 		if (rv != 0)
   2079       1.187    dyoung 			descendant->dv_flags = oflags;
   2080        1.33   thorpej 	}
   2081       1.187    dyoung 	deviter_release(&di);
   2082       1.175    cegger 	return rv;
   2083        1.33   thorpej }
   2084        1.33   thorpej 
   2085        1.33   thorpej /*
   2086        1.29   thorpej  * Defer the configuration of the specified device until all
   2087        1.29   thorpej  * of its parent's devices have been attached.
   2088        1.29   thorpej  */
   2089        1.29   thorpej void
   2090       1.102   thorpej config_defer(device_t dev, void (*func)(device_t))
   2091        1.29   thorpej {
   2092        1.29   thorpej 	struct deferred_config *dc;
   2093        1.29   thorpej 
   2094        1.29   thorpej 	if (dev->dv_parent == NULL)
   2095        1.29   thorpej 		panic("config_defer: can't defer config of a root device");
   2096        1.29   thorpej 
   2097       1.266  jdolecek 	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
   2098       1.266  jdolecek 
   2099       1.266  jdolecek 	config_pending_incr(dev);
   2100       1.266  jdolecek 
   2101       1.266  jdolecek 	mutex_enter(&config_misc_lock);
   2102        1.29   thorpej #ifdef DIAGNOSTIC
   2103       1.266  jdolecek 	struct deferred_config *odc;
   2104       1.266  jdolecek 	TAILQ_FOREACH(odc, &deferred_config_queue, dc_queue) {
   2105       1.266  jdolecek 		if (odc->dc_dev == dev)
   2106        1.29   thorpej 			panic("config_defer: deferred twice");
   2107        1.29   thorpej 	}
   2108        1.29   thorpej #endif
   2109        1.29   thorpej 	dc->dc_dev = dev;
   2110        1.29   thorpej 	dc->dc_func = func;
   2111        1.29   thorpej 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
   2112       1.266  jdolecek 	mutex_exit(&config_misc_lock);
   2113        1.29   thorpej }
   2114        1.29   thorpej 
   2115        1.29   thorpej /*
   2116        1.42   thorpej  * Defer some autoconfiguration for a device until after interrupts
   2117        1.42   thorpej  * are enabled.
   2118        1.42   thorpej  */
   2119        1.42   thorpej void
   2120       1.102   thorpej config_interrupts(device_t dev, void (*func)(device_t))
   2121        1.42   thorpej {
   2122        1.42   thorpej 	struct deferred_config *dc;
   2123        1.42   thorpej 
   2124        1.42   thorpej 	/*
   2125        1.42   thorpej 	 * If interrupts are enabled, callback now.
   2126        1.42   thorpej 	 */
   2127        1.43   thorpej 	if (cold == 0) {
   2128        1.42   thorpej 		(*func)(dev);
   2129        1.42   thorpej 		return;
   2130        1.42   thorpej 	}
   2131        1.42   thorpej 
   2132       1.266  jdolecek 	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
   2133       1.266  jdolecek 
   2134       1.266  jdolecek 	config_pending_incr(dev);
   2135       1.266  jdolecek 
   2136       1.266  jdolecek 	mutex_enter(&config_misc_lock);
   2137        1.42   thorpej #ifdef DIAGNOSTIC
   2138       1.266  jdolecek 	struct deferred_config *odc;
   2139       1.266  jdolecek 	TAILQ_FOREACH(odc, &interrupt_config_queue, dc_queue) {
   2140       1.266  jdolecek 		if (odc->dc_dev == dev)
   2141        1.42   thorpej 			panic("config_interrupts: deferred twice");
   2142        1.42   thorpej 	}
   2143        1.42   thorpej #endif
   2144        1.42   thorpej 	dc->dc_dev = dev;
   2145        1.42   thorpej 	dc->dc_func = func;
   2146        1.42   thorpej 	TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
   2147       1.264   msaitoh 	dev->dv_flags |= DVF_ATTACH_INPROGRESS;
   2148       1.266  jdolecek 	mutex_exit(&config_misc_lock);
   2149        1.42   thorpej }
   2150        1.42   thorpej 
   2151        1.42   thorpej /*
   2152       1.207   tsutsui  * Defer some autoconfiguration for a device until after root file system
   2153       1.207   tsutsui  * is mounted (to load firmware etc).
   2154       1.207   tsutsui  */
   2155       1.207   tsutsui void
   2156       1.207   tsutsui config_mountroot(device_t dev, void (*func)(device_t))
   2157       1.207   tsutsui {
   2158       1.207   tsutsui 	struct deferred_config *dc;
   2159       1.207   tsutsui 
   2160       1.207   tsutsui 	/*
   2161       1.207   tsutsui 	 * If root file system is mounted, callback now.
   2162       1.207   tsutsui 	 */
   2163       1.208   tsutsui 	if (root_is_mounted) {
   2164       1.207   tsutsui 		(*func)(dev);
   2165       1.207   tsutsui 		return;
   2166       1.207   tsutsui 	}
   2167       1.207   tsutsui 
   2168       1.266  jdolecek 	dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
   2169       1.266  jdolecek 
   2170       1.266  jdolecek 	mutex_enter(&config_misc_lock);
   2171       1.207   tsutsui #ifdef DIAGNOSTIC
   2172       1.266  jdolecek 	struct deferred_config *odc;
   2173       1.266  jdolecek 	TAILQ_FOREACH(odc, &mountroot_config_queue, dc_queue) {
   2174       1.266  jdolecek 		if (odc->dc_dev == dev)
   2175       1.207   tsutsui 			panic("%s: deferred twice", __func__);
   2176       1.207   tsutsui 	}
   2177       1.207   tsutsui #endif
   2178       1.207   tsutsui 
   2179       1.207   tsutsui 	dc->dc_dev = dev;
   2180       1.207   tsutsui 	dc->dc_func = func;
   2181       1.207   tsutsui 	TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
   2182       1.266  jdolecek 	mutex_exit(&config_misc_lock);
   2183       1.207   tsutsui }
   2184       1.207   tsutsui 
   2185       1.207   tsutsui /*
   2186        1.42   thorpej  * Process a deferred configuration queue.
   2187        1.29   thorpej  */
   2188        1.29   thorpej static void
   2189       1.243   msaitoh config_process_deferred(struct deferred_config_head *queue, device_t parent)
   2190        1.29   thorpej {
   2191       1.266  jdolecek 	struct deferred_config *dc;
   2192        1.29   thorpej 
   2193       1.266  jdolecek 	mutex_enter(&config_misc_lock);
   2194       1.266  jdolecek 	dc = TAILQ_FIRST(queue);
   2195       1.266  jdolecek 	while (dc) {
   2196        1.42   thorpej 		if (parent == NULL || dc->dc_dev->dv_parent == parent) {
   2197        1.42   thorpej 			TAILQ_REMOVE(queue, dc, dc_queue);
   2198       1.266  jdolecek 			mutex_exit(&config_misc_lock);
   2199       1.266  jdolecek 
   2200        1.29   thorpej 			(*dc->dc_func)(dc->dc_dev);
   2201       1.228  christos 			config_pending_decr(dc->dc_dev);
   2202       1.159      matt 			kmem_free(dc, sizeof(*dc));
   2203       1.266  jdolecek 
   2204       1.266  jdolecek 			mutex_enter(&config_misc_lock);
   2205       1.266  jdolecek 			/* Restart, queue might have changed */
   2206       1.266  jdolecek 			dc = TAILQ_FIRST(queue);
   2207       1.266  jdolecek 		} else {
   2208       1.266  jdolecek 			dc = TAILQ_NEXT(dc, dc_queue);
   2209        1.29   thorpej 		}
   2210        1.29   thorpej 	}
   2211       1.266  jdolecek 	mutex_exit(&config_misc_lock);
   2212        1.47   thorpej }
   2213        1.47   thorpej 
   2214        1.47   thorpej /*
   2215        1.47   thorpej  * Manipulate the config_pending semaphore.
   2216        1.47   thorpej  */
   2217        1.47   thorpej void
   2218       1.228  christos config_pending_incr(device_t dev)
   2219        1.47   thorpej {
   2220        1.47   thorpej 
   2221       1.151        ad 	mutex_enter(&config_misc_lock);
   2222       1.274  riastrad 	KASSERTMSG(dev->dv_pending < INT_MAX,
   2223       1.274  riastrad 	    "%s: excess config_pending_incr", device_xname(dev));
   2224       1.274  riastrad 	if (dev->dv_pending++ == 0)
   2225       1.274  riastrad 		TAILQ_INSERT_TAIL(&config_pending, dev, dv_pending_list);
   2226       1.228  christos #ifdef DEBUG_AUTOCONF
   2227       1.274  riastrad 	printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending);
   2228       1.228  christos #endif
   2229       1.151        ad 	mutex_exit(&config_misc_lock);
   2230        1.47   thorpej }
   2231        1.47   thorpej 
   2232        1.47   thorpej void
   2233       1.228  christos config_pending_decr(device_t dev)
   2234        1.47   thorpej {
   2235        1.47   thorpej 
   2236       1.151        ad 	mutex_enter(&config_misc_lock);
   2237       1.274  riastrad 	KASSERTMSG(dev->dv_pending > 0,
   2238       1.274  riastrad 	    "%s: excess config_pending_decr", device_xname(dev));
   2239       1.274  riastrad 	if (--dev->dv_pending == 0)
   2240       1.274  riastrad 		TAILQ_REMOVE(&config_pending, dev, dv_pending_list);
   2241       1.228  christos #ifdef DEBUG_AUTOCONF
   2242       1.274  riastrad 	printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending);
   2243       1.228  christos #endif
   2244       1.274  riastrad 	if (TAILQ_EMPTY(&config_pending))
   2245       1.151        ad 		cv_broadcast(&config_misc_cv);
   2246       1.151        ad 	mutex_exit(&config_misc_lock);
   2247        1.75   thorpej }
   2248        1.75   thorpej 
   2249        1.75   thorpej /*
   2250        1.75   thorpej  * Register a "finalization" routine.  Finalization routines are
   2251        1.75   thorpej  * called iteratively once all real devices have been found during
   2252        1.75   thorpej  * autoconfiguration, for as long as any one finalizer has done
   2253        1.75   thorpej  * any work.
   2254        1.75   thorpej  */
   2255        1.75   thorpej int
   2256       1.102   thorpej config_finalize_register(device_t dev, int (*fn)(device_t))
   2257        1.75   thorpej {
   2258        1.75   thorpej 	struct finalize_hook *f;
   2259        1.75   thorpej 
   2260        1.75   thorpej 	/*
   2261        1.75   thorpej 	 * If finalization has already been done, invoke the
   2262        1.75   thorpej 	 * callback function now.
   2263        1.75   thorpej 	 */
   2264        1.75   thorpej 	if (config_finalize_done) {
   2265        1.75   thorpej 		while ((*fn)(dev) != 0)
   2266        1.75   thorpej 			/* loop */ ;
   2267       1.238  pgoyette 		return 0;
   2268        1.75   thorpej 	}
   2269        1.75   thorpej 
   2270        1.75   thorpej 	/* Ensure this isn't already on the list. */
   2271        1.75   thorpej 	TAILQ_FOREACH(f, &config_finalize_list, f_list) {
   2272        1.75   thorpej 		if (f->f_func == fn && f->f_dev == dev)
   2273       1.175    cegger 			return EEXIST;
   2274        1.75   thorpej 	}
   2275        1.75   thorpej 
   2276       1.159      matt 	f = kmem_alloc(sizeof(*f), KM_SLEEP);
   2277        1.75   thorpej 	f->f_func = fn;
   2278        1.75   thorpej 	f->f_dev = dev;
   2279        1.75   thorpej 	TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
   2280        1.75   thorpej 
   2281       1.175    cegger 	return 0;
   2282        1.75   thorpej }
   2283        1.75   thorpej 
   2284        1.75   thorpej void
   2285        1.75   thorpej config_finalize(void)
   2286        1.75   thorpej {
   2287        1.75   thorpej 	struct finalize_hook *f;
   2288       1.142        ad 	struct pdevinit *pdev;
   2289       1.142        ad 	extern struct pdevinit pdevinit[];
   2290       1.142        ad 	int errcnt, rv;
   2291       1.142        ad 
   2292       1.142        ad 	/*
   2293       1.142        ad 	 * Now that device driver threads have been created, wait for
   2294       1.142        ad 	 * them to finish any deferred autoconfiguration.
   2295       1.142        ad 	 */
   2296       1.151        ad 	mutex_enter(&config_misc_lock);
   2297       1.274  riastrad 	while (!TAILQ_EMPTY(&config_pending)) {
   2298       1.274  riastrad 		device_t dev;
   2299       1.274  riastrad 		TAILQ_FOREACH(dev, &config_pending, dv_pending_list)
   2300       1.274  riastrad 			aprint_debug_dev(dev, "holding up boot\n");
   2301       1.151        ad 		cv_wait(&config_misc_cv, &config_misc_lock);
   2302       1.274  riastrad 	}
   2303       1.151        ad 	mutex_exit(&config_misc_lock);
   2304       1.142        ad 
   2305       1.167        ad 	KERNEL_LOCK(1, NULL);
   2306       1.167        ad 
   2307       1.142        ad 	/* Attach pseudo-devices. */
   2308       1.142        ad 	for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
   2309       1.142        ad 		(*pdev->pdev_attach)(pdev->pdev_count);
   2310        1.75   thorpej 
   2311        1.75   thorpej 	/* Run the hooks until none of them does any work. */
   2312        1.75   thorpej 	do {
   2313        1.75   thorpej 		rv = 0;
   2314        1.75   thorpej 		TAILQ_FOREACH(f, &config_finalize_list, f_list)
   2315        1.75   thorpej 			rv |= (*f->f_func)(f->f_dev);
   2316        1.75   thorpej 	} while (rv != 0);
   2317        1.75   thorpej 
   2318        1.75   thorpej 	config_finalize_done = 1;
   2319        1.75   thorpej 
   2320        1.75   thorpej 	/* Now free all the hooks. */
   2321        1.75   thorpej 	while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
   2322        1.75   thorpej 		TAILQ_REMOVE(&config_finalize_list, f, f_list);
   2323       1.159      matt 		kmem_free(f, sizeof(*f));
   2324        1.79   thorpej 	}
   2325       1.142        ad 
   2326       1.167        ad 	KERNEL_UNLOCK_ONE(NULL);
   2327       1.167        ad 
   2328       1.142        ad 	errcnt = aprint_get_error_count();
   2329       1.142        ad 	if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
   2330       1.142        ad 	    (boothowto & AB_VERBOSE) == 0) {
   2331       1.176        ad 		mutex_enter(&config_misc_lock);
   2332       1.142        ad 		if (config_do_twiddle) {
   2333       1.142        ad 			config_do_twiddle = 0;
   2334       1.169        ad 			printf_nolog(" done.\n");
   2335       1.142        ad 		}
   2336       1.176        ad 		mutex_exit(&config_misc_lock);
   2337       1.247   msaitoh 	}
   2338       1.247   msaitoh 	if (errcnt != 0) {
   2339       1.247   msaitoh 		printf("WARNING: %d error%s while detecting hardware; "
   2340       1.247   msaitoh 		    "check system log.\n", errcnt,
   2341       1.247   msaitoh 		    errcnt == 1 ? "" : "s");
   2342       1.142        ad 	}
   2343        1.79   thorpej }
   2344        1.79   thorpej 
   2345       1.176        ad void
   2346       1.222      matt config_twiddle_init(void)
   2347       1.180     pooka {
   2348       1.180     pooka 
   2349       1.180     pooka 	if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
   2350       1.180     pooka 		config_do_twiddle = 1;
   2351       1.180     pooka 	}
   2352       1.180     pooka 	callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL);
   2353       1.180     pooka }
   2354       1.180     pooka 
   2355       1.180     pooka void
   2356       1.176        ad config_twiddle_fn(void *cookie)
   2357       1.176        ad {
   2358       1.176        ad 
   2359       1.176        ad 	mutex_enter(&config_misc_lock);
   2360       1.176        ad 	if (config_do_twiddle) {
   2361       1.176        ad 		twiddle();
   2362       1.176        ad 		callout_schedule(&config_twiddle_ch, mstohz(100));
   2363       1.176        ad 	}
   2364       1.176        ad 	mutex_exit(&config_misc_lock);
   2365       1.176        ad }
   2366       1.176        ad 
   2367       1.187    dyoung static void
   2368       1.198    dyoung config_alldevs_enter(struct alldevs_foray *af)
   2369       1.198    dyoung {
   2370       1.198    dyoung 	TAILQ_INIT(&af->af_garbage);
   2371       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   2372       1.198    dyoung 	config_collect_garbage(&af->af_garbage);
   2373       1.243   msaitoh }
   2374       1.198    dyoung 
   2375       1.198    dyoung static void
   2376       1.198    dyoung config_alldevs_exit(struct alldevs_foray *af)
   2377       1.198    dyoung {
   2378       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   2379       1.198    dyoung 	config_dump_garbage(&af->af_garbage);
   2380       1.198    dyoung }
   2381       1.198    dyoung 
   2382       1.104   thorpej /*
   2383       1.107   thorpej  * device_lookup:
   2384       1.107   thorpej  *
   2385       1.107   thorpej  *	Look up a device instance for a given driver.
   2386       1.107   thorpej  */
   2387       1.156  drochner device_t
   2388       1.107   thorpej device_lookup(cfdriver_t cd, int unit)
   2389       1.107   thorpej {
   2390       1.187    dyoung 	device_t dv;
   2391       1.107   thorpej 
   2392       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   2393       1.107   thorpej 	if (unit < 0 || unit >= cd->cd_ndevs)
   2394       1.187    dyoung 		dv = NULL;
   2395       1.191    dyoung 	else if ((dv = cd->cd_devs[unit]) != NULL && dv->dv_del_gen != 0)
   2396       1.191    dyoung 		dv = NULL;
   2397       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   2398       1.187    dyoung 
   2399       1.187    dyoung 	return dv;
   2400       1.107   thorpej }
   2401       1.107   thorpej 
   2402       1.107   thorpej /*
   2403       1.191    dyoung  * device_lookup_private:
   2404       1.140      matt  *
   2405       1.191    dyoung  *	Look up a softc instance for a given driver.
   2406       1.140      matt  */
   2407       1.140      matt void *
   2408       1.140      matt device_lookup_private(cfdriver_t cd, int unit)
   2409       1.140      matt {
   2410       1.140      matt 
   2411       1.198    dyoung 	return device_private(device_lookup(cd, unit));
   2412       1.140      matt }
   2413       1.140      matt 
   2414       1.140      matt /*
   2415       1.131     joerg  * device_find_by_xname:
   2416       1.131     joerg  *
   2417       1.131     joerg  *	Returns the device of the given name or NULL if it doesn't exist.
   2418       1.131     joerg  */
   2419       1.131     joerg device_t
   2420       1.131     joerg device_find_by_xname(const char *name)
   2421       1.131     joerg {
   2422       1.131     joerg 	device_t dv;
   2423       1.136    dyoung 	deviter_t di;
   2424       1.131     joerg 
   2425       1.136    dyoung 	for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) {
   2426       1.131     joerg 		if (strcmp(device_xname(dv), name) == 0)
   2427       1.131     joerg 			break;
   2428       1.131     joerg 	}
   2429       1.136    dyoung 	deviter_release(&di);
   2430       1.131     joerg 
   2431       1.131     joerg 	return dv;
   2432       1.131     joerg }
   2433       1.131     joerg 
   2434       1.131     joerg /*
   2435       1.131     joerg  * device_find_by_driver_unit:
   2436       1.131     joerg  *
   2437       1.131     joerg  *	Returns the device of the given driver name and unit or
   2438       1.131     joerg  *	NULL if it doesn't exist.
   2439       1.131     joerg  */
   2440       1.131     joerg device_t
   2441       1.131     joerg device_find_by_driver_unit(const char *name, int unit)
   2442       1.131     joerg {
   2443       1.131     joerg 	struct cfdriver *cd;
   2444       1.131     joerg 
   2445       1.131     joerg 	if ((cd = config_cfdriver_lookup(name)) == NULL)
   2446       1.131     joerg 		return NULL;
   2447       1.131     joerg 	return device_lookup(cd, unit);
   2448       1.131     joerg }
   2449       1.131     joerg 
   2450       1.276   thorpej static bool
   2451       1.276   thorpej match_strcmp(const char * const s1, const char * const s2)
   2452       1.276   thorpej {
   2453       1.276   thorpej 	return strcmp(s1, s2) == 0;
   2454       1.276   thorpej }
   2455       1.276   thorpej 
   2456       1.276   thorpej static bool
   2457       1.276   thorpej match_pmatch(const char * const s1, const char * const s2)
   2458       1.276   thorpej {
   2459       1.276   thorpej 	return pmatch(s1, s2, NULL) == 2;
   2460       1.276   thorpej }
   2461       1.276   thorpej 
   2462       1.276   thorpej static bool
   2463       1.276   thorpej strarray_match_internal(const char ** const strings,
   2464       1.276   thorpej     unsigned int const nstrings, const char * const str,
   2465       1.276   thorpej     unsigned int * const indexp,
   2466       1.276   thorpej     bool (*match_fn)(const char *, const char *))
   2467       1.276   thorpej {
   2468       1.276   thorpej 	unsigned int i;
   2469       1.276   thorpej 
   2470       1.276   thorpej 	if (strings == NULL || nstrings == 0) {
   2471       1.277   thorpej 		return false;
   2472       1.276   thorpej 	}
   2473       1.276   thorpej 
   2474       1.276   thorpej 	for (i = 0; i < nstrings; i++) {
   2475       1.276   thorpej 		if ((*match_fn)(strings[i], str)) {
   2476       1.276   thorpej 			*indexp = i;
   2477       1.276   thorpej 			return true;
   2478       1.276   thorpej 		}
   2479       1.276   thorpej 	}
   2480       1.276   thorpej 
   2481       1.276   thorpej 	return false;
   2482       1.276   thorpej }
   2483       1.276   thorpej 
   2484       1.276   thorpej static int
   2485       1.276   thorpej strarray_match(const char ** const strings, unsigned int const nstrings,
   2486       1.276   thorpej     const char * const str)
   2487       1.276   thorpej {
   2488       1.276   thorpej 	unsigned int idx;
   2489       1.276   thorpej 
   2490       1.276   thorpej 	if (strarray_match_internal(strings, nstrings, str, &idx,
   2491       1.276   thorpej 				    match_strcmp)) {
   2492       1.276   thorpej 		return (int)(nstrings - idx);
   2493       1.276   thorpej 	}
   2494       1.276   thorpej 	return 0;
   2495       1.276   thorpej }
   2496       1.276   thorpej 
   2497       1.276   thorpej static int
   2498       1.276   thorpej strarray_pmatch(const char ** const strings, unsigned int const nstrings,
   2499       1.276   thorpej     const char * const pattern)
   2500       1.276   thorpej {
   2501       1.276   thorpej 	unsigned int idx;
   2502       1.276   thorpej 
   2503       1.276   thorpej 	if (strarray_match_internal(strings, nstrings, pattern, &idx,
   2504       1.276   thorpej 				    match_pmatch)) {
   2505       1.276   thorpej 		return (int)(nstrings - idx);
   2506       1.276   thorpej 	}
   2507       1.276   thorpej 	return 0;
   2508       1.276   thorpej }
   2509       1.276   thorpej 
   2510       1.276   thorpej static int
   2511       1.276   thorpej device_compatible_match_strarray_internal(
   2512       1.276   thorpej     const char **device_compats, int ndevice_compats,
   2513       1.276   thorpej     const struct device_compatible_entry *driver_compats,
   2514       1.276   thorpej     const struct device_compatible_entry **matching_entryp,
   2515       1.276   thorpej     int (*match_fn)(const char **, unsigned int, const char *))
   2516       1.276   thorpej {
   2517       1.276   thorpej 	const struct device_compatible_entry *dce = NULL;
   2518       1.276   thorpej 	int rv;
   2519       1.276   thorpej 
   2520       1.276   thorpej 	if (ndevice_compats == 0 || device_compats == NULL ||
   2521       1.276   thorpej 	    driver_compats == NULL)
   2522       1.276   thorpej 		return 0;
   2523       1.276   thorpej 
   2524       1.276   thorpej 	for (dce = driver_compats; dce->compat != NULL; dce++) {
   2525       1.276   thorpej 		rv = (*match_fn)(device_compats, ndevice_compats, dce->compat);
   2526       1.276   thorpej 		if (rv != 0) {
   2527       1.276   thorpej 			if (matching_entryp != NULL) {
   2528       1.276   thorpej 				*matching_entryp = dce;
   2529       1.276   thorpej 			}
   2530       1.276   thorpej 			return rv;
   2531       1.276   thorpej 		}
   2532       1.276   thorpej 	}
   2533       1.276   thorpej 	return 0;
   2534       1.276   thorpej }
   2535       1.276   thorpej 
   2536       1.131     joerg /*
   2537       1.258   thorpej  * device_compatible_match:
   2538       1.258   thorpej  *
   2539       1.258   thorpej  *	Match a driver's "compatible" data against a device's
   2540       1.276   thorpej  *	"compatible" strings.  Returns resulted weighted by
   2541       1.276   thorpej  *	which device "compatible" string was matched.
   2542       1.276   thorpej  */
   2543       1.276   thorpej int
   2544       1.276   thorpej device_compatible_match(const char **device_compats, int ndevice_compats,
   2545       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2546       1.276   thorpej {
   2547       1.276   thorpej 	return device_compatible_match_strarray_internal(device_compats,
   2548       1.276   thorpej 	    ndevice_compats, driver_compats, NULL, strarray_match);
   2549       1.276   thorpej }
   2550       1.276   thorpej 
   2551       1.276   thorpej /*
   2552       1.276   thorpej  * device_compatible_pmatch:
   2553       1.276   thorpej  *
   2554       1.276   thorpej  *	Like device_compatible_match(), but uses pmatch(9) to compare
   2555       1.276   thorpej  *	the device "compatible" strings against patterns in the
   2556       1.276   thorpej  *	driver's "compatible" data.
   2557       1.258   thorpej  */
   2558       1.276   thorpej int
   2559       1.276   thorpej device_compatible_pmatch(const char **device_compats, int ndevice_compats,
   2560       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2561       1.276   thorpej {
   2562       1.276   thorpej 	return device_compatible_match_strarray_internal(device_compats,
   2563       1.276   thorpej 	    ndevice_compats, driver_compats, NULL, strarray_pmatch);
   2564       1.276   thorpej }
   2565       1.276   thorpej 
   2566       1.275   thorpej static int
   2567       1.276   thorpej device_compatible_match_strlist_internal(
   2568       1.276   thorpej     const char * const device_compats, size_t const device_compatsize,
   2569       1.275   thorpej     const struct device_compatible_entry *driver_compats,
   2570       1.276   thorpej     const struct device_compatible_entry **matching_entryp,
   2571       1.276   thorpej     int (*match_fn)(const char *, size_t, const char *))
   2572       1.258   thorpej {
   2573       1.258   thorpej 	const struct device_compatible_entry *dce = NULL;
   2574       1.276   thorpej 	int rv;
   2575       1.258   thorpej 
   2576       1.276   thorpej 	if (device_compats == NULL || device_compatsize == 0 ||
   2577       1.258   thorpej 	    driver_compats == NULL)
   2578       1.261   thorpej 		return 0;
   2579       1.276   thorpej 
   2580       1.276   thorpej 	for (dce = driver_compats; dce->compat != NULL; dce++) {
   2581       1.276   thorpej 		rv = (*match_fn)(device_compats, device_compatsize,
   2582       1.276   thorpej 		    dce->compat);
   2583       1.276   thorpej 		if (rv != 0) {
   2584       1.276   thorpej 			if (matching_entryp != NULL) {
   2585       1.276   thorpej 				*matching_entryp = dce;
   2586       1.258   thorpej 			}
   2587       1.276   thorpej 			return rv;
   2588       1.258   thorpej 		}
   2589       1.258   thorpej 	}
   2590       1.261   thorpej 	return 0;
   2591       1.258   thorpej }
   2592       1.258   thorpej 
   2593       1.276   thorpej /*
   2594       1.276   thorpej  * device_compatible_match_strlist:
   2595       1.276   thorpej  *
   2596       1.276   thorpej  *	Like device_compatible_match(), but take the device
   2597       1.276   thorpej  *	"compatible" strings as an OpenFirmware-style string
   2598       1.276   thorpej  *	list.
   2599       1.276   thorpej  */
   2600       1.275   thorpej int
   2601       1.276   thorpej device_compatible_match_strlist(
   2602       1.276   thorpej     const char * const device_compats, size_t const device_compatsize,
   2603       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2604       1.276   thorpej {
   2605       1.276   thorpej 	return device_compatible_match_strlist_internal(device_compats,
   2606       1.276   thorpej 	    device_compatsize, driver_compats, NULL, strlist_match);
   2607       1.276   thorpej }
   2608       1.276   thorpej 
   2609       1.276   thorpej /*
   2610       1.276   thorpej  * device_compatible_pmatch_strlist:
   2611       1.276   thorpej  *
   2612       1.276   thorpej  *	Like device_compatible_pmatch(), but take the device
   2613       1.276   thorpej  *	"compatible" strings as an OpenFirmware-style string
   2614       1.276   thorpej  *	list.
   2615       1.276   thorpej  */
   2616       1.276   thorpej int
   2617       1.276   thorpej device_compatible_pmatch_strlist(
   2618       1.276   thorpej     const char * const device_compats, size_t const device_compatsize,
   2619       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2620       1.275   thorpej {
   2621       1.276   thorpej 	return device_compatible_match_strlist_internal(device_compats,
   2622       1.276   thorpej 	    device_compatsize, driver_compats, NULL, strlist_pmatch);
   2623       1.275   thorpej }
   2624       1.275   thorpej 
   2625       1.277   thorpej static int
   2626       1.277   thorpej device_compatible_match_id_internal(
   2627       1.277   thorpej     uintptr_t const id, uintptr_t const mask, uintptr_t const sentinel_id,
   2628       1.277   thorpej     const struct device_compatible_entry *driver_compats,
   2629       1.277   thorpej     const struct device_compatible_entry **matching_entryp)
   2630       1.277   thorpej {
   2631       1.277   thorpej 	const struct device_compatible_entry *dce = NULL;
   2632       1.277   thorpej 
   2633       1.277   thorpej 	if (mask == 0)
   2634       1.277   thorpej 		return 0;
   2635       1.277   thorpej 
   2636       1.277   thorpej 	for (dce = driver_compats; dce->id != sentinel_id; dce++) {
   2637       1.277   thorpej 		if ((id & mask) == dce->id) {
   2638       1.277   thorpej 			if (matching_entryp != NULL) {
   2639       1.277   thorpej 				*matching_entryp = dce;
   2640       1.277   thorpej 			}
   2641       1.277   thorpej 			return 1;
   2642       1.277   thorpej 		}
   2643       1.277   thorpej 	}
   2644       1.277   thorpej 	return 0;
   2645       1.277   thorpej }
   2646       1.277   thorpej 
   2647       1.277   thorpej /*
   2648       1.277   thorpej  * device_compatible_match_id:
   2649       1.277   thorpej  *
   2650       1.277   thorpej  *	Like device_compatible_match(), but takes a single
   2651       1.277   thorpej  *	unsigned integer device ID.
   2652       1.277   thorpej  */
   2653       1.277   thorpej int
   2654       1.277   thorpej device_compatible_match_id(
   2655       1.277   thorpej     uintptr_t const id, uintptr_t const sentinel_id,
   2656       1.277   thorpej     const struct device_compatible_entry *driver_compats)
   2657       1.277   thorpej {
   2658       1.277   thorpej 	return device_compatible_match_id_internal(id, (uintptr_t)-1,
   2659       1.277   thorpej 	    sentinel_id, driver_compats, NULL);
   2660       1.277   thorpej }
   2661       1.277   thorpej 
   2662       1.275   thorpej /*
   2663       1.275   thorpej  * device_compatible_lookup:
   2664       1.275   thorpej  *
   2665       1.275   thorpej  *	Look up and return the device_compatible_entry, using the
   2666       1.275   thorpej  *	same matching criteria used by device_compatible_match().
   2667       1.275   thorpej  */
   2668       1.275   thorpej const struct device_compatible_entry *
   2669       1.275   thorpej device_compatible_lookup(const char **device_compats, int ndevice_compats,
   2670       1.275   thorpej 			 const struct device_compatible_entry *driver_compats)
   2671       1.275   thorpej {
   2672       1.275   thorpej 	const struct device_compatible_entry *dce;
   2673       1.275   thorpej 
   2674       1.276   thorpej 	if (device_compatible_match_strarray_internal(device_compats,
   2675       1.276   thorpej 	    ndevice_compats, driver_compats, &dce, strarray_match)) {
   2676       1.276   thorpej 		return dce;
   2677       1.276   thorpej 	}
   2678       1.276   thorpej 	return NULL;
   2679       1.276   thorpej }
   2680       1.276   thorpej 
   2681       1.276   thorpej /*
   2682       1.276   thorpej  * device_compatible_plookup:
   2683       1.276   thorpej  *
   2684       1.276   thorpej  *	Look up and return the device_compatible_entry, using the
   2685       1.276   thorpej  *	same matching criteria used by device_compatible_pmatch().
   2686       1.276   thorpej  */
   2687       1.276   thorpej const struct device_compatible_entry *
   2688       1.276   thorpej device_compatible_plookup(const char **device_compats, int ndevice_compats,
   2689       1.276   thorpej 			  const struct device_compatible_entry *driver_compats)
   2690       1.276   thorpej {
   2691       1.276   thorpej 	const struct device_compatible_entry *dce;
   2692       1.276   thorpej 
   2693       1.276   thorpej 	if (device_compatible_match_strarray_internal(device_compats,
   2694       1.276   thorpej 	    ndevice_compats, driver_compats, &dce, strarray_pmatch)) {
   2695       1.276   thorpej 		return dce;
   2696       1.276   thorpej 	}
   2697       1.276   thorpej 	return NULL;
   2698       1.276   thorpej }
   2699       1.276   thorpej 
   2700       1.276   thorpej /*
   2701       1.276   thorpej  * device_compatible_lookup_strlist:
   2702       1.276   thorpej  *
   2703       1.276   thorpej  *	Like device_compatible_lookup(), but take the device
   2704       1.276   thorpej  *	"compatible" strings as an OpenFirmware-style string
   2705       1.276   thorpej  *	list.
   2706       1.276   thorpej  */
   2707       1.276   thorpej const struct device_compatible_entry *
   2708       1.276   thorpej device_compatible_lookup_strlist(
   2709       1.276   thorpej     const char * const device_compats, size_t const device_compatsize,
   2710       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2711       1.276   thorpej {
   2712       1.276   thorpej 	const struct device_compatible_entry *dce;
   2713       1.276   thorpej 
   2714       1.276   thorpej 	if (device_compatible_match_strlist_internal(device_compats,
   2715       1.276   thorpej 	    device_compatsize, driver_compats, &dce, strlist_match)) {
   2716       1.276   thorpej 		return dce;
   2717       1.276   thorpej 	}
   2718       1.276   thorpej 	return NULL;
   2719       1.276   thorpej }
   2720       1.276   thorpej 
   2721       1.276   thorpej /*
   2722       1.276   thorpej  * device_compatible_plookup_strlist:
   2723       1.276   thorpej  *
   2724       1.276   thorpej  *	Like device_compatible_plookup(), but take the device
   2725       1.276   thorpej  *	"compatible" strings as an OpenFirmware-style string
   2726       1.276   thorpej  *	list.
   2727       1.276   thorpej  */
   2728       1.276   thorpej const struct device_compatible_entry *
   2729       1.276   thorpej device_compatible_plookup_strlist(
   2730       1.276   thorpej     const char * const device_compats, size_t const device_compatsize,
   2731       1.276   thorpej     const struct device_compatible_entry *driver_compats)
   2732       1.276   thorpej {
   2733       1.276   thorpej 	const struct device_compatible_entry *dce;
   2734       1.276   thorpej 
   2735       1.276   thorpej 	if (device_compatible_match_strlist_internal(device_compats,
   2736       1.276   thorpej 	    device_compatsize, driver_compats, &dce, strlist_pmatch)) {
   2737       1.275   thorpej 		return dce;
   2738       1.275   thorpej 	}
   2739       1.275   thorpej 	return NULL;
   2740       1.275   thorpej }
   2741       1.275   thorpej 
   2742       1.258   thorpej /*
   2743       1.277   thorpej  * device_compatible_lookup_id:
   2744       1.277   thorpej  *
   2745       1.277   thorpej  *	Like device_compatible_lookup(), but takes a single
   2746       1.277   thorpej  *	unsigned integer device ID.
   2747       1.277   thorpej  */
   2748       1.277   thorpej const struct device_compatible_entry *
   2749       1.277   thorpej device_compatible_lookup_id(
   2750       1.277   thorpej     uintptr_t const id, uintptr_t const sentinel_id,
   2751       1.277   thorpej     const struct device_compatible_entry *driver_compats)
   2752       1.277   thorpej {
   2753       1.277   thorpej 	const struct device_compatible_entry *dce;
   2754       1.277   thorpej 
   2755       1.277   thorpej 	if (device_compatible_match_id_internal(id, (uintptr_t)-1,
   2756       1.277   thorpej 	    sentinel_id, driver_compats, &dce)) {
   2757       1.277   thorpej 		return dce;
   2758       1.277   thorpej 	}
   2759       1.277   thorpej 	return NULL;
   2760       1.277   thorpej }
   2761       1.277   thorpej 
   2762       1.277   thorpej /*
   2763       1.124  jmcneill  * Power management related functions.
   2764       1.124  jmcneill  */
   2765       1.124  jmcneill 
   2766       1.124  jmcneill bool
   2767       1.124  jmcneill device_pmf_is_registered(device_t dev)
   2768       1.124  jmcneill {
   2769       1.124  jmcneill 	return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
   2770       1.124  jmcneill }
   2771       1.124  jmcneill 
   2772       1.124  jmcneill bool
   2773       1.203    dyoung device_pmf_driver_suspend(device_t dev, const pmf_qual_t *qual)
   2774       1.124  jmcneill {
   2775       1.124  jmcneill 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
   2776       1.124  jmcneill 		return true;
   2777       1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
   2778       1.124  jmcneill 		return false;
   2779       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
   2780       1.183    dyoung 	    dev->dv_driver_suspend != NULL &&
   2781       1.195    dyoung 	    !(*dev->dv_driver_suspend)(dev, qual))
   2782       1.124  jmcneill 		return false;
   2783       1.124  jmcneill 
   2784       1.124  jmcneill 	dev->dv_flags |= DVF_DRIVER_SUSPENDED;
   2785       1.124  jmcneill 	return true;
   2786       1.124  jmcneill }
   2787       1.124  jmcneill 
   2788       1.124  jmcneill bool
   2789       1.203    dyoung device_pmf_driver_resume(device_t dev, const pmf_qual_t *qual)
   2790       1.124  jmcneill {
   2791       1.124  jmcneill 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
   2792       1.124  jmcneill 		return true;
   2793       1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
   2794       1.124  jmcneill 		return false;
   2795       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
   2796       1.183    dyoung 	    dev->dv_driver_resume != NULL &&
   2797       1.195    dyoung 	    !(*dev->dv_driver_resume)(dev, qual))
   2798       1.124  jmcneill 		return false;
   2799       1.124  jmcneill 
   2800       1.124  jmcneill 	dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
   2801       1.124  jmcneill 	return true;
   2802       1.124  jmcneill }
   2803       1.124  jmcneill 
   2804       1.133  drochner bool
   2805       1.133  drochner device_pmf_driver_shutdown(device_t dev, int how)
   2806       1.133  drochner {
   2807       1.133  drochner 
   2808       1.133  drochner 	if (*dev->dv_driver_shutdown != NULL &&
   2809       1.133  drochner 	    !(*dev->dv_driver_shutdown)(dev, how))
   2810       1.133  drochner 		return false;
   2811       1.133  drochner 	return true;
   2812       1.133  drochner }
   2813       1.133  drochner 
   2814       1.135    dyoung bool
   2815       1.124  jmcneill device_pmf_driver_register(device_t dev,
   2816       1.203    dyoung     bool (*suspend)(device_t, const pmf_qual_t *),
   2817       1.203    dyoung     bool (*resume)(device_t, const pmf_qual_t *),
   2818       1.133  drochner     bool (*shutdown)(device_t, int))
   2819       1.124  jmcneill {
   2820       1.124  jmcneill 	dev->dv_driver_suspend = suspend;
   2821       1.124  jmcneill 	dev->dv_driver_resume = resume;
   2822       1.133  drochner 	dev->dv_driver_shutdown = shutdown;
   2823       1.124  jmcneill 	dev->dv_flags |= DVF_POWER_HANDLERS;
   2824       1.135    dyoung 	return true;
   2825       1.124  jmcneill }
   2826       1.124  jmcneill 
   2827       1.139    dyoung static const char *
   2828       1.139    dyoung curlwp_name(void)
   2829       1.139    dyoung {
   2830       1.139    dyoung 	if (curlwp->l_name != NULL)
   2831       1.139    dyoung 		return curlwp->l_name;
   2832       1.139    dyoung 	else
   2833       1.139    dyoung 		return curlwp->l_proc->p_comm;
   2834       1.139    dyoung }
   2835       1.139    dyoung 
   2836       1.124  jmcneill void
   2837       1.124  jmcneill device_pmf_driver_deregister(device_t dev)
   2838       1.124  jmcneill {
   2839       1.174    dyoung 	device_lock_t dvl = device_getlock(dev);
   2840       1.157  drochner 
   2841       1.124  jmcneill 	dev->dv_driver_suspend = NULL;
   2842       1.124  jmcneill 	dev->dv_driver_resume = NULL;
   2843       1.139    dyoung 
   2844       1.174    dyoung 	mutex_enter(&dvl->dvl_mtx);
   2845       1.124  jmcneill 	dev->dv_flags &= ~DVF_POWER_HANDLERS;
   2846       1.174    dyoung 	while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) {
   2847       1.139    dyoung 		/* Wake a thread that waits for the lock.  That
   2848       1.139    dyoung 		 * thread will fail to acquire the lock, and then
   2849       1.139    dyoung 		 * it will wake the next thread that waits for the
   2850       1.139    dyoung 		 * lock, or else it will wake us.
   2851       1.139    dyoung 		 */
   2852       1.174    dyoung 		cv_signal(&dvl->dvl_cv);
   2853       1.139    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2854       1.174    dyoung 		cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
   2855       1.139    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2856       1.139    dyoung 	}
   2857       1.174    dyoung 	mutex_exit(&dvl->dvl_mtx);
   2858       1.124  jmcneill }
   2859       1.124  jmcneill 
   2860       1.124  jmcneill bool
   2861       1.124  jmcneill device_pmf_driver_child_register(device_t dev)
   2862       1.124  jmcneill {
   2863       1.124  jmcneill 	device_t parent = device_parent(dev);
   2864       1.124  jmcneill 
   2865       1.124  jmcneill 	if (parent == NULL || parent->dv_driver_child_register == NULL)
   2866       1.124  jmcneill 		return true;
   2867       1.124  jmcneill 	return (*parent->dv_driver_child_register)(dev);
   2868       1.124  jmcneill }
   2869       1.124  jmcneill 
   2870       1.124  jmcneill void
   2871       1.124  jmcneill device_pmf_driver_set_child_register(device_t dev,
   2872       1.124  jmcneill     bool (*child_register)(device_t))
   2873       1.124  jmcneill {
   2874       1.124  jmcneill 	dev->dv_driver_child_register = child_register;
   2875       1.124  jmcneill }
   2876       1.124  jmcneill 
   2877       1.139    dyoung static void
   2878       1.139    dyoung pmflock_debug(device_t dev, const char *func, int line)
   2879       1.139    dyoung {
   2880       1.174    dyoung 	device_lock_t dvl = device_getlock(dev);
   2881       1.139    dyoung 
   2882       1.243   msaitoh 	aprint_debug_dev(dev,
   2883       1.243   msaitoh 	    "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n", func, line,
   2884       1.243   msaitoh 	    curlwp_name(), dvl->dvl_nlock, dvl->dvl_nwait, dev->dv_flags);
   2885       1.139    dyoung }
   2886       1.139    dyoung 
   2887       1.139    dyoung static bool
   2888       1.183    dyoung device_pmf_lock1(device_t dev)
   2889       1.139    dyoung {
   2890       1.174    dyoung 	device_lock_t dvl = device_getlock(dev);
   2891       1.139    dyoung 
   2892       1.155    dyoung 	while (device_pmf_is_registered(dev) &&
   2893       1.174    dyoung 	    dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) {
   2894       1.174    dyoung 		dvl->dvl_nwait++;
   2895       1.183    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2896       1.174    dyoung 		cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
   2897       1.183    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2898       1.174    dyoung 		dvl->dvl_nwait--;
   2899       1.139    dyoung 	}
   2900       1.139    dyoung 	if (!device_pmf_is_registered(dev)) {
   2901       1.183    dyoung 		pmflock_debug(dev, __func__, __LINE__);
   2902       1.139    dyoung 		/* We could not acquire the lock, but some other thread may
   2903       1.139    dyoung 		 * wait for it, also.  Wake that thread.
   2904       1.139    dyoung 		 */
   2905       1.174    dyoung 		cv_signal(&dvl->dvl_cv);
   2906       1.139    dyoung 		return false;
   2907       1.139    dyoung 	}
   2908       1.174    dyoung 	dvl->dvl_nlock++;
   2909       1.174    dyoung 	dvl->dvl_holder = curlwp;
   2910       1.183    dyoung 	pmflock_debug(dev, __func__, __LINE__);
   2911       1.139    dyoung 	return true;
   2912       1.139    dyoung }
   2913       1.139    dyoung 
   2914       1.139    dyoung bool
   2915       1.183    dyoung device_pmf_lock(device_t dev)
   2916       1.139    dyoung {
   2917       1.139    dyoung 	bool rc;
   2918       1.174    dyoung 	device_lock_t dvl = device_getlock(dev);
   2919       1.139    dyoung 
   2920       1.174    dyoung 	mutex_enter(&dvl->dvl_mtx);
   2921       1.183    dyoung 	rc = device_pmf_lock1(dev);
   2922       1.174    dyoung 	mutex_exit(&dvl->dvl_mtx);
   2923       1.139    dyoung 
   2924       1.139    dyoung 	return rc;
   2925       1.139    dyoung }
   2926       1.139    dyoung 
   2927       1.139    dyoung void
   2928       1.183    dyoung device_pmf_unlock(device_t dev)
   2929       1.139    dyoung {
   2930       1.174    dyoung 	device_lock_t dvl = device_getlock(dev);
   2931       1.139    dyoung 
   2932       1.174    dyoung 	KASSERT(dvl->dvl_nlock > 0);
   2933       1.174    dyoung 	mutex_enter(&dvl->dvl_mtx);
   2934       1.174    dyoung 	if (--dvl->dvl_nlock == 0)
   2935       1.174    dyoung 		dvl->dvl_holder = NULL;
   2936       1.174    dyoung 	cv_signal(&dvl->dvl_cv);
   2937       1.183    dyoung 	pmflock_debug(dev, __func__, __LINE__);
   2938       1.174    dyoung 	mutex_exit(&dvl->dvl_mtx);
   2939       1.139    dyoung }
   2940       1.139    dyoung 
   2941       1.174    dyoung device_lock_t
   2942       1.174    dyoung device_getlock(device_t dev)
   2943       1.139    dyoung {
   2944       1.174    dyoung 	return &dev->dv_lock;
   2945       1.139    dyoung }
   2946       1.139    dyoung 
   2947       1.124  jmcneill void *
   2948       1.124  jmcneill device_pmf_bus_private(device_t dev)
   2949       1.124  jmcneill {
   2950       1.124  jmcneill 	return dev->dv_bus_private;
   2951       1.124  jmcneill }
   2952       1.124  jmcneill 
   2953       1.124  jmcneill bool
   2954       1.203    dyoung device_pmf_bus_suspend(device_t dev, const pmf_qual_t *qual)
   2955       1.124  jmcneill {
   2956       1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
   2957       1.124  jmcneill 		return true;
   2958       1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
   2959       1.124  jmcneill 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
   2960       1.124  jmcneill 		return false;
   2961       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
   2962       1.183    dyoung 	    dev->dv_bus_suspend != NULL &&
   2963       1.195    dyoung 	    !(*dev->dv_bus_suspend)(dev, qual))
   2964       1.124  jmcneill 		return false;
   2965       1.124  jmcneill 
   2966       1.124  jmcneill 	dev->dv_flags |= DVF_BUS_SUSPENDED;
   2967       1.124  jmcneill 	return true;
   2968       1.124  jmcneill }
   2969       1.124  jmcneill 
   2970       1.124  jmcneill bool
   2971       1.203    dyoung device_pmf_bus_resume(device_t dev, const pmf_qual_t *qual)
   2972       1.124  jmcneill {
   2973       1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
   2974       1.124  jmcneill 		return true;
   2975       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
   2976       1.183    dyoung 	    dev->dv_bus_resume != NULL &&
   2977       1.195    dyoung 	    !(*dev->dv_bus_resume)(dev, qual))
   2978       1.124  jmcneill 		return false;
   2979       1.124  jmcneill 
   2980       1.124  jmcneill 	dev->dv_flags &= ~DVF_BUS_SUSPENDED;
   2981       1.124  jmcneill 	return true;
   2982       1.124  jmcneill }
   2983       1.124  jmcneill 
   2984       1.133  drochner bool
   2985       1.133  drochner device_pmf_bus_shutdown(device_t dev, int how)
   2986       1.133  drochner {
   2987       1.133  drochner 
   2988       1.133  drochner 	if (*dev->dv_bus_shutdown != NULL &&
   2989       1.133  drochner 	    !(*dev->dv_bus_shutdown)(dev, how))
   2990       1.133  drochner 		return false;
   2991       1.133  drochner 	return true;
   2992       1.133  drochner }
   2993       1.133  drochner 
   2994       1.124  jmcneill void
   2995       1.124  jmcneill device_pmf_bus_register(device_t dev, void *priv,
   2996       1.203    dyoung     bool (*suspend)(device_t, const pmf_qual_t *),
   2997       1.203    dyoung     bool (*resume)(device_t, const pmf_qual_t *),
   2998       1.133  drochner     bool (*shutdown)(device_t, int), void (*deregister)(device_t))
   2999       1.124  jmcneill {
   3000       1.124  jmcneill 	dev->dv_bus_private = priv;
   3001       1.124  jmcneill 	dev->dv_bus_resume = resume;
   3002       1.124  jmcneill 	dev->dv_bus_suspend = suspend;
   3003       1.133  drochner 	dev->dv_bus_shutdown = shutdown;
   3004       1.124  jmcneill 	dev->dv_bus_deregister = deregister;
   3005       1.124  jmcneill }
   3006       1.124  jmcneill 
   3007       1.124  jmcneill void
   3008       1.124  jmcneill device_pmf_bus_deregister(device_t dev)
   3009       1.124  jmcneill {
   3010       1.124  jmcneill 	if (dev->dv_bus_deregister == NULL)
   3011       1.124  jmcneill 		return;
   3012       1.124  jmcneill 	(*dev->dv_bus_deregister)(dev);
   3013       1.124  jmcneill 	dev->dv_bus_private = NULL;
   3014       1.124  jmcneill 	dev->dv_bus_suspend = NULL;
   3015       1.124  jmcneill 	dev->dv_bus_resume = NULL;
   3016       1.124  jmcneill 	dev->dv_bus_deregister = NULL;
   3017       1.124  jmcneill }
   3018       1.124  jmcneill 
   3019       1.124  jmcneill void *
   3020       1.124  jmcneill device_pmf_class_private(device_t dev)
   3021       1.124  jmcneill {
   3022       1.124  jmcneill 	return dev->dv_class_private;
   3023       1.124  jmcneill }
   3024       1.124  jmcneill 
   3025       1.124  jmcneill bool
   3026       1.203    dyoung device_pmf_class_suspend(device_t dev, const pmf_qual_t *qual)
   3027       1.124  jmcneill {
   3028       1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
   3029       1.124  jmcneill 		return true;
   3030       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
   3031       1.183    dyoung 	    dev->dv_class_suspend != NULL &&
   3032       1.195    dyoung 	    !(*dev->dv_class_suspend)(dev, qual))
   3033       1.124  jmcneill 		return false;
   3034       1.124  jmcneill 
   3035       1.124  jmcneill 	dev->dv_flags |= DVF_CLASS_SUSPENDED;
   3036       1.124  jmcneill 	return true;
   3037       1.124  jmcneill }
   3038       1.124  jmcneill 
   3039       1.124  jmcneill bool
   3040       1.203    dyoung device_pmf_class_resume(device_t dev, const pmf_qual_t *qual)
   3041       1.124  jmcneill {
   3042       1.124  jmcneill 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
   3043       1.124  jmcneill 		return true;
   3044       1.124  jmcneill 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
   3045       1.124  jmcneill 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
   3046       1.124  jmcneill 		return false;
   3047       1.195    dyoung 	if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
   3048       1.183    dyoung 	    dev->dv_class_resume != NULL &&
   3049       1.195    dyoung 	    !(*dev->dv_class_resume)(dev, qual))
   3050       1.124  jmcneill 		return false;
   3051       1.124  jmcneill 
   3052       1.124  jmcneill 	dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
   3053       1.124  jmcneill 	return true;
   3054       1.124  jmcneill }
   3055       1.124  jmcneill 
   3056       1.124  jmcneill void
   3057       1.124  jmcneill device_pmf_class_register(device_t dev, void *priv,
   3058       1.203    dyoung     bool (*suspend)(device_t, const pmf_qual_t *),
   3059       1.203    dyoung     bool (*resume)(device_t, const pmf_qual_t *),
   3060       1.124  jmcneill     void (*deregister)(device_t))
   3061       1.124  jmcneill {
   3062       1.124  jmcneill 	dev->dv_class_private = priv;
   3063       1.124  jmcneill 	dev->dv_class_suspend = suspend;
   3064       1.124  jmcneill 	dev->dv_class_resume = resume;
   3065       1.124  jmcneill 	dev->dv_class_deregister = deregister;
   3066       1.124  jmcneill }
   3067       1.124  jmcneill 
   3068       1.124  jmcneill void
   3069       1.124  jmcneill device_pmf_class_deregister(device_t dev)
   3070       1.124  jmcneill {
   3071       1.124  jmcneill 	if (dev->dv_class_deregister == NULL)
   3072       1.124  jmcneill 		return;
   3073       1.124  jmcneill 	(*dev->dv_class_deregister)(dev);
   3074       1.124  jmcneill 	dev->dv_class_private = NULL;
   3075       1.124  jmcneill 	dev->dv_class_suspend = NULL;
   3076       1.124  jmcneill 	dev->dv_class_resume = NULL;
   3077       1.124  jmcneill 	dev->dv_class_deregister = NULL;
   3078       1.124  jmcneill }
   3079       1.124  jmcneill 
   3080       1.124  jmcneill bool
   3081       1.124  jmcneill device_active(device_t dev, devactive_t type)
   3082       1.124  jmcneill {
   3083       1.124  jmcneill 	size_t i;
   3084       1.124  jmcneill 
   3085       1.124  jmcneill 	if (dev->dv_activity_count == 0)
   3086       1.124  jmcneill 		return false;
   3087       1.124  jmcneill 
   3088       1.160      matt 	for (i = 0; i < dev->dv_activity_count; ++i) {
   3089       1.160      matt 		if (dev->dv_activity_handlers[i] == NULL)
   3090       1.160      matt 			break;
   3091       1.124  jmcneill 		(*dev->dv_activity_handlers[i])(dev, type);
   3092       1.160      matt 	}
   3093       1.124  jmcneill 
   3094       1.124  jmcneill 	return true;
   3095       1.124  jmcneill }
   3096       1.124  jmcneill 
   3097       1.124  jmcneill bool
   3098       1.124  jmcneill device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
   3099       1.124  jmcneill {
   3100       1.124  jmcneill 	void (**new_handlers)(device_t, devactive_t);
   3101       1.124  jmcneill 	void (**old_handlers)(device_t, devactive_t);
   3102       1.159      matt 	size_t i, old_size, new_size;
   3103       1.124  jmcneill 	int s;
   3104       1.124  jmcneill 
   3105       1.124  jmcneill 	old_handlers = dev->dv_activity_handlers;
   3106       1.159      matt 	old_size = dev->dv_activity_count;
   3107       1.124  jmcneill 
   3108       1.240   mlelstv 	KASSERT(old_size == 0 || old_handlers != NULL);
   3109       1.240   mlelstv 
   3110       1.159      matt 	for (i = 0; i < old_size; ++i) {
   3111       1.159      matt 		KASSERT(old_handlers[i] != handler);
   3112       1.159      matt 		if (old_handlers[i] == NULL) {
   3113       1.159      matt 			old_handlers[i] = handler;
   3114       1.159      matt 			return true;
   3115       1.159      matt 		}
   3116       1.124  jmcneill 	}
   3117       1.124  jmcneill 
   3118       1.159      matt 	new_size = old_size + 4;
   3119       1.273  jdolecek 	new_handlers = kmem_alloc(sizeof(void *) * new_size, KM_SLEEP);
   3120       1.124  jmcneill 
   3121       1.240   mlelstv 	for (i = 0; i < old_size; ++i)
   3122       1.240   mlelstv 		new_handlers[i] = old_handlers[i];
   3123       1.159      matt 	new_handlers[old_size] = handler;
   3124       1.240   mlelstv 	for (i = old_size+1; i < new_size; ++i)
   3125       1.240   mlelstv 		new_handlers[i] = NULL;
   3126       1.124  jmcneill 
   3127       1.124  jmcneill 	s = splhigh();
   3128       1.124  jmcneill 	dev->dv_activity_count = new_size;
   3129       1.124  jmcneill 	dev->dv_activity_handlers = new_handlers;
   3130       1.124  jmcneill 	splx(s);
   3131       1.124  jmcneill 
   3132       1.240   mlelstv 	if (old_size > 0)
   3133       1.273  jdolecek 		kmem_free(old_handlers, sizeof(void *) * old_size);
   3134       1.124  jmcneill 
   3135       1.124  jmcneill 	return true;
   3136       1.124  jmcneill }
   3137       1.124  jmcneill 
   3138       1.124  jmcneill void
   3139       1.124  jmcneill device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
   3140       1.124  jmcneill {
   3141       1.124  jmcneill 	void (**old_handlers)(device_t, devactive_t);
   3142       1.159      matt 	size_t i, old_size;
   3143       1.124  jmcneill 	int s;
   3144       1.124  jmcneill 
   3145       1.124  jmcneill 	old_handlers = dev->dv_activity_handlers;
   3146       1.159      matt 	old_size = dev->dv_activity_count;
   3147       1.124  jmcneill 
   3148       1.159      matt 	for (i = 0; i < old_size; ++i) {
   3149       1.124  jmcneill 		if (old_handlers[i] == handler)
   3150       1.124  jmcneill 			break;
   3151       1.159      matt 		if (old_handlers[i] == NULL)
   3152       1.159      matt 			return; /* XXX panic? */
   3153       1.124  jmcneill 	}
   3154       1.124  jmcneill 
   3155       1.159      matt 	if (i == old_size)
   3156       1.124  jmcneill 		return; /* XXX panic? */
   3157       1.124  jmcneill 
   3158       1.159      matt 	for (; i < old_size - 1; ++i) {
   3159       1.159      matt 		if ((old_handlers[i] = old_handlers[i + 1]) != NULL)
   3160       1.159      matt 			continue;
   3161       1.124  jmcneill 
   3162       1.159      matt 		if (i == 0) {
   3163       1.159      matt 			s = splhigh();
   3164       1.159      matt 			dev->dv_activity_count = 0;
   3165       1.159      matt 			dev->dv_activity_handlers = NULL;
   3166       1.159      matt 			splx(s);
   3167       1.273  jdolecek 			kmem_free(old_handlers, sizeof(void *) * old_size);
   3168       1.159      matt 		}
   3169       1.159      matt 		return;
   3170       1.124  jmcneill 	}
   3171       1.159      matt 	old_handlers[i] = NULL;
   3172       1.124  jmcneill }
   3173       1.136    dyoung 
   3174       1.187    dyoung /* Return true iff the device_t `dev' exists at generation `gen'. */
   3175       1.187    dyoung static bool
   3176       1.187    dyoung device_exists_at(device_t dv, devgen_t gen)
   3177       1.187    dyoung {
   3178       1.187    dyoung 	return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) &&
   3179       1.187    dyoung 	    dv->dv_add_gen <= gen;
   3180       1.187    dyoung }
   3181       1.187    dyoung 
   3182       1.187    dyoung static bool
   3183       1.187    dyoung deviter_visits(const deviter_t *di, device_t dv)
   3184       1.187    dyoung {
   3185       1.187    dyoung 	return device_exists_at(dv, di->di_gen);
   3186       1.187    dyoung }
   3187       1.187    dyoung 
   3188       1.136    dyoung /*
   3189       1.136    dyoung  * Device Iteration
   3190       1.136    dyoung  *
   3191       1.136    dyoung  * deviter_t: a device iterator.  Holds state for a "walk" visiting
   3192       1.136    dyoung  *     each device_t's in the device tree.
   3193       1.136    dyoung  *
   3194       1.136    dyoung  * deviter_init(di, flags): initialize the device iterator `di'
   3195       1.136    dyoung  *     to "walk" the device tree.  deviter_next(di) will return
   3196       1.136    dyoung  *     the first device_t in the device tree, or NULL if there are
   3197       1.136    dyoung  *     no devices.
   3198       1.136    dyoung  *
   3199       1.136    dyoung  *     `flags' is one or more of DEVITER_F_RW, indicating that the
   3200       1.136    dyoung  *     caller intends to modify the device tree by calling
   3201       1.136    dyoung  *     config_detach(9) on devices in the order that the iterator
   3202       1.136    dyoung  *     returns them; DEVITER_F_ROOT_FIRST, asking for the devices
   3203       1.136    dyoung  *     nearest the "root" of the device tree to be returned, first;
   3204       1.136    dyoung  *     DEVITER_F_LEAVES_FIRST, asking for the devices furthest from
   3205       1.136    dyoung  *     the root of the device tree, first; and DEVITER_F_SHUTDOWN,
   3206       1.136    dyoung  *     indicating both that deviter_init() should not respect any
   3207       1.136    dyoung  *     locks on the device tree, and that deviter_next(di) may run
   3208       1.136    dyoung  *     in more than one LWP before the walk has finished.
   3209       1.136    dyoung  *
   3210       1.136    dyoung  *     Only one DEVITER_F_RW iterator may be in the device tree at
   3211       1.136    dyoung  *     once.
   3212       1.136    dyoung  *
   3213       1.136    dyoung  *     DEVITER_F_SHUTDOWN implies DEVITER_F_RW.
   3214       1.136    dyoung  *
   3215       1.136    dyoung  *     Results are undefined if the flags DEVITER_F_ROOT_FIRST and
   3216       1.136    dyoung  *     DEVITER_F_LEAVES_FIRST are used in combination.
   3217       1.136    dyoung  *
   3218       1.136    dyoung  * deviter_first(di, flags): initialize the device iterator `di'
   3219       1.136    dyoung  *     and return the first device_t in the device tree, or NULL
   3220       1.136    dyoung  *     if there are no devices.  The statement
   3221       1.136    dyoung  *
   3222       1.136    dyoung  *         dv = deviter_first(di);
   3223       1.136    dyoung  *
   3224       1.136    dyoung  *     is shorthand for
   3225       1.136    dyoung  *
   3226       1.136    dyoung  *         deviter_init(di);
   3227       1.136    dyoung  *         dv = deviter_next(di);
   3228       1.136    dyoung  *
   3229       1.136    dyoung  * deviter_next(di): return the next device_t in the device tree,
   3230       1.136    dyoung  *     or NULL if there are no more devices.  deviter_next(di)
   3231       1.136    dyoung  *     is undefined if `di' was not initialized with deviter_init() or
   3232       1.136    dyoung  *     deviter_first().
   3233       1.136    dyoung  *
   3234       1.136    dyoung  * deviter_release(di): stops iteration (subsequent calls to
   3235       1.136    dyoung  *     deviter_next() will return NULL), releases any locks and
   3236       1.136    dyoung  *     resources held by the device iterator.
   3237       1.136    dyoung  *
   3238       1.136    dyoung  * Device iteration does not return device_t's in any particular
   3239       1.136    dyoung  * order.  An iterator will never return the same device_t twice.
   3240       1.136    dyoung  * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
   3241       1.136    dyoung  * is called repeatedly on the same `di', it will eventually return
   3242       1.136    dyoung  * NULL.  It is ok to attach/detach devices during device iteration.
   3243       1.136    dyoung  */
   3244       1.136    dyoung void
   3245       1.136    dyoung deviter_init(deviter_t *di, deviter_flags_t flags)
   3246       1.136    dyoung {
   3247       1.136    dyoung 	device_t dv;
   3248       1.136    dyoung 
   3249       1.187    dyoung 	memset(di, 0, sizeof(*di));
   3250       1.187    dyoung 
   3251       1.187    dyoung 	if ((flags & DEVITER_F_SHUTDOWN) != 0)
   3252       1.136    dyoung 		flags |= DEVITER_F_RW;
   3253       1.187    dyoung 
   3254       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   3255       1.187    dyoung 	if ((flags & DEVITER_F_RW) != 0)
   3256       1.257   mlelstv 		alldevs_nwrite++;
   3257       1.187    dyoung 	else
   3258       1.257   mlelstv 		alldevs_nread++;
   3259       1.257   mlelstv 	di->di_gen = alldevs_gen++;
   3260       1.136    dyoung 	di->di_flags = flags;
   3261       1.136    dyoung 
   3262       1.136    dyoung 	switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
   3263       1.136    dyoung 	case DEVITER_F_LEAVES_FIRST:
   3264       1.257   mlelstv 		TAILQ_FOREACH(dv, &alldevs, dv_list) {
   3265       1.187    dyoung 			if (!deviter_visits(di, dv))
   3266       1.187    dyoung 				continue;
   3267       1.136    dyoung 			di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
   3268       1.187    dyoung 		}
   3269       1.136    dyoung 		break;
   3270       1.136    dyoung 	case DEVITER_F_ROOT_FIRST:
   3271       1.257   mlelstv 		TAILQ_FOREACH(dv, &alldevs, dv_list) {
   3272       1.187    dyoung 			if (!deviter_visits(di, dv))
   3273       1.187    dyoung 				continue;
   3274       1.136    dyoung 			di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
   3275       1.187    dyoung 		}
   3276       1.136    dyoung 		break;
   3277       1.136    dyoung 	default:
   3278       1.136    dyoung 		break;
   3279       1.136    dyoung 	}
   3280       1.136    dyoung 
   3281       1.136    dyoung 	deviter_reinit(di);
   3282       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   3283       1.136    dyoung }
   3284       1.136    dyoung 
   3285       1.136    dyoung static void
   3286       1.136    dyoung deviter_reinit(deviter_t *di)
   3287       1.136    dyoung {
   3288       1.248  riastrad 
   3289       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   3290       1.136    dyoung 	if ((di->di_flags & DEVITER_F_RW) != 0)
   3291       1.257   mlelstv 		di->di_prev = TAILQ_LAST(&alldevs, devicelist);
   3292       1.136    dyoung 	else
   3293       1.257   mlelstv 		di->di_prev = TAILQ_FIRST(&alldevs);
   3294       1.136    dyoung }
   3295       1.136    dyoung 
   3296       1.136    dyoung device_t
   3297       1.136    dyoung deviter_first(deviter_t *di, deviter_flags_t flags)
   3298       1.136    dyoung {
   3299       1.248  riastrad 
   3300       1.136    dyoung 	deviter_init(di, flags);
   3301       1.136    dyoung 	return deviter_next(di);
   3302       1.136    dyoung }
   3303       1.136    dyoung 
   3304       1.136    dyoung static device_t
   3305       1.187    dyoung deviter_next2(deviter_t *di)
   3306       1.136    dyoung {
   3307       1.136    dyoung 	device_t dv;
   3308       1.136    dyoung 
   3309       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   3310       1.248  riastrad 
   3311       1.136    dyoung 	dv = di->di_prev;
   3312       1.136    dyoung 
   3313       1.136    dyoung 	if (dv == NULL)
   3314       1.191    dyoung 		return NULL;
   3315       1.191    dyoung 
   3316       1.191    dyoung 	if ((di->di_flags & DEVITER_F_RW) != 0)
   3317       1.136    dyoung 		di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
   3318       1.136    dyoung 	else
   3319       1.136    dyoung 		di->di_prev = TAILQ_NEXT(dv, dv_list);
   3320       1.136    dyoung 
   3321       1.136    dyoung 	return dv;
   3322       1.136    dyoung }
   3323       1.136    dyoung 
   3324       1.187    dyoung static device_t
   3325       1.187    dyoung deviter_next1(deviter_t *di)
   3326       1.187    dyoung {
   3327       1.187    dyoung 	device_t dv;
   3328       1.187    dyoung 
   3329       1.257   mlelstv 	KASSERT(mutex_owned(&alldevs_lock));
   3330       1.248  riastrad 
   3331       1.187    dyoung 	do {
   3332       1.187    dyoung 		dv = deviter_next2(di);
   3333       1.187    dyoung 	} while (dv != NULL && !deviter_visits(di, dv));
   3334       1.187    dyoung 
   3335       1.187    dyoung 	return dv;
   3336       1.187    dyoung }
   3337       1.187    dyoung 
   3338       1.136    dyoung device_t
   3339       1.136    dyoung deviter_next(deviter_t *di)
   3340       1.136    dyoung {
   3341       1.136    dyoung 	device_t dv = NULL;
   3342       1.136    dyoung 
   3343       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   3344       1.136    dyoung 	switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
   3345       1.136    dyoung 	case 0:
   3346       1.248  riastrad 		dv = deviter_next1(di);
   3347       1.248  riastrad 		break;
   3348       1.136    dyoung 	case DEVITER_F_LEAVES_FIRST:
   3349       1.136    dyoung 		while (di->di_curdepth >= 0) {
   3350       1.136    dyoung 			if ((dv = deviter_next1(di)) == NULL) {
   3351       1.136    dyoung 				di->di_curdepth--;
   3352       1.136    dyoung 				deviter_reinit(di);
   3353       1.136    dyoung 			} else if (dv->dv_depth == di->di_curdepth)
   3354       1.136    dyoung 				break;
   3355       1.136    dyoung 		}
   3356       1.248  riastrad 		break;
   3357       1.136    dyoung 	case DEVITER_F_ROOT_FIRST:
   3358       1.136    dyoung 		while (di->di_curdepth <= di->di_maxdepth) {
   3359       1.136    dyoung 			if ((dv = deviter_next1(di)) == NULL) {
   3360       1.136    dyoung 				di->di_curdepth++;
   3361       1.136    dyoung 				deviter_reinit(di);
   3362       1.136    dyoung 			} else if (dv->dv_depth == di->di_curdepth)
   3363       1.136    dyoung 				break;
   3364       1.136    dyoung 		}
   3365       1.248  riastrad 		break;
   3366       1.136    dyoung 	default:
   3367       1.248  riastrad 		break;
   3368       1.136    dyoung 	}
   3369       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   3370       1.248  riastrad 
   3371       1.248  riastrad 	return dv;
   3372       1.136    dyoung }
   3373       1.136    dyoung 
   3374       1.136    dyoung void
   3375       1.136    dyoung deviter_release(deviter_t *di)
   3376       1.136    dyoung {
   3377       1.136    dyoung 	bool rw = (di->di_flags & DEVITER_F_RW) != 0;
   3378       1.136    dyoung 
   3379       1.257   mlelstv 	mutex_enter(&alldevs_lock);
   3380       1.187    dyoung 	if (rw)
   3381       1.257   mlelstv 		--alldevs_nwrite;
   3382       1.187    dyoung 	else
   3383       1.257   mlelstv 		--alldevs_nread;
   3384       1.187    dyoung 	/* XXX wake a garbage-collection thread */
   3385       1.257   mlelstv 	mutex_exit(&alldevs_lock);
   3386       1.136    dyoung }
   3387       1.174    dyoung 
   3388       1.201    dyoung const char *
   3389       1.201    dyoung cfdata_ifattr(const struct cfdata *cf)
   3390       1.201    dyoung {
   3391       1.201    dyoung 	return cf->cf_pspec->cfp_iattr;
   3392       1.201    dyoung }
   3393       1.201    dyoung 
   3394       1.193    dyoung bool
   3395       1.193    dyoung ifattr_match(const char *snull, const char *t)
   3396       1.193    dyoung {
   3397       1.193    dyoung 	return (snull == NULL) || strcmp(snull, t) == 0;
   3398       1.193    dyoung }
   3399       1.193    dyoung 
   3400       1.192    dyoung void
   3401       1.192    dyoung null_childdetached(device_t self, device_t child)
   3402       1.192    dyoung {
   3403       1.192    dyoung 	/* do nothing */
   3404       1.192    dyoung }
   3405       1.192    dyoung 
   3406       1.182     pooka static void
   3407       1.182     pooka sysctl_detach_setup(struct sysctllog **clog)
   3408       1.174    dyoung {
   3409       1.174    dyoung 
   3410       1.230     pooka 	sysctl_createv(clog, 0, NULL, NULL,
   3411       1.174    dyoung 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   3412       1.205    jruoho 		CTLTYPE_BOOL, "detachall",
   3413       1.174    dyoung 		SYSCTL_DESCR("Detach all devices at shutdown"),
   3414       1.174    dyoung 		NULL, 0, &detachall, 0,
   3415       1.230     pooka 		CTL_KERN, CTL_CREATE, CTL_EOL);
   3416       1.174    dyoung }
   3417