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