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/kern_conf.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) 1999-2002 Poul-Henning Kamp
    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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/6.1/sys/kern/kern_conf.c 158179 2006-04-30 16:44:43Z cvs2svn $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/systm.h>
   33 #include <sys/bio.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/module.h>
   37 #include <sys/malloc.h>
   38 #include <sys/conf.h>
   39 #include <sys/vnode.h>
   40 #include <sys/queue.h>
   41 #include <sys/poll.h>
   42 #include <sys/ctype.h>
   43 #include <sys/tty.h>
   44 #include <sys/ucred.h>
   45 #include <machine/stdarg.h>
   46 
   47 #include <fs/devfs/devfs_int.h>
   48 
   49 static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
   50 
   51 struct mtx devmtx;
   52 static void destroy_devl(struct cdev *dev);
   53 static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr,
   54             struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
   55             va_list ap);
   56 
   57 void
   58 dev_lock(void)
   59 {
   60 
   61         mtx_lock(&devmtx);
   62 }
   63 
   64 void
   65 dev_unlock(void)
   66 {
   67 
   68         mtx_unlock(&devmtx);
   69 }
   70 
   71 void
   72 dev_ref(struct cdev *dev)
   73 {
   74 
   75         mtx_assert(&devmtx, MA_NOTOWNED);
   76         mtx_lock(&devmtx);
   77         dev->si_refcount++;
   78         mtx_unlock(&devmtx);
   79 }
   80 
   81 void
   82 dev_refl(struct cdev *dev)
   83 {
   84 
   85         mtx_assert(&devmtx, MA_OWNED);
   86         dev->si_refcount++;
   87 }
   88 
   89 void
   90 dev_rel(struct cdev *dev)
   91 {
   92         int flag = 0;
   93 
   94         mtx_assert(&devmtx, MA_NOTOWNED);
   95         dev_lock();
   96         dev->si_refcount--;
   97         KASSERT(dev->si_refcount >= 0,
   98             ("dev_rel(%s) gave negative count", devtoname(dev)));
   99 #if 0
  100         if (dev->si_usecount == 0 &&
  101             (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
  102                 ;
  103         else 
  104 #endif
  105 if (dev->si_devsw == NULL && dev->si_refcount == 0) {
  106                 LIST_REMOVE(dev, si_list);
  107                 flag = 1;
  108         }
  109         dev_unlock();
  110         if (flag)
  111                 devfs_free(dev);
  112 }
  113 
  114 struct cdevsw *
  115 dev_refthread(struct cdev *dev)
  116 {
  117         struct cdevsw *csw;
  118 
  119         mtx_assert(&devmtx, MA_NOTOWNED);
  120         dev_lock();
  121         csw = dev->si_devsw;
  122         if (csw != NULL)
  123                 dev->si_threadcount++;
  124         dev_unlock();
  125         return (csw);
  126 }
  127 
  128 void    
  129 dev_relthread(struct cdev *dev)
  130 {
  131 
  132         mtx_assert(&devmtx, MA_NOTOWNED);
  133         dev_lock();
  134         dev->si_threadcount--;
  135         dev_unlock();
  136 }
  137 
  138 int
  139 nullop(void)
  140 {
  141 
  142         return (0);
  143 }
  144 
  145 int
  146 eopnotsupp(void)
  147 {
  148 
  149         return (EOPNOTSUPP);
  150 }
  151 
  152 static int
  153 enxio(void)
  154 {
  155         return (ENXIO);
  156 }
  157 
  158 static int
  159 enodev(void)
  160 {
  161         return (ENODEV);
  162 }
  163 
  164 /* Define a dead_cdevsw for use when devices leave unexpectedly. */
  165 
  166 #define dead_open       (d_open_t *)enxio
  167 #define dead_close      (d_close_t *)enxio
  168 #define dead_read       (d_read_t *)enxio
  169 #define dead_write      (d_write_t *)enxio
  170 #define dead_ioctl      (d_ioctl_t *)enxio
  171 #define dead_poll       (d_poll_t *)enodev
  172 #define dead_mmap       (d_mmap_t *)enodev
  173 
  174 static void
  175 dead_strategy(struct bio *bp)
  176 {
  177 
  178         biofinish(bp, NULL, ENXIO);
  179 }
  180 
  181 #define dead_dump       (dumper_t *)enxio
  182 #define dead_kqfilter   (d_kqfilter_t *)enxio
  183 
  184 static struct cdevsw dead_cdevsw = {
  185         .d_version =    D_VERSION,
  186         .d_flags =      D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
  187         .d_open =       dead_open,
  188         .d_close =      dead_close,
  189         .d_read =       dead_read,
  190         .d_write =      dead_write,
  191         .d_ioctl =      dead_ioctl,
  192         .d_poll =       dead_poll,
  193         .d_mmap =       dead_mmap,
  194         .d_strategy =   dead_strategy,
  195         .d_name =       "dead",
  196         .d_dump =       dead_dump,
  197         .d_kqfilter =   dead_kqfilter
  198 };
  199 
  200 /* Default methods if driver does not specify method */
  201 
  202 #define null_open       (d_open_t *)nullop
  203 #define null_close      (d_close_t *)nullop
  204 #define no_read         (d_read_t *)enodev
  205 #define no_write        (d_write_t *)enodev
  206 #define no_ioctl        (d_ioctl_t *)enodev
  207 #define no_mmap         (d_mmap_t *)enodev
  208 #define no_kqfilter     (d_kqfilter_t *)enodev
  209 
  210 static void
  211 no_strategy(struct bio *bp)
  212 {
  213 
  214         biofinish(bp, NULL, ENODEV);
  215 }
  216 
  217 static int
  218 no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
  219 {
  220         /*
  221          * Return true for read/write.  If the user asked for something
  222          * special, return POLLNVAL, so that clients have a way of
  223          * determining reliably whether or not the extended
  224          * functionality is present without hard-coding knowledge
  225          * of specific filesystem implementations.
  226          * Stay in sync with vop_nopoll().
  227          */
  228         if (events & ~POLLSTANDARD)
  229                 return (POLLNVAL);
  230 
  231         return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
  232 }
  233 
  234 #define no_dump         (dumper_t *)enodev
  235 
  236 static int
  237 giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  238 {
  239         int retval;
  240 
  241         mtx_lock(&Giant);
  242         retval = dev->si_devsw->d_gianttrick->
  243             d_open(dev, oflags, devtype, td);
  244         mtx_unlock(&Giant);
  245         return (retval);
  246 }
  247 
  248 static int
  249 giant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx)
  250 {
  251         int retval;
  252 
  253         mtx_lock(&Giant);
  254         retval = dev->si_devsw->d_gianttrick->
  255             d_fdopen(dev, oflags, td, fdidx);
  256         mtx_unlock(&Giant);
  257         return (retval);
  258 }
  259 
  260 static int
  261 giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
  262 {
  263         int retval;
  264 
  265         mtx_lock(&Giant);
  266         retval = dev->si_devsw->d_gianttrick->
  267             d_close(dev, fflag, devtype, td);
  268         mtx_unlock(&Giant);
  269         return (retval);
  270 }
  271 
  272 static void
  273 giant_strategy(struct bio *bp)
  274 {
  275 
  276         mtx_lock(&Giant);
  277         bp->bio_dev->si_devsw->d_gianttrick->
  278             d_strategy(bp);
  279         mtx_unlock(&Giant);
  280 }
  281 
  282 static int
  283 giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  284 {
  285         int retval;
  286 
  287         mtx_lock(&Giant);
  288         retval = dev->si_devsw->d_gianttrick->
  289             d_ioctl(dev, cmd, data, fflag, td);
  290         mtx_unlock(&Giant);
  291         return (retval);
  292 }
  293   
  294 static int
  295 giant_read(struct cdev *dev, struct uio *uio, int ioflag)
  296 {
  297         int retval;
  298 
  299         mtx_lock(&Giant);
  300         retval = dev->si_devsw->d_gianttrick->
  301             d_read(dev, uio, ioflag);
  302         mtx_unlock(&Giant);
  303         return (retval);
  304 }
  305 
  306 static int
  307 giant_write(struct cdev *dev, struct uio *uio, int ioflag)
  308 {
  309         int retval;
  310 
  311         mtx_lock(&Giant);
  312         retval = dev->si_devsw->d_gianttrick->
  313                 d_write(dev, uio, ioflag);
  314         mtx_unlock(&Giant);
  315         return (retval);
  316 }
  317 
  318 static int
  319 giant_poll(struct cdev *dev, int events, struct thread *td)
  320 {
  321         int retval;
  322 
  323         mtx_lock(&Giant);
  324         retval = dev->si_devsw->d_gianttrick->
  325             d_poll(dev, events, td);
  326         mtx_unlock(&Giant);
  327         return (retval);
  328 }
  329 
  330 static int
  331 giant_kqfilter(struct cdev *dev, struct knote *kn)
  332 {
  333         int retval;
  334 
  335         mtx_lock(&Giant);
  336         retval = dev->si_devsw->d_gianttrick->
  337             d_kqfilter(dev, kn);
  338         mtx_unlock(&Giant);
  339         return (retval);
  340 }
  341 
  342 static int
  343 giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
  344 {
  345         int retval;
  346 
  347         mtx_lock(&Giant);
  348         retval = dev->si_devsw->d_gianttrick->
  349             d_mmap(dev, offset, paddr, nprot);
  350         mtx_unlock(&Giant);
  351         return (retval);
  352 }
  353 
  354 
  355 /*
  356  * struct cdev * and u_dev_t primitives
  357  */
  358 
  359 int
  360 minor(struct cdev *x)
  361 {
  362         if (x == NULL)
  363                 return NODEV;
  364         return(x->si_drv0 & MAXMINOR);
  365 }
  366 
  367 int
  368 dev2unit(struct cdev *x)
  369 {
  370 
  371         if (x == NULL)
  372                 return NODEV;
  373         return (minor2unit(minor(x)));
  374 }
  375 
  376 u_int
  377 minor2unit(u_int _minor)
  378 {
  379 
  380         KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
  381         return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
  382 }
  383 
  384 int
  385 unit2minor(int unit)
  386 {
  387 
  388         KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
  389         return ((unit & 0xff) | ((unit << 8) & ~0xffff));
  390 }
  391 
  392 static struct cdev *
  393 newdev(struct cdevsw *csw, int y, struct cdev *si)
  394 {
  395         struct cdev *si2;
  396         dev_t   udev;
  397 
  398         mtx_assert(&devmtx, MA_OWNED);
  399         udev = y;
  400         LIST_FOREACH(si2, &csw->d_devs, si_list) {
  401                 if (si2->si_drv0 == udev) {
  402                         devfs_free(si);
  403                         return (si2);
  404                 }
  405         }
  406         si->si_drv0 = udev;
  407         si->si_devsw = csw;
  408         LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
  409         return (si);
  410 }
  411 
  412 int
  413 uminor(dev_t dev)
  414 {
  415         return (dev & MAXMINOR);
  416 }
  417 
  418 int
  419 umajor(dev_t dev)
  420 {
  421         return ((dev & ~MAXMINOR) >> 8);
  422 }
  423 
  424 static void
  425 fini_cdevsw(struct cdevsw *devsw)
  426 {
  427         struct cdevsw *gt;
  428 
  429         if (devsw->d_gianttrick != NULL) {
  430                 gt = devsw->d_gianttrick;
  431                 memcpy(devsw, gt, sizeof *devsw);
  432                 free(gt, M_DEVT);
  433                 devsw->d_gianttrick = NULL;
  434         }
  435         devsw->d_flags &= ~D_INIT;
  436 }
  437 
  438 static void
  439 prep_cdevsw(struct cdevsw *devsw)
  440 {
  441         struct cdevsw *dsw2;
  442 
  443         if (devsw->d_flags & D_NEEDGIANT)
  444                 dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK);
  445         else
  446                 dsw2 = NULL;
  447         dev_lock();
  448 
  449         if (devsw->d_version != D_VERSION_01) {
  450                 printf(
  451                     "WARNING: Device driver \"%s\" has wrong version %s\n",
  452                     devsw->d_name, "and is disabled.  Recompile KLD module.");
  453                 devsw->d_open = dead_open;
  454                 devsw->d_close = dead_close;
  455                 devsw->d_read = dead_read;
  456                 devsw->d_write = dead_write;
  457                 devsw->d_ioctl = dead_ioctl;
  458                 devsw->d_poll = dead_poll;
  459                 devsw->d_mmap = dead_mmap;
  460                 devsw->d_strategy = dead_strategy;
  461                 devsw->d_dump = dead_dump;
  462                 devsw->d_kqfilter = dead_kqfilter;
  463         }
  464         
  465         if (devsw->d_flags & D_TTY) {
  466                 if (devsw->d_ioctl == NULL)     devsw->d_ioctl = ttyioctl;
  467                 if (devsw->d_read == NULL)      devsw->d_read = ttyread;
  468                 if (devsw->d_write == NULL)     devsw->d_write = ttywrite;
  469                 if (devsw->d_kqfilter == NULL)  devsw->d_kqfilter = ttykqfilter;
  470                 if (devsw->d_poll == NULL)      devsw->d_poll = ttypoll;
  471         }
  472 
  473         if (devsw->d_flags & D_NEEDGIANT) {
  474                 if (devsw->d_gianttrick == NULL) {
  475                         memcpy(dsw2, devsw, sizeof *dsw2);
  476                         devsw->d_gianttrick = dsw2;
  477                 } else
  478                         free(dsw2, M_DEVT);
  479         }
  480 
  481 #define FIXUP(member, noop, giant)                              \
  482         do {                                                    \
  483                 if (devsw->member == NULL) {                    \
  484                         devsw->member = noop;                   \
  485                 } else if (devsw->d_flags & D_NEEDGIANT)        \
  486                         devsw->member = giant;                  \
  487                 }                                               \
  488         while (0)
  489 
  490         FIXUP(d_open,           null_open,      giant_open);
  491         FIXUP(d_fdopen,         NULL,           giant_fdopen);
  492         FIXUP(d_close,          null_close,     giant_close);
  493         FIXUP(d_read,           no_read,        giant_read);
  494         FIXUP(d_write,          no_write,       giant_write);
  495         FIXUP(d_ioctl,          no_ioctl,       giant_ioctl);
  496         FIXUP(d_poll,           no_poll,        giant_poll);
  497         FIXUP(d_mmap,           no_mmap,        giant_mmap);
  498         FIXUP(d_strategy,       no_strategy,    giant_strategy);
  499         FIXUP(d_kqfilter,       no_kqfilter,    giant_kqfilter);
  500 
  501         if (devsw->d_dump == NULL)      devsw->d_dump = no_dump;
  502 
  503         LIST_INIT(&devsw->d_devs);
  504 
  505         devsw->d_flags |= D_INIT;
  506 
  507         dev_unlock();
  508 }
  509 
  510 static struct cdev *
  511 make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
  512     gid_t gid, int mode, const char *fmt, va_list ap)
  513 {
  514         struct cdev *dev;
  515         int i;
  516 
  517         KASSERT((minornr & ~MAXMINOR) == 0,
  518             ("Invalid minor (0x%x) in make_dev", minornr));
  519 
  520         if (!(devsw->d_flags & D_INIT)) 
  521                 prep_cdevsw(devsw);
  522         dev = devfs_alloc();
  523         dev_lock();
  524         dev = newdev(devsw, minornr, dev);
  525         if (dev->si_flags & SI_CHEAPCLONE &&
  526             dev->si_flags & SI_NAMED) {
  527                 /*
  528                  * This is allowed as it removes races and generally
  529                  * simplifies cloning devices.
  530                  * XXX: still ??
  531                  */
  532                 dev_unlock();
  533                 return (dev);
  534         }
  535         KASSERT(!(dev->si_flags & SI_NAMED),
  536             ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
  537             devsw->d_name, minor(dev), devtoname(dev)));
  538 
  539         i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
  540         if (i > (sizeof dev->__si_namebuf - 1)) {
  541                 printf("WARNING: Device name truncated! (%s)\n", 
  542                     dev->__si_namebuf);
  543         }
  544                 
  545         dev->si_flags |= SI_NAMED;
  546         if (cr != NULL)
  547                 dev->si_cred = crhold(cr);
  548         else
  549                 dev->si_cred = NULL;
  550         dev->si_uid = uid;
  551         dev->si_gid = gid;
  552         dev->si_mode = mode;
  553 
  554         devfs_create(dev);
  555         dev_unlock();
  556         return (dev);
  557 }
  558 
  559 struct cdev *
  560 make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode,
  561     const char *fmt, ...)
  562 {
  563         struct cdev *dev;
  564         va_list ap;
  565 
  566         va_start(ap, fmt);
  567         dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap);
  568         va_end(ap);
  569         return (dev);
  570 }
  571 
  572 struct cdev *
  573 make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
  574     gid_t gid, int mode, const char *fmt, ...)
  575 {
  576         struct cdev *dev;
  577         va_list ap;
  578 
  579         va_start(ap, fmt);
  580         dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap);
  581         va_end(ap);
  582 
  583         return (dev);
  584 }
  585 
  586 static void
  587 dev_dependsl(struct cdev *pdev, struct cdev *cdev)
  588 {
  589 
  590         cdev->si_parent = pdev;
  591         cdev->si_flags |= SI_CHILD;
  592         LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
  593 }
  594 
  595 
  596 void
  597 dev_depends(struct cdev *pdev, struct cdev *cdev)
  598 {
  599 
  600         dev_lock();
  601         dev_dependsl(pdev, cdev);
  602         dev_unlock();
  603 }
  604 
  605 struct cdev *
  606 make_dev_alias(struct cdev *pdev, const char *fmt, ...)
  607 {
  608         struct cdev *dev;
  609         va_list ap;
  610         int i;
  611 
  612         dev = devfs_alloc();
  613         dev_lock();
  614         dev->si_flags |= SI_ALIAS;
  615         dev->si_flags |= SI_NAMED;
  616         va_start(ap, fmt);
  617         i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
  618         if (i > (sizeof dev->__si_namebuf - 1)) {
  619                 printf("WARNING: Device name truncated! (%s)\n", 
  620                     dev->__si_namebuf);
  621         }
  622         va_end(ap);
  623 
  624         devfs_create(dev);
  625         dev_unlock();
  626         dev_depends(pdev, dev);
  627         return (dev);
  628 }
  629 
  630 static void
  631 destroy_devl(struct cdev *dev)
  632 {
  633         struct cdevsw *csw;
  634 
  635         mtx_assert(&devmtx, MA_OWNED);
  636         KASSERT(dev->si_flags & SI_NAMED,
  637             ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
  638                 
  639         devfs_destroy(dev);
  640 
  641         /* Remove name marking */
  642         dev->si_flags &= ~SI_NAMED;
  643 
  644         /* If we are a child, remove us from the parents list */
  645         if (dev->si_flags & SI_CHILD) {
  646                 LIST_REMOVE(dev, si_siblings);
  647                 dev->si_flags &= ~SI_CHILD;
  648         }
  649 
  650         /* Kill our children */
  651         while (!LIST_EMPTY(&dev->si_children))
  652                 destroy_devl(LIST_FIRST(&dev->si_children));
  653 
  654         /* Remove from clone list */
  655         if (dev->si_flags & SI_CLONELIST) {
  656                 LIST_REMOVE(dev, si_clone);
  657                 dev->si_flags &= ~SI_CLONELIST;
  658         }
  659 
  660         csw = dev->si_devsw;
  661         dev->si_devsw = NULL;   /* already NULL for SI_ALIAS */
  662         while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
  663                 printf("Purging %lu threads from %s\n",
  664                     dev->si_threadcount, devtoname(dev));
  665                 csw->d_purge(dev);
  666                 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
  667         }
  668         if (csw != NULL && csw->d_purge != NULL)
  669                 printf("All threads purged from %s\n", devtoname(dev));
  670 
  671         dev->si_drv1 = 0;
  672         dev->si_drv2 = 0;
  673         bzero(&dev->__si_u, sizeof(dev->__si_u));
  674 
  675         if (!(dev->si_flags & SI_ALIAS)) {
  676                 /* Remove from cdevsw list */
  677                 LIST_REMOVE(dev, si_list);
  678 
  679                 /* If cdevsw has no more struct cdev *'s, clean it */
  680                 if (LIST_EMPTY(&csw->d_devs))
  681                         fini_cdevsw(csw);
  682         }
  683         dev->si_flags &= ~SI_ALIAS;
  684 
  685         if (dev->si_refcount > 0) {
  686                 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
  687         } else {
  688                 devfs_free(dev);
  689         }
  690 }
  691 
  692 void
  693 destroy_dev(struct cdev *dev)
  694 {
  695 
  696         dev_lock();
  697         destroy_devl(dev);
  698         dev_unlock();
  699 }
  700 
  701 const char *
  702 devtoname(struct cdev *dev)
  703 {
  704         char *p;
  705         struct cdevsw *csw;
  706         int mynor;
  707 
  708         if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
  709                 p = dev->si_name;
  710                 csw = dev_refthread(dev);
  711                 if (csw != NULL) {
  712                         sprintf(p, "(%s)", csw->d_name);
  713                         dev_relthread(dev);
  714                 }
  715                 p += strlen(p);
  716                 mynor = minor(dev);
  717                 if (mynor < 0 || mynor > 255)
  718                         sprintf(p, "/%#x", (u_int)mynor);
  719                 else
  720                         sprintf(p, "/%d", mynor);
  721         }
  722         return (dev->si_name);
  723 }
  724 
  725 int
  726 dev_stdclone(char *name, char **namep, const char *stem, int *unit)
  727 {
  728         int u, i;
  729 
  730         i = strlen(stem);
  731         if (bcmp(stem, name, i) != 0)
  732                 return (0);
  733         if (!isdigit(name[i]))
  734                 return (0);
  735         u = 0;
  736         if (name[i] == '' && isdigit(name[i+1]))
  737                 return (0);
  738         while (isdigit(name[i])) {
  739                 u *= 10;
  740                 u += name[i++] - '';
  741         }
  742         if (u > 0xffffff)
  743                 return (0);
  744         *unit = u;
  745         if (namep)
  746                 *namep = &name[i];
  747         if (name[i]) 
  748                 return (2);
  749         return (1);
  750 }
  751 
  752 /*
  753  * Helper functions for cloning device drivers.
  754  *
  755  * The objective here is to make it unnecessary for the device drivers to
  756  * use rman or similar to manage their unit number space.  Due to the way
  757  * we do "on-demand" devices, using rman or other "private" methods 
  758  * will be very tricky to lock down properly once we lock down this file.
  759  *
  760  * Instead we give the drivers these routines which puts the struct cdev *'s
  761  * that are to be managed on their own list, and gives the driver the ability
  762  * to ask for the first free unit number or a given specified unit number.
  763  *
  764  * In addition these routines support paired devices (pty, nmdm and similar)
  765  * by respecting a number of "flag" bits in the minor number.
  766  *
  767  */
  768 
  769 struct clonedevs {
  770         LIST_HEAD(,cdev)        head;
  771 };
  772 
  773 void
  774 clone_setup(struct clonedevs **cdp)
  775 {
  776 
  777         *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
  778         LIST_INIT(&(*cdp)->head);
  779 }
  780 
  781 int
  782 clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
  783 {
  784         struct clonedevs *cd;
  785         struct cdev *dev, *ndev, *dl, *de;
  786         int unit, low, u;
  787 
  788         KASSERT(*cdp != NULL,
  789             ("clone_setup() not called in driver \"%s\"", csw->d_name));
  790         KASSERT(!(extra & CLONE_UNITMASK),
  791             ("Illegal extra bits (0x%x) in clone_create", extra));
  792         KASSERT(*up <= CLONE_UNITMASK,
  793             ("Too high unit (0x%x) in clone_create", *up));
  794 
  795         if (!(csw->d_flags & D_INIT))
  796                 prep_cdevsw(csw);
  797 
  798         /*
  799          * Search the list for a lot of things in one go:
  800          *   A preexisting match is returned immediately.
  801          *   The lowest free unit number if we are passed -1, and the place
  802          *       in the list where we should insert that new element.
  803          *   The place to insert a specified unit number, if applicable
  804          *       the end of the list.
  805          */
  806         unit = *up;
  807         ndev = devfs_alloc();
  808         dev_lock();
  809         low = extra;
  810         de = dl = NULL;
  811         cd = *cdp;
  812         LIST_FOREACH(dev, &cd->head, si_clone) {
  813                 KASSERT(dev->si_flags & SI_CLONELIST,
  814                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
  815                 u = dev2unit(dev);
  816                 if (u == (unit | extra)) {
  817                         *dp = dev;
  818                         devfs_free(ndev);
  819                         dev_unlock();
  820                         return (0);
  821                 }
  822                 if (unit == -1 && u == low) {
  823                         low++;
  824                         de = dev;
  825                         continue;
  826                 } else if (u < (unit | extra)) {
  827                         de = dev;
  828                         continue;
  829                 } else if (u > (unit | extra)) {
  830                         dl = dev;
  831                         break;
  832                 }
  833         }
  834         if (unit == -1)
  835                 unit = low & CLONE_UNITMASK;
  836         dev = newdev(csw, unit2minor(unit | extra), ndev);
  837         if (dev->si_flags & SI_CLONELIST) {
  838                 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
  839                 printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
  840                 LIST_FOREACH(dev, &cd->head, si_clone) {
  841                         printf("\t%p %s\n", dev, dev->si_name);
  842                 }
  843                 panic("foo");
  844         }
  845         KASSERT(!(dev->si_flags & SI_CLONELIST),
  846             ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
  847         if (dl != NULL)
  848                 LIST_INSERT_BEFORE(dl, dev, si_clone);
  849         else if (de != NULL)
  850                 LIST_INSERT_AFTER(de, dev, si_clone);
  851         else
  852                 LIST_INSERT_HEAD(&cd->head, dev, si_clone);
  853         dev->si_flags |= SI_CLONELIST;
  854         *up = unit;
  855         dev_unlock();
  856         return (1);
  857 }
  858 
  859 /*
  860  * Kill everything still on the list.  The driver should already have
  861  * disposed of any softc hung of the struct cdev *'s at this time.
  862  */
  863 void
  864 clone_cleanup(struct clonedevs **cdp)
  865 {
  866         struct cdev *dev, *tdev;
  867         struct clonedevs *cd;
  868         
  869         cd = *cdp;
  870         if (cd == NULL)
  871                 return;
  872         dev_lock();
  873         LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
  874                 KASSERT(dev->si_flags & SI_CLONELIST,
  875                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
  876                 KASSERT(dev->si_flags & SI_NAMED,
  877                     ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
  878                 destroy_devl(dev);
  879         }
  880         dev_unlock();
  881         free(cd, M_DEVBUF);
  882         *cdp = NULL;
  883 }

Cache object: 68993dd221cbdb878f17b400c932eb9c


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