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

Cache object: 80de657d2207c5aef347da2cd6b204b8


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