The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_autoconf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: subr_autoconf.c,v 1.93 2005/02/26 21:34:55 perry Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1996, 2000 Christopher G. Demetriou
    5  * All rights reserved.
    6  *
    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:
   17  *          This product includes software developed for the
   18  *          NetBSD Project.  See http://www.NetBSD.org/ for
   19  *          information about NetBSD.
   20  * 4. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   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.
   33  *
   34  * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
   35  */
   36 
   37 /*
   38  * Copyright (c) 1992, 1993
   39  *      The Regents of the University of California.  All rights reserved.
   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  *
   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.
   58  * 3. Neither the name of the University nor the names of its contributors
   59  *    may be used to endorse or promote products derived from this software
   60  *    without specific prior written permission.
   61  *
   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.
   73  *
   74  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
   75  *
   76  *      @(#)subr_autoconf.c     8.3 (Berkeley) 5/17/94
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.93 2005/02/26 21:34:55 perry Exp $");
   81 
   82 #include "opt_ddb.h"
   83 
   84 #include <sys/param.h>
   85 #include <sys/device.h>
   86 #include <sys/malloc.h>
   87 #include <sys/systm.h>
   88 #include <sys/kernel.h>
   89 #include <sys/errno.h>
   90 #include <sys/proc.h>
   91 #include <sys/reboot.h>
   92 #include <machine/limits.h>
   93 
   94 #include "opt_userconf.h"
   95 #ifdef USERCONF
   96 #include <sys/userconf.h>
   97 #endif
   98 
   99 /*
  100  * Autoconfiguration subroutines.
  101  */
  102 
  103 /*
  104  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
  105  * devices and drivers are found via these tables.
  106  */
  107 extern struct cfdata cfdata[];
  108 extern const short cfroots[];
  109 
  110 /*
  111  * List of all cfdriver structures.  We use this to detect duplicates
  112  * when other cfdrivers are loaded.
  113  */
  114 struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
  115 extern struct cfdriver * const cfdriver_list_initial[];
  116 
  117 /*
  118  * Initial list of cfattach's.
  119  */
  120 extern const struct cfattachinit cfattachinit[];
  121 
  122 /*
  123  * List of cfdata tables.  We always have one such list -- the one
  124  * built statically when the kernel was configured.
  125  */
  126 struct cftablelist allcftables;
  127 static struct cftable initcftable;
  128 
  129 /*
  130  * Database of device properties.
  131  */
  132 propdb_t dev_propdb;
  133 
  134 #define ROOT ((struct device *)NULL)
  135 
  136 struct matchinfo {
  137         cfmatch_t fn;
  138         cfmatch_loc_t fn_loc;
  139         struct  device *parent;
  140         const locdesc_t *ldesc;
  141         void    *aux;
  142         struct  cfdata *match;
  143         int     pri;
  144 };
  145 
  146 static char *number(char *, int);
  147 static void mapply(struct matchinfo *, struct cfdata *);
  148 
  149 struct deferred_config {
  150         TAILQ_ENTRY(deferred_config) dc_queue;
  151         struct device *dc_dev;
  152         void (*dc_func)(struct device *);
  153 };
  154 
  155 TAILQ_HEAD(deferred_config_head, deferred_config);
  156 
  157 struct deferred_config_head deferred_config_queue;
  158 struct deferred_config_head interrupt_config_queue;
  159 
  160 static void config_process_deferred(struct deferred_config_head *,
  161         struct device *);
  162 
  163 /* Hooks to finalize configuration once all real devices have been found. */
  164 struct finalize_hook {
  165         TAILQ_ENTRY(finalize_hook) f_list;
  166         int (*f_func)(struct device *);
  167         struct device *f_dev;
  168 };
  169 static TAILQ_HEAD(, finalize_hook) config_finalize_list;
  170 static int config_finalize_done;
  171 
  172 /* list of all devices */
  173 struct devicelist alldevs;
  174 
  175 __volatile int config_pending;          /* semaphore for mountroot */
  176 
  177 #define STREQ(s1, s2)                   \
  178         (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
  179 
  180 static int config_initialized;          /* config_init() has been called. */
  181 
  182 static int config_do_twiddle;
  183 
  184 /*
  185  * Initialize the autoconfiguration data structures.  Normally this
  186  * is done by configure(), but some platforms need to do this very
  187  * early (to e.g. initialize the console).
  188  */
  189 void
  190 config_init(void)
  191 {
  192         const struct cfattachinit *cfai;
  193         int i, j;
  194 
  195         if (config_initialized)
  196                 return;
  197 
  198         /* allcfdrivers is statically initialized. */
  199         for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
  200                 if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
  201                         panic("configure: duplicate `%s' drivers",
  202                             cfdriver_list_initial[i]->cd_name);
  203         }
  204 
  205         for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
  206                 for (j = 0; cfai->cfai_list[j] != NULL; j++) {
  207                         if (config_cfattach_attach(cfai->cfai_name,
  208                                                    cfai->cfai_list[j]) != 0)
  209                                 panic("configure: duplicate `%s' attachment "
  210                                     "of `%s' driver",
  211                                     cfai->cfai_list[j]->ca_name,
  212                                     cfai->cfai_name);
  213                 }
  214         }
  215 
  216         TAILQ_INIT(&allcftables);
  217         initcftable.ct_cfdata = cfdata;
  218         TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
  219 
  220         TAILQ_INIT(&deferred_config_queue);
  221         TAILQ_INIT(&interrupt_config_queue);
  222         TAILQ_INIT(&config_finalize_list);
  223         TAILQ_INIT(&alldevs);
  224 
  225         config_initialized = 1;
  226 }
  227 
  228 /*
  229  * Configure the system's hardware.
  230  */
  231 void
  232 configure(void)
  233 {
  234         int errcnt;
  235 
  236         /* Initialize data structures. */
  237         config_init();
  238 
  239         /* Initialize the device property database. */
  240         dev_propdb = propdb_create("device properties");
  241         if (dev_propdb == NULL)
  242                 panic("unable to create device property database");
  243 
  244 #ifdef USERCONF
  245         if (boothowto & RB_USERCONF)
  246                 user_config();
  247 #endif
  248 
  249         if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
  250                 config_do_twiddle = 1;
  251                 printf_nolog("Detecting hardware...");
  252         }
  253 
  254         /*
  255          * Do the machine-dependent portion of autoconfiguration.  This
  256          * sets the configuration machinery here in motion by "finding"
  257          * the root bus.  When this function returns, we expect interrupts
  258          * to be enabled.
  259          */
  260         cpu_configure();
  261 
  262         /*
  263          * Now that we've found all the hardware, start the real time
  264          * and statistics clocks.
  265          */
  266         initclocks();
  267 
  268         cold = 0;       /* clocks are running, we're warm now! */
  269 
  270         /*
  271          * Now callback to finish configuration for devices which want
  272          * to do this once interrupts are enabled.
  273          */
  274         config_process_deferred(&interrupt_config_queue, NULL);
  275 
  276         errcnt = aprint_get_error_count();
  277         if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
  278             (boothowto & AB_VERBOSE) == 0) {
  279                 if (config_do_twiddle) {
  280                         config_do_twiddle = 0;
  281                         printf_nolog("done.\n");
  282                 }
  283                 if (errcnt != 0) {
  284                         printf("WARNING: %d error%s while detecting hardware; "
  285                             "check system log.\n", errcnt,
  286                             errcnt == 1 ? "" : "s");
  287                 }
  288         }
  289 }
  290 
  291 /*
  292  * Add a cfdriver to the system.
  293  */
  294 int
  295 config_cfdriver_attach(struct cfdriver *cd)
  296 {
  297         struct cfdriver *lcd;
  298 
  299         /* Make sure this driver isn't already in the system. */
  300         LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
  301                 if (STREQ(lcd->cd_name, cd->cd_name))
  302                         return (EEXIST);
  303         }
  304 
  305         LIST_INIT(&cd->cd_attach);
  306         LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
  307 
  308         return (0);
  309 }
  310 
  311 /*
  312  * Remove a cfdriver from the system.
  313  */
  314 int
  315 config_cfdriver_detach(struct cfdriver *cd)
  316 {
  317         int i;
  318 
  319         /* Make sure there are no active instances. */
  320         for (i = 0; i < cd->cd_ndevs; i++) {
  321                 if (cd->cd_devs[i] != NULL)
  322                         return (EBUSY);
  323         }
  324 
  325         /* ...and no attachments loaded. */
  326         if (LIST_EMPTY(&cd->cd_attach) == 0)
  327                 return (EBUSY);
  328 
  329         LIST_REMOVE(cd, cd_list);
  330 
  331         KASSERT(cd->cd_devs == NULL);
  332 
  333         return (0);
  334 }
  335 
  336 /*
  337  * Look up a cfdriver by name.
  338  */
  339 struct cfdriver *
  340 config_cfdriver_lookup(const char *name)
  341 {
  342         struct cfdriver *cd;
  343 
  344         LIST_FOREACH(cd, &allcfdrivers, cd_list) {
  345                 if (STREQ(cd->cd_name, name))
  346                         return (cd);
  347         }
  348 
  349         return (NULL);
  350 }
  351 
  352 /*
  353  * Add a cfattach to the specified driver.
  354  */
  355 int
  356 config_cfattach_attach(const char *driver, struct cfattach *ca)
  357 {
  358         struct cfattach *lca;
  359         struct cfdriver *cd;
  360 
  361         cd = config_cfdriver_lookup(driver);
  362         if (cd == NULL)
  363                 return (ESRCH);
  364 
  365         /* Make sure this attachment isn't already on this driver. */
  366         LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
  367                 if (STREQ(lca->ca_name, ca->ca_name))
  368                         return (EEXIST);
  369         }
  370 
  371         LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
  372 
  373         return (0);
  374 }
  375 
  376 /*
  377  * Remove a cfattach from the specified driver.
  378  */
  379 int
  380 config_cfattach_detach(const char *driver, struct cfattach *ca)
  381 {
  382         struct cfdriver *cd;
  383         struct device *dev;
  384         int i;
  385 
  386         cd = config_cfdriver_lookup(driver);
  387         if (cd == NULL)
  388                 return (ESRCH);
  389 
  390         /* Make sure there are no active instances. */
  391         for (i = 0; i < cd->cd_ndevs; i++) {
  392                 if ((dev = cd->cd_devs[i]) == NULL)
  393                         continue;
  394                 if (dev->dv_cfattach == ca)
  395                         return (EBUSY);
  396         }
  397 
  398         LIST_REMOVE(ca, ca_list);
  399 
  400         return (0);
  401 }
  402 
  403 /*
  404  * Look up a cfattach by name.
  405  */
  406 static struct cfattach *
  407 config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
  408 {
  409         struct cfattach *ca;
  410 
  411         LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
  412                 if (STREQ(ca->ca_name, atname))
  413                         return (ca);
  414         }
  415 
  416         return (NULL);
  417 }
  418 
  419 /*
  420  * Look up a cfattach by driver/attachment name.
  421  */
  422 struct cfattach *
  423 config_cfattach_lookup(const char *name, const char *atname)
  424 {
  425         struct cfdriver *cd;
  426 
  427         cd = config_cfdriver_lookup(name);
  428         if (cd == NULL)
  429                 return (NULL);
  430 
  431         return (config_cfattach_lookup_cd(cd, atname));
  432 }
  433 
  434 /*
  435  * Apply the matching function and choose the best.  This is used
  436  * a few times and we want to keep the code small.
  437  */
  438 static void
  439 mapply(struct matchinfo *m, struct cfdata *cf)
  440 {
  441         int pri;
  442 
  443         if (m->fn != NULL) {
  444                 KASSERT(m->fn_loc == NULL);
  445                 pri = (*m->fn)(m->parent, cf, m->aux);
  446         } else if (m->fn_loc != NULL) {
  447                 pri = (*m->fn_loc)(m->parent, cf, m->ldesc, m->aux);
  448         } else {
  449                 struct cfattach *ca;
  450 
  451                 ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
  452                 if (ca == NULL) {
  453                         /* No attachment for this entry, oh well. */
  454                         return;
  455                 }
  456                 if (ca->ca_match == NULL) {
  457                         panic("mapply: no match function for '%s' attachment "
  458                             "of '%s'", cf->cf_atname, cf->cf_name);
  459                 }
  460                 pri = (*ca->ca_match)(m->parent, cf, m->aux);
  461         }
  462         if (pri > m->pri) {
  463                 m->match = cf;
  464                 m->pri = pri;
  465         }
  466 }
  467 
  468 /*
  469  * Helper function: check whether the driver supports the interface attribute.
  470  */
  471 static int
  472 cfdriver_has_iattr(const struct cfdriver *cd, const char *ia)
  473 {
  474         const char * const *cpp;
  475 
  476         if (cd->cd_attrs == NULL)
  477                 return (0);
  478 
  479         for (cpp = cd->cd_attrs; *cpp; cpp++) {
  480                 if (STREQ(*cpp, ia)) {
  481                         /* Match. */
  482                         return (1);
  483                 }
  484         }
  485         return (0);
  486 }
  487 
  488 /*
  489  * Determine if `parent' is a potential parent for a device spec based
  490  * on `cfp'.
  491  */
  492 static int
  493 cfparent_match(const struct device *parent, const struct cfparent *cfp)
  494 {
  495         struct cfdriver *pcd;
  496 
  497         /* We don't match root nodes here. */
  498         if (cfp == NULL)
  499                 return (0);
  500 
  501         pcd = parent->dv_cfdriver;
  502         KASSERT(pcd != NULL);
  503 
  504         /*
  505          * First, ensure this parent has the correct interface
  506          * attribute.
  507          */
  508         if (!cfdriver_has_iattr(pcd, cfp->cfp_iattr))
  509                 return (0);
  510 
  511         /*
  512          * If no specific parent device instance was specified (i.e.
  513          * we're attaching to the attribute only), we're done!
  514          */
  515         if (cfp->cfp_parent == NULL)
  516                 return (1);
  517 
  518         /*
  519          * Check the parent device's name.
  520          */
  521         if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
  522                 return (0);     /* not the same parent */
  523 
  524         /*
  525          * Make sure the unit number matches.
  526          */
  527         if (cfp->cfp_unit == DVUNIT_ANY ||      /* wildcard */
  528             cfp->cfp_unit == parent->dv_unit)
  529                 return (1);
  530 
  531         /* Unit numbers don't match. */
  532         return (0);
  533 }
  534 
  535 /*
  536  * Helper for config_cfdata_attach(): check all devices whether it could be
  537  * parent any attachment in the config data table passed, and rescan.
  538  */
  539 static void
  540 rescan_with_cfdata(const struct cfdata *cf)
  541 {
  542         struct device *d;
  543         const struct cfdata *cf1;
  544 
  545         /*
  546          * "alldevs" is likely longer than an LKM's cfdata, so make it
  547          * the outer loop.
  548          */
  549         TAILQ_FOREACH(d, &alldevs, dv_list) {
  550 
  551                 if (!(d->dv_cfattach->ca_rescan))
  552                         continue;
  553 
  554                 for (cf1 = cf; cf1->cf_name; cf1++) {
  555 
  556                         if (!cfparent_match(d, cf1->cf_pspec))
  557                                 continue;
  558 
  559                         (*d->dv_cfattach->ca_rescan)(d,
  560                                 cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
  561                 }
  562         }
  563 }
  564 
  565 /*
  566  * Attach a supplemental config data table and rescan potential
  567  * parent devices if required.
  568  */
  569 int
  570 config_cfdata_attach(struct cfdata *cf, int scannow)
  571 {
  572         struct cftable *ct;
  573 
  574         ct = malloc(sizeof(struct cftable), M_DEVBUF, M_WAITOK);
  575         ct->ct_cfdata = cf;
  576         TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
  577 
  578         if (scannow)
  579                 rescan_with_cfdata(cf);
  580 
  581         return (0);
  582 }
  583 
  584 /*
  585  * Helper for config_cfdata_detach: check whether a device is
  586  * found through any attachment in the config data table.
  587  */
  588 static int
  589 dev_in_cfdata(const struct device *d, const struct cfdata *cf)
  590 {
  591         const struct cfdata *cf1;
  592 
  593         for (cf1 = cf; cf1->cf_name; cf1++)
  594                 if (d->dv_cfdata == cf1)
  595                         return (1);
  596 
  597         return (0);
  598 }
  599 
  600 /*
  601  * Detach a supplemental config data table. Detach all devices found
  602  * through that table (and thus keeping references to it) before.
  603  */
  604 int
  605 config_cfdata_detach(struct cfdata *cf)
  606 {
  607         struct device *d;
  608         int error;
  609         struct cftable *ct;
  610 
  611 again:
  612         TAILQ_FOREACH(d, &alldevs, dv_list) {
  613                 if (dev_in_cfdata(d, cf)) {
  614                         error = config_detach(d, 0);
  615                         if (error) {
  616                                 aprint_error("%s: unable to detach instance\n",
  617                                         d->dv_xname);
  618                                 return (error);
  619                         }
  620                         goto again;
  621                 }
  622         }
  623 
  624         TAILQ_FOREACH(ct, &allcftables, ct_list) {
  625                 if (ct->ct_cfdata == cf) {
  626                         TAILQ_REMOVE(&allcftables, ct, ct_list);
  627                         free(ct, M_DEVBUF);
  628                         return (0);
  629                 }
  630         }
  631 
  632         /* not found -- shouldn't happen */
  633         return (EINVAL);
  634 }
  635 
  636 /*
  637  * Invoke the "match" routine for a cfdata entry on behalf of
  638  * an external caller, usually a "submatch" routine.
  639  */
  640 int
  641 config_match(struct device *parent, struct cfdata *cf, void *aux)
  642 {
  643         struct cfattach *ca;
  644 
  645         ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
  646         if (ca == NULL) {
  647                 /* No attachment for this entry, oh well. */
  648                 return (0);
  649         }
  650 
  651         return ((*ca->ca_match)(parent, cf, aux));
  652 }
  653 
  654 /*
  655  * Iterate over all potential children of some device, calling the given
  656  * function (default being the child's match function) for each one.
  657  * Nonzero returns are matches; the highest value returned is considered
  658  * the best match.  Return the `found child' if we got a match, or NULL
  659  * otherwise.  The `aux' pointer is simply passed on through.
  660  *
  661  * Note that this function is designed so that it can be used to apply
  662  * an arbitrary function to all potential children (its return value
  663  * can be ignored).
  664  */
  665 struct cfdata *
  666 config_search(cfmatch_t fn, struct device *parent, void *aux)
  667 {
  668         struct cftable *ct;
  669         struct cfdata *cf;
  670         struct matchinfo m;
  671 
  672         KASSERT(config_initialized);
  673 
  674         m.fn = fn;
  675         m.fn_loc = NULL;
  676         m.parent = parent;
  677         m.aux = aux;
  678         m.match = NULL;
  679         m.pri = 0;
  680 
  681         TAILQ_FOREACH(ct, &allcftables, ct_list) {
  682                 for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
  683                         /*
  684                          * Skip cf if no longer eligible, otherwise scan
  685                          * through parents for one matching `parent', and
  686                          * try match function.
  687                          */
  688                         if (cf->cf_fstate == FSTATE_FOUND)
  689                                 continue;
  690                         if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  691                             cf->cf_fstate == FSTATE_DSTAR)
  692                                 continue;
  693                         if (cfparent_match(parent, cf->cf_pspec))
  694                                 mapply(&m, cf);
  695                 }
  696         }
  697         return (m.match);
  698 }
  699 
  700 /* same as above, with real locators passed */
  701 struct cfdata *
  702 config_search_loc(cfmatch_loc_t fn, struct device *parent,
  703                   const char *ifattr, const locdesc_t *ldesc, void *aux)
  704 {
  705         struct cftable *ct;
  706         struct cfdata *cf;
  707         struct matchinfo m;
  708 
  709         KASSERT(config_initialized);
  710         KASSERT(!ifattr || cfdriver_has_iattr(parent->dv_cfdriver, ifattr));
  711 
  712         m.fn = NULL;
  713         m.fn_loc = fn;
  714         m.parent = parent;
  715         m.ldesc = ldesc;
  716         m.aux = aux;
  717         m.match = NULL;
  718         m.pri = 0;
  719 
  720         TAILQ_FOREACH(ct, &allcftables, ct_list) {
  721                 for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
  722 
  723                         /* We don't match root nodes here. */
  724                         if (!cf->cf_pspec)
  725                                 continue;
  726 
  727                         /*
  728                          * Skip cf if no longer eligible, otherwise scan
  729                          * through parents for one matching `parent', and
  730                          * try match function.
  731                          */
  732                         if (cf->cf_fstate == FSTATE_FOUND)
  733                                 continue;
  734                         if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  735                             cf->cf_fstate == FSTATE_DSTAR)
  736                                 continue;
  737 
  738                         /*
  739                          * If an interface attribute was specified,
  740                          * consider only children which attach to
  741                          * that attribute.
  742                          */
  743                         if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
  744                                 continue;
  745 
  746                         if (cfparent_match(parent, cf->cf_pspec))
  747                                 mapply(&m, cf);
  748                 }
  749         }
  750         return (m.match);
  751 }
  752 
  753 /*
  754  * Find the given root device.
  755  * This is much like config_search, but there is no parent.
  756  * Don't bother with multiple cfdata tables; the root node
  757  * must always be in the initial table.
  758  */
  759 struct cfdata *
  760 config_rootsearch(cfmatch_t fn, const char *rootname, void *aux)
  761 {
  762         struct cfdata *cf;
  763         const short *p;
  764         struct matchinfo m;
  765 
  766         m.fn = fn;
  767         m.fn_loc = NULL;
  768         m.parent = ROOT;
  769         m.aux = aux;
  770         m.match = NULL;
  771         m.pri = 0;
  772         /*
  773          * Look at root entries for matching name.  We do not bother
  774          * with found-state here since only one root should ever be
  775          * searched (and it must be done first).
  776          */
  777         for (p = cfroots; *p >= 0; p++) {
  778                 cf = &cfdata[*p];
  779                 if (strcmp(cf->cf_name, rootname) == 0)
  780                         mapply(&m, cf);
  781         }
  782         return (m.match);
  783 }
  784 
  785 static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
  786 
  787 /*
  788  * The given `aux' argument describes a device that has been found
  789  * on the given parent, but not necessarily configured.  Locate the
  790  * configuration data for that device (using the submatch function
  791  * provided, or using candidates' cd_match configuration driver
  792  * functions) and attach it, and return true.  If the device was
  793  * not configured, call the given `print' function and return 0.
  794  */
  795 struct device *
  796 config_found_sm(struct device *parent, void *aux, cfprint_t print,
  797     cfmatch_t submatch)
  798 {
  799         struct cfdata *cf;
  800 
  801         if ((cf = config_search(submatch, parent, aux)) != NULL)
  802                 return (config_attach(parent, cf, aux, print));
  803         if (print) {
  804                 if (config_do_twiddle)
  805                         twiddle();
  806                 aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
  807         }
  808         return (NULL);
  809 }
  810 
  811 /* same as above, with real locators passed */
  812 struct device *
  813 config_found_sm_loc(struct device *parent,
  814                 const char *ifattr, const locdesc_t *ldesc, void *aux,
  815                 cfprint_t print, cfmatch_loc_t submatch)
  816 {
  817         struct cfdata *cf;
  818 
  819         if ((cf = config_search_loc(submatch, parent, ifattr, ldesc, aux)))
  820                 return(config_attach_loc(parent, cf, ldesc, aux, print));
  821         if (print) {
  822                 if (config_do_twiddle)
  823                         twiddle();
  824                 aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
  825         }
  826         return (NULL);
  827 }
  828 
  829 /*
  830  * As above, but for root devices.
  831  */
  832 struct device *
  833 config_rootfound(const char *rootname, void *aux)
  834 {
  835         struct cfdata *cf;
  836 
  837         if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
  838                 return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
  839         aprint_error("root device %s not configured\n", rootname);
  840         return (NULL);
  841 }
  842 
  843 /* just like sprintf(buf, "%d") except that it works from the end */
  844 static char *
  845 number(char *ep, int n)
  846 {
  847 
  848         *--ep = 0;
  849         while (n >= 10) {
  850                 *--ep = (n % 10) + '';
  851                 n /= 10;
  852         }
  853         *--ep = n + '';
  854         return (ep);
  855 }
  856 
  857 /*
  858  * Expand the size of the cd_devs array if necessary.
  859  */
  860 void
  861 config_makeroom(int n, struct cfdriver *cd)
  862 {
  863         int old, new;
  864         void **nsp;
  865 
  866         if (n < cd->cd_ndevs)
  867                 return;
  868 
  869         /*
  870          * Need to expand the array.
  871          */
  872         old = cd->cd_ndevs;
  873         if (old == 0)
  874                 new = MINALLOCSIZE / sizeof(void *);
  875         else
  876                 new = old * 2;
  877         while (new <= n)
  878                 new *= 2;
  879         cd->cd_ndevs = new;
  880         nsp = malloc(new * sizeof(void *), M_DEVBUF,
  881             cold ? M_NOWAIT : M_WAITOK);
  882         if (nsp == NULL)
  883                 panic("config_attach: %sing dev array",
  884                     old != 0 ? "expand" : "creat");
  885         memset(nsp + old, 0, (new - old) * sizeof(void *));
  886         if (old != 0) {
  887                 memcpy(nsp, cd->cd_devs, old * sizeof(void *));
  888                 free(cd->cd_devs, M_DEVBUF);
  889         }
  890         cd->cd_devs = nsp;
  891 }
  892 
  893 /*
  894  * Attach a found device.  Allocates memory for device variables.
  895  */
  896 struct device *
  897 config_attach_loc(struct device *parent, struct cfdata *cf,
  898         const locdesc_t *ldesc, void *aux, cfprint_t print)
  899 {
  900         struct device *dev;
  901         struct cftable *ct;
  902         struct cfdriver *cd;
  903         struct cfattach *ca;
  904         size_t lname, lunit;
  905         const char *xunit;
  906         int myunit;
  907         char num[10];
  908 
  909         cd = config_cfdriver_lookup(cf->cf_name);
  910         KASSERT(cd != NULL);
  911 
  912         ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
  913         KASSERT(ca != NULL);
  914 
  915         if (ca->ca_devsize < sizeof(struct device))
  916                 panic("config_attach");
  917 
  918 #ifndef __BROKEN_CONFIG_UNIT_USAGE
  919         if (cf->cf_fstate == FSTATE_STAR) {
  920                 for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
  921                         if (cd->cd_devs[myunit] == NULL)
  922                                 break;
  923                 /*
  924                  * myunit is now the unit of the first NULL device pointer,
  925                  * or max(cd->cd_ndevs,cf->cf_unit).
  926                  */
  927         } else {
  928                 myunit = cf->cf_unit;
  929                 KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
  930                 cf->cf_fstate = FSTATE_FOUND;
  931         }
  932 #else
  933         myunit = cf->cf_unit;
  934         if (cf->cf_fstate == FSTATE_STAR)
  935                 cf->cf_unit++;
  936         else {
  937                 KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
  938                 cf->cf_fstate = FSTATE_FOUND;
  939         }
  940 #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
  941 
  942         /* compute length of name and decimal expansion of unit number */
  943         lname = strlen(cd->cd_name);
  944         xunit = number(&num[sizeof(num)], myunit);
  945         lunit = &num[sizeof(num)] - xunit;
  946         if (lname + lunit > sizeof(dev->dv_xname))
  947                 panic("config_attach: device name too long");
  948 
  949         /* get memory for all device vars */
  950         dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF,
  951             cold ? M_NOWAIT : M_WAITOK);
  952         if (!dev)
  953             panic("config_attach: memory allocation for device softc failed");
  954         memset(dev, 0, ca->ca_devsize);
  955         TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);      /* link up */
  956         dev->dv_class = cd->cd_class;
  957         dev->dv_cfdata = cf;
  958         dev->dv_cfdriver = cd;
  959         dev->dv_cfattach = ca;
  960         dev->dv_unit = myunit;
  961         memcpy(dev->dv_xname, cd->cd_name, lname);
  962         memcpy(dev->dv_xname + lname, xunit, lunit);
  963         dev->dv_parent = parent;
  964         dev->dv_flags = DVF_ACTIVE;     /* always initially active */
  965         if (ldesc) {
  966                 dev->dv_locators = malloc(ldesc->len * sizeof(int),
  967                                           M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
  968                 memcpy(dev->dv_locators, ldesc->locs, ldesc->len * sizeof(int));
  969         }
  970 
  971         if (config_do_twiddle)
  972                 twiddle();
  973         else
  974                 aprint_naive("Found ");
  975         /*
  976          * We want the next two printfs for normal, verbose, and quiet,
  977          * but not silent (in which case, we're twiddling, instead).
  978          */
  979         if (parent == ROOT) {
  980                 aprint_naive("%s (root)", dev->dv_xname);
  981                 aprint_normal("%s (root)", dev->dv_xname);
  982         } else {
  983                 aprint_naive("%s at %s", dev->dv_xname, parent->dv_xname);
  984                 aprint_normal("%s at %s", dev->dv_xname, parent->dv_xname);
  985                 if (print)
  986                         (void) (*print)(aux, NULL);
  987         }
  988 
  989         /* put this device in the devices array */
  990         config_makeroom(dev->dv_unit, cd);
  991         if (cd->cd_devs[dev->dv_unit])
  992                 panic("config_attach: duplicate %s", dev->dv_xname);
  993         cd->cd_devs[dev->dv_unit] = dev;
  994 
  995         /*
  996          * Before attaching, clobber any unfound devices that are
  997          * otherwise identical.
  998          */
  999         TAILQ_FOREACH(ct, &allcftables, ct_list) {
 1000                 for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
 1001                         if (STREQ(cf->cf_name, cd->cd_name) &&
 1002                             cf->cf_unit == dev->dv_unit) {
 1003                                 if (cf->cf_fstate == FSTATE_NOTFOUND)
 1004                                         cf->cf_fstate = FSTATE_FOUND;
 1005 #ifdef __BROKEN_CONFIG_UNIT_USAGE
 1006                                 /*
 1007                                  * Bump the unit number on all starred cfdata
 1008                                  * entries for this device.
 1009                                  */
 1010                                 if (cf->cf_fstate == FSTATE_STAR)
 1011                                         cf->cf_unit++;
 1012 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
 1013                         }
 1014                 }
 1015         }
 1016 #ifdef __HAVE_DEVICE_REGISTER
 1017         device_register(dev, aux);
 1018 #endif
 1019         (*ca->ca_attach)(parent, dev, aux);
 1020         config_process_deferred(&deferred_config_queue, dev);
 1021         return (dev);
 1022 }
 1023 
 1024 /*
 1025  * As above, but for pseudo-devices.  Pseudo-devices attached in this
 1026  * way are silently inserted into the device tree, and their children
 1027  * attached.
 1028  *
 1029  * Note that because pseudo-devices are attached silently, any information
 1030  * the attach routine wishes to print should be prefixed with the device
 1031  * name by the attach routine.
 1032  */
 1033 struct device *
 1034 config_attach_pseudo(struct cfdata *cf)
 1035 {
 1036         struct device *dev;
 1037         struct cfdriver *cd;
 1038         struct cfattach *ca;
 1039         size_t lname, lunit;
 1040         const char *xunit;
 1041         int myunit;
 1042         char num[10];
 1043 
 1044         cd = config_cfdriver_lookup(cf->cf_name);
 1045         if (cd == NULL)
 1046                 return (NULL);
 1047 
 1048         ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
 1049         if (ca == NULL)
 1050                 return (NULL);
 1051 
 1052         if (ca->ca_devsize < sizeof(struct device))
 1053                 panic("config_attach_pseudo");
 1054 
 1055         /*
 1056          * We just ignore cf_fstate, instead doing everything with
 1057          * cf_unit.
 1058          *
 1059          * XXX Should we change this and use FSTATE_NOTFOUND and
 1060          * XXX FSTATE_STAR?
 1061          */
 1062 
 1063         if (cf->cf_unit == DVUNIT_ANY) {
 1064                 for (myunit = 0; myunit < cd->cd_ndevs; myunit++)
 1065                         if (cd->cd_devs[myunit] == NULL)
 1066                                 break;
 1067                 /*
 1068                  * myunit is now the unit of the first NULL device pointer.
 1069                  */
 1070         } else {
 1071                 myunit = cf->cf_unit;
 1072                 if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
 1073                         return (NULL);
 1074         }
 1075 
 1076         /* compute length of name and decimal expansion of unit number */
 1077         lname = strlen(cd->cd_name);
 1078         xunit = number(&num[sizeof(num)], myunit);
 1079         lunit = &num[sizeof(num)] - xunit;
 1080         if (lname + lunit > sizeof(dev->dv_xname))
 1081                 panic("config_attach_pseudo: device name too long");
 1082 
 1083         /* get memory for all device vars */
 1084         dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF,
 1085             cold ? M_NOWAIT : M_WAITOK);
 1086         if (!dev)
 1087                 panic("config_attach_pseudo: memory allocation for device "
 1088                     "softc failed");
 1089         memset(dev, 0, ca->ca_devsize);
 1090         TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);      /* link up */
 1091         dev->dv_class = cd->cd_class;
 1092         dev->dv_cfdata = cf;
 1093         dev->dv_cfdriver = cd;
 1094         dev->dv_cfattach = ca;
 1095         dev->dv_unit = myunit;
 1096         memcpy(dev->dv_xname, cd->cd_name, lname);
 1097         memcpy(dev->dv_xname + lname, xunit, lunit);
 1098         dev->dv_parent = ROOT;
 1099         dev->dv_flags = DVF_ACTIVE;     /* always initially active */
 1100 
 1101         /* put this device in the devices array */
 1102         config_makeroom(dev->dv_unit, cd);
 1103         if (cd->cd_devs[dev->dv_unit])
 1104                 panic("config_attach_pseudo: duplicate %s", dev->dv_xname);
 1105         cd->cd_devs[dev->dv_unit] = dev;
 1106 
 1107 #if 0   /* XXXJRT not yet */
 1108 #ifdef __HAVE_DEVICE_REGISTER
 1109         device_register(dev, NULL);     /* like a root node */
 1110 #endif
 1111 #endif
 1112         (*ca->ca_attach)(ROOT, dev, NULL);
 1113         config_process_deferred(&deferred_config_queue, dev);
 1114         return (dev);
 1115 }
 1116 
 1117 /*
 1118  * Detach a device.  Optionally forced (e.g. because of hardware
 1119  * removal) and quiet.  Returns zero if successful, non-zero
 1120  * (an error code) otherwise.
 1121  *
 1122  * Note that this code wants to be run from a process context, so
 1123  * that the detach can sleep to allow processes which have a device
 1124  * open to run and unwind their stacks.
 1125  */
 1126 int
 1127 config_detach(struct device *dev, int flags)
 1128 {
 1129         struct cftable *ct;
 1130         struct cfdata *cf;
 1131         const struct cfattach *ca;
 1132         struct cfdriver *cd;
 1133 #ifdef DIAGNOSTIC
 1134         struct device *d;
 1135 #endif
 1136         int rv = 0, i;
 1137 
 1138 #ifdef DIAGNOSTIC
 1139         if (dev->dv_cfdata != NULL &&
 1140             dev->dv_cfdata->cf_fstate != FSTATE_FOUND &&
 1141             dev->dv_cfdata->cf_fstate != FSTATE_STAR)
 1142                 panic("config_detach: bad device fstate");
 1143 #endif
 1144         cd = dev->dv_cfdriver;
 1145         KASSERT(cd != NULL);
 1146 
 1147         ca = dev->dv_cfattach;
 1148         KASSERT(ca != NULL);
 1149 
 1150         /*
 1151          * Ensure the device is deactivated.  If the device doesn't
 1152          * have an activation entry point, we allow DVF_ACTIVE to
 1153          * remain set.  Otherwise, if DVF_ACTIVE is still set, the
 1154          * device is busy, and the detach fails.
 1155          */
 1156         if (ca->ca_activate != NULL)
 1157                 rv = config_deactivate(dev);
 1158 
 1159         /*
 1160          * Try to detach the device.  If that's not possible, then
 1161          * we either panic() (for the forced but failed case), or
 1162          * return an error.
 1163          */
 1164         if (rv == 0) {
 1165                 if (ca->ca_detach != NULL)
 1166                         rv = (*ca->ca_detach)(dev, flags);
 1167                 else
 1168                         rv = EOPNOTSUPP;
 1169         }
 1170         if (rv != 0) {
 1171                 if ((flags & DETACH_FORCE) == 0)
 1172                         return (rv);
 1173                 else
 1174                         panic("config_detach: forced detach of %s failed (%d)",
 1175                             dev->dv_xname, rv);
 1176         }
 1177 
 1178         /*
 1179          * The device has now been successfully detached.
 1180          */
 1181 
 1182 #ifdef DIAGNOSTIC
 1183         /*
 1184          * Sanity: If you're successfully detached, you should have no
 1185          * children.  (Note that because children must be attached
 1186          * after parents, we only need to search the latter part of
 1187          * the list.)
 1188          */
 1189         for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
 1190             d = TAILQ_NEXT(d, dv_list)) {
 1191                 if (d->dv_parent == dev) {
 1192                         printf("config_detach: detached device %s"
 1193                             " has children %s\n", dev->dv_xname, d->dv_xname);
 1194                         panic("config_detach");
 1195                 }
 1196         }
 1197 #endif
 1198 
 1199         /* notify the parent that the child is gone */
 1200         if (dev->dv_parent) {
 1201                 struct device *p = dev->dv_parent;
 1202                 if (p->dv_cfattach->ca_childdetached)
 1203                         (*p->dv_cfattach->ca_childdetached)(p, dev);
 1204         }
 1205 
 1206         /*
 1207          * Mark cfdata to show that the unit can be reused, if possible.
 1208          */
 1209         TAILQ_FOREACH(ct, &allcftables, ct_list) {
 1210                 for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
 1211                         if (STREQ(cf->cf_name, cd->cd_name)) {
 1212                                 if (cf->cf_fstate == FSTATE_FOUND &&
 1213                                     cf->cf_unit == dev->dv_unit)
 1214                                         cf->cf_fstate = FSTATE_NOTFOUND;
 1215 #ifdef __BROKEN_CONFIG_UNIT_USAGE
 1216                                 /*
 1217                                  * Note that we can only re-use a starred
 1218                                  * unit number if the unit being detached
 1219                                  * had the last assigned unit number.
 1220                                  */
 1221                                 if (cf->cf_fstate == FSTATE_STAR &&
 1222                                     cf->cf_unit == dev->dv_unit + 1)
 1223                                         cf->cf_unit--;
 1224 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
 1225                         }
 1226                 }
 1227         }
 1228 
 1229         /*
 1230          * Unlink from device list.
 1231          */
 1232         TAILQ_REMOVE(&alldevs, dev, dv_list);
 1233 
 1234         /*
 1235          * Remove from cfdriver's array, tell the world (unless it was
 1236          * a pseudo-device), and free softc.
 1237          */
 1238         cd->cd_devs[dev->dv_unit] = NULL;
 1239         if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
 1240                 aprint_normal("%s detached\n", dev->dv_xname);
 1241         if (dev->dv_locators)
 1242                 free(dev->dv_locators, M_DEVBUF);
 1243         free(dev, M_DEVBUF);
 1244 
 1245         /*
 1246          * If the device now has no units in use, deallocate its softc array.
 1247          */
 1248         for (i = 0; i < cd->cd_ndevs; i++)
 1249                 if (cd->cd_devs[i] != NULL)
 1250                         break;
 1251         if (i == cd->cd_ndevs) {                /* nothing found; deallocate */
 1252                 free(cd->cd_devs, M_DEVBUF);
 1253                 cd->cd_devs = NULL;
 1254                 cd->cd_ndevs = 0;
 1255         }
 1256 
 1257         /*
 1258          * Return success.
 1259          */
 1260         return (0);
 1261 }
 1262 
 1263 int
 1264 config_activate(struct device *dev)
 1265 {
 1266         const struct cfattach *ca = dev->dv_cfattach;
 1267         int rv = 0, oflags = dev->dv_flags;
 1268 
 1269         if (ca->ca_activate == NULL)
 1270                 return (EOPNOTSUPP);
 1271 
 1272         if ((dev->dv_flags & DVF_ACTIVE) == 0) {
 1273                 dev->dv_flags |= DVF_ACTIVE;
 1274                 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
 1275                 if (rv)
 1276                         dev->dv_flags = oflags;
 1277         }
 1278         return (rv);
 1279 }
 1280 
 1281 int
 1282 config_deactivate(struct device *dev)
 1283 {
 1284         const struct cfattach *ca = dev->dv_cfattach;
 1285         int rv = 0, oflags = dev->dv_flags;
 1286 
 1287         if (ca->ca_activate == NULL)
 1288                 return (EOPNOTSUPP);
 1289 
 1290         if (dev->dv_flags & DVF_ACTIVE) {
 1291                 dev->dv_flags &= ~DVF_ACTIVE;
 1292                 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
 1293                 if (rv)
 1294                         dev->dv_flags = oflags;
 1295         }
 1296         return (rv);
 1297 }
 1298 
 1299 /*
 1300  * Defer the configuration of the specified device until all
 1301  * of its parent's devices have been attached.
 1302  */
 1303 void
 1304 config_defer(struct device *dev, void (*func)(struct device *))
 1305 {
 1306         struct deferred_config *dc;
 1307 
 1308         if (dev->dv_parent == NULL)
 1309                 panic("config_defer: can't defer config of a root device");
 1310 
 1311 #ifdef DIAGNOSTIC
 1312         for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
 1313              dc = TAILQ_NEXT(dc, dc_queue)) {
 1314                 if (dc->dc_dev == dev)
 1315                         panic("config_defer: deferred twice");
 1316         }
 1317 #endif
 1318 
 1319         dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
 1320         if (dc == NULL)
 1321                 panic("config_defer: unable to allocate callback");
 1322 
 1323         dc->dc_dev = dev;
 1324         dc->dc_func = func;
 1325         TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
 1326         config_pending_incr();
 1327 }
 1328 
 1329 /*
 1330  * Defer some autoconfiguration for a device until after interrupts
 1331  * are enabled.
 1332  */
 1333 void
 1334 config_interrupts(struct device *dev, void (*func)(struct device *))
 1335 {
 1336         struct deferred_config *dc;
 1337 
 1338         /*
 1339          * If interrupts are enabled, callback now.
 1340          */
 1341         if (cold == 0) {
 1342                 (*func)(dev);
 1343                 return;
 1344         }
 1345 
 1346 #ifdef DIAGNOSTIC
 1347         for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
 1348              dc = TAILQ_NEXT(dc, dc_queue)) {
 1349                 if (dc->dc_dev == dev)
 1350                         panic("config_interrupts: deferred twice");
 1351         }
 1352 #endif
 1353 
 1354         dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
 1355         if (dc == NULL)
 1356                 panic("config_interrupts: unable to allocate callback");
 1357 
 1358         dc->dc_dev = dev;
 1359         dc->dc_func = func;
 1360         TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
 1361         config_pending_incr();
 1362 }
 1363 
 1364 /*
 1365  * Process a deferred configuration queue.
 1366  */
 1367 static void
 1368 config_process_deferred(struct deferred_config_head *queue,
 1369     struct device *parent)
 1370 {
 1371         struct deferred_config *dc, *ndc;
 1372 
 1373         for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
 1374                 ndc = TAILQ_NEXT(dc, dc_queue);
 1375                 if (parent == NULL || dc->dc_dev->dv_parent == parent) {
 1376                         TAILQ_REMOVE(queue, dc, dc_queue);
 1377                         (*dc->dc_func)(dc->dc_dev);
 1378                         free(dc, M_DEVBUF);
 1379                         config_pending_decr();
 1380                 }
 1381         }
 1382 }
 1383 
 1384 /*
 1385  * Manipulate the config_pending semaphore.
 1386  */
 1387 void
 1388 config_pending_incr(void)
 1389 {
 1390 
 1391         config_pending++;
 1392 }
 1393 
 1394 void
 1395 config_pending_decr(void)
 1396 {
 1397 
 1398 #ifdef DIAGNOSTIC
 1399         if (config_pending == 0)
 1400                 panic("config_pending_decr: config_pending == 0");
 1401 #endif
 1402         config_pending--;
 1403         if (config_pending == 0)
 1404                 wakeup((void *)&config_pending);
 1405 }
 1406 
 1407 /*
 1408  * Register a "finalization" routine.  Finalization routines are
 1409  * called iteratively once all real devices have been found during
 1410  * autoconfiguration, for as long as any one finalizer has done
 1411  * any work.
 1412  */
 1413 int
 1414 config_finalize_register(struct device *dev, int (*fn)(struct device *))
 1415 {
 1416         struct finalize_hook *f;
 1417 
 1418         /*
 1419          * If finalization has already been done, invoke the
 1420          * callback function now.
 1421          */
 1422         if (config_finalize_done) {
 1423                 while ((*fn)(dev) != 0)
 1424                         /* loop */ ;
 1425         }
 1426 
 1427         /* Ensure this isn't already on the list. */
 1428         TAILQ_FOREACH(f, &config_finalize_list, f_list) {
 1429                 if (f->f_func == fn && f->f_dev == dev)
 1430                         return (EEXIST);
 1431         }
 1432 
 1433         f = malloc(sizeof(*f), M_TEMP, M_WAITOK);
 1434         f->f_func = fn;
 1435         f->f_dev = dev;
 1436         TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
 1437 
 1438         return (0);
 1439 }
 1440 
 1441 void
 1442 config_finalize(void)
 1443 {
 1444         struct finalize_hook *f;
 1445         int rv;
 1446 
 1447         /* Run the hooks until none of them does any work. */
 1448         do {
 1449                 rv = 0;
 1450                 TAILQ_FOREACH(f, &config_finalize_list, f_list)
 1451                         rv |= (*f->f_func)(f->f_dev);
 1452         } while (rv != 0);
 1453 
 1454         config_finalize_done = 1;
 1455 
 1456         /* Now free all the hooks. */
 1457         while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
 1458                 TAILQ_REMOVE(&config_finalize_list, f, f_list);
 1459                 free(f, M_TEMP);
 1460         }
 1461 }
 1462 

Cache object: 9ff19a47b847f7165daeb72f403f199b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.