root/kern/subr_autoconf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TAILQ_HEAD
  2. mapply
  3. config_search
  4. config_scan
  5. config_rootsearch
  6. config_found_sm
  7. config_rootfound
  8. config_attach
  9. config_make_softc
  10. config_detach
  11. config_activate
  12. config_deactivate
  13. config_defer
  14. config_process_deferred_children
  15. config_pending_incr
  16. config_pending_decr
  17. config_detach_children
  18. config_activate_children
  19. device_lookup
  20. device_ref
  21. device_unref

    1 /*      $OpenBSD: subr_autoconf.c,v 1.52 2007/05/30 05:36:36 deraadt Exp $      */
    2 /*      $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1992, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This software was developed by the Computer Systems Engineering group
    9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   10  * contributed to Berkeley.
   11  *
   12  * All advertising materials mentioning features or use of this software
   13  * must display the following acknowledgement:
   14  *      This product includes software developed by the University of
   15  *      California, Lawrence Berkeley Laboratories.
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  * 3. Neither the name of the University nor the names of its contributors
   26  *    may be used to endorse or promote products derived from this software
   27  *    without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   39  * SUCH DAMAGE.
   40  *
   41  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
   42  *
   43  *      @(#)subr_autoconf.c     8.1 (Berkeley) 6/10/93
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/device.h>
   48 #include <sys/hotplug.h>
   49 #include <sys/limits.h>
   50 #include <sys/malloc.h>
   51 #include <sys/systm.h>
   52 /* Extra stuff from Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de> */
   53 #include <sys/queue.h>
   54 #include <sys/proc.h>
   55 
   56 #include "hotplug.h"
   57 
   58 /*
   59  * Autoconfiguration subroutines.
   60  */
   61 
   62 typedef int (*cond_predicate_t)(struct device *, void *);
   63 
   64 /*
   65  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
   66  * devices and drivers are found via these tables.
   67  */
   68 extern short cfroots[];
   69 
   70 #define ROOT ((struct device *)NULL)
   71 
   72 struct matchinfo {
   73         cfmatch_t fn;
   74         struct  device *parent;
   75         void    *match, *aux;
   76         int     indirect, pri;
   77 };
   78 
   79 struct cftable_head allcftables;
   80 
   81 static struct cftable staticcftable = {
   82         cfdata
   83 };
   84 
   85 #ifndef AUTOCONF_VERBOSE
   86 #define AUTOCONF_VERBOSE 0
   87 #endif /* AUTOCONF_VERBOSE */
   88 int autoconf_verbose = AUTOCONF_VERBOSE;        /* trace probe calls */
   89 
   90 static void mapply(struct matchinfo *, struct cfdata *);
   91 
   92 struct deferred_config {
   93         TAILQ_ENTRY(deferred_config) dc_queue;
   94         struct device *dc_dev;
   95         void (*dc_func)(struct device *);
   96 };
   97 
   98 TAILQ_HEAD(, deferred_config) deferred_config_queue;
   99 
  100 void config_process_deferred_children(struct device *);
  101 
  102 struct devicelist alldevs;              /* list of all devices */
  103 
  104 __volatile int config_pending;          /* semaphore for mountroot */
  105 
  106 /*
  107  * Initialize autoconfiguration data structures.  This occurs before console
  108  * initialization as that might require use of this subsystem.  Furthermore
  109  * this means that malloc et al. isn't yet available.
  110  */
  111 void
  112 config_init(void)
  113 {
  114         TAILQ_INIT(&deferred_config_queue);
  115         TAILQ_INIT(&alldevs);
  116         TAILQ_INIT(&allcftables);
  117         TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
  118 }
  119 
  120 /*
  121  * Apply the matching function and choose the best.  This is used
  122  * a few times and we want to keep the code small.
  123  */
  124 void
  125 mapply(struct matchinfo *m, struct cfdata *cf)
  126 {
  127         int pri;
  128         void *match;
  129 
  130         if (m->indirect)
  131                 match = config_make_softc(m->parent, cf);
  132         else
  133                 match = cf;
  134 
  135         if (autoconf_verbose) {
  136                 printf(">>> probing for %s", cf->cf_driver->cd_name);
  137                 if (cf->cf_fstate == FSTATE_STAR)
  138                         printf("*\n");
  139                 else
  140                         printf("%d\n", cf->cf_unit);
  141         }
  142         if (m->fn != NULL)
  143                 pri = (*m->fn)(m->parent, match, m->aux);
  144         else {
  145                 if (cf->cf_attach->ca_match == NULL) {
  146                         panic("mapply: no match function for '%s' device",
  147                             cf->cf_driver->cd_name);
  148                 }
  149                 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
  150         }
  151         if (autoconf_verbose)
  152                 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
  153                     pri);
  154 
  155         if (pri > m->pri) {
  156                 if (m->indirect && m->match)
  157                         free(m->match, M_DEVBUF);
  158                 m->match = match;
  159                 m->pri = pri;
  160         } else {
  161                 if (m->indirect)
  162                         free(match, M_DEVBUF);
  163         }
  164 }
  165 
  166 /*
  167  * Iterate over all potential children of some device, calling the given
  168  * function (default being the child's match function) for each one.
  169  * Nonzero returns are matches; the highest value returned is considered
  170  * the best match.  Return the `found child' if we got a match, or NULL
  171  * otherwise.  The `aux' pointer is simply passed on through.
  172  *
  173  * Note that this function is designed so that it can be used to apply
  174  * an arbitrary function to all potential children (its return value
  175  * can be ignored).
  176  */
  177 void *
  178 config_search(cfmatch_t fn, struct device *parent, void *aux)
  179 {
  180         struct cfdata *cf;
  181         short *p;
  182         struct matchinfo m;
  183         struct cftable *t;
  184 
  185         m.fn = fn;
  186         m.parent = parent;
  187         m.match = NULL;
  188         m.aux = aux;
  189         m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
  190         m.pri = 0;
  191         TAILQ_FOREACH(t, &allcftables, list) {
  192                 for (cf = t->tab; cf->cf_driver; cf++) {
  193                         /*
  194                          * Skip cf if no longer eligible, otherwise scan
  195                          * through parents for one matching `parent',
  196                          * and try match function.
  197                          */
  198                         if (cf->cf_fstate == FSTATE_FOUND)
  199                                 continue;
  200                         if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  201                             cf->cf_fstate == FSTATE_DSTAR)
  202                                 continue;
  203                         for (p = cf->cf_parents; *p >= 0; p++)
  204                                 if (parent->dv_cfdata == &(t->tab)[*p])
  205                                         mapply(&m, cf);
  206                 }
  207         }
  208         if (autoconf_verbose) {
  209                 if (m.match) {
  210                         if (m.indirect)
  211                                 cf = ((struct device *)m.match)->dv_cfdata;
  212                         else
  213                                 cf = (struct cfdata *)m.match;
  214                         printf(">>> %s probe won\n",
  215                             cf->cf_driver->cd_name);
  216                 } else
  217                         printf(">>> no winning probe\n");
  218         }
  219         return (m.match);
  220 }
  221 
  222 /*
  223  * Iterate over all potential children of some device, calling the given
  224  * function for each one.
  225  *
  226  * Note that this function is designed so that it can be used to apply
  227  * an arbitrary function to all potential children (its return value
  228  * can be ignored).
  229  */
  230 void
  231 config_scan(cfscan_t fn, struct device *parent)
  232 {
  233         struct cfdata *cf;
  234         short *p;
  235         void *match;
  236         int indirect;
  237         struct cftable *t;
  238 
  239         indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
  240         TAILQ_FOREACH(t, &allcftables, list) {
  241                 for (cf = t->tab; cf->cf_driver; cf++) {
  242                         /*
  243                          * Skip cf if no longer eligible, otherwise scan
  244                          * through parents for one matching `parent',
  245                          * and try match function.
  246                          */
  247                         if (cf->cf_fstate == FSTATE_FOUND)
  248                                 continue;
  249                         if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  250                             cf->cf_fstate == FSTATE_DSTAR)
  251                                 continue;
  252                         for (p = cf->cf_parents; *p >= 0; p++)
  253                                 if (parent->dv_cfdata == &(t->tab)[*p]) {
  254                                         match = indirect?
  255                                             config_make_softc(parent, cf) :
  256                                             (void *)cf;
  257                                         (*fn)(parent, match);
  258                                 }
  259                 }
  260         }
  261 }
  262 
  263 /*
  264  * Find the given root device.
  265  * This is much like config_search, but there is no parent.
  266  */
  267 void *
  268 config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
  269 {
  270         struct cfdata *cf;
  271         short *p;
  272         struct matchinfo m;
  273 
  274         m.fn = fn;
  275         m.parent = ROOT;
  276         m.match = NULL;
  277         m.aux = aux;
  278         m.indirect = 0;
  279         m.pri = 0;
  280         /*
  281          * Look at root entries for matching name.  We do not bother
  282          * with found-state here since only one root should ever be
  283          * searched (and it must be done first).
  284          */
  285         for (p = cfroots; *p >= 0; p++) {
  286                 cf = &cfdata[*p];
  287                 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
  288                         mapply(&m, cf);
  289         }
  290         return (m.match);
  291 }
  292 
  293 char *msgs[3] = { "", " not configured\n", " unsupported\n" };
  294 
  295 /*
  296  * The given `aux' argument describes a device that has been found
  297  * on the given parent, but not necessarily configured.  Locate the
  298  * configuration data for that device (using the submatch function
  299  * provided, or using candidates' cd_match configuration driver
  300  * functions) and attach it, and return true.  If the device was
  301  * not configured, call the given `print' function and return 0.
  302  */
  303 struct device *
  304 config_found_sm(struct device *parent, void *aux, cfprint_t print,
  305     cfmatch_t submatch)
  306 {
  307         void *match;
  308 
  309         if ((match = config_search(submatch, parent, aux)) != NULL)
  310                 return (config_attach(parent, match, aux, print));
  311         if (print)
  312                 printf(msgs[(*print)(aux, parent->dv_xname)]);
  313         return (NULL);
  314 }
  315 
  316 /*
  317  * As above, but for root devices.
  318  */
  319 struct device *
  320 config_rootfound(char *rootname, void *aux)
  321 {
  322         void *match;
  323 
  324         if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
  325                 return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
  326         printf("root device %s not configured\n", rootname);
  327         return (NULL);
  328 }
  329 
  330 /*
  331  * Attach a found device.  Allocates memory for device variables.
  332  */
  333 struct device *
  334 config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
  335 {
  336         struct cfdata *cf;
  337         struct device *dev;
  338         struct cfdriver *cd;
  339         struct cfattach *ca;
  340         struct cftable *t;
  341 
  342         if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
  343                 dev = match;
  344                 cf = dev->dv_cfdata;
  345         } else {
  346                 cf = match;
  347                 dev = config_make_softc(parent, cf);
  348         }
  349 
  350         cd = cf->cf_driver;
  351         ca = cf->cf_attach;
  352 
  353         cd->cd_devs[dev->dv_unit] = dev;
  354 
  355         /*
  356          * If this is a "STAR" device and we used the last unit, prepare for
  357          * another one.
  358          */
  359         if (cf->cf_fstate == FSTATE_STAR) {
  360                 if (dev->dv_unit == cf->cf_unit)
  361                         cf->cf_unit++;
  362         } else
  363                 cf->cf_fstate = FSTATE_FOUND;
  364 
  365         TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
  366         device_ref(dev);
  367 
  368         if (parent == ROOT)
  369                 printf("%s at root", dev->dv_xname);
  370         else {
  371                 printf("%s at %s", dev->dv_xname, parent->dv_xname);
  372                 if (print)
  373                         (void) (*print)(aux, (char *)0);
  374         }
  375 
  376         /*
  377          * Before attaching, clobber any unfound devices that are
  378          * otherwise identical, or bump the unit number on all starred
  379          * cfdata for this device.
  380          */
  381         TAILQ_FOREACH(t, &allcftables, list) {
  382                 for (cf = t->tab; cf->cf_driver; cf++)
  383                         if (cf->cf_driver == cd &&
  384                             cf->cf_unit == dev->dv_unit) {
  385                                 if (cf->cf_fstate == FSTATE_NOTFOUND)
  386                                         cf->cf_fstate = FSTATE_FOUND;
  387                                 if (cf->cf_fstate == FSTATE_STAR)
  388                                         cf->cf_unit++;
  389                         }
  390         }
  391         device_register(dev, aux);
  392         (*ca->ca_attach)(parent, dev, aux);
  393         config_process_deferred_children(dev);
  394 #if NHOTPLUG > 0
  395         if (!cold)
  396                 hotplug_device_attach(cd->cd_class, dev->dv_xname);
  397 #endif
  398         return (dev);
  399 }
  400 
  401 struct device *
  402 config_make_softc(struct device *parent, struct cfdata *cf)
  403 {
  404         struct device *dev;
  405         struct cfdriver *cd;
  406         struct cfattach *ca;
  407 
  408         cd = cf->cf_driver;
  409         ca = cf->cf_attach;
  410         if (ca->ca_devsize < sizeof(struct device))
  411                 panic("config_make_softc");
  412 
  413         /* get memory for all device vars */
  414         dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
  415         if (!dev)
  416                 panic("config_make_softc: allocation for device softc failed");
  417         bzero(dev, ca->ca_devsize);
  418         dev->dv_class = cd->cd_class;
  419         dev->dv_cfdata = cf;
  420         dev->dv_flags = DVF_ACTIVE;     /* always initially active */
  421 
  422         /* If this is a STAR device, search for a free unit number */
  423         if (cf->cf_fstate == FSTATE_STAR) {
  424                 for (dev->dv_unit = cf->cf_starunit1;
  425                     dev->dv_unit < cf->cf_unit; dev->dv_unit++)
  426                         if (cd->cd_ndevs == 0 ||
  427                             dev->dv_unit >= cd->cd_ndevs ||
  428                             cd->cd_devs[dev->dv_unit] == NULL)
  429                                 break;
  430         } else
  431                 dev->dv_unit = cf->cf_unit;
  432 
  433         /* Build the device name into dv_xname. */
  434         if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
  435             cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
  436                 panic("config_make_softc: device name too long");
  437         dev->dv_parent = parent;
  438 
  439         /* put this device in the devices array */
  440         if (dev->dv_unit >= cd->cd_ndevs) {
  441                 /*
  442                  * Need to expand the array.
  443                  */
  444                 int old = cd->cd_ndevs, new;
  445                 void **nsp;
  446 
  447                 if (old == 0)
  448                         new = MINALLOCSIZE / sizeof(void *);
  449                 else
  450                         new = old * 2;
  451                 while (new <= dev->dv_unit)
  452                         new *= 2;
  453                 cd->cd_ndevs = new;
  454                 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT); 
  455                 if (nsp == 0)
  456                         panic("config_make_softc: %sing dev array",
  457                             old != 0 ? "expand" : "creat");
  458                 bzero(nsp + old, (new - old) * sizeof(void *));
  459                 if (old != 0) {
  460                         bcopy(cd->cd_devs, nsp, old * sizeof(void *));
  461                         free(cd->cd_devs, M_DEVBUF);
  462                 }
  463                 cd->cd_devs = nsp;
  464         }
  465         if (cd->cd_devs[dev->dv_unit])
  466                 panic("config_make_softc: duplicate %s", dev->dv_xname);
  467 
  468         dev->dv_ref = 1;
  469 
  470         return (dev);
  471 }
  472 
  473 /*
  474  * Detach a device.  Optionally forced (e.g. because of hardware
  475  * removal) and quiet.  Returns zero if successful, non-zero
  476  * (an error code) otherwise.
  477  *
  478  * Note that this code wants to be run from a process context, so
  479  * that the detach can sleep to allow processes which have a device
  480  * open to run and unwind their stacks.
  481  */
  482 int
  483 config_detach(struct device *dev, int flags)
  484 {
  485         struct cfdata *cf;
  486         struct cfattach *ca;
  487         struct cfdriver *cd;
  488         int rv = 0, i;
  489 #ifdef DIAGNOSTIC
  490         struct device *d;
  491 #endif
  492 #if NHOTPLUG > 0
  493         char devname[16];
  494 #endif
  495 
  496 #if NHOTPLUG > 0
  497         strlcpy(devname, dev->dv_xname, sizeof(devname));
  498 #endif
  499 
  500         cf = dev->dv_cfdata;
  501 #ifdef DIAGNOSTIC
  502         if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
  503                 panic("config_detach: bad device fstate");
  504 #endif
  505         ca = cf->cf_attach;
  506         cd = cf->cf_driver;
  507 
  508         /*
  509          * Ensure the device is deactivated.  If the device doesn't
  510          * have an activation entry point, we allow DVF_ACTIVE to
  511          * remain set.  Otherwise, if DVF_ACTIVE is still set, the
  512          * device is busy, and the detach fails.
  513          */
  514         if (ca->ca_activate != NULL)
  515                 rv = config_deactivate(dev);
  516 
  517         /*
  518          * Try to detach the device.  If that's not possible, then
  519          * we either panic() (for the forced but failed case), or
  520          * return an error.
  521          */
  522         if (rv == 0) {
  523                 if (ca->ca_detach != NULL)
  524                         rv = (*ca->ca_detach)(dev, flags);
  525                 else
  526                         rv = EOPNOTSUPP;
  527         }
  528         if (rv != 0) {
  529                 if ((flags & DETACH_FORCE) == 0)
  530                         return (rv);
  531                 else
  532                         panic("config_detach: forced detach of %s failed (%d)",
  533                             dev->dv_xname, rv);
  534         }
  535 
  536         /*
  537          * The device has now been successfully detached.
  538          */
  539 
  540 #ifdef DIAGNOSTIC
  541         /*
  542          * Sanity: If you're successfully detached, you should have no
  543          * children.  (Note that because children must be attached
  544          * after parents, we only need to search the latter part of
  545          * the list.)
  546          */
  547         for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
  548              d = TAILQ_NEXT(d, dv_list)) {
  549                 if (d->dv_parent == dev)
  550                         panic("config_detach: detached device has children");
  551         }
  552 #endif
  553 
  554         /*
  555          * Mark cfdata to show that the unit can be reused, if possible.
  556          * Note that we can only re-use a starred unit number if the unit
  557          * being detached had the last assigned unit number.
  558          */
  559         for (cf = cfdata; cf->cf_driver; cf++) {
  560                 if (cf->cf_driver == cd) {
  561                         if (cf->cf_fstate == FSTATE_FOUND &&
  562                             cf->cf_unit == dev->dv_unit)
  563                                 cf->cf_fstate = FSTATE_NOTFOUND;
  564                         if (cf->cf_fstate == FSTATE_STAR &&
  565                             cf->cf_unit == dev->dv_unit + 1)
  566                                 cf->cf_unit--;
  567                 }
  568         }
  569 
  570         /*
  571          * Unlink from device list.
  572          */
  573         TAILQ_REMOVE(&alldevs, dev, dv_list);
  574         device_unref(dev);
  575 
  576         /*
  577          * Remove from cfdriver's array, tell the world, and free softc.
  578          */
  579         cd->cd_devs[dev->dv_unit] = NULL;
  580         if ((flags & DETACH_QUIET) == 0)
  581                 printf("%s detached\n", dev->dv_xname);
  582 
  583         device_unref(dev);
  584         /*
  585          * If the device now has no units in use, deallocate its softc array.
  586          */
  587         for (i = 0; i < cd->cd_ndevs; i++)
  588                 if (cd->cd_devs[i] != NULL)
  589                         break;
  590         if (i == cd->cd_ndevs) {                /* nothing found; deallocate */
  591                 free(cd->cd_devs, M_DEVBUF);
  592                 cd->cd_devs = NULL;
  593                 cd->cd_ndevs = 0;
  594                 cf->cf_unit = 0;
  595         }
  596 
  597 #if NHOTPLUG > 0
  598         if (!cold)
  599                 hotplug_device_detach(cd->cd_class, devname);
  600 #endif
  601 
  602         /*
  603          * Return success.
  604          */
  605         return (0);
  606 }
  607 
  608 int
  609 config_activate(struct device *dev)
  610 {
  611         struct cfattach *ca = dev->dv_cfdata->cf_attach;
  612         int rv = 0, oflags = dev->dv_flags;
  613 
  614         if (ca->ca_activate == NULL)
  615                 return (EOPNOTSUPP);
  616 
  617         if ((dev->dv_flags & DVF_ACTIVE) == 0) {
  618                 dev->dv_flags |= DVF_ACTIVE;
  619                 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
  620                 if (rv)
  621                         dev->dv_flags = oflags;
  622         }
  623         return (rv);
  624 }
  625 
  626 int
  627 config_deactivate(struct device *dev)
  628 {
  629         struct cfattach *ca = dev->dv_cfdata->cf_attach;
  630         int rv = 0, oflags = dev->dv_flags;
  631 
  632         if (ca->ca_activate == NULL)
  633                 return (EOPNOTSUPP);
  634 
  635         if (dev->dv_flags & DVF_ACTIVE) {
  636                 dev->dv_flags &= ~DVF_ACTIVE;
  637                 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
  638                 if (rv)
  639                         dev->dv_flags = oflags;
  640         }
  641         return (rv);
  642 }
  643 
  644 /*
  645  * Defer the configuration of the specified device until all
  646  * of its parent's devices have been attached.
  647  */
  648 void
  649 config_defer(struct device *dev, void (*func)(struct device *))
  650 {
  651         struct deferred_config *dc;
  652 
  653         if (dev->dv_parent == NULL)
  654                 panic("config_defer: can't defer config of a root device");
  655 
  656 #ifdef DIAGNOSTIC
  657         for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
  658              dc = TAILQ_NEXT(dc, dc_queue)) {
  659                 if (dc->dc_dev == dev)
  660                         panic("config_defer: deferred twice");
  661         }
  662 #endif
  663 
  664         if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
  665                 panic("config_defer: can't allocate defer structure");
  666 
  667         dc->dc_dev = dev;
  668         dc->dc_func = func;
  669         TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
  670         config_pending_incr();
  671 }
  672 
  673 /*
  674  * Process the deferred configuration queue for a device.
  675  */
  676 void
  677 config_process_deferred_children(struct device *parent)
  678 {
  679         struct deferred_config *dc, *ndc;
  680 
  681         for (dc = TAILQ_FIRST(&deferred_config_queue);
  682              dc != NULL; dc = ndc) {
  683                 ndc = TAILQ_NEXT(dc, dc_queue);
  684                 if (dc->dc_dev->dv_parent == parent) {
  685                         TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
  686                         (*dc->dc_func)(dc->dc_dev);
  687                         free(dc, M_DEVBUF);
  688                         config_pending_decr();
  689                 }
  690         }
  691 }
  692 
  693 /*
  694  * Manipulate the config_pending semaphore.
  695  */
  696 void
  697 config_pending_incr(void)
  698 {
  699 
  700         config_pending++;
  701 }
  702 
  703 void
  704 config_pending_decr(void)
  705 {
  706 
  707 #ifdef DIAGNOSTIC
  708         if (config_pending == 0)
  709                 panic("config_pending_decr: config_pending == 0");
  710 #endif
  711         config_pending--;
  712         if (config_pending == 0)
  713                 wakeup((void *)&config_pending);
  714 }
  715 
  716 int
  717 config_detach_children(struct device *parent, int flags)
  718 {
  719         struct device *dev, *next_dev, *prev_dev;
  720         int rv = 0;
  721 
  722         /*
  723          * The config_detach routine may sleep, meaning devices
  724          * may be added to the queue. However, all devices will
  725          * be added to the tail of the queue, the queue won't
  726          * be re-organized, and the subtree of parent here should be locked
  727          * for purposes of adding/removing children.
  728          *
  729          * Note that we can not afford trying to walk the device list
  730          * once - our ``next'' device might be a child of the device
  731          * we are about to detach, so it would disappear.
  732          * Just play it safe and restart from the parent.
  733          */
  734         for (prev_dev = NULL, dev = TAILQ_LAST(&alldevs, devicelist);
  735             dev != NULL; dev = next_dev) {
  736                 if (dev->dv_parent == parent) {
  737                         if ((rv = config_detach(dev, flags)) != 0)
  738                                 return (rv);
  739                         next_dev = prev_dev ? prev_dev : TAILQ_LAST(&alldevs,
  740                             devicelist);
  741                 } else {
  742                         prev_dev = dev;
  743                         next_dev = TAILQ_PREV(dev, devicelist, dv_list);
  744                 }
  745         }
  746 
  747         return (0);
  748 }
  749 
  750 int
  751 config_activate_children(struct device *parent, enum devact act)
  752 {
  753         struct device *dev, *next_dev;
  754         int  rv = 0;
  755 
  756         /* The config_deactivate routine may sleep, meaning devices
  757            may be added to the queue. However, all devices will
  758            be added to the tail of the queue, the queue won't
  759            be re-organized, and the subtree of parent here should be locked
  760            for purposes of adding/removing children.
  761         */
  762         for (dev = TAILQ_FIRST(&alldevs);
  763              dev != NULL; dev = next_dev) {
  764                 next_dev = TAILQ_NEXT(dev, dv_list);
  765                 if (dev->dv_parent == parent) {
  766                         switch (act) {
  767                         case DVACT_ACTIVATE:
  768                                 rv = config_activate(dev);
  769                                 break;
  770                         case DVACT_DEACTIVATE:
  771                                 rv = config_deactivate(dev);
  772                                 break;
  773                         default:
  774 #ifdef DIAGNOSTIC
  775                                 printf ("config_activate_children: shouldn't get here");
  776 #endif
  777                                 rv = EOPNOTSUPP;
  778                                 break;
  779 
  780                         }
  781                                                 
  782                         if (rv)
  783                                 break;
  784                 }
  785         }
  786 
  787         return  (rv);
  788 }
  789 
  790 /* 
  791  * Lookup a device in the cfdriver device array.  Does not return a
  792  * device if it is not active.
  793  *
  794  * Increments ref count on the device by one, reflecting the
  795  * new reference created on the stack.
  796  *
  797  * Context: process only 
  798  */
  799 struct device *
  800 device_lookup(struct cfdriver *cd, int unit)
  801 {
  802         struct device *dv = NULL;
  803 
  804         if (unit >= 0 && unit < cd->cd_ndevs)
  805                 dv = (struct device *)(cd->cd_devs[unit]);
  806         
  807         if (!dv)
  808                 return (NULL);
  809 
  810         if (!(dv->dv_flags & DVF_ACTIVE))
  811                 dv = NULL;
  812 
  813         if (dv != NULL)
  814                 device_ref(dv);
  815 
  816         return (dv);
  817 }
  818 
  819 
  820 /*
  821  * Increments the ref count on the device structure. The device
  822  * structure is freed when the ref count hits 0.
  823  *
  824  * Context: process or interrupt
  825  */
  826 void
  827 device_ref(struct device *dv)
  828 {
  829         dv->dv_ref++;
  830 }
  831 
  832 /*
  833  * Decrement the ref count on the device structure.
  834  *
  835  * free's the structure when the ref count hits zero.
  836  *
  837  * Context: process or interrupt
  838  */
  839 void
  840 device_unref(struct device *dv)
  841 {
  842         dv->dv_ref--;
  843         if (dv->dv_ref == 0) {
  844                 free(dv, M_DEVBUF);
  845         }
  846 }

/* [<][>][^][v][top][bottom][index][help] */