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