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 /*
    2  * Copyright (c) 1992, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This software was developed by the Computer Systems Engineering group
    6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
    7  * contributed to Berkeley.
    8  *
    9  * All advertising materials mentioning features or use of this software
   10  * must display the following acknowledgement:
   11  *      This product includes software developed by the University of
   12  *      California, Lawrence Berkeley Laboratories.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  * 3. All advertising materials mentioning features or use of this software
   23  *    must display the following acknowledgement:
   24  *      This product includes software developed by the University of
   25  *      California, Berkeley and its contributors.
   26  * 4. Neither the name of the University nor the names of its contributors
   27  *    may be used to endorse or promote products derived from this software
   28  *    without specific prior written permission.
   29  *
   30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   40  * SUCH DAMAGE.
   41  *
   42  *      @(#)subr_autoconf.c     8.1 (Berkeley) 6/10/93
   43  *
   44  * $FreeBSD: src/sys/kern/subr_autoconf.c,v 1.2.12.2 1999/09/05 08:15:10 peter Exp $
   45  */
   46 
   47 #include <sys/param.h>
   48 #include <sys/kernel.h>
   49 #include <sys/systm.h>
   50 #include <sys/device.h>
   51 #ifdef UNUSED
   52 #include <sys/malloc.h>
   53 #endif
   54 
   55 /*
   56  * Autoconfiguration subroutines.
   57  */
   58 
   59 #ifdef UNUSED
   60 /*
   61  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
   62  * devices and drivers are found via these tables.
   63  */
   64 extern struct cfdata cfdata[];
   65 extern short cfroots[];
   66 
   67 #define ROOT ((struct device *)NULL)
   68 
   69 struct matchinfo {
   70         cfmatch_t fn;
   71         struct  device *parent;
   72         void    *aux;
   73         struct  cfdata *match;
   74         int     pri;
   75 };
   76 
   77 /*
   78  * Apply the matching function and choose the best.  This is used
   79  * a few times and we want to keep the code small.
   80  */
   81 static void
   82 mapply(m, cf)
   83         register struct matchinfo *m;
   84         register struct cfdata *cf;
   85 {
   86         register int pri;
   87 
   88         if (m->fn != NULL)
   89                 pri = (*m->fn)(m->parent, cf, m->aux);
   90         else
   91                 pri = (*cf->cf_driver->cd_match)(m->parent, cf, m->aux);
   92         if (pri > m->pri) {
   93                 m->match = cf;
   94                 m->pri = pri;
   95         }
   96 }
   97 
   98 /*
   99  * Iterate over all potential children of some device, calling the given
  100  * function (default being the child's match function) for each one.
  101  * Nonzero returns are matches; the highest value returned is considered
  102  * the best match.  Return the `found child' if we got a match, or NULL
  103  * otherwise.  The `aux' pointer is simply passed on through.
  104  *
  105  * Note that this function is designed so that it can be used to apply
  106  * an arbitrary function to all potential children (its return value
  107  * can be ignored).
  108  */
  109 struct cfdata *
  110 config_search(fn, parent, aux)
  111         cfmatch_t fn;
  112         register struct device *parent;
  113         void *aux;
  114 {
  115         register struct cfdata *cf;
  116         register short *p;
  117         struct matchinfo m;
  118 
  119         m.fn = fn;
  120         m.parent = parent;
  121         m.aux = aux;
  122         m.match = NULL;
  123         m.pri = 0;
  124         for (cf = cfdata; cf->cf_driver; cf++) {
  125                 /*
  126                  * Skip cf if no longer eligible, otherwise scan through
  127                  * parents for one matching `parent', and try match function.
  128                  */
  129                 if (cf->cf_fstate == FSTATE_FOUND)
  130                         continue;
  131                 for (p = cf->cf_parents; *p >= 0; p++)
  132                         if (parent->dv_cfdata == &cfdata[*p])
  133                                 mapply(&m, cf);
  134         }
  135         return (m.match);
  136 }
  137 
  138 /*
  139  * Find the given root device.
  140  * This is much like config_search, but there is no parent.
  141  */
  142 struct cfdata *
  143 config_rootsearch(fn, rootname, aux)
  144         register cfmatch_t fn;
  145         register char *rootname;
  146         register void *aux;
  147 {
  148         register struct cfdata *cf;
  149         register short *p;
  150         struct matchinfo m;
  151 
  152         m.fn = fn;
  153         m.parent = ROOT;
  154         m.aux = aux;
  155         m.match = NULL;
  156         m.pri = 0;
  157         /*
  158          * Look at root entries for matching name.  We do not bother
  159          * with found-state here since only one root should ever be
  160          * searched (and it must be done first).
  161          */
  162         for (p = cfroots; *p >= 0; p++) {
  163                 cf = &cfdata[*p];
  164                 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
  165                         mapply(&m, cf);
  166         }
  167         return (m.match);
  168 }
  169 
  170 static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
  171 
  172 /*
  173  * The given `aux' argument describes a device that has been found
  174  * on the given parent, but not necessarily configured.  Locate the
  175  * configuration data for that device (using the cd_match configuration
  176  * driver function) and attach it, and return true.  If the device was
  177  * not configured, call the given `print' function and return 0.
  178  */
  179 int
  180 config_found(parent, aux, print)
  181         struct device *parent;
  182         void *aux;
  183         cfprint_t print;
  184 {
  185         struct cfdata *cf;
  186 
  187         if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) {
  188                 config_attach(parent, cf, aux, print);
  189                 return (1);
  190         }
  191         printf(msgs[(*print)(aux, parent->dv_xname)]);
  192         return (0);
  193 }
  194 
  195 /*
  196  * As above, but for root devices.
  197  */
  198 int
  199 config_rootfound(rootname, aux)
  200         char *rootname;
  201         void *aux;
  202 {
  203         struct cfdata *cf;
  204 
  205         if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) {
  206                 config_attach(ROOT, cf, aux, (cfprint_t)NULL);
  207                 return (1);
  208         }
  209         printf("root device %s not configured\n", rootname);
  210         return (0);
  211 }
  212 
  213 /* just like sprintf(buf, "%d") except that it works from the end */
  214 static char *
  215 number(ep, n)
  216         register char *ep;
  217         register int n;
  218 {
  219 
  220         *--ep = 0;
  221         while (n >= 10) {
  222                 *--ep = (n % 10) + '';
  223                 n /= 10;
  224         }
  225         *--ep = n + '';
  226         return (ep);
  227 }
  228 
  229 /*
  230  * Attach a found device.  Allocates memory for device variables.
  231  */
  232 void
  233 config_attach(parent, cf, aux, print)
  234         register struct device *parent;
  235         register struct cfdata *cf;
  236         register void *aux;
  237         cfprint_t print;
  238 {
  239         register struct device *dev;
  240         register struct cfdriver *cd;
  241         register size_t lname, lunit;
  242         register char *xunit;
  243         int myunit;
  244         char num[10];
  245         static struct device **nextp = &alldevs;
  246 
  247         cd = cf->cf_driver;
  248         if (cd->cd_devsize < sizeof(struct device))
  249                 panic("config_attach");
  250         myunit = cf->cf_unit;
  251         if (cf->cf_fstate == FSTATE_NOTFOUND)
  252                 cf->cf_fstate = FSTATE_FOUND;
  253         else
  254                 cf->cf_unit++;
  255 
  256         /* compute length of name and decimal expansion of unit number */
  257         lname = strlen(cd->cd_name);
  258         xunit = number(&num[sizeof num], myunit);
  259         lunit = &num[sizeof num] - xunit;
  260         if (lname + lunit >= sizeof(dev->dv_xname))
  261                 panic("config_attach: device name too long");
  262 
  263         /* get memory for all device vars */
  264         dev = (struct device *)malloc(cd->cd_devsize, M_DEVBUF, M_WAITOK);
  265                                         /* XXX cannot wait! */
  266         bzero(dev, cd->cd_devsize);
  267         *nextp = dev;                   /* link up */
  268         nextp = &dev->dv_next;
  269         dev->dv_class = cd->cd_class;
  270         dev->dv_cfdata = cf;
  271         dev->dv_unit = myunit;
  272         bcopy(cd->cd_name, dev->dv_xname, lname);
  273         bcopy(xunit, dev->dv_xname + lname, lunit);
  274         dev->dv_parent = parent;
  275         if (parent == ROOT)
  276                 printf("%s (root)", dev->dv_xname);
  277         else {
  278                 printf("%s at %s", dev->dv_xname, parent->dv_xname);
  279                 (void) (*print)(aux, (char *)0);
  280         }
  281 
  282         /* put this device in the devices array */
  283         if (dev->dv_unit >= cd->cd_ndevs) {
  284                 /*
  285                  * Need to expand the array.
  286                  */
  287                 int old = cd->cd_ndevs, oldbytes, new, newbytes;
  288                 void **nsp;
  289 
  290                 if (old == 0) {
  291                         nsp = malloc(MINALLOCSIZE, M_DEVBUF, M_WAITOK); /*XXX*/
  292                         bzero(nsp, MINALLOCSIZE);
  293                         cd->cd_ndevs = MINALLOCSIZE / sizeof(void *);
  294                 } else {
  295                         new = cd->cd_ndevs;
  296                         do {
  297                                 new *= 2;
  298                         } while (new <= dev->dv_unit);
  299                         cd->cd_ndevs = new;
  300                         oldbytes = old * sizeof(void *);
  301                         newbytes = new * sizeof(void *);
  302                         nsp = malloc(newbytes, M_DEVBUF, M_WAITOK);     /*XXX*/
  303                         bcopy(cd->cd_devs, nsp, oldbytes);
  304                         bzero(&nsp[old], newbytes - oldbytes);
  305                         free(cd->cd_devs, M_DEVBUF);
  306                 }
  307                 cd->cd_devs = nsp;
  308         }
  309         if (cd->cd_devs[dev->dv_unit])
  310                 panic("config_attach: duplicate %s", dev->dv_xname);
  311         cd->cd_devs[dev->dv_unit] = dev;
  312 
  313         /*
  314          * Before attaching, clobber any unfound devices that are
  315          * otherwise identical.
  316          */
  317         for (cf = cfdata; cf->cf_driver; cf++)
  318                 if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit &&
  319                     cf->cf_fstate == FSTATE_NOTFOUND)
  320                         cf->cf_fstate = FSTATE_FOUND;
  321         (*cd->cd_attach)(parent, dev, aux);
  322 }
  323 
  324 /*
  325  * Attach an event.  These must come from initially-zero space (see
  326  * commented-out assignments below), but that occurs naturally for
  327  * device instance variables.
  328  */
  329 void
  330 evcnt_attach(dev, name, ev)
  331         struct device *dev;
  332         const char *name;
  333         struct evcnt *ev;
  334 {
  335         static struct evcnt **nextp = &allevents;
  336 
  337 #ifdef DIAGNOSTIC
  338         if (strlen(name) >= sizeof(ev->ev_name))
  339                 panic("evcnt_attach");
  340 #endif
  341         /* ev->ev_next = NULL; */
  342         ev->ev_dev = dev;
  343         /* ev->ev_count = 0; */
  344         strcpy(ev->ev_name, name);
  345         *nextp = ev;
  346         nextp = &ev->ev_next;
  347 }
  348 
  349 #endif
  350 
  351 /*
  352  * "Interrupt driven config" functions.
  353  */
  354 static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list =
  355         TAILQ_HEAD_INITIALIZER(intr_config_hook_list);
  356 
  357 
  358 /* ARGSUSED */
  359 static void run_interrupt_driven_config_hooks __P((void *dummy));
  360 static void
  361 run_interrupt_driven_config_hooks(dummy)
  362         void *dummy;
  363 {
  364         struct intr_config_hook *hook;
  365 
  366         for (hook = intr_config_hook_list.tqh_first; hook != NULL;
  367              hook = hook->ich_links.tqe_next) {
  368                 (*hook->ich_func)(hook->ich_arg);
  369         }
  370 
  371         while (intr_config_hook_list.tqh_first != NULL) {
  372                 tsleep(&intr_config_hook_list, PCONFIG, "conifhk", 0);
  373         }
  374 }
  375 SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
  376         run_interrupt_driven_config_hooks, NULL)
  377 
  378 /*
  379  * Register a hook that will be called after "cold"
  380  * autoconfiguration is complete and interrupts can
  381  * be used to complete initialization.
  382  */
  383 int
  384 config_intrhook_establish(hook)
  385         struct intr_config_hook *hook;
  386 {
  387         struct intr_config_hook *hook_entry;
  388 
  389         for (hook_entry = intr_config_hook_list.tqh_first; hook_entry != NULL;
  390              hook_entry = hook_entry->ich_links.tqe_next)
  391                 if (hook_entry == hook)
  392                         break;
  393         if (hook_entry != NULL) {
  394                 printf("config_intrhook_establish: establishing an "
  395                        "already established hook.\n");
  396                 return (1);
  397         }
  398         TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links);
  399         if (cold == 0)
  400                 /* XXX Sufficient for LKMs loaded after initial config??? */
  401                 run_interrupt_driven_config_hooks(NULL);        
  402         return (0);
  403 }
  404 
  405 void
  406 config_intrhook_disestablish(hook)
  407         struct intr_config_hook *hook;
  408 {
  409         struct intr_config_hook *hook_entry;
  410 
  411         for (hook_entry = intr_config_hook_list.tqh_first; hook_entry != NULL;
  412              hook_entry = hook_entry->ich_links.tqe_next)
  413                 if (hook_entry == hook)
  414                         break;
  415         if (hook_entry == NULL)
  416                 panic("config_intrhook_disestablish: disestablishing an "
  417                       "unestablished hook");
  418 
  419         TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
  420         /* Wakeup anyone watching the list */
  421         wakeup(&intr_config_hook_list);
  422 }

Cache object: c86621cf9e70c8756075be5c617f30bc


[ 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.