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_bus.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) 1997,1998 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/queue.h>
   31 #include <sys/malloc.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/bus_private.h>
   35 #include <sys/systm.h>
   36 #include <machine/stdarg.h>     /* for device_printf() */
   37 
   38 #include "opt_bus.h"
   39 
   40 #ifdef BUS_DEBUG
   41 #define PDEBUG(a)       (printf(__FUNCTION__ ":%d: ", __LINE__), printf a, printf("\n"))
   42 #define DEVICENAME(d)   ((d)? device_get_name(d): "no device")
   43 #define DRIVERNAME(d)   ((d)? d->name : "no driver")
   44 #define DEVCLANAME(d)   ((d)? d->name : "no devclass")
   45 
   46 /* Produce the indenting, indent*2 spaces plus a '.' ahead of that to 
   47  * prevent syslog from deleting initial spaces
   48  */
   49 #define indentprintf(p) do { int iJ; printf("."); for (iJ=0; iJ<indent; iJ++) printf("  "); printf p ; } while(0)
   50 
   51 static void print_method_list(device_method_t *m, int indent);
   52 static void print_device_ops(device_ops_t ops, int indent);
   53 static void print_device_short(device_t dev, int indent);
   54 static void print_device(device_t dev, int indent);
   55 void print_device_tree_short(device_t dev, int indent);
   56 void print_device_tree(device_t dev, int indent);
   57 static void print_driver_short(driver_t *driver, int indent);
   58 static void print_driver(driver_t *driver, int indent);
   59 static void print_driver_list(driver_list_t drivers, int indent);
   60 static void print_devclass_short(devclass_t dc, int indent);
   61 static void print_devclass(devclass_t dc, int indent);
   62 void print_devclass_list_short(void);
   63 void print_devclass_list(void);
   64 
   65 #else
   66 /* Make the compiler ignore the function calls */
   67 #define PDEBUG(a)                       /* nop */
   68 #define DEVICENAME(d)                   /* nop */
   69 #define DRIVERNAME(d)                   /* nop */
   70 #define DEVCLANAME(d)                   /* nop */
   71 
   72 #define print_method_list(m,i)          /* nop */
   73 #define print_device_ops(o,i)           /* nop */
   74 #define print_device_short(d,i)         /* nop */
   75 #define print_device(d,i)               /* nop */
   76 #define print_device_tree_short(d,i)    /* nop */
   77 #define print_device_tree(d,i)          /* nop */
   78 #define print_driver_short(d,i)         /* nop */
   79 #define print_driver(d,i)               /* nop */
   80 #define print_driver_list(d,i)          /* nop */
   81 #define print_devclass_short(d,i)       /* nop */
   82 #define print_devclass(d,i)             /* nop */
   83 #define print_devclass_list_short()     /* nop */
   84 #define print_devclass_list()           /* nop */
   85 #endif
   86 
   87 
   88 /*
   89  * Method table handling
   90  */
   91 static int next_method_offset = 1;
   92 static int methods_count = 0;
   93 static int methods_size = 0;
   94 
   95 struct method {
   96     int offset;
   97     char* name;
   98 };
   99 
  100 static struct method *methods = 0;
  101 
  102 static void
  103 register_method(struct device_op_desc *desc)
  104 {
  105     int i;
  106     struct method* m;
  107 
  108     for (i = 0; i < methods_count; i++)
  109         if (!strcmp(methods[i].name, desc->name)) {
  110             desc->offset = methods[i].offset;
  111             PDEBUG(("methods[%d] has the same name, %s, with offset %d",
  112                         i, desc->name, desc->offset));
  113             return;
  114         }
  115 
  116     if (methods_count == methods_size) {
  117         struct method* p;
  118 
  119         methods_size += 10;
  120         p = (struct method*) malloc(methods_size * sizeof(struct method),
  121                                      M_DEVBUF, M_NOWAIT);
  122         if (!p)
  123             panic("register_method: out of memory");
  124         if (methods) {
  125             bcopy(methods, p, methods_count * sizeof(struct method));
  126             free(methods, M_DEVBUF);
  127         }
  128         methods = p;
  129     }
  130     m = &methods[methods_count++];
  131     m->name = malloc(strlen(desc->name) + 1, M_DEVBUF, M_NOWAIT);
  132     if (!m->name)
  133             panic("register_method: out of memory");
  134     strcpy(m->name, desc->name);
  135     desc->offset = m->offset = next_method_offset++;
  136 }
  137 
  138 static int error_method(void)
  139 {
  140     return ENXIO;
  141 }
  142 
  143 static struct device_ops null_ops = {
  144     1, 
  145     { error_method }
  146 };
  147 
  148 static void
  149 compile_methods(driver_t *driver)
  150 {
  151     device_ops_t ops;
  152     struct device_method *m;
  153     int i;
  154 
  155     /*
  156      * First register any methods which need it.
  157      */
  158     for (i = 0, m = driver->methods; m->desc; i++, m++)
  159         if (!m->desc->offset)
  160             register_method(m->desc);
  161         else
  162             PDEBUG(("offset not equal to zero, method desc %d left as is", i));
  163 
  164     /*
  165      * Then allocate the compiled op table.
  166      */
  167     ops = malloc(sizeof(struct device_ops) + (next_method_offset-1) * sizeof(devop_t),
  168                  M_DEVBUF, M_NOWAIT);
  169     if (!ops)
  170         panic("compile_methods: out of memory");
  171 
  172     ops->maxoffset = next_method_offset;
  173     for (i = 0; i < next_method_offset; i++)
  174         ops->methods[i] = error_method;
  175     for (i = 0, m = driver->methods; m->desc; i++, m++)
  176         ops->methods[m->desc->offset] = m->func;
  177     PDEBUG(("%s has %d method%s, wasting %d bytes",
  178                 DRIVERNAME(driver), i, (i==1?"":"s"),
  179                 (next_method_offset-i)*sizeof(devop_t)));
  180 
  181     driver->ops = ops;
  182 }
  183 
  184 /*
  185  * Devclass implementation
  186  */
  187 
  188 static devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses);
  189 
  190 static devclass_t
  191 devclass_find_internal(const char *classname, int create)
  192 {
  193     devclass_t dc;
  194 
  195     PDEBUG(("looking for %s", classname));
  196     if (!classname)
  197         return NULL;
  198 
  199     for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link))
  200         if (!strcmp(dc->name, classname))
  201             return dc;
  202 
  203     PDEBUG(("%s not found%s", classname, (create? ", creating": "")));
  204     if (create) {
  205         dc = malloc(sizeof(struct devclass) + strlen(classname) + 1,
  206                     M_DEVBUF, M_NOWAIT);
  207         if (!dc)
  208             return NULL;
  209         dc->name = (char*) (dc + 1);
  210         strcpy(dc->name, classname);
  211         dc->devices = NULL;
  212         dc->maxunit = 0;
  213         dc->nextunit = 0;
  214         TAILQ_INIT(&dc->drivers);
  215         TAILQ_INSERT_TAIL(&devclasses, dc, link);
  216     }
  217 
  218     return dc;
  219 }
  220 
  221 devclass_t
  222 devclass_find(const char *classname)
  223 {
  224     return devclass_find_internal(classname, FALSE);
  225 }
  226 
  227 int
  228 devclass_add_driver(devclass_t dc, driver_t *driver)
  229 {
  230     PDEBUG(("%s", DRIVERNAME(driver)));
  231     /*
  232      * Compile the drivers methods.
  233      */
  234     compile_methods(driver);
  235 
  236     /*
  237      * Make sure the devclass which the driver is implementing exists.
  238      */
  239     devclass_find_internal(driver->name, TRUE);
  240 
  241     TAILQ_INSERT_TAIL(&dc->drivers, driver, link);
  242 
  243     return 0;
  244 }
  245 
  246 int
  247 devclass_delete_driver(devclass_t busclass, driver_t *driver)
  248 {
  249     devclass_t dc = devclass_find(driver->name);
  250     device_t dev;
  251     int i;
  252     int error;
  253 
  254     PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
  255 
  256     if (!dc)
  257         return 0;
  258 
  259     /*
  260      * Disassociate from any devices.  We iterate through all the
  261      * devices in the devclass of the driver and detach any which are
  262      * using the driver.
  263      */
  264     for (i = 0; i < dc->maxunit; i++) {
  265         if (dc->devices[i]) {
  266             dev = dc->devices[i];
  267             if (dev->driver == driver) {
  268                 if (error = device_detach(dev))
  269                     return error;
  270                 device_set_driver(dev, NULL);
  271             }
  272         }
  273     }
  274 
  275     TAILQ_REMOVE(&busclass->drivers, driver, link);
  276     return 0;
  277 }
  278 
  279 driver_t *
  280 devclass_find_driver(devclass_t dc, const char *classname)
  281 {
  282     driver_t *driver;
  283 
  284     PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc)));
  285 
  286     for (driver = TAILQ_FIRST(&dc->drivers); driver;
  287          driver = TAILQ_NEXT(driver, link)) {
  288         if (!strcmp(driver->name, classname))
  289             return driver;
  290     }
  291 
  292     PDEBUG(("not found"));
  293     return NULL;
  294 }
  295 
  296 const char *
  297 devclass_get_name(devclass_t dc)
  298 {
  299     return dc->name;
  300 }
  301 
  302 device_t
  303 devclass_get_device(devclass_t dc, int unit)
  304 {
  305     if (unit < 0 || unit >= dc->maxunit)
  306         return NULL;
  307     return dc->devices[unit];
  308 }
  309 
  310 void *
  311 devclass_get_softc(devclass_t dc, int unit)
  312 {
  313     device_t dev;
  314 
  315     if (unit < 0 || unit >= dc->maxunit)
  316         return NULL;
  317     dev = dc->devices[unit];
  318     if (!dev || dev->state < DS_ATTACHED)
  319         return NULL;
  320     return dev->softc;
  321 }
  322 
  323 int
  324 devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp)
  325 {
  326     int i;
  327     int count;
  328     device_t *list;
  329     
  330     count = 0;
  331     for (i = 0; i < dc->maxunit; i++)
  332         if (dc->devices[i])
  333             count++;
  334 
  335     list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT);
  336     if (!list)
  337         return ENOMEM;
  338 
  339     count = 0;
  340     for (i = 0; i < dc->maxunit; i++)
  341         if (dc->devices[i]) {
  342             list[count] = dc->devices[i];
  343             count++;
  344         }
  345 
  346     *devlistp = list;
  347     *devcountp = count;
  348 
  349     return 0;
  350 }
  351 
  352 int
  353 devclass_get_maxunit(devclass_t dc)
  354 {
  355     return dc->maxunit;
  356 }
  357 
  358 static int
  359 devclass_alloc_unit(devclass_t dc, int *unitp)
  360 {
  361     int unit = *unitp;
  362 
  363     PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc)));
  364 
  365     /*
  366      * If we have been given a wired unit number, check for existing
  367      * device.
  368      */
  369     if (unit != -1) {
  370         device_t dev;
  371         dev = devclass_get_device(dc, unit);
  372         if (dev) {
  373             printf("devclass_alloc_unit: %s%d already exists, using next available unit number\n", dc->name, unit);
  374             unit = -1;
  375         }
  376     }
  377 
  378     if (unit == -1) {
  379         unit = dc->nextunit;
  380         dc->nextunit++;
  381     } else if (dc->nextunit <= unit)
  382         dc->nextunit = unit + 1;
  383 
  384     if (unit >= dc->maxunit) {
  385         device_t *newlist;
  386         int newsize;
  387 
  388         newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t));
  389         newlist = malloc(sizeof(device_t) * newsize, M_DEVBUF, M_NOWAIT);
  390         if (!newlist)
  391             return ENOMEM;
  392         bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit);
  393         bzero(newlist + dc->maxunit,
  394               sizeof(device_t) * (newsize - dc->maxunit));
  395         if (dc->devices)
  396             free(dc->devices, M_DEVBUF);
  397         dc->devices = newlist;
  398         dc->maxunit = newsize;
  399     }
  400     PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc)));
  401 
  402     *unitp = unit;
  403     return 0;
  404 }
  405 
  406 static int
  407 devclass_add_device(devclass_t dc, device_t dev)
  408 {
  409     int error;
  410 
  411     PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
  412 
  413     if (error = devclass_alloc_unit(dc, &dev->unit))
  414         return error;
  415     dc->devices[dev->unit] = dev;
  416     dev->devclass = dc;
  417     return 0;
  418 }
  419 
  420 static int
  421 devclass_delete_device(devclass_t dc, device_t dev)
  422 {
  423     if (!dc || !dev)
  424         return 0;
  425 
  426     PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
  427 
  428     if (dev->devclass != dc
  429         || dc->devices[dev->unit] != dev)
  430         panic("devclass_delete_device: inconsistent device class");
  431     dc->devices[dev->unit] = NULL;
  432     if (dev->flags & DF_WILDCARD)
  433         dev->unit = -1;
  434     dev->devclass = NULL;
  435     while (dc->nextunit > 0 && dc->devices[dc->nextunit - 1] == NULL)
  436         dc->nextunit--;
  437     return 0;
  438 }
  439 
  440 static device_t
  441 make_device(device_t parent, const char *name,
  442             int unit, void *ivars)
  443 {
  444     device_t dev;
  445     devclass_t dc;
  446     int error;
  447 
  448     PDEBUG(("%s at %s as unit %d with%s ivars",
  449             name, DEVICENAME(parent), unit, (ivars? "":"out")));
  450 
  451     if (name) {
  452         dc = devclass_find_internal(name, TRUE);
  453         if (!dc) {
  454             printf("make_device: can't find device class %s\n", name);
  455             return NULL;
  456         }
  457 
  458         if (error = devclass_alloc_unit(dc, &unit))
  459             return NULL;
  460     } else
  461         dc = NULL;
  462 
  463     dev = malloc(sizeof(struct device), M_DEVBUF, M_NOWAIT);
  464     if (!dev)
  465         return 0;
  466 
  467     dev->parent = parent;
  468     TAILQ_INIT(&dev->children);
  469     dev->ops = &null_ops;
  470     dev->driver = NULL;
  471     dev->devclass = dc;
  472     dev->unit = unit;
  473     dev->desc = NULL;
  474     dev->busy = 0;
  475     dev->flags = DF_ENABLED;
  476     if (unit == -1)
  477         dev->flags |= DF_WILDCARD;
  478     if (name)
  479         dev->flags |= DF_FIXEDCLASS;
  480     dev->ivars = ivars;
  481     dev->softc = NULL;
  482 
  483     if (dc)
  484         dc->devices[unit] = dev;
  485 
  486     dev->state = DS_NOTPRESENT;
  487 
  488     return dev;
  489 }
  490 
  491 static void
  492 device_print_child(device_t dev, device_t child)
  493 {
  494     printf("%s%d", device_get_name(child), device_get_unit(child));
  495     if (device_is_alive(child)) {
  496         if (device_get_desc(child))
  497             printf(": <%s>", device_get_desc(child));
  498         BUS_PRINT_CHILD(dev, child);
  499     } else
  500         printf(" not found");
  501     printf("\n");
  502 }
  503 
  504 device_t
  505 device_add_child(device_t dev, const char *name, int unit, void *ivars)
  506 {
  507     device_t child;
  508 
  509     PDEBUG(("%s at %s as unit %d with%s ivars",
  510             name, DEVICENAME(dev), unit, (ivars? "":"out")));
  511 
  512     child = make_device(dev, name, unit, ivars);
  513 
  514     if (child)
  515         TAILQ_INSERT_TAIL(&dev->children, child, link);
  516     else
  517         PDEBUG(("%s failed", name));
  518 
  519     return child;
  520 }
  521 
  522 device_t
  523 device_add_child_after(device_t dev, device_t place, const char *name,
  524                        int unit, void *ivars)
  525 {
  526     device_t child;
  527 
  528     PDEBUG(("%s at %s after %s as unit %d with%s ivars",
  529             name, DEVICENAME(dev), DEVICENAME(place), unit, (ivars? "":"out")));
  530 
  531     child = make_device(dev, name, unit, ivars);
  532 
  533     if (place) {
  534         TAILQ_INSERT_AFTER(&dev->children, place, dev, link);
  535     } else {
  536         TAILQ_INSERT_HEAD(&dev->children, dev, link);
  537     }
  538 
  539     return child;
  540 }
  541 
  542 int
  543 device_delete_child(device_t dev, device_t child)
  544 {
  545     int error;
  546     device_t grandchild;
  547 
  548     PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev)));
  549 
  550     /* remove children first */
  551     while ( (grandchild = TAILQ_FIRST(&child->children)) ) {
  552         error = device_delete_child(child, grandchild);
  553         if (error)
  554             return error;
  555     }
  556 
  557     if (error = device_detach(child))
  558         return error;
  559     if (child->devclass)
  560         devclass_delete_device(child->devclass, child);
  561     TAILQ_REMOVE(&dev->children, child, link);
  562     free(child, M_DEVBUF);
  563 
  564     return 0;
  565 }
  566 
  567 /*
  568  * Find only devices attached to this bus.
  569  */
  570 device_t
  571 device_find_child(device_t dev, const char *classname, int unit)
  572 {
  573     devclass_t dc;
  574     device_t child;
  575 
  576     dc = devclass_find(classname);
  577     if (!dc)
  578         return NULL;
  579 
  580     child = devclass_get_device(dc, unit);
  581     if (child && child->parent == dev)
  582         return child;
  583     return NULL;
  584 }
  585 
  586 static driver_t *
  587 first_matching_driver(devclass_t dc, device_t dev)
  588 {
  589     if (dev->devclass)
  590         return devclass_find_driver(dc, dev->devclass->name);
  591     else
  592         return TAILQ_FIRST(&dc->drivers);
  593 }
  594 
  595 static driver_t *
  596 next_matching_driver(devclass_t dc, device_t dev, driver_t *last)
  597 {
  598     if (dev->devclass) {
  599         driver_t *driver;
  600         for (driver = TAILQ_NEXT(last, link); driver;
  601              driver = TAILQ_NEXT(driver, link))
  602             if (!strcmp(dev->devclass->name, driver->name))
  603                 return driver;
  604         return NULL;
  605     } else
  606         return TAILQ_NEXT(last, link);
  607 }
  608 
  609 static int
  610 device_probe_child(device_t dev, device_t child)
  611 {
  612     devclass_t dc;
  613     driver_t *driver;
  614 
  615     dc = dev->devclass;
  616     if (dc == NULL)
  617         panic("device_probe_child: parent device has no devclass");
  618 
  619     if (child->state == DS_ALIVE)
  620         return 0;
  621 
  622     for (driver = first_matching_driver(dc, child);
  623          driver;
  624          driver = next_matching_driver(dc, child, driver)) {
  625         PDEBUG(("Trying %s", DRIVERNAME(driver)));
  626         device_set_driver(child, driver);
  627         if (DEVICE_PROBE(child) == 0) {
  628             if (!child->devclass)
  629                 device_set_devclass(child, driver->name);
  630             child->state = DS_ALIVE;
  631             return 0;
  632         }
  633     }
  634 
  635     return ENXIO;
  636 }
  637 
  638 device_t
  639 device_get_parent(device_t dev)
  640 {
  641     return dev->parent;
  642 }
  643 
  644 int
  645 device_get_children(device_t dev, device_t **devlistp, int *devcountp)
  646 {
  647     int count;
  648     device_t child;
  649     device_t *list;
  650     
  651     count = 0;
  652     for (child = TAILQ_FIRST(&dev->children); child;
  653          child = TAILQ_NEXT(child, link))
  654         count++;
  655 
  656     list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT);
  657     if (!list)
  658         return ENOMEM;
  659 
  660     count = 0;
  661     for (child = TAILQ_FIRST(&dev->children); child;
  662          child = TAILQ_NEXT(child, link)) {
  663         list[count] = child;
  664         count++;
  665     }
  666 
  667     *devlistp = list;
  668     *devcountp = count;
  669 
  670     return 0;
  671 }
  672 
  673 driver_t *
  674 device_get_driver(device_t dev)
  675 {
  676     return dev->driver;
  677 }
  678 
  679 devclass_t
  680 device_get_devclass(device_t dev)
  681 {
  682     return dev->devclass;
  683 }
  684 
  685 const char *
  686 device_get_name(device_t dev)
  687 {
  688     if (dev->devclass)
  689         return devclass_get_name(dev->devclass);
  690     return NULL;
  691 }
  692 
  693 int
  694 device_get_unit(device_t dev)
  695 {
  696     return dev->unit;
  697 }
  698 
  699 const char *
  700 device_get_desc(device_t dev)
  701 {
  702     return dev->desc;
  703 }
  704 
  705 void
  706 device_print_prettyname(device_t dev)
  707 {
  708         const char *name = device_get_name(dev);
  709 
  710         if (name == 0)
  711                 name = "(no driver assigned)";
  712         printf("%s%d: ", name, device_get_unit(dev));
  713 }
  714 
  715 void
  716 device_printf(device_t dev, const char * fmt, ...)
  717 {
  718         va_list ap;
  719 
  720         device_print_prettyname(dev);
  721         va_start(ap, fmt);
  722         vprintf(fmt, ap);
  723         va_end(ap);
  724 }
  725 
  726 void
  727 device_set_desc(device_t dev, const char* desc)
  728 {
  729     dev->desc = desc;
  730 }
  731 
  732 void *
  733 device_get_softc(device_t dev)
  734 {
  735     return dev->softc;
  736 }
  737 
  738 void *
  739 device_get_ivars(device_t dev)
  740 {
  741     return dev->ivars;
  742 }
  743 
  744 device_state_t
  745 device_get_state(device_t dev)
  746 {
  747     return dev->state;
  748 }
  749 
  750 void
  751 device_enable(device_t dev)
  752 {
  753     dev->flags |= DF_ENABLED;
  754 }
  755 
  756 void
  757 device_disable(device_t dev)
  758 {
  759     dev->flags &= ~DF_ENABLED;
  760 }
  761 
  762 void
  763 device_busy(device_t dev)
  764 {
  765     if (dev->state < DS_ATTACHED)
  766         panic("device_busy: called for unattached device");
  767     if (dev->busy == 0 && dev->parent)
  768         device_busy(dev->parent);
  769     dev->busy++;
  770     dev->state = DS_BUSY;
  771 }
  772 
  773 void
  774 device_unbusy(device_t dev)
  775 {
  776     if (dev->state != DS_BUSY)
  777         panic("device_unbusy: called for non-busy device");
  778     dev->busy--;
  779     if (dev->busy == 0) {
  780         if (dev->parent)
  781             device_unbusy(dev->parent);
  782         dev->state = DS_ATTACHED;
  783     }
  784 }
  785 
  786 int
  787 device_is_enabled(device_t dev)
  788 {
  789     return (dev->flags & DF_ENABLED) != 0;
  790 }
  791 
  792 int
  793 device_is_alive(device_t dev)
  794 {
  795     return dev->state >= DS_ALIVE;
  796 }
  797 
  798 int
  799 device_set_devclass(device_t dev, const char *classname)
  800 {
  801     devclass_t dc;
  802 
  803     if (dev->devclass) {
  804         printf("device_set_devclass: device class already set\n");
  805         return EINVAL;
  806     }
  807 
  808     dc = devclass_find_internal(classname, TRUE);
  809     if (!dc)
  810         return ENOMEM;
  811 
  812     return devclass_add_device(dc, dev);
  813 }
  814 
  815 int
  816 device_set_driver(device_t dev, driver_t *driver)
  817 {
  818     if (dev->state >= DS_ATTACHED)
  819         return EBUSY;
  820 
  821     if (dev->driver == driver)
  822         return 0;
  823 
  824     if (dev->softc) {
  825         free(dev->softc, M_DEVBUF);
  826         dev->softc = NULL;
  827     }
  828     dev->ops = &null_ops;
  829     dev->driver = driver;
  830     if (driver) {
  831         dev->ops = driver->ops;
  832         dev->softc = malloc(driver->softc, M_DEVBUF, M_NOWAIT);
  833         if (!dev->softc) {
  834             dev->ops = &null_ops;
  835             dev->driver = NULL;
  836             return ENOMEM;
  837         }
  838         bzero(dev->softc, driver->softc);
  839     }
  840     return 0;
  841 }
  842 
  843 int
  844 device_probe_and_attach(device_t dev)
  845 {
  846     device_t bus = dev->parent;
  847     int error = 0;
  848 
  849     if (dev->state >= DS_ALIVE)
  850         return 0;
  851 
  852     if (dev->flags & DF_ENABLED) {
  853         error = device_probe_child(bus, dev);
  854         if (!error) {
  855             device_print_child(bus, dev);
  856             error = DEVICE_ATTACH(dev);
  857             if (!error)
  858                 dev->state = DS_ATTACHED;
  859             else {
  860                 printf("device_probe_and_attach: %s%d attach returned %d\n",
  861                        dev->driver->name, dev->unit, error);
  862                 device_set_driver(dev, NULL);
  863                 dev->state = DS_NOTPRESENT;
  864             }
  865         }
  866     } else {
  867             device_print_prettyname(dev);
  868             printf("not probed (disabled)\n");
  869     }
  870 
  871     return error;
  872 }
  873 
  874 int
  875 device_detach(device_t dev)
  876 {
  877     int error;
  878 
  879     PDEBUG(("%s", DEVICENAME(dev)));
  880     if (dev->state == DS_BUSY)
  881         return EBUSY;
  882     if (dev->state != DS_ATTACHED)
  883         return 0;
  884 
  885     if (error = DEVICE_DETACH(dev))
  886             return error;
  887 
  888     if (!(dev->flags & DF_FIXEDCLASS))
  889         devclass_delete_device(dev->devclass, dev);
  890 
  891     dev->state = DS_NOTPRESENT;
  892     device_set_driver(dev, NULL);
  893 
  894     return 0;
  895 }
  896 
  897 int
  898 device_shutdown(device_t dev)
  899 {
  900     if (dev->state < DS_ATTACHED)
  901         return 0;
  902     return DEVICE_SHUTDOWN(dev);
  903 }
  904 
  905 /*
  906  * Access functions for device resources.
  907  */
  908 extern struct config_device devtab[];
  909 extern int devtab_count;
  910 
  911 static int
  912 resource_match_string(int i, char *resname, char *value)
  913 {
  914         int j;
  915         struct config_resource *res;
  916 
  917         for (j = 0, res = devtab[i].resources;
  918              j < devtab[i].resource_count; j++, res++)
  919                 if (!strcmp(res->name, resname)
  920                     && res->type == RES_STRING
  921                     && !strcmp(res->u.stringval, value))
  922                         return TRUE;
  923         return FALSE;
  924 }
  925 
  926 static int
  927 resource_find(const char *name, int unit, char *resname, 
  928               struct config_resource **result)
  929 {
  930         int i, j;
  931         struct config_resource *res;
  932 
  933         /*
  934          * First check specific instances, then generic.
  935          */
  936         for (i = 0; i < devtab_count; i++) {
  937                 if (devtab[i].unit < 0)
  938                         continue;
  939                 if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
  940                         res = devtab[i].resources;
  941                         for (j = 0; j < devtab[i].resource_count; j++, res++)
  942                                 if (!strcmp(res->name, resname)) {
  943                                         *result = res;
  944                                         return 0;
  945                                 }
  946                 }
  947         }
  948         for (i = 0; i < devtab_count; i++) {
  949                 if (devtab[i].unit >= 0)
  950                         continue;
  951                 if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
  952                         res = devtab[i].resources;
  953                         for (j = 0; j < devtab[i].resource_count; j++, res++)
  954                                 if (!strcmp(res->name, resname)) {
  955                                         *result = res;
  956                                         return 0;
  957                                 }
  958                 }
  959         }
  960         return ENOENT;
  961 }
  962 
  963 int
  964 resource_int_value(const char *name, int unit, char *resname, int *result)
  965 {
  966         int error;
  967         struct config_resource *res;
  968         if ((error = resource_find(name, unit, resname, &res)) != 0)
  969                 return error;
  970         if (res->type != RES_INT)
  971                 return EFTYPE;
  972         *result = res->u.intval;
  973         return 0;
  974 }
  975 
  976 int
  977 resource_long_value(const char *name, int unit, char *resname, long *result)
  978 {
  979         int error;
  980         struct config_resource *res;
  981         if ((error = resource_find(name, unit, resname, &res)) != 0)
  982                 return error;
  983         if (res->type != RES_LONG)
  984                 return EFTYPE;
  985         *result = res->u.longval;
  986         return 0;
  987 }
  988 
  989 int
  990 resource_string_value(const char *name, int unit, char *resname, char **result)
  991 {
  992         int error;
  993         struct config_resource *res;
  994         if ((error = resource_find(name, unit, resname, &res)) != 0)
  995                 return error;
  996         if (res->type != RES_STRING)
  997                 return EFTYPE;
  998         *result = res->u.stringval;
  999         return 0;
 1000 }
 1001 
 1002 int
 1003 resource_query_string(int i, char *resname, char *value)
 1004 {
 1005         if (i < 0)
 1006                 i = 0;
 1007         else
 1008                 i = i + 1;
 1009         for (; i < devtab_count; i++)
 1010                 if (resource_match_string(i, resname, value))
 1011                         return i;
 1012         return -1;
 1013 }
 1014 
 1015 char *
 1016 resource_query_name(int i)
 1017 {
 1018         return devtab[i].name;
 1019 }
 1020 
 1021 int
 1022 resource_query_unit(int i)
 1023 {
 1024         return devtab[i].unit;
 1025 }
 1026 
 1027 
 1028 /*
 1029  * Some useful method implementations to make life easier for bus drivers.
 1030  */
 1031 int
 1032 bus_generic_attach(device_t dev)
 1033 {
 1034     device_t child;
 1035 
 1036     for (child = TAILQ_FIRST(&dev->children);
 1037          child; child = TAILQ_NEXT(child, link))
 1038         device_probe_and_attach(child);
 1039 
 1040     return 0;
 1041 }
 1042 
 1043 int
 1044 bus_generic_detach(device_t dev)
 1045 {
 1046     device_t child;
 1047     int error;
 1048 
 1049     if (dev->state != DS_ATTACHED)
 1050         return EBUSY;
 1051 
 1052     for (child = TAILQ_FIRST(&dev->children);
 1053          child; child = TAILQ_NEXT(child, link))
 1054         if (error = device_detach(child))
 1055             return error;
 1056 
 1057     return 0;
 1058 }
 1059 
 1060 int
 1061 bus_generic_shutdown(device_t dev)
 1062 {
 1063     device_t child;
 1064 
 1065     for (child = TAILQ_FIRST(&dev->children);
 1066          child; child = TAILQ_NEXT(child, link))
 1067         DEVICE_SHUTDOWN(child);
 1068 
 1069     return 0;
 1070 }
 1071 
 1072 int
 1073 bus_generic_suspend(device_t dev)
 1074 {
 1075         int             error;
 1076         device_t        child, child2;
 1077 
 1078         for (child = TAILQ_FIRST(&dev->children);
 1079              child; child = TAILQ_NEXT(child, link)) {
 1080                 error = DEVICE_SUSPEND(child);
 1081                 if (error) {
 1082                         for (child2 = TAILQ_FIRST(&dev->children);
 1083                              child2 && child2 != child; 
 1084                              child2 = TAILQ_NEXT(child2, link))
 1085                                 DEVICE_RESUME(child2);
 1086                         return (error);
 1087                 }
 1088         }
 1089         return 0;
 1090 }
 1091 
 1092 int
 1093 bus_generic_resume(device_t dev)
 1094 {
 1095         device_t        child;
 1096 
 1097         for (child = TAILQ_FIRST(&dev->children);
 1098              child; child = TAILQ_NEXT(child, link)) {
 1099                 DEVICE_RESUME(child);
 1100                 /* if resume fails, there's nothing we can usefully do... */
 1101         }
 1102         return 0;
 1103 }
 1104 
 1105 void
 1106 bus_generic_print_child(device_t dev, device_t child)
 1107 {
 1108         printf(" on %s%d", device_get_name(dev), device_get_unit(dev));
 1109 }
 1110 
 1111 int
 1112 bus_generic_read_ivar(device_t dev, device_t child, int index, 
 1113                       uintptr_t * result)
 1114 {
 1115     return ENOENT;
 1116 }
 1117 
 1118 int
 1119 bus_generic_write_ivar(device_t dev, device_t child, int index, 
 1120                        uintptr_t value)
 1121 {
 1122     return ENOENT;
 1123 }
 1124 
 1125 int
 1126 bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq, 
 1127                        driver_intr_t *intr, void *arg, void **cookiep)
 1128 {
 1129         /* Propagate up the bus hierarchy until someone handles it. */
 1130         if (dev->parent)
 1131                 return (BUS_SETUP_INTR(dev->parent, child, irq, intr, arg, 
 1132                                        cookiep));
 1133         else
 1134                 return (EINVAL);
 1135 }
 1136 
 1137 int
 1138 bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq,
 1139                           void *cookie)
 1140 {
 1141         /* Propagate up the bus hierarchy until someone handles it. */
 1142         if (dev->parent)
 1143                 return (BUS_TEARDOWN_INTR(dev->parent, child, irq, cookie));
 1144         else
 1145                 return (EINVAL);
 1146 }
 1147 
 1148 struct resource *
 1149 bus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid,
 1150                            u_long start, u_long end, u_long count, u_int flags)
 1151 {
 1152         /* Propagate up the bus hierarchy until someone handles it. */
 1153         if (dev->parent)
 1154                 return (BUS_ALLOC_RESOURCE(dev->parent, child, type, rid, 
 1155                                            start, end, count, flags));
 1156         else
 1157                 return (NULL);
 1158 }
 1159 
 1160 int
 1161 bus_generic_release_resource(device_t dev, device_t child, int type, int rid,
 1162                              struct resource *r)
 1163 {
 1164         /* Propagate up the bus hierarchy until someone handles it. */
 1165         if (dev->parent)
 1166                 return (BUS_RELEASE_RESOURCE(dev->parent, child, type, rid, 
 1167                                              r));
 1168         else
 1169                 return (EINVAL);
 1170 }
 1171 
 1172 int
 1173 bus_generic_activate_resource(device_t dev, device_t child, int type, int rid,
 1174                               struct resource *r)
 1175 {
 1176         /* Propagate up the bus hierarchy until someone handles it. */
 1177         if (dev->parent)
 1178                 return (BUS_ACTIVATE_RESOURCE(dev->parent, child, type, rid, 
 1179                                               r));
 1180         else
 1181                 return (EINVAL);
 1182 }
 1183 
 1184 int
 1185 bus_generic_deactivate_resource(device_t dev, device_t child, int type,
 1186                                 int rid, struct resource *r)
 1187 {
 1188         /* Propagate up the bus hierarchy until someone handles it. */
 1189         if (dev->parent)
 1190                 return (BUS_DEACTIVATE_RESOURCE(dev->parent, child, type, rid,
 1191                                                 r));
 1192         else
 1193                 return (EINVAL);
 1194 }
 1195 
 1196 /*
 1197  * Some convenience functions to make it easier for drivers to use the
 1198  * resource-management functions.  All these really do is hide the
 1199  * indirection through the parent's method table, making for slightly
 1200  * less-wordy code.  In the future, it might make sense for this code
 1201  * to maintain some sort of a list of resources allocated by each device.
 1202  */
 1203 struct resource *
 1204 bus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end,
 1205                    u_long count, u_int flags)
 1206 {
 1207         if (dev->parent == 0)
 1208                 return (0);
 1209         return (BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end,
 1210                                    count, flags));
 1211 }
 1212 
 1213 int
 1214 bus_activate_resource(device_t dev, int type, int rid, struct resource *r)
 1215 {
 1216         if (dev->parent == 0)
 1217                 return (EINVAL);
 1218         return (BUS_ACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
 1219 }
 1220 
 1221 int
 1222 bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r)
 1223 {
 1224         if (dev->parent == 0)
 1225                 return (EINVAL);
 1226         return (BUS_DEACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
 1227 }
 1228 
 1229 int
 1230 bus_release_resource(device_t dev, int type, int rid, struct resource *r)
 1231 {
 1232         if (dev->parent == 0)
 1233                 return (EINVAL);
 1234         return (BUS_RELEASE_RESOURCE(dev->parent, dev,
 1235                                      type, rid, r));
 1236 }
 1237 
 1238 static void
 1239 root_print_child(device_t dev, device_t child)
 1240 {
 1241 }
 1242 
 1243 static int
 1244 root_setup_intr(device_t dev, device_t child, driver_intr_t *intr, void *arg,
 1245                 void **cookiep)
 1246 {
 1247         /*
 1248          * If an interrupt mapping gets to here something bad has happened.
 1249          */
 1250         panic("root_setup_intr");
 1251 }
 1252 
 1253 static device_method_t root_methods[] = {
 1254         /* Device interface */
 1255         DEVMETHOD(device_suspend,       bus_generic_suspend),
 1256         DEVMETHOD(device_resume,        bus_generic_resume),
 1257 
 1258         /* Bus interface */
 1259         DEVMETHOD(bus_print_child,      root_print_child),
 1260         DEVMETHOD(bus_read_ivar,        bus_generic_read_ivar),
 1261         DEVMETHOD(bus_write_ivar,       bus_generic_write_ivar),
 1262         DEVMETHOD(bus_setup_intr,       root_setup_intr),
 1263 
 1264         { 0, 0 }
 1265 };
 1266 
 1267 static driver_t root_driver = {
 1268         "root",
 1269         root_methods,
 1270         DRIVER_TYPE_MISC,
 1271         1,                      /* no softc */
 1272 };
 1273 
 1274 device_t        root_bus;
 1275 devclass_t      root_devclass;
 1276 
 1277 static int
 1278 root_bus_module_handler(module_t mod, int what, void* arg)
 1279 {
 1280     switch (what) {
 1281     case MOD_LOAD:
 1282         compile_methods(&root_driver);
 1283         root_bus = make_device(NULL, "root", 0, NULL);
 1284         root_bus->desc = "System root bus";
 1285         root_bus->ops = root_driver.ops;
 1286         root_bus->driver = &root_driver;
 1287         root_bus->state = DS_ATTACHED;
 1288         root_devclass = devclass_find_internal("root", FALSE);
 1289         return 0;
 1290     }
 1291 
 1292     return 0;
 1293 }
 1294 
 1295 static moduledata_t root_bus_mod = {
 1296         "rootbus",
 1297         root_bus_module_handler,
 1298         0
 1299 };
 1300 DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
 1301 
 1302 void
 1303 root_bus_configure(void)
 1304 {
 1305     device_t dev;
 1306 
 1307     PDEBUG(("."));
 1308 
 1309     for (dev = TAILQ_FIRST(&root_bus->children); dev;
 1310          dev = TAILQ_NEXT(dev, link)) {
 1311         device_probe_and_attach(dev);
 1312     }
 1313 }
 1314 
 1315 int
 1316 driver_module_handler(module_t mod, int what, void *arg)
 1317 {
 1318         int error, i;
 1319         struct driver_module_data *dmd;
 1320         devclass_t bus_devclass;
 1321 
 1322         dmd = (struct driver_module_data *)arg;
 1323         bus_devclass = devclass_find_internal(dmd->dmd_busname, TRUE);
 1324         error = 0;
 1325 
 1326         switch (what) {
 1327         case MOD_LOAD:
 1328                 for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
 1329                         PDEBUG(("Loading module: driver %s on bus %s",
 1330                                 DRIVERNAME(dmd->dmd_drivers[i]), 
 1331                                 dmd->dmd_busname));
 1332                         error = devclass_add_driver(bus_devclass,
 1333                                                     dmd->dmd_drivers[i]);
 1334                 }
 1335                 if (error)
 1336                         break;
 1337 
 1338                 /*
 1339                  * The drivers loaded in this way are assumed to all
 1340                  * implement the same devclass.
 1341                  */
 1342                 *dmd->dmd_devclass =
 1343                         devclass_find_internal(dmd->dmd_drivers[0]->name,
 1344                                                TRUE);
 1345                 break;
 1346 
 1347         case MOD_UNLOAD:
 1348                 for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
 1349                         PDEBUG(("Unloading module: driver %s from bus %s",
 1350                                 DRIVERNAME(dmd->dmd_drivers[i]), 
 1351                                 dmd->dmd_busname));
 1352                         error = devclass_delete_driver(bus_devclass,
 1353                                                        dmd->dmd_drivers[i]);
 1354                 }
 1355                 break;
 1356         }
 1357 
 1358         if (!error && dmd->dmd_chainevh)
 1359                 error = dmd->dmd_chainevh(mod, what, dmd->dmd_chainarg);
 1360         return (error);
 1361 }
 1362 
 1363 #ifdef BUS_DEBUG
 1364 
 1365 /* the _short versions avoid iteration by not calling anything that prints
 1366  * more than oneliners. I love oneliners.
 1367  */
 1368 
 1369 static void
 1370 print_method_list(device_method_t *m, int indent)
 1371 {
 1372         int i;
 1373 
 1374         if (!m)
 1375                 return;
 1376 
 1377         for (i = 0; m->desc; i++, m++)
 1378                 indentprintf(("method %d: %s, offset=%d\n",
 1379                         i, m->desc->name, m->desc->offset));
 1380 }
 1381 
 1382 static void
 1383 print_device_ops(device_ops_t ops, int indent)
 1384 {
 1385         int i;
 1386         int count = 0;
 1387 
 1388         if (!ops)
 1389                 return;
 1390 
 1391         /* we present a list of the methods that are pointing to the
 1392          * error_method, but ignore the 0'th elements; it is always
 1393          * error_method.
 1394          */
 1395         for (i = 1; i < ops->maxoffset; i++) {
 1396                 if (ops->methods[i] == error_method) {
 1397                         if (count == 0)
 1398                                 indentprintf(("error_method:"));
 1399                         printf(" %d", i);
 1400                         count++;
 1401                 }
 1402         }
 1403         if (count)
 1404                 printf("\n");
 1405 
 1406         indentprintf(("(%d method%s, %d valid, %d error_method%s)\n",
 1407                 ops->maxoffset-1, (ops->maxoffset-1 == 1? "":"s"),
 1408                 ops->maxoffset-1-count,
 1409                 count, (count == 1? "":"'s")));
 1410 }
 1411 
 1412 static void
 1413 print_device_short(device_t dev, int indent)
 1414 {
 1415         if (!dev)
 1416                 return;
 1417 
 1418         indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%sivars,%ssoftc,busy=%d\n",
 1419                 dev->unit, dev->desc,
 1420                 (dev->parent? "":"no "),
 1421                 (TAILQ_EMPTY(&dev->children)? "no ":""),
 1422                 (dev->flags&DF_ENABLED? "enabled,":"disabled,"),
 1423                 (dev->flags&DF_FIXEDCLASS? "fixed,":""),
 1424                 (dev->flags&DF_WILDCARD? "wildcard,":""),
 1425                 (dev->ivars? "":"no "),
 1426                 (dev->softc? "":"no "),
 1427                 dev->busy));
 1428 }
 1429 
 1430 static void
 1431 print_device(device_t dev, int indent)
 1432 {
 1433         if (!dev)
 1434                 return;
 1435 
 1436         print_device_short(dev, indent);
 1437 
 1438         indentprintf(("Parent:\n"));
 1439         print_device_short(dev->parent, indent+1);
 1440         indentprintf(("Methods:\n"));
 1441         print_device_ops(dev->ops, indent+1);
 1442         indentprintf(("Driver:\n"));
 1443         print_driver_short(dev->driver, indent+1);
 1444         indentprintf(("Devclass:\n"));
 1445         print_devclass_short(dev->devclass, indent+1);
 1446 }
 1447 
 1448 void
 1449 print_device_tree_short(device_t dev, int indent)
 1450 /* print the device and all its children (indented) */
 1451 {
 1452         device_t child;
 1453 
 1454         if (!dev)
 1455                 return;
 1456 
 1457         print_device_short(dev, indent);
 1458 
 1459         for (child = TAILQ_FIRST(&dev->children); child;
 1460                  child = TAILQ_NEXT(child, link))
 1461                 print_device_tree_short(child, indent+1);
 1462 }
 1463 
 1464 void
 1465 print_device_tree(device_t dev, int indent)
 1466 /* print the device and all its children (indented) */
 1467 {
 1468         device_t child;
 1469 
 1470         if (!dev)
 1471                 return;
 1472 
 1473         print_device(dev, indent);
 1474 
 1475         for (child = TAILQ_FIRST(&dev->children); child;
 1476                  child = TAILQ_NEXT(child, link))
 1477                 print_device_tree(child, indent+1);
 1478 }
 1479 
 1480 static void
 1481 print_driver_short(driver_t *driver, int indent)
 1482 {
 1483         if (!driver)
 1484                 return;
 1485 
 1486         indentprintf(("driver %s: type = %s%s%s%s, softc size = %d\n",
 1487                 driver->name,
 1488                 /* yes, I know this looks silly, but going to bed at
 1489                  * two o'clock and having to get up at 7:30 again is silly
 1490                  * as well. As is sticking your head in a bucket of water.
 1491                  */
 1492                 (driver->type == DRIVER_TYPE_TTY? "tty":""),
 1493                 (driver->type == DRIVER_TYPE_BIO? "bio":""),
 1494                 (driver->type == DRIVER_TYPE_NET? "net":""),
 1495                 (driver->type == DRIVER_TYPE_MISC? "misc":""),
 1496                 driver->softc));
 1497 }
 1498 
 1499 static void
 1500 print_driver(driver_t *driver, int indent)
 1501 {
 1502         if (!driver)
 1503                 return;
 1504 
 1505         print_driver_short(driver, indent);
 1506         indentprintf(("Methods:\n"));
 1507         print_method_list(driver->methods, indent+1);
 1508         indentprintf(("Operations:\n"));
 1509         print_device_ops(driver->ops, indent+1);
 1510 }
 1511 
 1512 
 1513 static void
 1514 print_driver_list(driver_list_t drivers, int indent)
 1515 {
 1516         driver_t *driver;
 1517 
 1518         for (driver = TAILQ_FIRST(&drivers); driver;
 1519              driver = TAILQ_NEXT(driver, link))
 1520                 print_driver(driver, indent);
 1521 }
 1522 
 1523 static void
 1524 print_devclass_short(devclass_t dc, int indent)
 1525 {
 1526         if ( !dc )
 1527                 return;
 1528 
 1529         indentprintf(("devclass %s: max units = %d, next unit = %d\n",
 1530                 dc->name, dc->maxunit, dc->nextunit));
 1531 }
 1532 
 1533 static void
 1534 print_devclass(devclass_t dc, int indent)
 1535 {
 1536         int i;
 1537 
 1538         if ( !dc )
 1539                 return;
 1540 
 1541         print_devclass_short(dc, indent);
 1542         indentprintf(("Drivers:\n"));
 1543         print_driver_list(dc->drivers, indent+1);
 1544 
 1545         indentprintf(("Devices:\n"));
 1546         for (i = 0; i < dc->maxunit; i++)
 1547                 if (dc->devices[i])
 1548                         print_device(dc->devices[i], indent+1);
 1549 }
 1550 
 1551 void
 1552 print_devclass_list_short(void)
 1553 {
 1554         devclass_t dc;
 1555 
 1556         printf("Short listing of devclasses, drivers & devices:\n");
 1557         for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link))
 1558                 print_devclass_short(dc, 0);
 1559 }
 1560 
 1561 void
 1562 print_devclass_list(void)
 1563 {
 1564         devclass_t dc;
 1565 
 1566         printf("Full listing of devclasses, drivers & devices:\n");
 1567         for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link))
 1568                 print_devclass(dc, 0);
 1569 }
 1570 
 1571 #endif

Cache object: 29ee31adf2f32c4ee500b82c51d36179


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