subr_autoconf.c revision 1.119.10.2 1 1.119.10.2 tsutsui /* $NetBSD: subr_autoconf.c,v 1.119.10.2 2007/07/20 22:15:48 tsutsui Exp $ */
2 1.119.10.2 tsutsui
3 1.119.10.2 tsutsui /*
4 1.119.10.2 tsutsui * Copyright (c) 1996, 2000 Christopher G. Demetriou
5 1.119.10.2 tsutsui * All rights reserved.
6 1.119.10.2 tsutsui *
7 1.119.10.2 tsutsui * Redistribution and use in source and binary forms, with or without
8 1.119.10.2 tsutsui * modification, are permitted provided that the following conditions
9 1.119.10.2 tsutsui * are met:
10 1.119.10.2 tsutsui * 1. Redistributions of source code must retain the above copyright
11 1.119.10.2 tsutsui * notice, this list of conditions and the following disclaimer.
12 1.119.10.2 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
13 1.119.10.2 tsutsui * notice, this list of conditions and the following disclaimer in the
14 1.119.10.2 tsutsui * documentation and/or other materials provided with the distribution.
15 1.119.10.2 tsutsui * 3. All advertising materials mentioning features or use of this software
16 1.119.10.2 tsutsui * must display the following acknowledgement:
17 1.119.10.2 tsutsui * This product includes software developed for the
18 1.119.10.2 tsutsui * NetBSD Project. See http://www.NetBSD.org/ for
19 1.119.10.2 tsutsui * information about NetBSD.
20 1.119.10.2 tsutsui * 4. The name of the author may not be used to endorse or promote products
21 1.119.10.2 tsutsui * derived from this software without specific prior written permission.
22 1.119.10.2 tsutsui *
23 1.119.10.2 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 1.119.10.2 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 1.119.10.2 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.119.10.2 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 1.119.10.2 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 1.119.10.2 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 1.119.10.2 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 1.119.10.2 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 1.119.10.2 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 1.119.10.2 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 1.119.10.2 tsutsui *
34 1.119.10.2 tsutsui * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
35 1.119.10.2 tsutsui */
36 1.119.10.2 tsutsui
37 1.119.10.2 tsutsui /*
38 1.119.10.2 tsutsui * Copyright (c) 1992, 1993
39 1.119.10.2 tsutsui * The Regents of the University of California. All rights reserved.
40 1.119.10.2 tsutsui *
41 1.119.10.2 tsutsui * This software was developed by the Computer Systems Engineering group
42 1.119.10.2 tsutsui * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43 1.119.10.2 tsutsui * contributed to Berkeley.
44 1.119.10.2 tsutsui *
45 1.119.10.2 tsutsui * All advertising materials mentioning features or use of this software
46 1.119.10.2 tsutsui * must display the following acknowledgement:
47 1.119.10.2 tsutsui * This product includes software developed by the University of
48 1.119.10.2 tsutsui * California, Lawrence Berkeley Laboratories.
49 1.119.10.2 tsutsui *
50 1.119.10.2 tsutsui * Redistribution and use in source and binary forms, with or without
51 1.119.10.2 tsutsui * modification, are permitted provided that the following conditions
52 1.119.10.2 tsutsui * are met:
53 1.119.10.2 tsutsui * 1. Redistributions of source code must retain the above copyright
54 1.119.10.2 tsutsui * notice, this list of conditions and the following disclaimer.
55 1.119.10.2 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
56 1.119.10.2 tsutsui * notice, this list of conditions and the following disclaimer in the
57 1.119.10.2 tsutsui * documentation and/or other materials provided with the distribution.
58 1.119.10.2 tsutsui * 3. Neither the name of the University nor the names of its contributors
59 1.119.10.2 tsutsui * may be used to endorse or promote products derived from this software
60 1.119.10.2 tsutsui * without specific prior written permission.
61 1.119.10.2 tsutsui *
62 1.119.10.2 tsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 1.119.10.2 tsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 1.119.10.2 tsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 1.119.10.2 tsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 1.119.10.2 tsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 1.119.10.2 tsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 1.119.10.2 tsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 1.119.10.2 tsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 1.119.10.2 tsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 1.119.10.2 tsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 1.119.10.2 tsutsui * SUCH DAMAGE.
73 1.119.10.2 tsutsui *
74 1.119.10.2 tsutsui * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
75 1.119.10.2 tsutsui *
76 1.119.10.2 tsutsui * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
77 1.119.10.2 tsutsui */
78 1.119.10.2 tsutsui
79 1.119.10.2 tsutsui #include <sys/cdefs.h>
80 1.119.10.2 tsutsui __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.119.10.2 2007/07/20 22:15:48 tsutsui Exp $");
81 1.119.10.2 tsutsui
82 1.119.10.2 tsutsui #include "opt_ddb.h"
83 1.119.10.2 tsutsui
84 1.119.10.2 tsutsui #include <sys/param.h>
85 1.119.10.2 tsutsui #include <sys/device.h>
86 1.119.10.2 tsutsui #include <sys/disklabel.h>
87 1.119.10.2 tsutsui #include <sys/conf.h>
88 1.119.10.2 tsutsui #include <sys/kauth.h>
89 1.119.10.2 tsutsui #include <sys/malloc.h>
90 1.119.10.2 tsutsui #include <sys/systm.h>
91 1.119.10.2 tsutsui #include <sys/kernel.h>
92 1.119.10.2 tsutsui #include <sys/errno.h>
93 1.119.10.2 tsutsui #include <sys/proc.h>
94 1.119.10.2 tsutsui #include <sys/reboot.h>
95 1.119.10.2 tsutsui
96 1.119.10.2 tsutsui #include <sys/buf.h>
97 1.119.10.2 tsutsui #include <sys/dirent.h>
98 1.119.10.2 tsutsui #include <sys/lock.h>
99 1.119.10.2 tsutsui #include <sys/vnode.h>
100 1.119.10.2 tsutsui #include <sys/mount.h>
101 1.119.10.2 tsutsui #include <sys/namei.h>
102 1.119.10.2 tsutsui #include <sys/unistd.h>
103 1.119.10.2 tsutsui #include <sys/fcntl.h>
104 1.119.10.2 tsutsui #include <sys/lockf.h>
105 1.119.10.2 tsutsui
106 1.119.10.2 tsutsui #include <sys/disk.h>
107 1.119.10.2 tsutsui
108 1.119.10.2 tsutsui #include <machine/limits.h>
109 1.119.10.2 tsutsui
110 1.119.10.2 tsutsui #include "opt_userconf.h"
111 1.119.10.2 tsutsui #ifdef USERCONF
112 1.119.10.2 tsutsui #include <sys/userconf.h>
113 1.119.10.2 tsutsui #endif
114 1.119.10.2 tsutsui
115 1.119.10.2 tsutsui #ifdef __i386__
116 1.119.10.2 tsutsui #include "opt_splash.h"
117 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
118 1.119.10.2 tsutsui #include <dev/splash/splash.h>
119 1.119.10.2 tsutsui extern struct splash_progress *splash_progress_state;
120 1.119.10.2 tsutsui #endif
121 1.119.10.2 tsutsui #endif
122 1.119.10.2 tsutsui
123 1.119.10.2 tsutsui /*
124 1.119.10.2 tsutsui * Autoconfiguration subroutines.
125 1.119.10.2 tsutsui */
126 1.119.10.2 tsutsui
127 1.119.10.2 tsutsui /*
128 1.119.10.2 tsutsui * ioconf.c exports exactly two names: cfdata and cfroots. All system
129 1.119.10.2 tsutsui * devices and drivers are found via these tables.
130 1.119.10.2 tsutsui */
131 1.119.10.2 tsutsui extern struct cfdata cfdata[];
132 1.119.10.2 tsutsui extern const short cfroots[];
133 1.119.10.2 tsutsui
134 1.119.10.2 tsutsui /*
135 1.119.10.2 tsutsui * List of all cfdriver structures. We use this to detect duplicates
136 1.119.10.2 tsutsui * when other cfdrivers are loaded.
137 1.119.10.2 tsutsui */
138 1.119.10.2 tsutsui struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
139 1.119.10.2 tsutsui extern struct cfdriver * const cfdriver_list_initial[];
140 1.119.10.2 tsutsui
141 1.119.10.2 tsutsui /*
142 1.119.10.2 tsutsui * Initial list of cfattach's.
143 1.119.10.2 tsutsui */
144 1.119.10.2 tsutsui extern const struct cfattachinit cfattachinit[];
145 1.119.10.2 tsutsui
146 1.119.10.2 tsutsui /*
147 1.119.10.2 tsutsui * List of cfdata tables. We always have one such list -- the one
148 1.119.10.2 tsutsui * built statically when the kernel was configured.
149 1.119.10.2 tsutsui */
150 1.119.10.2 tsutsui struct cftablelist allcftables;
151 1.119.10.2 tsutsui static struct cftable initcftable;
152 1.119.10.2 tsutsui
153 1.119.10.2 tsutsui #define ROOT ((device_t)NULL)
154 1.119.10.2 tsutsui
155 1.119.10.2 tsutsui struct matchinfo {
156 1.119.10.2 tsutsui cfsubmatch_t fn;
157 1.119.10.2 tsutsui struct device *parent;
158 1.119.10.2 tsutsui const int *locs;
159 1.119.10.2 tsutsui void *aux;
160 1.119.10.2 tsutsui struct cfdata *match;
161 1.119.10.2 tsutsui int pri;
162 1.119.10.2 tsutsui };
163 1.119.10.2 tsutsui
164 1.119.10.2 tsutsui static char *number(char *, int);
165 1.119.10.2 tsutsui static void mapply(struct matchinfo *, cfdata_t);
166 1.119.10.2 tsutsui static device_t config_devalloc(const device_t, const cfdata_t, const int *);
167 1.119.10.2 tsutsui static void config_devdealloc(device_t);
168 1.119.10.2 tsutsui static void config_makeroom(int, struct cfdriver *);
169 1.119.10.2 tsutsui static void config_devlink(device_t);
170 1.119.10.2 tsutsui static void config_devunlink(device_t);
171 1.119.10.2 tsutsui
172 1.119.10.2 tsutsui struct deferred_config {
173 1.119.10.2 tsutsui TAILQ_ENTRY(deferred_config) dc_queue;
174 1.119.10.2 tsutsui device_t dc_dev;
175 1.119.10.2 tsutsui void (*dc_func)(device_t);
176 1.119.10.2 tsutsui };
177 1.119.10.2 tsutsui
178 1.119.10.2 tsutsui TAILQ_HEAD(deferred_config_head, deferred_config);
179 1.119.10.2 tsutsui
180 1.119.10.2 tsutsui struct deferred_config_head deferred_config_queue;
181 1.119.10.2 tsutsui struct deferred_config_head interrupt_config_queue;
182 1.119.10.2 tsutsui
183 1.119.10.2 tsutsui static void config_process_deferred(struct deferred_config_head *, device_t);
184 1.119.10.2 tsutsui
185 1.119.10.2 tsutsui /* Hooks to finalize configuration once all real devices have been found. */
186 1.119.10.2 tsutsui struct finalize_hook {
187 1.119.10.2 tsutsui TAILQ_ENTRY(finalize_hook) f_list;
188 1.119.10.2 tsutsui int (*f_func)(device_t);
189 1.119.10.2 tsutsui device_t f_dev;
190 1.119.10.2 tsutsui };
191 1.119.10.2 tsutsui static TAILQ_HEAD(, finalize_hook) config_finalize_list;
192 1.119.10.2 tsutsui static int config_finalize_done;
193 1.119.10.2 tsutsui
194 1.119.10.2 tsutsui /* list of all devices */
195 1.119.10.2 tsutsui struct devicelist alldevs;
196 1.119.10.2 tsutsui
197 1.119.10.2 tsutsui volatile int config_pending; /* semaphore for mountroot */
198 1.119.10.2 tsutsui
199 1.119.10.2 tsutsui #define STREQ(s1, s2) \
200 1.119.10.2 tsutsui (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
201 1.119.10.2 tsutsui
202 1.119.10.2 tsutsui static int config_initialized; /* config_init() has been called. */
203 1.119.10.2 tsutsui
204 1.119.10.2 tsutsui static int config_do_twiddle;
205 1.119.10.2 tsutsui
206 1.119.10.2 tsutsui struct vnode *
207 1.119.10.2 tsutsui opendisk(struct device *dv)
208 1.119.10.2 tsutsui {
209 1.119.10.2 tsutsui int bmajor, bminor;
210 1.119.10.2 tsutsui struct vnode *tmpvn;
211 1.119.10.2 tsutsui int error;
212 1.119.10.2 tsutsui dev_t dev;
213 1.119.10.2 tsutsui
214 1.119.10.2 tsutsui /*
215 1.119.10.2 tsutsui * Lookup major number for disk block device.
216 1.119.10.2 tsutsui */
217 1.119.10.2 tsutsui bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
218 1.119.10.2 tsutsui if (bmajor == -1)
219 1.119.10.2 tsutsui return NULL;
220 1.119.10.2 tsutsui
221 1.119.10.2 tsutsui bminor = minor(device_unit(dv));
222 1.119.10.2 tsutsui /*
223 1.119.10.2 tsutsui * Fake a temporary vnode for the disk, open it, and read
224 1.119.10.2 tsutsui * and hash the sectors.
225 1.119.10.2 tsutsui */
226 1.119.10.2 tsutsui dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
227 1.119.10.2 tsutsui MAKEDISKDEV(bmajor, bminor, RAW_PART);
228 1.119.10.2 tsutsui if (bdevvp(dev, &tmpvn))
229 1.119.10.2 tsutsui panic("%s: can't alloc vnode for %s", __func__,
230 1.119.10.2 tsutsui device_xname(dv));
231 1.119.10.2 tsutsui error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
232 1.119.10.2 tsutsui if (error) {
233 1.119.10.2 tsutsui #ifndef DEBUG
234 1.119.10.2 tsutsui /*
235 1.119.10.2 tsutsui * Ignore errors caused by missing device, partition,
236 1.119.10.2 tsutsui * or medium.
237 1.119.10.2 tsutsui */
238 1.119.10.2 tsutsui if (error != ENXIO && error != ENODEV)
239 1.119.10.2 tsutsui #endif
240 1.119.10.2 tsutsui printf("%s: can't open dev %s (%d)\n",
241 1.119.10.2 tsutsui __func__, device_xname(dv), error);
242 1.119.10.2 tsutsui vput(tmpvn);
243 1.119.10.2 tsutsui return NULL;
244 1.119.10.2 tsutsui }
245 1.119.10.2 tsutsui
246 1.119.10.2 tsutsui return tmpvn;
247 1.119.10.2 tsutsui }
248 1.119.10.2 tsutsui
249 1.119.10.2 tsutsui int
250 1.119.10.2 tsutsui config_handle_wedges(struct device *dv, int par)
251 1.119.10.2 tsutsui {
252 1.119.10.2 tsutsui struct dkwedge_list wl;
253 1.119.10.2 tsutsui struct dkwedge_info *wi;
254 1.119.10.2 tsutsui struct vnode *vn;
255 1.119.10.2 tsutsui char diskname[16];
256 1.119.10.2 tsutsui int i, error;
257 1.119.10.2 tsutsui
258 1.119.10.2 tsutsui if ((vn = opendisk(dv)) == NULL)
259 1.119.10.2 tsutsui return -1;
260 1.119.10.2 tsutsui
261 1.119.10.2 tsutsui wl.dkwl_bufsize = sizeof(*wi) * 16;
262 1.119.10.2 tsutsui wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
263 1.119.10.2 tsutsui
264 1.119.10.2 tsutsui error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED, 0);
265 1.119.10.2 tsutsui VOP_CLOSE(vn, FREAD, NOCRED, 0);
266 1.119.10.2 tsutsui vput(vn);
267 1.119.10.2 tsutsui if (error) {
268 1.119.10.2 tsutsui #ifdef DEBUG_WEDGE
269 1.119.10.2 tsutsui printf("%s: List wedges returned %d\n",
270 1.119.10.2 tsutsui device_xname(dv), error);
271 1.119.10.2 tsutsui #endif
272 1.119.10.2 tsutsui free(wi, M_TEMP);
273 1.119.10.2 tsutsui return -1;
274 1.119.10.2 tsutsui }
275 1.119.10.2 tsutsui
276 1.119.10.2 tsutsui #ifdef DEBUG_WEDGE
277 1.119.10.2 tsutsui printf("%s: Returned %u(%u) wedges\n", device_xname(dv),
278 1.119.10.2 tsutsui wl.dkwl_nwedges, wl.dkwl_ncopied);
279 1.119.10.2 tsutsui #endif
280 1.119.10.2 tsutsui snprintf(diskname, sizeof(diskname), "%s%c", device_xname(dv),
281 1.119.10.2 tsutsui par + 'a');
282 1.119.10.2 tsutsui
283 1.119.10.2 tsutsui for (i = 0; i < wl.dkwl_ncopied; i++) {
284 1.119.10.2 tsutsui #ifdef DEBUG_WEDGE
285 1.119.10.2 tsutsui printf("%s: Looking for %s in %s\n",
286 1.119.10.2 tsutsui device_xname(dv), diskname, wi[i].dkw_wname);
287 1.119.10.2 tsutsui #endif
288 1.119.10.2 tsutsui if (strcmp(wi[i].dkw_wname, diskname) == 0)
289 1.119.10.2 tsutsui break;
290 1.119.10.2 tsutsui }
291 1.119.10.2 tsutsui
292 1.119.10.2 tsutsui if (i == wl.dkwl_ncopied) {
293 1.119.10.2 tsutsui #ifdef DEBUG_WEDGE
294 1.119.10.2 tsutsui printf("%s: Cannot find wedge with parent %s\n",
295 1.119.10.2 tsutsui device_xname(dv), diskname);
296 1.119.10.2 tsutsui #endif
297 1.119.10.2 tsutsui free(wi, M_TEMP);
298 1.119.10.2 tsutsui return -1;
299 1.119.10.2 tsutsui }
300 1.119.10.2 tsutsui
301 1.119.10.2 tsutsui #ifdef DEBUG_WEDGE
302 1.119.10.2 tsutsui printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
303 1.119.10.2 tsutsui device_xname(dv), wi[i].dkw_devname, wi[i].dkw_wname,
304 1.119.10.2 tsutsui (unsigned long long)wi[i].dkw_offset,
305 1.119.10.2 tsutsui (unsigned long long)wi[i].dkw_size);
306 1.119.10.2 tsutsui #endif
307 1.119.10.2 tsutsui dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
308 1.119.10.2 tsutsui free(wi, M_TEMP);
309 1.119.10.2 tsutsui return 0;
310 1.119.10.2 tsutsui }
311 1.119.10.2 tsutsui
312 1.119.10.2 tsutsui /*
313 1.119.10.2 tsutsui * Initialize the autoconfiguration data structures. Normally this
314 1.119.10.2 tsutsui * is done by configure(), but some platforms need to do this very
315 1.119.10.2 tsutsui * early (to e.g. initialize the console).
316 1.119.10.2 tsutsui */
317 1.119.10.2 tsutsui void
318 1.119.10.2 tsutsui config_init(void)
319 1.119.10.2 tsutsui {
320 1.119.10.2 tsutsui const struct cfattachinit *cfai;
321 1.119.10.2 tsutsui int i, j;
322 1.119.10.2 tsutsui
323 1.119.10.2 tsutsui if (config_initialized)
324 1.119.10.2 tsutsui return;
325 1.119.10.2 tsutsui
326 1.119.10.2 tsutsui /* allcfdrivers is statically initialized. */
327 1.119.10.2 tsutsui for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
328 1.119.10.2 tsutsui if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
329 1.119.10.2 tsutsui panic("configure: duplicate `%s' drivers",
330 1.119.10.2 tsutsui cfdriver_list_initial[i]->cd_name);
331 1.119.10.2 tsutsui }
332 1.119.10.2 tsutsui
333 1.119.10.2 tsutsui for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
334 1.119.10.2 tsutsui for (j = 0; cfai->cfai_list[j] != NULL; j++) {
335 1.119.10.2 tsutsui if (config_cfattach_attach(cfai->cfai_name,
336 1.119.10.2 tsutsui cfai->cfai_list[j]) != 0)
337 1.119.10.2 tsutsui panic("configure: duplicate `%s' attachment "
338 1.119.10.2 tsutsui "of `%s' driver",
339 1.119.10.2 tsutsui cfai->cfai_list[j]->ca_name,
340 1.119.10.2 tsutsui cfai->cfai_name);
341 1.119.10.2 tsutsui }
342 1.119.10.2 tsutsui }
343 1.119.10.2 tsutsui
344 1.119.10.2 tsutsui TAILQ_INIT(&allcftables);
345 1.119.10.2 tsutsui initcftable.ct_cfdata = cfdata;
346 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
347 1.119.10.2 tsutsui
348 1.119.10.2 tsutsui TAILQ_INIT(&deferred_config_queue);
349 1.119.10.2 tsutsui TAILQ_INIT(&interrupt_config_queue);
350 1.119.10.2 tsutsui TAILQ_INIT(&config_finalize_list);
351 1.119.10.2 tsutsui TAILQ_INIT(&alldevs);
352 1.119.10.2 tsutsui
353 1.119.10.2 tsutsui config_initialized = 1;
354 1.119.10.2 tsutsui }
355 1.119.10.2 tsutsui
356 1.119.10.2 tsutsui /*
357 1.119.10.2 tsutsui * Configure the system's hardware.
358 1.119.10.2 tsutsui */
359 1.119.10.2 tsutsui void
360 1.119.10.2 tsutsui configure(void)
361 1.119.10.2 tsutsui {
362 1.119.10.2 tsutsui int errcnt;
363 1.119.10.2 tsutsui
364 1.119.10.2 tsutsui /* Initialize data structures. */
365 1.119.10.2 tsutsui config_init();
366 1.119.10.2 tsutsui
367 1.119.10.2 tsutsui #ifdef USERCONF
368 1.119.10.2 tsutsui if (boothowto & RB_USERCONF)
369 1.119.10.2 tsutsui user_config();
370 1.119.10.2 tsutsui #endif
371 1.119.10.2 tsutsui
372 1.119.10.2 tsutsui if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
373 1.119.10.2 tsutsui config_do_twiddle = 1;
374 1.119.10.2 tsutsui printf_nolog("Detecting hardware...");
375 1.119.10.2 tsutsui }
376 1.119.10.2 tsutsui
377 1.119.10.2 tsutsui /*
378 1.119.10.2 tsutsui * Do the machine-dependent portion of autoconfiguration. This
379 1.119.10.2 tsutsui * sets the configuration machinery here in motion by "finding"
380 1.119.10.2 tsutsui * the root bus. When this function returns, we expect interrupts
381 1.119.10.2 tsutsui * to be enabled.
382 1.119.10.2 tsutsui */
383 1.119.10.2 tsutsui cpu_configure();
384 1.119.10.2 tsutsui
385 1.119.10.2 tsutsui /* Initialize callouts, part 2. */
386 1.119.10.2 tsutsui callout_startup2();
387 1.119.10.2 tsutsui
388 1.119.10.2 tsutsui /*
389 1.119.10.2 tsutsui * Now that we've found all the hardware, start the real time
390 1.119.10.2 tsutsui * and statistics clocks.
391 1.119.10.2 tsutsui */
392 1.119.10.2 tsutsui initclocks();
393 1.119.10.2 tsutsui
394 1.119.10.2 tsutsui cold = 0; /* clocks are running, we're warm now! */
395 1.119.10.2 tsutsui
396 1.119.10.2 tsutsui /*
397 1.119.10.2 tsutsui * Now callback to finish configuration for devices which want
398 1.119.10.2 tsutsui * to do this once interrupts are enabled.
399 1.119.10.2 tsutsui */
400 1.119.10.2 tsutsui config_process_deferred(&interrupt_config_queue, NULL);
401 1.119.10.2 tsutsui
402 1.119.10.2 tsutsui errcnt = aprint_get_error_count();
403 1.119.10.2 tsutsui if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
404 1.119.10.2 tsutsui (boothowto & AB_VERBOSE) == 0) {
405 1.119.10.2 tsutsui if (config_do_twiddle) {
406 1.119.10.2 tsutsui config_do_twiddle = 0;
407 1.119.10.2 tsutsui printf_nolog("done.\n");
408 1.119.10.2 tsutsui }
409 1.119.10.2 tsutsui if (errcnt != 0) {
410 1.119.10.2 tsutsui printf("WARNING: %d error%s while detecting hardware; "
411 1.119.10.2 tsutsui "check system log.\n", errcnt,
412 1.119.10.2 tsutsui errcnt == 1 ? "" : "s");
413 1.119.10.2 tsutsui }
414 1.119.10.2 tsutsui }
415 1.119.10.2 tsutsui }
416 1.119.10.2 tsutsui
417 1.119.10.2 tsutsui /*
418 1.119.10.2 tsutsui * Add a cfdriver to the system.
419 1.119.10.2 tsutsui */
420 1.119.10.2 tsutsui int
421 1.119.10.2 tsutsui config_cfdriver_attach(struct cfdriver *cd)
422 1.119.10.2 tsutsui {
423 1.119.10.2 tsutsui struct cfdriver *lcd;
424 1.119.10.2 tsutsui
425 1.119.10.2 tsutsui /* Make sure this driver isn't already in the system. */
426 1.119.10.2 tsutsui LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
427 1.119.10.2 tsutsui if (STREQ(lcd->cd_name, cd->cd_name))
428 1.119.10.2 tsutsui return (EEXIST);
429 1.119.10.2 tsutsui }
430 1.119.10.2 tsutsui
431 1.119.10.2 tsutsui LIST_INIT(&cd->cd_attach);
432 1.119.10.2 tsutsui LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
433 1.119.10.2 tsutsui
434 1.119.10.2 tsutsui return (0);
435 1.119.10.2 tsutsui }
436 1.119.10.2 tsutsui
437 1.119.10.2 tsutsui /*
438 1.119.10.2 tsutsui * Remove a cfdriver from the system.
439 1.119.10.2 tsutsui */
440 1.119.10.2 tsutsui int
441 1.119.10.2 tsutsui config_cfdriver_detach(struct cfdriver *cd)
442 1.119.10.2 tsutsui {
443 1.119.10.2 tsutsui int i;
444 1.119.10.2 tsutsui
445 1.119.10.2 tsutsui /* Make sure there are no active instances. */
446 1.119.10.2 tsutsui for (i = 0; i < cd->cd_ndevs; i++) {
447 1.119.10.2 tsutsui if (cd->cd_devs[i] != NULL)
448 1.119.10.2 tsutsui return (EBUSY);
449 1.119.10.2 tsutsui }
450 1.119.10.2 tsutsui
451 1.119.10.2 tsutsui /* ...and no attachments loaded. */
452 1.119.10.2 tsutsui if (LIST_EMPTY(&cd->cd_attach) == 0)
453 1.119.10.2 tsutsui return (EBUSY);
454 1.119.10.2 tsutsui
455 1.119.10.2 tsutsui LIST_REMOVE(cd, cd_list);
456 1.119.10.2 tsutsui
457 1.119.10.2 tsutsui KASSERT(cd->cd_devs == NULL);
458 1.119.10.2 tsutsui
459 1.119.10.2 tsutsui return (0);
460 1.119.10.2 tsutsui }
461 1.119.10.2 tsutsui
462 1.119.10.2 tsutsui /*
463 1.119.10.2 tsutsui * Look up a cfdriver by name.
464 1.119.10.2 tsutsui */
465 1.119.10.2 tsutsui struct cfdriver *
466 1.119.10.2 tsutsui config_cfdriver_lookup(const char *name)
467 1.119.10.2 tsutsui {
468 1.119.10.2 tsutsui struct cfdriver *cd;
469 1.119.10.2 tsutsui
470 1.119.10.2 tsutsui LIST_FOREACH(cd, &allcfdrivers, cd_list) {
471 1.119.10.2 tsutsui if (STREQ(cd->cd_name, name))
472 1.119.10.2 tsutsui return (cd);
473 1.119.10.2 tsutsui }
474 1.119.10.2 tsutsui
475 1.119.10.2 tsutsui return (NULL);
476 1.119.10.2 tsutsui }
477 1.119.10.2 tsutsui
478 1.119.10.2 tsutsui /*
479 1.119.10.2 tsutsui * Add a cfattach to the specified driver.
480 1.119.10.2 tsutsui */
481 1.119.10.2 tsutsui int
482 1.119.10.2 tsutsui config_cfattach_attach(const char *driver, struct cfattach *ca)
483 1.119.10.2 tsutsui {
484 1.119.10.2 tsutsui struct cfattach *lca;
485 1.119.10.2 tsutsui struct cfdriver *cd;
486 1.119.10.2 tsutsui
487 1.119.10.2 tsutsui cd = config_cfdriver_lookup(driver);
488 1.119.10.2 tsutsui if (cd == NULL)
489 1.119.10.2 tsutsui return (ESRCH);
490 1.119.10.2 tsutsui
491 1.119.10.2 tsutsui /* Make sure this attachment isn't already on this driver. */
492 1.119.10.2 tsutsui LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
493 1.119.10.2 tsutsui if (STREQ(lca->ca_name, ca->ca_name))
494 1.119.10.2 tsutsui return (EEXIST);
495 1.119.10.2 tsutsui }
496 1.119.10.2 tsutsui
497 1.119.10.2 tsutsui LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
498 1.119.10.2 tsutsui
499 1.119.10.2 tsutsui return (0);
500 1.119.10.2 tsutsui }
501 1.119.10.2 tsutsui
502 1.119.10.2 tsutsui /*
503 1.119.10.2 tsutsui * Remove a cfattach from the specified driver.
504 1.119.10.2 tsutsui */
505 1.119.10.2 tsutsui int
506 1.119.10.2 tsutsui config_cfattach_detach(const char *driver, struct cfattach *ca)
507 1.119.10.2 tsutsui {
508 1.119.10.2 tsutsui struct cfdriver *cd;
509 1.119.10.2 tsutsui device_t dev;
510 1.119.10.2 tsutsui int i;
511 1.119.10.2 tsutsui
512 1.119.10.2 tsutsui cd = config_cfdriver_lookup(driver);
513 1.119.10.2 tsutsui if (cd == NULL)
514 1.119.10.2 tsutsui return (ESRCH);
515 1.119.10.2 tsutsui
516 1.119.10.2 tsutsui /* Make sure there are no active instances. */
517 1.119.10.2 tsutsui for (i = 0; i < cd->cd_ndevs; i++) {
518 1.119.10.2 tsutsui if ((dev = cd->cd_devs[i]) == NULL)
519 1.119.10.2 tsutsui continue;
520 1.119.10.2 tsutsui if (dev->dv_cfattach == ca)
521 1.119.10.2 tsutsui return (EBUSY);
522 1.119.10.2 tsutsui }
523 1.119.10.2 tsutsui
524 1.119.10.2 tsutsui LIST_REMOVE(ca, ca_list);
525 1.119.10.2 tsutsui
526 1.119.10.2 tsutsui return (0);
527 1.119.10.2 tsutsui }
528 1.119.10.2 tsutsui
529 1.119.10.2 tsutsui /*
530 1.119.10.2 tsutsui * Look up a cfattach by name.
531 1.119.10.2 tsutsui */
532 1.119.10.2 tsutsui static struct cfattach *
533 1.119.10.2 tsutsui config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
534 1.119.10.2 tsutsui {
535 1.119.10.2 tsutsui struct cfattach *ca;
536 1.119.10.2 tsutsui
537 1.119.10.2 tsutsui LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
538 1.119.10.2 tsutsui if (STREQ(ca->ca_name, atname))
539 1.119.10.2 tsutsui return (ca);
540 1.119.10.2 tsutsui }
541 1.119.10.2 tsutsui
542 1.119.10.2 tsutsui return (NULL);
543 1.119.10.2 tsutsui }
544 1.119.10.2 tsutsui
545 1.119.10.2 tsutsui /*
546 1.119.10.2 tsutsui * Look up a cfattach by driver/attachment name.
547 1.119.10.2 tsutsui */
548 1.119.10.2 tsutsui struct cfattach *
549 1.119.10.2 tsutsui config_cfattach_lookup(const char *name, const char *atname)
550 1.119.10.2 tsutsui {
551 1.119.10.2 tsutsui struct cfdriver *cd;
552 1.119.10.2 tsutsui
553 1.119.10.2 tsutsui cd = config_cfdriver_lookup(name);
554 1.119.10.2 tsutsui if (cd == NULL)
555 1.119.10.2 tsutsui return (NULL);
556 1.119.10.2 tsutsui
557 1.119.10.2 tsutsui return (config_cfattach_lookup_cd(cd, atname));
558 1.119.10.2 tsutsui }
559 1.119.10.2 tsutsui
560 1.119.10.2 tsutsui /*
561 1.119.10.2 tsutsui * Apply the matching function and choose the best. This is used
562 1.119.10.2 tsutsui * a few times and we want to keep the code small.
563 1.119.10.2 tsutsui */
564 1.119.10.2 tsutsui static void
565 1.119.10.2 tsutsui mapply(struct matchinfo *m, cfdata_t cf)
566 1.119.10.2 tsutsui {
567 1.119.10.2 tsutsui int pri;
568 1.119.10.2 tsutsui
569 1.119.10.2 tsutsui if (m->fn != NULL) {
570 1.119.10.2 tsutsui pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
571 1.119.10.2 tsutsui } else {
572 1.119.10.2 tsutsui pri = config_match(m->parent, cf, m->aux);
573 1.119.10.2 tsutsui }
574 1.119.10.2 tsutsui if (pri > m->pri) {
575 1.119.10.2 tsutsui m->match = cf;
576 1.119.10.2 tsutsui m->pri = pri;
577 1.119.10.2 tsutsui }
578 1.119.10.2 tsutsui }
579 1.119.10.2 tsutsui
580 1.119.10.2 tsutsui int
581 1.119.10.2 tsutsui config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
582 1.119.10.2 tsutsui {
583 1.119.10.2 tsutsui const struct cfiattrdata *ci;
584 1.119.10.2 tsutsui const struct cflocdesc *cl;
585 1.119.10.2 tsutsui int nlocs, i;
586 1.119.10.2 tsutsui
587 1.119.10.2 tsutsui ci = cfiattr_lookup(cf->cf_pspec->cfp_iattr, parent->dv_cfdriver);
588 1.119.10.2 tsutsui KASSERT(ci);
589 1.119.10.2 tsutsui nlocs = ci->ci_loclen;
590 1.119.10.2 tsutsui for (i = 0; i < nlocs; i++) {
591 1.119.10.2 tsutsui cl = &ci->ci_locdesc[i];
592 1.119.10.2 tsutsui /* !cld_defaultstr means no default value */
593 1.119.10.2 tsutsui if ((!(cl->cld_defaultstr)
594 1.119.10.2 tsutsui || (cf->cf_loc[i] != cl->cld_default))
595 1.119.10.2 tsutsui && cf->cf_loc[i] != locs[i])
596 1.119.10.2 tsutsui return (0);
597 1.119.10.2 tsutsui }
598 1.119.10.2 tsutsui
599 1.119.10.2 tsutsui return (config_match(parent, cf, aux));
600 1.119.10.2 tsutsui }
601 1.119.10.2 tsutsui
602 1.119.10.2 tsutsui /*
603 1.119.10.2 tsutsui * Helper function: check whether the driver supports the interface attribute
604 1.119.10.2 tsutsui * and return its descriptor structure.
605 1.119.10.2 tsutsui */
606 1.119.10.2 tsutsui static const struct cfiattrdata *
607 1.119.10.2 tsutsui cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
608 1.119.10.2 tsutsui {
609 1.119.10.2 tsutsui const struct cfiattrdata * const *cpp;
610 1.119.10.2 tsutsui
611 1.119.10.2 tsutsui if (cd->cd_attrs == NULL)
612 1.119.10.2 tsutsui return (0);
613 1.119.10.2 tsutsui
614 1.119.10.2 tsutsui for (cpp = cd->cd_attrs; *cpp; cpp++) {
615 1.119.10.2 tsutsui if (STREQ((*cpp)->ci_name, ia)) {
616 1.119.10.2 tsutsui /* Match. */
617 1.119.10.2 tsutsui return (*cpp);
618 1.119.10.2 tsutsui }
619 1.119.10.2 tsutsui }
620 1.119.10.2 tsutsui return (0);
621 1.119.10.2 tsutsui }
622 1.119.10.2 tsutsui
623 1.119.10.2 tsutsui /*
624 1.119.10.2 tsutsui * Lookup an interface attribute description by name.
625 1.119.10.2 tsutsui * If the driver is given, consider only its supported attributes.
626 1.119.10.2 tsutsui */
627 1.119.10.2 tsutsui const struct cfiattrdata *
628 1.119.10.2 tsutsui cfiattr_lookup(const char *name, const struct cfdriver *cd)
629 1.119.10.2 tsutsui {
630 1.119.10.2 tsutsui const struct cfdriver *d;
631 1.119.10.2 tsutsui const struct cfiattrdata *ia;
632 1.119.10.2 tsutsui
633 1.119.10.2 tsutsui if (cd)
634 1.119.10.2 tsutsui return (cfdriver_get_iattr(cd, name));
635 1.119.10.2 tsutsui
636 1.119.10.2 tsutsui LIST_FOREACH(d, &allcfdrivers, cd_list) {
637 1.119.10.2 tsutsui ia = cfdriver_get_iattr(d, name);
638 1.119.10.2 tsutsui if (ia)
639 1.119.10.2 tsutsui return (ia);
640 1.119.10.2 tsutsui }
641 1.119.10.2 tsutsui return (0);
642 1.119.10.2 tsutsui }
643 1.119.10.2 tsutsui
644 1.119.10.2 tsutsui /*
645 1.119.10.2 tsutsui * Determine if `parent' is a potential parent for a device spec based
646 1.119.10.2 tsutsui * on `cfp'.
647 1.119.10.2 tsutsui */
648 1.119.10.2 tsutsui static int
649 1.119.10.2 tsutsui cfparent_match(const device_t parent, const struct cfparent *cfp)
650 1.119.10.2 tsutsui {
651 1.119.10.2 tsutsui struct cfdriver *pcd;
652 1.119.10.2 tsutsui
653 1.119.10.2 tsutsui /* We don't match root nodes here. */
654 1.119.10.2 tsutsui if (cfp == NULL)
655 1.119.10.2 tsutsui return (0);
656 1.119.10.2 tsutsui
657 1.119.10.2 tsutsui pcd = parent->dv_cfdriver;
658 1.119.10.2 tsutsui KASSERT(pcd != NULL);
659 1.119.10.2 tsutsui
660 1.119.10.2 tsutsui /*
661 1.119.10.2 tsutsui * First, ensure this parent has the correct interface
662 1.119.10.2 tsutsui * attribute.
663 1.119.10.2 tsutsui */
664 1.119.10.2 tsutsui if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
665 1.119.10.2 tsutsui return (0);
666 1.119.10.2 tsutsui
667 1.119.10.2 tsutsui /*
668 1.119.10.2 tsutsui * If no specific parent device instance was specified (i.e.
669 1.119.10.2 tsutsui * we're attaching to the attribute only), we're done!
670 1.119.10.2 tsutsui */
671 1.119.10.2 tsutsui if (cfp->cfp_parent == NULL)
672 1.119.10.2 tsutsui return (1);
673 1.119.10.2 tsutsui
674 1.119.10.2 tsutsui /*
675 1.119.10.2 tsutsui * Check the parent device's name.
676 1.119.10.2 tsutsui */
677 1.119.10.2 tsutsui if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
678 1.119.10.2 tsutsui return (0); /* not the same parent */
679 1.119.10.2 tsutsui
680 1.119.10.2 tsutsui /*
681 1.119.10.2 tsutsui * Make sure the unit number matches.
682 1.119.10.2 tsutsui */
683 1.119.10.2 tsutsui if (cfp->cfp_unit == DVUNIT_ANY || /* wildcard */
684 1.119.10.2 tsutsui cfp->cfp_unit == parent->dv_unit)
685 1.119.10.2 tsutsui return (1);
686 1.119.10.2 tsutsui
687 1.119.10.2 tsutsui /* Unit numbers don't match. */
688 1.119.10.2 tsutsui return (0);
689 1.119.10.2 tsutsui }
690 1.119.10.2 tsutsui
691 1.119.10.2 tsutsui /*
692 1.119.10.2 tsutsui * Helper for config_cfdata_attach(): check all devices whether it could be
693 1.119.10.2 tsutsui * parent any attachment in the config data table passed, and rescan.
694 1.119.10.2 tsutsui */
695 1.119.10.2 tsutsui static void
696 1.119.10.2 tsutsui rescan_with_cfdata(const struct cfdata *cf)
697 1.119.10.2 tsutsui {
698 1.119.10.2 tsutsui device_t d;
699 1.119.10.2 tsutsui const struct cfdata *cf1;
700 1.119.10.2 tsutsui
701 1.119.10.2 tsutsui /*
702 1.119.10.2 tsutsui * "alldevs" is likely longer than an LKM's cfdata, so make it
703 1.119.10.2 tsutsui * the outer loop.
704 1.119.10.2 tsutsui */
705 1.119.10.2 tsutsui TAILQ_FOREACH(d, &alldevs, dv_list) {
706 1.119.10.2 tsutsui
707 1.119.10.2 tsutsui if (!(d->dv_cfattach->ca_rescan))
708 1.119.10.2 tsutsui continue;
709 1.119.10.2 tsutsui
710 1.119.10.2 tsutsui for (cf1 = cf; cf1->cf_name; cf1++) {
711 1.119.10.2 tsutsui
712 1.119.10.2 tsutsui if (!cfparent_match(d, cf1->cf_pspec))
713 1.119.10.2 tsutsui continue;
714 1.119.10.2 tsutsui
715 1.119.10.2 tsutsui (*d->dv_cfattach->ca_rescan)(d,
716 1.119.10.2 tsutsui cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
717 1.119.10.2 tsutsui }
718 1.119.10.2 tsutsui }
719 1.119.10.2 tsutsui }
720 1.119.10.2 tsutsui
721 1.119.10.2 tsutsui /*
722 1.119.10.2 tsutsui * Attach a supplemental config data table and rescan potential
723 1.119.10.2 tsutsui * parent devices if required.
724 1.119.10.2 tsutsui */
725 1.119.10.2 tsutsui int
726 1.119.10.2 tsutsui config_cfdata_attach(cfdata_t cf, int scannow)
727 1.119.10.2 tsutsui {
728 1.119.10.2 tsutsui struct cftable *ct;
729 1.119.10.2 tsutsui
730 1.119.10.2 tsutsui ct = malloc(sizeof(struct cftable), M_DEVBUF, M_WAITOK);
731 1.119.10.2 tsutsui ct->ct_cfdata = cf;
732 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
733 1.119.10.2 tsutsui
734 1.119.10.2 tsutsui if (scannow)
735 1.119.10.2 tsutsui rescan_with_cfdata(cf);
736 1.119.10.2 tsutsui
737 1.119.10.2 tsutsui return (0);
738 1.119.10.2 tsutsui }
739 1.119.10.2 tsutsui
740 1.119.10.2 tsutsui /*
741 1.119.10.2 tsutsui * Helper for config_cfdata_detach: check whether a device is
742 1.119.10.2 tsutsui * found through any attachment in the config data table.
743 1.119.10.2 tsutsui */
744 1.119.10.2 tsutsui static int
745 1.119.10.2 tsutsui dev_in_cfdata(const struct device *d, const struct cfdata *cf)
746 1.119.10.2 tsutsui {
747 1.119.10.2 tsutsui const struct cfdata *cf1;
748 1.119.10.2 tsutsui
749 1.119.10.2 tsutsui for (cf1 = cf; cf1->cf_name; cf1++)
750 1.119.10.2 tsutsui if (d->dv_cfdata == cf1)
751 1.119.10.2 tsutsui return (1);
752 1.119.10.2 tsutsui
753 1.119.10.2 tsutsui return (0);
754 1.119.10.2 tsutsui }
755 1.119.10.2 tsutsui
756 1.119.10.2 tsutsui /*
757 1.119.10.2 tsutsui * Detach a supplemental config data table. Detach all devices found
758 1.119.10.2 tsutsui * through that table (and thus keeping references to it) before.
759 1.119.10.2 tsutsui */
760 1.119.10.2 tsutsui int
761 1.119.10.2 tsutsui config_cfdata_detach(cfdata_t cf)
762 1.119.10.2 tsutsui {
763 1.119.10.2 tsutsui device_t d;
764 1.119.10.2 tsutsui int error;
765 1.119.10.2 tsutsui struct cftable *ct;
766 1.119.10.2 tsutsui
767 1.119.10.2 tsutsui again:
768 1.119.10.2 tsutsui TAILQ_FOREACH(d, &alldevs, dv_list) {
769 1.119.10.2 tsutsui if (dev_in_cfdata(d, cf)) {
770 1.119.10.2 tsutsui error = config_detach(d, 0);
771 1.119.10.2 tsutsui if (error) {
772 1.119.10.2 tsutsui aprint_error("%s: unable to detach instance\n",
773 1.119.10.2 tsutsui d->dv_xname);
774 1.119.10.2 tsutsui return (error);
775 1.119.10.2 tsutsui }
776 1.119.10.2 tsutsui goto again;
777 1.119.10.2 tsutsui }
778 1.119.10.2 tsutsui }
779 1.119.10.2 tsutsui
780 1.119.10.2 tsutsui TAILQ_FOREACH(ct, &allcftables, ct_list) {
781 1.119.10.2 tsutsui if (ct->ct_cfdata == cf) {
782 1.119.10.2 tsutsui TAILQ_REMOVE(&allcftables, ct, ct_list);
783 1.119.10.2 tsutsui free(ct, M_DEVBUF);
784 1.119.10.2 tsutsui return (0);
785 1.119.10.2 tsutsui }
786 1.119.10.2 tsutsui }
787 1.119.10.2 tsutsui
788 1.119.10.2 tsutsui /* not found -- shouldn't happen */
789 1.119.10.2 tsutsui return (EINVAL);
790 1.119.10.2 tsutsui }
791 1.119.10.2 tsutsui
792 1.119.10.2 tsutsui /*
793 1.119.10.2 tsutsui * Invoke the "match" routine for a cfdata entry on behalf of
794 1.119.10.2 tsutsui * an external caller, usually a "submatch" routine.
795 1.119.10.2 tsutsui */
796 1.119.10.2 tsutsui int
797 1.119.10.2 tsutsui config_match(device_t parent, cfdata_t cf, void *aux)
798 1.119.10.2 tsutsui {
799 1.119.10.2 tsutsui struct cfattach *ca;
800 1.119.10.2 tsutsui
801 1.119.10.2 tsutsui ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
802 1.119.10.2 tsutsui if (ca == NULL) {
803 1.119.10.2 tsutsui /* No attachment for this entry, oh well. */
804 1.119.10.2 tsutsui return (0);
805 1.119.10.2 tsutsui }
806 1.119.10.2 tsutsui
807 1.119.10.2 tsutsui return ((*ca->ca_match)(parent, cf, aux));
808 1.119.10.2 tsutsui }
809 1.119.10.2 tsutsui
810 1.119.10.2 tsutsui /*
811 1.119.10.2 tsutsui * Iterate over all potential children of some device, calling the given
812 1.119.10.2 tsutsui * function (default being the child's match function) for each one.
813 1.119.10.2 tsutsui * Nonzero returns are matches; the highest value returned is considered
814 1.119.10.2 tsutsui * the best match. Return the `found child' if we got a match, or NULL
815 1.119.10.2 tsutsui * otherwise. The `aux' pointer is simply passed on through.
816 1.119.10.2 tsutsui *
817 1.119.10.2 tsutsui * Note that this function is designed so that it can be used to apply
818 1.119.10.2 tsutsui * an arbitrary function to all potential children (its return value
819 1.119.10.2 tsutsui * can be ignored).
820 1.119.10.2 tsutsui */
821 1.119.10.2 tsutsui cfdata_t
822 1.119.10.2 tsutsui config_search_loc(cfsubmatch_t fn, device_t parent,
823 1.119.10.2 tsutsui const char *ifattr, const int *locs, void *aux)
824 1.119.10.2 tsutsui {
825 1.119.10.2 tsutsui struct cftable *ct;
826 1.119.10.2 tsutsui cfdata_t cf;
827 1.119.10.2 tsutsui struct matchinfo m;
828 1.119.10.2 tsutsui
829 1.119.10.2 tsutsui KASSERT(config_initialized);
830 1.119.10.2 tsutsui KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
831 1.119.10.2 tsutsui
832 1.119.10.2 tsutsui m.fn = fn;
833 1.119.10.2 tsutsui m.parent = parent;
834 1.119.10.2 tsutsui m.locs = locs;
835 1.119.10.2 tsutsui m.aux = aux;
836 1.119.10.2 tsutsui m.match = NULL;
837 1.119.10.2 tsutsui m.pri = 0;
838 1.119.10.2 tsutsui
839 1.119.10.2 tsutsui TAILQ_FOREACH(ct, &allcftables, ct_list) {
840 1.119.10.2 tsutsui for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
841 1.119.10.2 tsutsui
842 1.119.10.2 tsutsui /* We don't match root nodes here. */
843 1.119.10.2 tsutsui if (!cf->cf_pspec)
844 1.119.10.2 tsutsui continue;
845 1.119.10.2 tsutsui
846 1.119.10.2 tsutsui /*
847 1.119.10.2 tsutsui * Skip cf if no longer eligible, otherwise scan
848 1.119.10.2 tsutsui * through parents for one matching `parent', and
849 1.119.10.2 tsutsui * try match function.
850 1.119.10.2 tsutsui */
851 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_FOUND)
852 1.119.10.2 tsutsui continue;
853 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_DNOTFOUND ||
854 1.119.10.2 tsutsui cf->cf_fstate == FSTATE_DSTAR)
855 1.119.10.2 tsutsui continue;
856 1.119.10.2 tsutsui
857 1.119.10.2 tsutsui /*
858 1.119.10.2 tsutsui * If an interface attribute was specified,
859 1.119.10.2 tsutsui * consider only children which attach to
860 1.119.10.2 tsutsui * that attribute.
861 1.119.10.2 tsutsui */
862 1.119.10.2 tsutsui if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
863 1.119.10.2 tsutsui continue;
864 1.119.10.2 tsutsui
865 1.119.10.2 tsutsui if (cfparent_match(parent, cf->cf_pspec))
866 1.119.10.2 tsutsui mapply(&m, cf);
867 1.119.10.2 tsutsui }
868 1.119.10.2 tsutsui }
869 1.119.10.2 tsutsui return (m.match);
870 1.119.10.2 tsutsui }
871 1.119.10.2 tsutsui
872 1.119.10.2 tsutsui cfdata_t
873 1.119.10.2 tsutsui config_search_ia(cfsubmatch_t fn, device_t parent, const char *ifattr,
874 1.119.10.2 tsutsui void *aux)
875 1.119.10.2 tsutsui {
876 1.119.10.2 tsutsui
877 1.119.10.2 tsutsui return (config_search_loc(fn, parent, ifattr, NULL, aux));
878 1.119.10.2 tsutsui }
879 1.119.10.2 tsutsui
880 1.119.10.2 tsutsui /*
881 1.119.10.2 tsutsui * Find the given root device.
882 1.119.10.2 tsutsui * This is much like config_search, but there is no parent.
883 1.119.10.2 tsutsui * Don't bother with multiple cfdata tables; the root node
884 1.119.10.2 tsutsui * must always be in the initial table.
885 1.119.10.2 tsutsui */
886 1.119.10.2 tsutsui cfdata_t
887 1.119.10.2 tsutsui config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
888 1.119.10.2 tsutsui {
889 1.119.10.2 tsutsui cfdata_t cf;
890 1.119.10.2 tsutsui const short *p;
891 1.119.10.2 tsutsui struct matchinfo m;
892 1.119.10.2 tsutsui
893 1.119.10.2 tsutsui m.fn = fn;
894 1.119.10.2 tsutsui m.parent = ROOT;
895 1.119.10.2 tsutsui m.aux = aux;
896 1.119.10.2 tsutsui m.match = NULL;
897 1.119.10.2 tsutsui m.pri = 0;
898 1.119.10.2 tsutsui m.locs = 0;
899 1.119.10.2 tsutsui /*
900 1.119.10.2 tsutsui * Look at root entries for matching name. We do not bother
901 1.119.10.2 tsutsui * with found-state here since only one root should ever be
902 1.119.10.2 tsutsui * searched (and it must be done first).
903 1.119.10.2 tsutsui */
904 1.119.10.2 tsutsui for (p = cfroots; *p >= 0; p++) {
905 1.119.10.2 tsutsui cf = &cfdata[*p];
906 1.119.10.2 tsutsui if (strcmp(cf->cf_name, rootname) == 0)
907 1.119.10.2 tsutsui mapply(&m, cf);
908 1.119.10.2 tsutsui }
909 1.119.10.2 tsutsui return (m.match);
910 1.119.10.2 tsutsui }
911 1.119.10.2 tsutsui
912 1.119.10.2 tsutsui static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
913 1.119.10.2 tsutsui
914 1.119.10.2 tsutsui /*
915 1.119.10.2 tsutsui * The given `aux' argument describes a device that has been found
916 1.119.10.2 tsutsui * on the given parent, but not necessarily configured. Locate the
917 1.119.10.2 tsutsui * configuration data for that device (using the submatch function
918 1.119.10.2 tsutsui * provided, or using candidates' cd_match configuration driver
919 1.119.10.2 tsutsui * functions) and attach it, and return true. If the device was
920 1.119.10.2 tsutsui * not configured, call the given `print' function and return 0.
921 1.119.10.2 tsutsui */
922 1.119.10.2 tsutsui device_t
923 1.119.10.2 tsutsui config_found_sm_loc(device_t parent,
924 1.119.10.2 tsutsui const char *ifattr, const int *locs, void *aux,
925 1.119.10.2 tsutsui cfprint_t print, cfsubmatch_t submatch)
926 1.119.10.2 tsutsui {
927 1.119.10.2 tsutsui cfdata_t cf;
928 1.119.10.2 tsutsui
929 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
930 1.119.10.2 tsutsui if (splash_progress_state)
931 1.119.10.2 tsutsui splash_progress_update(splash_progress_state);
932 1.119.10.2 tsutsui #endif
933 1.119.10.2 tsutsui
934 1.119.10.2 tsutsui if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux)))
935 1.119.10.2 tsutsui return(config_attach_loc(parent, cf, locs, aux, print));
936 1.119.10.2 tsutsui if (print) {
937 1.119.10.2 tsutsui if (config_do_twiddle)
938 1.119.10.2 tsutsui twiddle();
939 1.119.10.2 tsutsui aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
940 1.119.10.2 tsutsui }
941 1.119.10.2 tsutsui
942 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
943 1.119.10.2 tsutsui if (splash_progress_state)
944 1.119.10.2 tsutsui splash_progress_update(splash_progress_state);
945 1.119.10.2 tsutsui #endif
946 1.119.10.2 tsutsui
947 1.119.10.2 tsutsui return (NULL);
948 1.119.10.2 tsutsui }
949 1.119.10.2 tsutsui
950 1.119.10.2 tsutsui device_t
951 1.119.10.2 tsutsui config_found_ia(device_t parent, const char *ifattr, void *aux,
952 1.119.10.2 tsutsui cfprint_t print)
953 1.119.10.2 tsutsui {
954 1.119.10.2 tsutsui
955 1.119.10.2 tsutsui return (config_found_sm_loc(parent, ifattr, NULL, aux, print, NULL));
956 1.119.10.2 tsutsui }
957 1.119.10.2 tsutsui
958 1.119.10.2 tsutsui device_t
959 1.119.10.2 tsutsui config_found(device_t parent, void *aux, cfprint_t print)
960 1.119.10.2 tsutsui {
961 1.119.10.2 tsutsui
962 1.119.10.2 tsutsui return (config_found_sm_loc(parent, NULL, NULL, aux, print, NULL));
963 1.119.10.2 tsutsui }
964 1.119.10.2 tsutsui
965 1.119.10.2 tsutsui /*
966 1.119.10.2 tsutsui * As above, but for root devices.
967 1.119.10.2 tsutsui */
968 1.119.10.2 tsutsui device_t
969 1.119.10.2 tsutsui config_rootfound(const char *rootname, void *aux)
970 1.119.10.2 tsutsui {
971 1.119.10.2 tsutsui cfdata_t cf;
972 1.119.10.2 tsutsui
973 1.119.10.2 tsutsui if ((cf = config_rootsearch((cfsubmatch_t)NULL, rootname, aux)) != NULL)
974 1.119.10.2 tsutsui return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
975 1.119.10.2 tsutsui aprint_error("root device %s not configured\n", rootname);
976 1.119.10.2 tsutsui return (NULL);
977 1.119.10.2 tsutsui }
978 1.119.10.2 tsutsui
979 1.119.10.2 tsutsui /* just like sprintf(buf, "%d") except that it works from the end */
980 1.119.10.2 tsutsui static char *
981 1.119.10.2 tsutsui number(char *ep, int n)
982 1.119.10.2 tsutsui {
983 1.119.10.2 tsutsui
984 1.119.10.2 tsutsui *--ep = 0;
985 1.119.10.2 tsutsui while (n >= 10) {
986 1.119.10.2 tsutsui *--ep = (n % 10) + '0';
987 1.119.10.2 tsutsui n /= 10;
988 1.119.10.2 tsutsui }
989 1.119.10.2 tsutsui *--ep = n + '0';
990 1.119.10.2 tsutsui return (ep);
991 1.119.10.2 tsutsui }
992 1.119.10.2 tsutsui
993 1.119.10.2 tsutsui /*
994 1.119.10.2 tsutsui * Expand the size of the cd_devs array if necessary.
995 1.119.10.2 tsutsui */
996 1.119.10.2 tsutsui static void
997 1.119.10.2 tsutsui config_makeroom(int n, struct cfdriver *cd)
998 1.119.10.2 tsutsui {
999 1.119.10.2 tsutsui int old, new;
1000 1.119.10.2 tsutsui void **nsp;
1001 1.119.10.2 tsutsui
1002 1.119.10.2 tsutsui if (n < cd->cd_ndevs)
1003 1.119.10.2 tsutsui return;
1004 1.119.10.2 tsutsui
1005 1.119.10.2 tsutsui /*
1006 1.119.10.2 tsutsui * Need to expand the array.
1007 1.119.10.2 tsutsui */
1008 1.119.10.2 tsutsui old = cd->cd_ndevs;
1009 1.119.10.2 tsutsui if (old == 0)
1010 1.119.10.2 tsutsui new = 4;
1011 1.119.10.2 tsutsui else
1012 1.119.10.2 tsutsui new = old * 2;
1013 1.119.10.2 tsutsui while (new <= n)
1014 1.119.10.2 tsutsui new *= 2;
1015 1.119.10.2 tsutsui cd->cd_ndevs = new;
1016 1.119.10.2 tsutsui nsp = malloc(new * sizeof(void *), M_DEVBUF,
1017 1.119.10.2 tsutsui cold ? M_NOWAIT : M_WAITOK);
1018 1.119.10.2 tsutsui if (nsp == NULL)
1019 1.119.10.2 tsutsui panic("config_attach: %sing dev array",
1020 1.119.10.2 tsutsui old != 0 ? "expand" : "creat");
1021 1.119.10.2 tsutsui memset(nsp + old, 0, (new - old) * sizeof(void *));
1022 1.119.10.2 tsutsui if (old != 0) {
1023 1.119.10.2 tsutsui memcpy(nsp, cd->cd_devs, old * sizeof(void *));
1024 1.119.10.2 tsutsui free(cd->cd_devs, M_DEVBUF);
1025 1.119.10.2 tsutsui }
1026 1.119.10.2 tsutsui cd->cd_devs = nsp;
1027 1.119.10.2 tsutsui }
1028 1.119.10.2 tsutsui
1029 1.119.10.2 tsutsui static void
1030 1.119.10.2 tsutsui config_devlink(device_t dev)
1031 1.119.10.2 tsutsui {
1032 1.119.10.2 tsutsui struct cfdriver *cd = dev->dv_cfdriver;
1033 1.119.10.2 tsutsui
1034 1.119.10.2 tsutsui /* put this device in the devices array */
1035 1.119.10.2 tsutsui config_makeroom(dev->dv_unit, cd);
1036 1.119.10.2 tsutsui if (cd->cd_devs[dev->dv_unit])
1037 1.119.10.2 tsutsui panic("config_attach: duplicate %s", dev->dv_xname);
1038 1.119.10.2 tsutsui cd->cd_devs[dev->dv_unit] = dev;
1039 1.119.10.2 tsutsui
1040 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */
1041 1.119.10.2 tsutsui }
1042 1.119.10.2 tsutsui
1043 1.119.10.2 tsutsui static void
1044 1.119.10.2 tsutsui config_devunlink(device_t dev)
1045 1.119.10.2 tsutsui {
1046 1.119.10.2 tsutsui struct cfdriver *cd = dev->dv_cfdriver;
1047 1.119.10.2 tsutsui int i;
1048 1.119.10.2 tsutsui
1049 1.119.10.2 tsutsui /* Unlink from device list. */
1050 1.119.10.2 tsutsui TAILQ_REMOVE(&alldevs, dev, dv_list);
1051 1.119.10.2 tsutsui
1052 1.119.10.2 tsutsui /* Remove from cfdriver's array. */
1053 1.119.10.2 tsutsui cd->cd_devs[dev->dv_unit] = NULL;
1054 1.119.10.2 tsutsui
1055 1.119.10.2 tsutsui /*
1056 1.119.10.2 tsutsui * If the device now has no units in use, deallocate its softc array.
1057 1.119.10.2 tsutsui */
1058 1.119.10.2 tsutsui for (i = 0; i < cd->cd_ndevs; i++)
1059 1.119.10.2 tsutsui if (cd->cd_devs[i] != NULL)
1060 1.119.10.2 tsutsui break;
1061 1.119.10.2 tsutsui if (i == cd->cd_ndevs) { /* nothing found; deallocate */
1062 1.119.10.2 tsutsui free(cd->cd_devs, M_DEVBUF);
1063 1.119.10.2 tsutsui cd->cd_devs = NULL;
1064 1.119.10.2 tsutsui cd->cd_ndevs = 0;
1065 1.119.10.2 tsutsui }
1066 1.119.10.2 tsutsui }
1067 1.119.10.2 tsutsui
1068 1.119.10.2 tsutsui static device_t
1069 1.119.10.2 tsutsui config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
1070 1.119.10.2 tsutsui {
1071 1.119.10.2 tsutsui struct cfdriver *cd;
1072 1.119.10.2 tsutsui struct cfattach *ca;
1073 1.119.10.2 tsutsui size_t lname, lunit;
1074 1.119.10.2 tsutsui const char *xunit;
1075 1.119.10.2 tsutsui int myunit;
1076 1.119.10.2 tsutsui char num[10];
1077 1.119.10.2 tsutsui device_t dev;
1078 1.119.10.2 tsutsui const struct cfiattrdata *ia;
1079 1.119.10.2 tsutsui
1080 1.119.10.2 tsutsui cd = config_cfdriver_lookup(cf->cf_name);
1081 1.119.10.2 tsutsui if (cd == NULL)
1082 1.119.10.2 tsutsui return (NULL);
1083 1.119.10.2 tsutsui
1084 1.119.10.2 tsutsui ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
1085 1.119.10.2 tsutsui if (ca == NULL)
1086 1.119.10.2 tsutsui return (NULL);
1087 1.119.10.2 tsutsui
1088 1.119.10.2 tsutsui if (ca->ca_devsize < sizeof(struct device))
1089 1.119.10.2 tsutsui panic("config_devalloc");
1090 1.119.10.2 tsutsui
1091 1.119.10.2 tsutsui #ifndef __BROKEN_CONFIG_UNIT_USAGE
1092 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_STAR) {
1093 1.119.10.2 tsutsui for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
1094 1.119.10.2 tsutsui if (cd->cd_devs[myunit] == NULL)
1095 1.119.10.2 tsutsui break;
1096 1.119.10.2 tsutsui /*
1097 1.119.10.2 tsutsui * myunit is now the unit of the first NULL device pointer,
1098 1.119.10.2 tsutsui * or max(cd->cd_ndevs,cf->cf_unit).
1099 1.119.10.2 tsutsui */
1100 1.119.10.2 tsutsui } else {
1101 1.119.10.2 tsutsui myunit = cf->cf_unit;
1102 1.119.10.2 tsutsui if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
1103 1.119.10.2 tsutsui return (NULL);
1104 1.119.10.2 tsutsui }
1105 1.119.10.2 tsutsui #else
1106 1.119.10.2 tsutsui myunit = cf->cf_unit;
1107 1.119.10.2 tsutsui #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
1108 1.119.10.2 tsutsui
1109 1.119.10.2 tsutsui /* compute length of name and decimal expansion of unit number */
1110 1.119.10.2 tsutsui lname = strlen(cd->cd_name);
1111 1.119.10.2 tsutsui xunit = number(&num[sizeof(num)], myunit);
1112 1.119.10.2 tsutsui lunit = &num[sizeof(num)] - xunit;
1113 1.119.10.2 tsutsui if (lname + lunit > sizeof(dev->dv_xname))
1114 1.119.10.2 tsutsui panic("config_devalloc: device name too long");
1115 1.119.10.2 tsutsui
1116 1.119.10.2 tsutsui /* get memory for all device vars */
1117 1.119.10.2 tsutsui dev = (device_t)malloc(ca->ca_devsize, M_DEVBUF,
1118 1.119.10.2 tsutsui M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
1119 1.119.10.2 tsutsui if (!dev)
1120 1.119.10.2 tsutsui panic("config_devalloc: memory allocation for device softc failed");
1121 1.119.10.2 tsutsui dev->dv_class = cd->cd_class;
1122 1.119.10.2 tsutsui dev->dv_cfdata = cf;
1123 1.119.10.2 tsutsui dev->dv_cfdriver = cd;
1124 1.119.10.2 tsutsui dev->dv_cfattach = ca;
1125 1.119.10.2 tsutsui dev->dv_unit = myunit;
1126 1.119.10.2 tsutsui memcpy(dev->dv_xname, cd->cd_name, lname);
1127 1.119.10.2 tsutsui memcpy(dev->dv_xname + lname, xunit, lunit);
1128 1.119.10.2 tsutsui dev->dv_parent = parent;
1129 1.119.10.2 tsutsui dev->dv_flags = DVF_ACTIVE; /* always initially active */
1130 1.119.10.2 tsutsui if (locs) {
1131 1.119.10.2 tsutsui KASSERT(parent); /* no locators at root */
1132 1.119.10.2 tsutsui ia = cfiattr_lookup(cf->cf_pspec->cfp_iattr,
1133 1.119.10.2 tsutsui parent->dv_cfdriver);
1134 1.119.10.2 tsutsui dev->dv_locators = malloc(ia->ci_loclen * sizeof(int),
1135 1.119.10.2 tsutsui M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
1136 1.119.10.2 tsutsui memcpy(dev->dv_locators, locs, ia->ci_loclen * sizeof(int));
1137 1.119.10.2 tsutsui }
1138 1.119.10.2 tsutsui dev->dv_properties = prop_dictionary_create();
1139 1.119.10.2 tsutsui KASSERT(dev->dv_properties != NULL);
1140 1.119.10.2 tsutsui
1141 1.119.10.2 tsutsui return (dev);
1142 1.119.10.2 tsutsui }
1143 1.119.10.2 tsutsui
1144 1.119.10.2 tsutsui static void
1145 1.119.10.2 tsutsui config_devdealloc(device_t dev)
1146 1.119.10.2 tsutsui {
1147 1.119.10.2 tsutsui
1148 1.119.10.2 tsutsui KASSERT(dev->dv_properties != NULL);
1149 1.119.10.2 tsutsui prop_object_release(dev->dv_properties);
1150 1.119.10.2 tsutsui
1151 1.119.10.2 tsutsui if (dev->dv_locators)
1152 1.119.10.2 tsutsui free(dev->dv_locators, M_DEVBUF);
1153 1.119.10.2 tsutsui
1154 1.119.10.2 tsutsui free(dev, M_DEVBUF);
1155 1.119.10.2 tsutsui }
1156 1.119.10.2 tsutsui
1157 1.119.10.2 tsutsui /*
1158 1.119.10.2 tsutsui * Attach a found device.
1159 1.119.10.2 tsutsui */
1160 1.119.10.2 tsutsui device_t
1161 1.119.10.2 tsutsui config_attach_loc(device_t parent, cfdata_t cf,
1162 1.119.10.2 tsutsui const int *locs, void *aux, cfprint_t print)
1163 1.119.10.2 tsutsui {
1164 1.119.10.2 tsutsui device_t dev;
1165 1.119.10.2 tsutsui struct cftable *ct;
1166 1.119.10.2 tsutsui const char *drvname;
1167 1.119.10.2 tsutsui
1168 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1169 1.119.10.2 tsutsui if (splash_progress_state)
1170 1.119.10.2 tsutsui splash_progress_update(splash_progress_state);
1171 1.119.10.2 tsutsui #endif
1172 1.119.10.2 tsutsui
1173 1.119.10.2 tsutsui dev = config_devalloc(parent, cf, locs);
1174 1.119.10.2 tsutsui if (!dev)
1175 1.119.10.2 tsutsui panic("config_attach: allocation of device softc failed");
1176 1.119.10.2 tsutsui
1177 1.119.10.2 tsutsui /* XXX redundant - see below? */
1178 1.119.10.2 tsutsui if (cf->cf_fstate != FSTATE_STAR) {
1179 1.119.10.2 tsutsui KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1180 1.119.10.2 tsutsui cf->cf_fstate = FSTATE_FOUND;
1181 1.119.10.2 tsutsui }
1182 1.119.10.2 tsutsui #ifdef __BROKEN_CONFIG_UNIT_USAGE
1183 1.119.10.2 tsutsui else
1184 1.119.10.2 tsutsui cf->cf_unit++;
1185 1.119.10.2 tsutsui #endif
1186 1.119.10.2 tsutsui
1187 1.119.10.2 tsutsui config_devlink(dev);
1188 1.119.10.2 tsutsui
1189 1.119.10.2 tsutsui if (config_do_twiddle)
1190 1.119.10.2 tsutsui twiddle();
1191 1.119.10.2 tsutsui else
1192 1.119.10.2 tsutsui aprint_naive("Found ");
1193 1.119.10.2 tsutsui /*
1194 1.119.10.2 tsutsui * We want the next two printfs for normal, verbose, and quiet,
1195 1.119.10.2 tsutsui * but not silent (in which case, we're twiddling, instead).
1196 1.119.10.2 tsutsui */
1197 1.119.10.2 tsutsui if (parent == ROOT) {
1198 1.119.10.2 tsutsui aprint_naive("%s (root)", dev->dv_xname);
1199 1.119.10.2 tsutsui aprint_normal("%s (root)", dev->dv_xname);
1200 1.119.10.2 tsutsui } else {
1201 1.119.10.2 tsutsui aprint_naive("%s at %s", dev->dv_xname, parent->dv_xname);
1202 1.119.10.2 tsutsui aprint_normal("%s at %s", dev->dv_xname, parent->dv_xname);
1203 1.119.10.2 tsutsui if (print)
1204 1.119.10.2 tsutsui (void) (*print)(aux, NULL);
1205 1.119.10.2 tsutsui }
1206 1.119.10.2 tsutsui
1207 1.119.10.2 tsutsui /*
1208 1.119.10.2 tsutsui * Before attaching, clobber any unfound devices that are
1209 1.119.10.2 tsutsui * otherwise identical.
1210 1.119.10.2 tsutsui * XXX code above is redundant?
1211 1.119.10.2 tsutsui */
1212 1.119.10.2 tsutsui drvname = dev->dv_cfdriver->cd_name;
1213 1.119.10.2 tsutsui TAILQ_FOREACH(ct, &allcftables, ct_list) {
1214 1.119.10.2 tsutsui for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1215 1.119.10.2 tsutsui if (STREQ(cf->cf_name, drvname) &&
1216 1.119.10.2 tsutsui cf->cf_unit == dev->dv_unit) {
1217 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_NOTFOUND)
1218 1.119.10.2 tsutsui cf->cf_fstate = FSTATE_FOUND;
1219 1.119.10.2 tsutsui #ifdef __BROKEN_CONFIG_UNIT_USAGE
1220 1.119.10.2 tsutsui /*
1221 1.119.10.2 tsutsui * Bump the unit number on all starred cfdata
1222 1.119.10.2 tsutsui * entries for this device.
1223 1.119.10.2 tsutsui */
1224 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_STAR)
1225 1.119.10.2 tsutsui cf->cf_unit++;
1226 1.119.10.2 tsutsui #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1227 1.119.10.2 tsutsui }
1228 1.119.10.2 tsutsui }
1229 1.119.10.2 tsutsui }
1230 1.119.10.2 tsutsui #ifdef __HAVE_DEVICE_REGISTER
1231 1.119.10.2 tsutsui device_register(dev, aux);
1232 1.119.10.2 tsutsui #endif
1233 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1234 1.119.10.2 tsutsui if (splash_progress_state)
1235 1.119.10.2 tsutsui splash_progress_update(splash_progress_state);
1236 1.119.10.2 tsutsui #endif
1237 1.119.10.2 tsutsui (*dev->dv_cfattach->ca_attach)(parent, dev, aux);
1238 1.119.10.2 tsutsui #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1239 1.119.10.2 tsutsui if (splash_progress_state)
1240 1.119.10.2 tsutsui splash_progress_update(splash_progress_state);
1241 1.119.10.2 tsutsui #endif
1242 1.119.10.2 tsutsui config_process_deferred(&deferred_config_queue, dev);
1243 1.119.10.2 tsutsui return (dev);
1244 1.119.10.2 tsutsui }
1245 1.119.10.2 tsutsui
1246 1.119.10.2 tsutsui device_t
1247 1.119.10.2 tsutsui config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print)
1248 1.119.10.2 tsutsui {
1249 1.119.10.2 tsutsui
1250 1.119.10.2 tsutsui return (config_attach_loc(parent, cf, NULL, aux, print));
1251 1.119.10.2 tsutsui }
1252 1.119.10.2 tsutsui
1253 1.119.10.2 tsutsui /*
1254 1.119.10.2 tsutsui * As above, but for pseudo-devices. Pseudo-devices attached in this
1255 1.119.10.2 tsutsui * way are silently inserted into the device tree, and their children
1256 1.119.10.2 tsutsui * attached.
1257 1.119.10.2 tsutsui *
1258 1.119.10.2 tsutsui * Note that because pseudo-devices are attached silently, any information
1259 1.119.10.2 tsutsui * the attach routine wishes to print should be prefixed with the device
1260 1.119.10.2 tsutsui * name by the attach routine.
1261 1.119.10.2 tsutsui */
1262 1.119.10.2 tsutsui device_t
1263 1.119.10.2 tsutsui config_attach_pseudo(cfdata_t cf)
1264 1.119.10.2 tsutsui {
1265 1.119.10.2 tsutsui device_t dev;
1266 1.119.10.2 tsutsui
1267 1.119.10.2 tsutsui dev = config_devalloc(ROOT, cf, NULL);
1268 1.119.10.2 tsutsui if (!dev)
1269 1.119.10.2 tsutsui return (NULL);
1270 1.119.10.2 tsutsui
1271 1.119.10.2 tsutsui /* XXX mark busy in cfdata */
1272 1.119.10.2 tsutsui
1273 1.119.10.2 tsutsui config_devlink(dev);
1274 1.119.10.2 tsutsui
1275 1.119.10.2 tsutsui #if 0 /* XXXJRT not yet */
1276 1.119.10.2 tsutsui #ifdef __HAVE_DEVICE_REGISTER
1277 1.119.10.2 tsutsui device_register(dev, NULL); /* like a root node */
1278 1.119.10.2 tsutsui #endif
1279 1.119.10.2 tsutsui #endif
1280 1.119.10.2 tsutsui (*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
1281 1.119.10.2 tsutsui config_process_deferred(&deferred_config_queue, dev);
1282 1.119.10.2 tsutsui return (dev);
1283 1.119.10.2 tsutsui }
1284 1.119.10.2 tsutsui
1285 1.119.10.2 tsutsui /*
1286 1.119.10.2 tsutsui * Detach a device. Optionally forced (e.g. because of hardware
1287 1.119.10.2 tsutsui * removal) and quiet. Returns zero if successful, non-zero
1288 1.119.10.2 tsutsui * (an error code) otherwise.
1289 1.119.10.2 tsutsui *
1290 1.119.10.2 tsutsui * Note that this code wants to be run from a process context, so
1291 1.119.10.2 tsutsui * that the detach can sleep to allow processes which have a device
1292 1.119.10.2 tsutsui * open to run and unwind their stacks.
1293 1.119.10.2 tsutsui */
1294 1.119.10.2 tsutsui int
1295 1.119.10.2 tsutsui config_detach(device_t dev, int flags)
1296 1.119.10.2 tsutsui {
1297 1.119.10.2 tsutsui struct cftable *ct;
1298 1.119.10.2 tsutsui cfdata_t cf;
1299 1.119.10.2 tsutsui const struct cfattach *ca;
1300 1.119.10.2 tsutsui struct cfdriver *cd;
1301 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1302 1.119.10.2 tsutsui device_t d;
1303 1.119.10.2 tsutsui #endif
1304 1.119.10.2 tsutsui int rv = 0;
1305 1.119.10.2 tsutsui
1306 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1307 1.119.10.2 tsutsui if (dev->dv_cfdata != NULL &&
1308 1.119.10.2 tsutsui dev->dv_cfdata->cf_fstate != FSTATE_FOUND &&
1309 1.119.10.2 tsutsui dev->dv_cfdata->cf_fstate != FSTATE_STAR)
1310 1.119.10.2 tsutsui panic("config_detach: bad device fstate");
1311 1.119.10.2 tsutsui #endif
1312 1.119.10.2 tsutsui cd = dev->dv_cfdriver;
1313 1.119.10.2 tsutsui KASSERT(cd != NULL);
1314 1.119.10.2 tsutsui
1315 1.119.10.2 tsutsui ca = dev->dv_cfattach;
1316 1.119.10.2 tsutsui KASSERT(ca != NULL);
1317 1.119.10.2 tsutsui
1318 1.119.10.2 tsutsui /*
1319 1.119.10.2 tsutsui * Ensure the device is deactivated. If the device doesn't
1320 1.119.10.2 tsutsui * have an activation entry point, we allow DVF_ACTIVE to
1321 1.119.10.2 tsutsui * remain set. Otherwise, if DVF_ACTIVE is still set, the
1322 1.119.10.2 tsutsui * device is busy, and the detach fails.
1323 1.119.10.2 tsutsui */
1324 1.119.10.2 tsutsui if (ca->ca_activate != NULL)
1325 1.119.10.2 tsutsui rv = config_deactivate(dev);
1326 1.119.10.2 tsutsui
1327 1.119.10.2 tsutsui /*
1328 1.119.10.2 tsutsui * Try to detach the device. If that's not possible, then
1329 1.119.10.2 tsutsui * we either panic() (for the forced but failed case), or
1330 1.119.10.2 tsutsui * return an error.
1331 1.119.10.2 tsutsui */
1332 1.119.10.2 tsutsui if (rv == 0) {
1333 1.119.10.2 tsutsui if (ca->ca_detach != NULL)
1334 1.119.10.2 tsutsui rv = (*ca->ca_detach)(dev, flags);
1335 1.119.10.2 tsutsui else
1336 1.119.10.2 tsutsui rv = EOPNOTSUPP;
1337 1.119.10.2 tsutsui }
1338 1.119.10.2 tsutsui if (rv != 0) {
1339 1.119.10.2 tsutsui if ((flags & DETACH_FORCE) == 0)
1340 1.119.10.2 tsutsui return (rv);
1341 1.119.10.2 tsutsui else
1342 1.119.10.2 tsutsui panic("config_detach: forced detach of %s failed (%d)",
1343 1.119.10.2 tsutsui dev->dv_xname, rv);
1344 1.119.10.2 tsutsui }
1345 1.119.10.2 tsutsui
1346 1.119.10.2 tsutsui /*
1347 1.119.10.2 tsutsui * The device has now been successfully detached.
1348 1.119.10.2 tsutsui */
1349 1.119.10.2 tsutsui
1350 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1351 1.119.10.2 tsutsui /*
1352 1.119.10.2 tsutsui * Sanity: If you're successfully detached, you should have no
1353 1.119.10.2 tsutsui * children. (Note that because children must be attached
1354 1.119.10.2 tsutsui * after parents, we only need to search the latter part of
1355 1.119.10.2 tsutsui * the list.)
1356 1.119.10.2 tsutsui */
1357 1.119.10.2 tsutsui for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1358 1.119.10.2 tsutsui d = TAILQ_NEXT(d, dv_list)) {
1359 1.119.10.2 tsutsui if (d->dv_parent == dev) {
1360 1.119.10.2 tsutsui printf("config_detach: detached device %s"
1361 1.119.10.2 tsutsui " has children %s\n", dev->dv_xname, d->dv_xname);
1362 1.119.10.2 tsutsui panic("config_detach");
1363 1.119.10.2 tsutsui }
1364 1.119.10.2 tsutsui }
1365 1.119.10.2 tsutsui #endif
1366 1.119.10.2 tsutsui
1367 1.119.10.2 tsutsui /* notify the parent that the child is gone */
1368 1.119.10.2 tsutsui if (dev->dv_parent) {
1369 1.119.10.2 tsutsui device_t p = dev->dv_parent;
1370 1.119.10.2 tsutsui if (p->dv_cfattach->ca_childdetached)
1371 1.119.10.2 tsutsui (*p->dv_cfattach->ca_childdetached)(p, dev);
1372 1.119.10.2 tsutsui }
1373 1.119.10.2 tsutsui
1374 1.119.10.2 tsutsui /*
1375 1.119.10.2 tsutsui * Mark cfdata to show that the unit can be reused, if possible.
1376 1.119.10.2 tsutsui */
1377 1.119.10.2 tsutsui TAILQ_FOREACH(ct, &allcftables, ct_list) {
1378 1.119.10.2 tsutsui for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1379 1.119.10.2 tsutsui if (STREQ(cf->cf_name, cd->cd_name)) {
1380 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_FOUND &&
1381 1.119.10.2 tsutsui cf->cf_unit == dev->dv_unit)
1382 1.119.10.2 tsutsui cf->cf_fstate = FSTATE_NOTFOUND;
1383 1.119.10.2 tsutsui #ifdef __BROKEN_CONFIG_UNIT_USAGE
1384 1.119.10.2 tsutsui /*
1385 1.119.10.2 tsutsui * Note that we can only re-use a starred
1386 1.119.10.2 tsutsui * unit number if the unit being detached
1387 1.119.10.2 tsutsui * had the last assigned unit number.
1388 1.119.10.2 tsutsui */
1389 1.119.10.2 tsutsui if (cf->cf_fstate == FSTATE_STAR &&
1390 1.119.10.2 tsutsui cf->cf_unit == dev->dv_unit + 1)
1391 1.119.10.2 tsutsui cf->cf_unit--;
1392 1.119.10.2 tsutsui #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1393 1.119.10.2 tsutsui }
1394 1.119.10.2 tsutsui }
1395 1.119.10.2 tsutsui }
1396 1.119.10.2 tsutsui
1397 1.119.10.2 tsutsui config_devunlink(dev);
1398 1.119.10.2 tsutsui
1399 1.119.10.2 tsutsui if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1400 1.119.10.2 tsutsui aprint_normal("%s detached\n", dev->dv_xname);
1401 1.119.10.2 tsutsui
1402 1.119.10.2 tsutsui config_devdealloc(dev);
1403 1.119.10.2 tsutsui
1404 1.119.10.2 tsutsui return (0);
1405 1.119.10.2 tsutsui }
1406 1.119.10.2 tsutsui
1407 1.119.10.2 tsutsui int
1408 1.119.10.2 tsutsui config_activate(device_t dev)
1409 1.119.10.2 tsutsui {
1410 1.119.10.2 tsutsui const struct cfattach *ca = dev->dv_cfattach;
1411 1.119.10.2 tsutsui int rv = 0, oflags = dev->dv_flags;
1412 1.119.10.2 tsutsui
1413 1.119.10.2 tsutsui if (ca->ca_activate == NULL)
1414 1.119.10.2 tsutsui return (EOPNOTSUPP);
1415 1.119.10.2 tsutsui
1416 1.119.10.2 tsutsui if ((dev->dv_flags & DVF_ACTIVE) == 0) {
1417 1.119.10.2 tsutsui dev->dv_flags |= DVF_ACTIVE;
1418 1.119.10.2 tsutsui rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
1419 1.119.10.2 tsutsui if (rv)
1420 1.119.10.2 tsutsui dev->dv_flags = oflags;
1421 1.119.10.2 tsutsui }
1422 1.119.10.2 tsutsui return (rv);
1423 1.119.10.2 tsutsui }
1424 1.119.10.2 tsutsui
1425 1.119.10.2 tsutsui int
1426 1.119.10.2 tsutsui config_deactivate(device_t dev)
1427 1.119.10.2 tsutsui {
1428 1.119.10.2 tsutsui const struct cfattach *ca = dev->dv_cfattach;
1429 1.119.10.2 tsutsui int rv = 0, oflags = dev->dv_flags;
1430 1.119.10.2 tsutsui
1431 1.119.10.2 tsutsui if (ca->ca_activate == NULL)
1432 1.119.10.2 tsutsui return (EOPNOTSUPP);
1433 1.119.10.2 tsutsui
1434 1.119.10.2 tsutsui if (dev->dv_flags & DVF_ACTIVE) {
1435 1.119.10.2 tsutsui dev->dv_flags &= ~DVF_ACTIVE;
1436 1.119.10.2 tsutsui rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
1437 1.119.10.2 tsutsui if (rv)
1438 1.119.10.2 tsutsui dev->dv_flags = oflags;
1439 1.119.10.2 tsutsui }
1440 1.119.10.2 tsutsui return (rv);
1441 1.119.10.2 tsutsui }
1442 1.119.10.2 tsutsui
1443 1.119.10.2 tsutsui /*
1444 1.119.10.2 tsutsui * Defer the configuration of the specified device until all
1445 1.119.10.2 tsutsui * of its parent's devices have been attached.
1446 1.119.10.2 tsutsui */
1447 1.119.10.2 tsutsui void
1448 1.119.10.2 tsutsui config_defer(device_t dev, void (*func)(device_t))
1449 1.119.10.2 tsutsui {
1450 1.119.10.2 tsutsui struct deferred_config *dc;
1451 1.119.10.2 tsutsui
1452 1.119.10.2 tsutsui if (dev->dv_parent == NULL)
1453 1.119.10.2 tsutsui panic("config_defer: can't defer config of a root device");
1454 1.119.10.2 tsutsui
1455 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1456 1.119.10.2 tsutsui for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
1457 1.119.10.2 tsutsui dc = TAILQ_NEXT(dc, dc_queue)) {
1458 1.119.10.2 tsutsui if (dc->dc_dev == dev)
1459 1.119.10.2 tsutsui panic("config_defer: deferred twice");
1460 1.119.10.2 tsutsui }
1461 1.119.10.2 tsutsui #endif
1462 1.119.10.2 tsutsui
1463 1.119.10.2 tsutsui dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
1464 1.119.10.2 tsutsui if (dc == NULL)
1465 1.119.10.2 tsutsui panic("config_defer: unable to allocate callback");
1466 1.119.10.2 tsutsui
1467 1.119.10.2 tsutsui dc->dc_dev = dev;
1468 1.119.10.2 tsutsui dc->dc_func = func;
1469 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1470 1.119.10.2 tsutsui config_pending_incr();
1471 1.119.10.2 tsutsui }
1472 1.119.10.2 tsutsui
1473 1.119.10.2 tsutsui /*
1474 1.119.10.2 tsutsui * Defer some autoconfiguration for a device until after interrupts
1475 1.119.10.2 tsutsui * are enabled.
1476 1.119.10.2 tsutsui */
1477 1.119.10.2 tsutsui void
1478 1.119.10.2 tsutsui config_interrupts(device_t dev, void (*func)(device_t))
1479 1.119.10.2 tsutsui {
1480 1.119.10.2 tsutsui struct deferred_config *dc;
1481 1.119.10.2 tsutsui
1482 1.119.10.2 tsutsui /*
1483 1.119.10.2 tsutsui * If interrupts are enabled, callback now.
1484 1.119.10.2 tsutsui */
1485 1.119.10.2 tsutsui if (cold == 0) {
1486 1.119.10.2 tsutsui (*func)(dev);
1487 1.119.10.2 tsutsui return;
1488 1.119.10.2 tsutsui }
1489 1.119.10.2 tsutsui
1490 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1491 1.119.10.2 tsutsui for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
1492 1.119.10.2 tsutsui dc = TAILQ_NEXT(dc, dc_queue)) {
1493 1.119.10.2 tsutsui if (dc->dc_dev == dev)
1494 1.119.10.2 tsutsui panic("config_interrupts: deferred twice");
1495 1.119.10.2 tsutsui }
1496 1.119.10.2 tsutsui #endif
1497 1.119.10.2 tsutsui
1498 1.119.10.2 tsutsui dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
1499 1.119.10.2 tsutsui if (dc == NULL)
1500 1.119.10.2 tsutsui panic("config_interrupts: unable to allocate callback");
1501 1.119.10.2 tsutsui
1502 1.119.10.2 tsutsui dc->dc_dev = dev;
1503 1.119.10.2 tsutsui dc->dc_func = func;
1504 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1505 1.119.10.2 tsutsui config_pending_incr();
1506 1.119.10.2 tsutsui }
1507 1.119.10.2 tsutsui
1508 1.119.10.2 tsutsui /*
1509 1.119.10.2 tsutsui * Process a deferred configuration queue.
1510 1.119.10.2 tsutsui */
1511 1.119.10.2 tsutsui static void
1512 1.119.10.2 tsutsui config_process_deferred(struct deferred_config_head *queue,
1513 1.119.10.2 tsutsui device_t parent)
1514 1.119.10.2 tsutsui {
1515 1.119.10.2 tsutsui struct deferred_config *dc, *ndc;
1516 1.119.10.2 tsutsui
1517 1.119.10.2 tsutsui for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
1518 1.119.10.2 tsutsui ndc = TAILQ_NEXT(dc, dc_queue);
1519 1.119.10.2 tsutsui if (parent == NULL || dc->dc_dev->dv_parent == parent) {
1520 1.119.10.2 tsutsui TAILQ_REMOVE(queue, dc, dc_queue);
1521 1.119.10.2 tsutsui (*dc->dc_func)(dc->dc_dev);
1522 1.119.10.2 tsutsui free(dc, M_DEVBUF);
1523 1.119.10.2 tsutsui config_pending_decr();
1524 1.119.10.2 tsutsui }
1525 1.119.10.2 tsutsui }
1526 1.119.10.2 tsutsui }
1527 1.119.10.2 tsutsui
1528 1.119.10.2 tsutsui /*
1529 1.119.10.2 tsutsui * Manipulate the config_pending semaphore.
1530 1.119.10.2 tsutsui */
1531 1.119.10.2 tsutsui void
1532 1.119.10.2 tsutsui config_pending_incr(void)
1533 1.119.10.2 tsutsui {
1534 1.119.10.2 tsutsui
1535 1.119.10.2 tsutsui config_pending++;
1536 1.119.10.2 tsutsui }
1537 1.119.10.2 tsutsui
1538 1.119.10.2 tsutsui void
1539 1.119.10.2 tsutsui config_pending_decr(void)
1540 1.119.10.2 tsutsui {
1541 1.119.10.2 tsutsui
1542 1.119.10.2 tsutsui #ifdef DIAGNOSTIC
1543 1.119.10.2 tsutsui if (config_pending == 0)
1544 1.119.10.2 tsutsui panic("config_pending_decr: config_pending == 0");
1545 1.119.10.2 tsutsui #endif
1546 1.119.10.2 tsutsui config_pending--;
1547 1.119.10.2 tsutsui if (config_pending == 0)
1548 1.119.10.2 tsutsui wakeup(&config_pending);
1549 1.119.10.2 tsutsui }
1550 1.119.10.2 tsutsui
1551 1.119.10.2 tsutsui /*
1552 1.119.10.2 tsutsui * Register a "finalization" routine. Finalization routines are
1553 1.119.10.2 tsutsui * called iteratively once all real devices have been found during
1554 1.119.10.2 tsutsui * autoconfiguration, for as long as any one finalizer has done
1555 1.119.10.2 tsutsui * any work.
1556 1.119.10.2 tsutsui */
1557 1.119.10.2 tsutsui int
1558 1.119.10.2 tsutsui config_finalize_register(device_t dev, int (*fn)(device_t))
1559 1.119.10.2 tsutsui {
1560 1.119.10.2 tsutsui struct finalize_hook *f;
1561 1.119.10.2 tsutsui
1562 1.119.10.2 tsutsui /*
1563 1.119.10.2 tsutsui * If finalization has already been done, invoke the
1564 1.119.10.2 tsutsui * callback function now.
1565 1.119.10.2 tsutsui */
1566 1.119.10.2 tsutsui if (config_finalize_done) {
1567 1.119.10.2 tsutsui while ((*fn)(dev) != 0)
1568 1.119.10.2 tsutsui /* loop */ ;
1569 1.119.10.2 tsutsui }
1570 1.119.10.2 tsutsui
1571 1.119.10.2 tsutsui /* Ensure this isn't already on the list. */
1572 1.119.10.2 tsutsui TAILQ_FOREACH(f, &config_finalize_list, f_list) {
1573 1.119.10.2 tsutsui if (f->f_func == fn && f->f_dev == dev)
1574 1.119.10.2 tsutsui return (EEXIST);
1575 1.119.10.2 tsutsui }
1576 1.119.10.2 tsutsui
1577 1.119.10.2 tsutsui f = malloc(sizeof(*f), M_TEMP, M_WAITOK);
1578 1.119.10.2 tsutsui f->f_func = fn;
1579 1.119.10.2 tsutsui f->f_dev = dev;
1580 1.119.10.2 tsutsui TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
1581 1.119.10.2 tsutsui
1582 1.119.10.2 tsutsui return (0);
1583 1.119.10.2 tsutsui }
1584 1.119.10.2 tsutsui
1585 1.119.10.2 tsutsui void
1586 1.119.10.2 tsutsui config_finalize(void)
1587 1.119.10.2 tsutsui {
1588 1.119.10.2 tsutsui struct finalize_hook *f;
1589 1.119.10.2 tsutsui int rv;
1590 1.119.10.2 tsutsui
1591 1.119.10.2 tsutsui /* Run the hooks until none of them does any work. */
1592 1.119.10.2 tsutsui do {
1593 1.119.10.2 tsutsui rv = 0;
1594 1.119.10.2 tsutsui TAILQ_FOREACH(f, &config_finalize_list, f_list)
1595 1.119.10.2 tsutsui rv |= (*f->f_func)(f->f_dev);
1596 1.119.10.2 tsutsui } while (rv != 0);
1597 1.119.10.2 tsutsui
1598 1.119.10.2 tsutsui config_finalize_done = 1;
1599 1.119.10.2 tsutsui
1600 1.119.10.2 tsutsui /* Now free all the hooks. */
1601 1.119.10.2 tsutsui while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
1602 1.119.10.2 tsutsui TAILQ_REMOVE(&config_finalize_list, f, f_list);
1603 1.119.10.2 tsutsui free(f, M_TEMP);
1604 1.119.10.2 tsutsui }
1605 1.119.10.2 tsutsui }
1606 1.119.10.2 tsutsui
1607 1.119.10.2 tsutsui /*
1608 1.119.10.2 tsutsui * device_lookup:
1609 1.119.10.2 tsutsui *
1610 1.119.10.2 tsutsui * Look up a device instance for a given driver.
1611 1.119.10.2 tsutsui */
1612 1.119.10.2 tsutsui void *
1613 1.119.10.2 tsutsui device_lookup(cfdriver_t cd, int unit)
1614 1.119.10.2 tsutsui {
1615 1.119.10.2 tsutsui
1616 1.119.10.2 tsutsui if (unit < 0 || unit >= cd->cd_ndevs)
1617 1.119.10.2 tsutsui return (NULL);
1618 1.119.10.2 tsutsui
1619 1.119.10.2 tsutsui return (cd->cd_devs[unit]);
1620 1.119.10.2 tsutsui }
1621 1.119.10.2 tsutsui
1622 1.119.10.2 tsutsui /*
1623 1.119.10.2 tsutsui * Accessor functions for the device_t type.
1624 1.119.10.2 tsutsui */
1625 1.119.10.2 tsutsui devclass_t
1626 1.119.10.2 tsutsui device_class(device_t dev)
1627 1.119.10.2 tsutsui {
1628 1.119.10.2 tsutsui
1629 1.119.10.2 tsutsui return (dev->dv_class);
1630 1.119.10.2 tsutsui }
1631 1.119.10.2 tsutsui
1632 1.119.10.2 tsutsui cfdata_t
1633 1.119.10.2 tsutsui device_cfdata(device_t dev)
1634 1.119.10.2 tsutsui {
1635 1.119.10.2 tsutsui
1636 1.119.10.2 tsutsui return (dev->dv_cfdata);
1637 1.119.10.2 tsutsui }
1638 1.119.10.2 tsutsui
1639 1.119.10.2 tsutsui cfdriver_t
1640 1.119.10.2 tsutsui device_cfdriver(device_t dev)
1641 1.119.10.2 tsutsui {
1642 1.119.10.2 tsutsui
1643 1.119.10.2 tsutsui return (dev->dv_cfdriver);
1644 1.119.10.2 tsutsui }
1645 1.119.10.2 tsutsui
1646 1.119.10.2 tsutsui cfattach_t
1647 1.119.10.2 tsutsui device_cfattach(device_t dev)
1648 1.119.10.2 tsutsui {
1649 1.119.10.2 tsutsui
1650 1.119.10.2 tsutsui return (dev->dv_cfattach);
1651 1.119.10.2 tsutsui }
1652 1.119.10.2 tsutsui
1653 1.119.10.2 tsutsui int
1654 1.119.10.2 tsutsui device_unit(device_t dev)
1655 1.119.10.2 tsutsui {
1656 1.119.10.2 tsutsui
1657 1.119.10.2 tsutsui return (dev->dv_unit);
1658 1.119.10.2 tsutsui }
1659 1.119.10.2 tsutsui
1660 1.119.10.2 tsutsui const char *
1661 1.119.10.2 tsutsui device_xname(device_t dev)
1662 1.119.10.2 tsutsui {
1663 1.119.10.2 tsutsui
1664 1.119.10.2 tsutsui return (dev->dv_xname);
1665 1.119.10.2 tsutsui }
1666 1.119.10.2 tsutsui
1667 1.119.10.2 tsutsui device_t
1668 1.119.10.2 tsutsui device_parent(device_t dev)
1669 1.119.10.2 tsutsui {
1670 1.119.10.2 tsutsui
1671 1.119.10.2 tsutsui return (dev->dv_parent);
1672 1.119.10.2 tsutsui }
1673 1.119.10.2 tsutsui
1674 1.119.10.2 tsutsui bool
1675 1.119.10.2 tsutsui device_is_active(device_t dev)
1676 1.119.10.2 tsutsui {
1677 1.119.10.2 tsutsui
1678 1.119.10.2 tsutsui return ((dev->dv_flags & DVF_ACTIVE) != 0);
1679 1.119.10.2 tsutsui }
1680 1.119.10.2 tsutsui
1681 1.119.10.2 tsutsui int
1682 1.119.10.2 tsutsui device_locator(device_t dev, u_int locnum)
1683 1.119.10.2 tsutsui {
1684 1.119.10.2 tsutsui
1685 1.119.10.2 tsutsui KASSERT(dev->dv_locators != NULL);
1686 1.119.10.2 tsutsui return (dev->dv_locators[locnum]);
1687 1.119.10.2 tsutsui }
1688 1.119.10.2 tsutsui
1689 1.119.10.2 tsutsui void *
1690 1.119.10.2 tsutsui device_private(device_t dev)
1691 1.119.10.2 tsutsui {
1692 1.119.10.2 tsutsui
1693 1.119.10.2 tsutsui /*
1694 1.119.10.2 tsutsui * For now, at least, "struct device" is the first thing in
1695 1.119.10.2 tsutsui * the driver's private data. So, we just return ourselves.
1696 1.119.10.2 tsutsui */
1697 1.119.10.2 tsutsui return (dev);
1698 1.119.10.2 tsutsui }
1699 1.119.10.2 tsutsui
1700 1.119.10.2 tsutsui prop_dictionary_t
1701 1.119.10.2 tsutsui device_properties(device_t dev)
1702 1.119.10.2 tsutsui {
1703 1.119.10.2 tsutsui
1704 1.119.10.2 tsutsui return (dev->dv_properties);
1705 1.119.10.2 tsutsui }
1706 1.119.10.2 tsutsui
1707 1.119.10.2 tsutsui /*
1708 1.119.10.2 tsutsui * device_is_a:
1709 1.119.10.2 tsutsui *
1710 1.119.10.2 tsutsui * Returns true if the device is an instance of the specified
1711 1.119.10.2 tsutsui * driver.
1712 1.119.10.2 tsutsui */
1713 1.119.10.2 tsutsui bool
1714 1.119.10.2 tsutsui device_is_a(device_t dev, const char *dname)
1715 1.119.10.2 tsutsui {
1716 1.119.10.2 tsutsui
1717 1.119.10.2 tsutsui return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
1718 1.119.10.2 tsutsui }
1719