kern_conf.c revision 135726
121308Sache/*- 221308Sache * Copyright (c) 1999-2002 Poul-Henning Kamp 3157184Sache * All rights reserved. 421308Sache * 521308Sache * Redistribution and use in source and binary forms, with or without 621308Sache * modification, are permitted provided that the following conditions 721308Sache * are met: 821308Sache * 1. Redistributions of source code must retain the above copyright 921308Sache * notice, this list of conditions and the following disclaimer. 1058310Sache * 2. Redistributions in binary form must reproduce the above copyright 1121308Sache * notice, this list of conditions and the following disclaimer in the 1221308Sache * documentation and/or other materials provided with the distribution. 1321308Sache * 1421308Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1521308Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1621308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1721308Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1821308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1921308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2021308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2158310Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2221308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2321308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2421308Sache * SUCH DAMAGE. 2521308Sache */ 2621308Sache 2721308Sache#include <sys/cdefs.h> 2821308Sache__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 135726 2004-09-24 08:30:57Z phk $"); 2921308Sache 3021308Sache#include <sys/param.h> 3121308Sache#include <sys/kernel.h> 3221308Sache#include <sys/systm.h> 3321308Sache#include <sys/bio.h> 3421308Sache#include <sys/lock.h> 3521308Sache#include <sys/mutex.h> 3621308Sache#include <sys/sysctl.h> 3721308Sache#include <sys/module.h> 3821308Sache#include <sys/malloc.h> 3921308Sache#include <sys/conf.h> 4021308Sache#include <sys/vnode.h> 4121308Sache#include <sys/queue.h> 4221308Sache#include <sys/poll.h> 4321308Sache#include <sys/ctype.h> 4421308Sache#include <sys/tty.h> 4521308Sache#include <machine/stdarg.h> 4621308Sache 4721308Sachestatic MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 4858310Sache 4958310Sache/* Built at compile time from sys/conf/majors */ 5021308Sacheextern unsigned char reserved_majors[256]; 5121308Sache 5221308Sache/* 5321308Sache * This is the number of hash-buckets. Experiments with 'real-life' 5421308Sache * dev_t's show that a prime halfway between two powers of two works 5521308Sache * best. 5621308Sache */ 5721308Sache#define DEVT_HASH 83 5821308Sache 5921308Sache/* The number of struct cdev *'s we can create before malloc(9) kick in. */ 6021308Sache#define DEVT_STASH 50 6121308Sache 6221308Sachestatic struct cdev devt_stash[DEVT_STASH]; 6321308Sache 6475406Sachestatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 6521308Sache 6621308Sachestatic LIST_HEAD(, cdev) dev_free; 6721308Sache 6858310Sachestatic int free_devt; 6958310SacheSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 7058310Sache 7158310Sachestatic struct mtx devmtx; 7258310Sachestatic void freedev(struct cdev *dev); 7358310Sachestatic struct cdev *newdev(int x, int y); 7458310Sache 7547558Sache 76136644Sachevoid 77136644Sachedev_lock(void) 78136644Sache{ 79136644Sache if (!mtx_initialized(&devmtx)) 80119610Sache mtx_init(&devmtx, "cdev", NULL, MTX_DEF); 81119610Sache mtx_lock(&devmtx); 8247558Sache} 8347558Sache 8447558Sachevoid 8547558Sachedev_unlock(void) 8647558Sache{ 8747558Sache 8847558Sache mtx_unlock(&devmtx); 8947558Sache} 9047558Sache 9147558Sachevoid 92136644Sachedev_ref(struct cdev *dev) 93136644Sache{ 9447558Sache 9547558Sache dev_lock(); 9647558Sache dev->si_refcount++; 9747558Sache dev_unlock(); 9847558Sache} 9921308Sache 10021308Sachevoid 10121308Sachedev_rel(struct cdev *dev) 10221308Sache{ 10321308Sache 10421308Sache dev->si_refcount--; 10547558Sache KASSERT(dev->si_refcount >= 0, 10647558Sache ("dev_rel(%s) gave negative count", devtoname(dev))); 10726497Sache if (dev->si_devsw == NULL && dev->si_refcount == 0) { 10826497Sache LIST_REMOVE(dev, si_list); 10921308Sache freedev(dev); 11021308Sache } 11121308Sache} 11221308Sachestruct cdevsw * 11321308Sachedev_refthread(struct cdev *dev) 11421308Sache{ 11521308Sache struct cdevsw *csw; 11621308Sache 11721308Sache mtx_assert(&devmtx, MA_NOTOWNED); 11821308Sache dev_lock(); 11921308Sache csw = dev->si_devsw; 12021308Sache if (csw != NULL) 12121308Sache dev->si_threadcount++; 12221308Sache dev_unlock(); 12321308Sache return (csw); 12426497Sache} 12526497Sache 12626497Sachevoid 12721308Sachedev_relthread(struct cdev *dev) 12821308Sache{ 12975406Sache 13075406Sache mtx_assert(&devmtx, MA_NOTOWNED); 13121308Sache dev_lock(); 13221308Sache dev->si_threadcount--; 13321308Sache dev_unlock(); 134157184Sache} 13521308Sache 136157184Sacheint 137157184Sachenullop(void) 138157184Sache{ 13926497Sache 14021308Sache return (0); 14121308Sache} 14221308Sache 14321308Sacheint 14421308Sacheeopnotsupp(void) 14547558Sache{ 14647558Sache 14721308Sache return (EOPNOTSUPP); 148157184Sache} 14921308Sache 15021308Sachestatic int 15121308Sacheenxio(void) 15221308Sache{ 15321308Sache return (ENXIO); 154157184Sache} 15521308Sache 156157184Sachestatic int 157157184Sacheenodev(void) 15847558Sache{ 159157184Sache return (ENODEV); 16047558Sache} 16121308Sache 16221308Sache/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 163165670Sache 16421308Sache#define dead_open (d_open_t *)enxio 16521308Sache#define dead_close (d_close_t *)enxio 16621308Sache#define dead_read (d_read_t *)enxio 16721308Sache#define dead_write (d_write_t *)enxio 16821308Sache#define dead_ioctl (d_ioctl_t *)enxio 16921308Sache#define dead_poll (d_poll_t *)enodev 17021308Sache#define dead_mmap (d_mmap_t *)enodev 17121308Sache 17258310Sachestatic void 17358310Sachedead_strategy(struct bio *bp) 17458310Sache{ 17558310Sache 176157184Sache biofinish(bp, NULL, ENXIO); 17721308Sache} 178157184Sache 179157184Sache#define dead_dump (dumper_t *)enxio 180157184Sache#define dead_kqfilter (d_kqfilter_t *)enxio 18121308Sache 18221308Sachestatic struct cdevsw dead_cdevsw = { 18321308Sache .d_version = D_VERSION, 18421308Sache .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 18521308Sache .d_open = dead_open, 18621308Sache .d_close = dead_close, 18721308Sache .d_read = dead_read, 18821308Sache .d_write = dead_write, 18921308Sache .d_ioctl = dead_ioctl, 19021308Sache .d_poll = dead_poll, 19147558Sache .d_mmap = dead_mmap, 19221308Sache .d_strategy = dead_strategy, 19321308Sache .d_name = "dead", 19475406Sache .d_maj = 255, 19521308Sache .d_dump = dead_dump, 19621308Sache .d_kqfilter = dead_kqfilter 19721308Sache}; 19821308Sache 19921308Sache/* Default methods if driver does not specify method */ 20047558Sache 20121308Sache#define null_open (d_open_t *)nullop 20221308Sache#define null_close (d_close_t *)nullop 20321308Sache#define no_read (d_read_t *)enodev 20421308Sache#define no_write (d_write_t *)enodev 20526497Sache#define no_ioctl (d_ioctl_t *)enodev 20626497Sache#define no_mmap (d_mmap_t *)enodev 20726497Sache#define no_kqfilter (d_kqfilter_t *)enodev 20826497Sache 20926497Sachestatic void 21026497Sacheno_strategy(struct bio *bp) 21126497Sache{ 21247558Sache 21326497Sache biofinish(bp, NULL, ENODEV); 21426497Sache} 21575406Sache 21647558Sachestatic int 21721308Sacheno_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 21821308Sache{ 21921308Sache /* 22021308Sache * Return true for read/write. If the user asked for something 22121308Sache * special, return POLLNVAL, so that clients have a way of 22221308Sache * determining reliably whether or not the extended 22375406Sache * functionality is present without hard-coding knowledge 22421308Sache * of specific filesystem implementations. 22521308Sache * Stay in sync with vop_nopoll(). 22621308Sache */ 22721308Sache if (events & ~POLLSTANDARD) 22821308Sache return (POLLNVAL); 22921308Sache 23021308Sache return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 23121308Sache} 23221308Sache 23321308Sache#define no_dump (dumper_t *)enodev 23421308Sache 23521308Sache/* 23621308Sache * struct cdev * and u_dev_t primitives 23721308Sache */ 23821308Sache 23921308Sacheint 24021308Sachemajor(struct cdev *x) 24121308Sache{ 24221308Sache if (x == NULL) 24321308Sache return NODEV; 24421308Sache return((x->si_udev >> 8) & 0xff); 24521308Sache} 24621308Sache 24721308Sacheint 24821308Sacheminor(struct cdev *x) 24921308Sache{ 25058310Sache if (x == NULL) 25121308Sache return NODEV; 25221308Sache return(x->si_udev & 0xffff00ff); 25321308Sache} 25421308Sache 255136644Sacheint 25621308Sachedev2unit(struct cdev *x) 25721308Sache{ 25858310Sache int i; 25921308Sache 26058310Sache if (x == NULL) 26121308Sache return NODEV; 26258310Sache i = minor(x); 26358310Sache return ((i & 0xff) | (i >> 8)); 26458310Sache} 26558310Sache 26658310Sacheint 26758310Sacheunit2minor(int unit) 26858310Sache{ 26921308Sache 27021308Sache KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 27121308Sache return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 27247558Sache} 27347558Sache 27447558Sachestatic struct cdev * 27547558Sacheallocdev(void) 27647558Sache{ 27747558Sache static int stashed; 27847558Sache struct cdev *si; 27947558Sache 28047558Sache if (LIST_FIRST(&dev_free)) { 28147558Sache si = LIST_FIRST(&dev_free); 28247558Sache LIST_REMOVE(si, si_hash); 28347558Sache } else if (stashed >= DEVT_STASH) { 28447558Sache MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 28547558Sache M_USE_RESERVE | M_ZERO | M_WAITOK); 28647558Sache } else { 28721308Sache si = devt_stash + stashed++; 28821308Sache bzero(si, sizeof *si); 28921308Sache si->si_flags |= SI_STASHED; 29021308Sache } 29121308Sache si->__si_namebuf[0] = '\0'; 292165670Sache si->si_name = si->__si_namebuf; 293165670Sache LIST_INIT(&si->si_children); 294165670Sache return (si); 295165670Sache} 29621308Sache 297165670Sachestatic struct cdev * 298165670Sachenewdev(int x, int y) 299165670Sache{ 300165670Sache struct cdev *si; 301165670Sache dev_t udev; 302165670Sache int hash; 303165670Sache 304165670Sache if (x == umajor(NODEV) && y == uminor(NODEV)) 305165670Sache panic("newdev of NODEV"); 306165670Sache udev = (x << 8) | y; 307165670Sache hash = udev % DEVT_HASH; 308165670Sache LIST_FOREACH(si, &dev_hash[hash], si_hash) { 309165670Sache if (si->si_udev == udev) 310165670Sache return (si); 311165670Sache } 312165670Sache si = allocdev(); 313165670Sache si->si_udev = udev; 314165670Sache LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 315165670Sache return (si); 316165670Sache} 317165670Sache 318165670Sachestatic void 319165670Sachefreedev(struct cdev *dev) 320165670Sache{ 321165670Sache 322165670Sache if (dev->si_flags & SI_STASHED) { 32347558Sache bzero(dev, sizeof(*dev)); 32447558Sache dev->si_flags |= SI_STASHED; 325165670Sache LIST_INSERT_HEAD(&dev_free, dev, si_hash); 326165670Sache } else { 327165670Sache FREE(dev, M_DEVT); 328165670Sache } 329165670Sache} 33047558Sache 33147558Sachedev_t 332157184Sachedev2udev(struct cdev *x) 33347558Sache{ 334157184Sache if (x == NULL) 33521308Sache return (NODEV); 336157184Sache return (x->si_udev); 33747558Sache} 33847558Sache 33947558Sachestruct cdev * 34021308Sachefindcdev(dev_t udev) 34147558Sache{ 34247558Sache struct cdev *si; 34347558Sache int hash; 34447558Sache 34547558Sache if (udev == NODEV) 34647558Sache return (NULL); 34721308Sache hash = udev % DEVT_HASH; 348157184Sache LIST_FOREACH(si, &dev_hash[hash], si_hash) { 34921308Sache if (si->si_udev == udev) 35021308Sache return (si); 35147558Sache } 35221308Sache return (NULL); 35321308Sache} 35421308Sache 35547558Sacheint 35621308Sacheuminor(dev_t dev) 35721308Sache{ 35847558Sache return (dev & 0xffff00ff); 35947558Sache} 36047558Sache 36126497Sacheint 36247558Sacheumajor(dev_t dev) 363165670Sache{ 364165670Sache return ((dev & 0xff00) >> 8); 365165670Sache} 366165670Sache 36747558Sachestatic void 36821308Sachefind_major(struct cdevsw *devsw) 36921308Sache{ 37047558Sache int i; 37147558Sache 37247558Sache for (i = NUMCDEVSW - 1; i > 0; i--) 37347558Sache if (reserved_majors[i] != i) 37447558Sache break; 37521308Sache KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 37621308Sache devsw->d_maj = i; 37721308Sache reserved_majors[i] = i; 37821308Sache devsw->d_flags |= D_ALLOCMAJ; 37921308Sache} 38021308Sache 38121308Sachestatic void 38221308Sachefini_cdevsw(struct cdevsw *devsw) 38321308Sache{ 38421308Sache if (devsw->d_flags & D_ALLOCMAJ) { 38547558Sache reserved_majors[devsw->d_maj] = 0; 38647558Sache devsw->d_maj = MAJOR_AUTO; 38747558Sache devsw->d_flags &= ~D_ALLOCMAJ; 38821308Sache } else if (devsw->d_maj == 0) 38947558Sache devsw->d_maj = 256; 39047558Sache devsw->d_flags &= ~D_INIT; 391157184Sache} 39247558Sache 393157184Sachestatic void 394157184Sacheprep_cdevsw(struct cdevsw *devsw) 39547558Sache{ 396157184Sache 39721308Sache dev_lock(); 39821308Sache 39947558Sache if (devsw->d_version != D_VERSION_00) { 40047558Sache printf( 40121308Sache "WARNING: Device driver \"%s\" has wrong version %s\n", 40221308Sache devsw->d_name, "and is disabled. Recompile KLD module."); 40347558Sache devsw->d_open = dead_open; 40421308Sache devsw->d_close = dead_close; 40521308Sache devsw->d_read = dead_read; 40647558Sache devsw->d_write = dead_write; 40747558Sache devsw->d_ioctl = dead_ioctl; 40847558Sache devsw->d_poll = dead_poll; 40926497Sache devsw->d_mmap = dead_mmap; 41047558Sache devsw->d_strategy = dead_strategy; 41147558Sache devsw->d_dump = dead_dump; 41221308Sache devsw->d_kqfilter = dead_kqfilter; 41321308Sache } 41447558Sache 41547558Sache if (devsw->d_flags & D_TTY) { 41647558Sache if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 41747558Sache if (devsw->d_read == NULL) devsw->d_read = ttyread; 41847558Sache if (devsw->d_write == NULL) devsw->d_write = ttywrite; 41947558Sache if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 42021308Sache if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 42121308Sache } 42221308Sache 42321308Sache if (devsw->d_open == NULL) devsw->d_open = null_open; 42447558Sache if (devsw->d_close == NULL) devsw->d_close = null_close; 42547558Sache if (devsw->d_read == NULL) devsw->d_read = no_read; 42647558Sache if (devsw->d_write == NULL) devsw->d_write = no_write; 42747558Sache if (devsw->d_ioctl == NULL) devsw->d_ioctl = no_ioctl; 42847558Sache if (devsw->d_poll == NULL) devsw->d_poll = no_poll; 42947558Sache if (devsw->d_mmap == NULL) devsw->d_mmap = no_mmap; 43047558Sache if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy; 431157184Sache if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 432157184Sache if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter; 433165670Sache 43447558Sache LIST_INIT(&devsw->d_devs); 43547558Sache 43647558Sache devsw->d_flags |= D_INIT; 43747558Sache 43847558Sache if (devsw->d_maj == MAJOR_AUTO) { 43947558Sache find_major(devsw); 44047558Sache } else { 441157184Sache if (devsw->d_maj == 256) /* XXX: tty_cons.c is magic */ 442157184Sache devsw->d_maj = 0; 44347558Sache KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256, 44447558Sache ("Invalid major (%d) in make_dev", devsw->d_maj)); 44547558Sache if (reserved_majors[devsw->d_maj] != devsw->d_maj) { 44647558Sache printf("WARNING: driver \"%s\" used %s %d\n", 44747558Sache devsw->d_name, "unreserved major device number", 44847558Sache devsw->d_maj); 44947558Sache reserved_majors[devsw->d_maj] = devsw->d_maj; 45047558Sache } 45147558Sache } 45247558Sache dev_unlock(); 45347558Sache} 45447558Sache 45575406Sachestruct cdev * 45647558Sachemake_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 45747558Sache{ 45847558Sache struct cdev *dev; 45947558Sache va_list ap; 46047558Sache int i; 46147558Sache 46247558Sache KASSERT((minornr & ~0xffff00ff) == 0, 463157184Sache ("Invalid minor (0x%x) in make_dev", minornr)); 46447558Sache 46547558Sache if (!(devsw->d_flags & D_INIT)) 46621308Sache prep_cdevsw(devsw); 467 dev = newdev(devsw->d_maj, minornr); 468 if (dev->si_flags & SI_CHEAPCLONE && 469 dev->si_flags & SI_NAMED && 470 dev->si_devsw == devsw) { 471 /* 472 * This is allowed as it removes races and generally 473 * simplifies cloning devices. 474 * XXX: still ?? 475 */ 476 return (dev); 477 } 478 dev_lock(); 479 KASSERT(!(dev->si_flags & SI_NAMED), 480 ("make_dev() by driver %s on pre-existing device (maj=%d, min=%d, name=%s)", 481 devsw->d_name, major(dev), minor(dev), devtoname(dev))); 482 483 va_start(ap, fmt); 484 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 485 if (i > (sizeof dev->__si_namebuf - 1)) { 486 printf("WARNING: Device name truncated! (%s)\n", 487 dev->__si_namebuf); 488 } 489 va_end(ap); 490 dev->si_devsw = devsw; 491 dev->si_uid = uid; 492 dev->si_gid = gid; 493 dev->si_mode = perms; 494 dev->si_flags |= SI_NAMED; 495 496 LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list); 497 devfs_create(dev); 498 dev_unlock(); 499 return (dev); 500} 501 502int 503dev_named(struct cdev *pdev, const char *name) 504{ 505 struct cdev *cdev; 506 507 if (strcmp(devtoname(pdev), name) == 0) 508 return (1); 509 LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 510 if (strcmp(devtoname(cdev), name) == 0) 511 return (1); 512 return (0); 513} 514 515void 516dev_depends(struct cdev *pdev, struct cdev *cdev) 517{ 518 519 dev_lock(); 520 cdev->si_parent = pdev; 521 cdev->si_flags |= SI_CHILD; 522 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 523 dev_unlock(); 524} 525 526struct cdev * 527make_dev_alias(struct cdev *pdev, const char *fmt, ...) 528{ 529 struct cdev *dev; 530 va_list ap; 531 int i; 532 533 dev = allocdev(); 534 dev_lock(); 535 dev->si_flags |= SI_ALIAS; 536 dev->si_flags |= SI_NAMED; 537 va_start(ap, fmt); 538 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 539 if (i > (sizeof dev->__si_namebuf - 1)) { 540 printf("WARNING: Device name truncated! (%s)\n", 541 dev->__si_namebuf); 542 } 543 va_end(ap); 544 545 devfs_create(dev); 546 dev_unlock(); 547 dev_depends(pdev, dev); 548 return (dev); 549} 550 551static void 552idestroy_dev(struct cdev *dev) 553{ 554 if (!(dev->si_flags & SI_NAMED)) { 555 printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 556 major(dev), minor(dev)); 557 panic("don't do that"); 558 } 559 560 devfs_destroy(dev); 561 562 /* Remove name marking */ 563 dev->si_flags &= ~SI_NAMED; 564 565 /* If we are a child, remove us from the parents list */ 566 if (dev->si_flags & SI_CHILD) { 567 LIST_REMOVE(dev, si_siblings); 568 dev->si_flags &= ~SI_CHILD; 569 } 570 571 /* Kill our children */ 572 while (!LIST_EMPTY(&dev->si_children)) 573 idestroy_dev(LIST_FIRST(&dev->si_children)); 574 575 /* Remove from clone list */ 576 if (dev->si_flags & SI_CLONELIST) { 577 LIST_REMOVE(dev, si_clone); 578 dev->si_flags &= ~SI_CLONELIST; 579 } 580 581 if (!(dev->si_flags & SI_ALIAS)) { 582 /* Remove from cdevsw list */ 583 LIST_REMOVE(dev, si_list); 584 585 /* If cdevsw has no struct cdev *'s, clean it */ 586 if (LIST_EMPTY(&dev->si_devsw->d_devs)) 587 fini_cdevsw(dev->si_devsw); 588 589 LIST_REMOVE(dev, si_hash); 590 } 591 dev->si_drv1 = 0; 592 dev->si_drv2 = 0; 593 dev->si_devsw = NULL; 594 bzero(&dev->__si_u, sizeof(dev->__si_u)); 595 dev->si_flags &= ~SI_ALIAS; 596 if (dev->si_refcount > 0) { 597 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 598 } else { 599 freedev(dev); 600 } 601} 602 603void 604destroy_dev(struct cdev *dev) 605{ 606 607 dev_lock(); 608 idestroy_dev(dev); 609 dev_unlock(); 610} 611 612const char * 613devtoname(struct cdev *dev) 614{ 615 char *p; 616 struct cdevsw *csw; 617 int mynor; 618 619 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 620 p = dev->si_name; 621 sprintf(p, "#%d", major(dev)); 622 p += strlen(p); 623 csw = dev_refthread(dev); 624 if (csw != NULL) { 625 sprintf(p, "(%s)", csw->d_name); 626 dev_relthread(dev); 627 } 628 p += strlen(p); 629 mynor = minor(dev); 630 if (mynor < 0 || mynor > 255) 631 sprintf(p, "/%#x", (u_int)mynor); 632 else 633 sprintf(p, "/%d", mynor); 634 } 635 return (dev->si_name); 636} 637 638int 639dev_stdclone(char *name, char **namep, const char *stem, int *unit) 640{ 641 int u, i; 642 643 i = strlen(stem); 644 if (bcmp(stem, name, i) != 0) 645 return (0); 646 if (!isdigit(name[i])) 647 return (0); 648 u = 0; 649 if (name[i] == '0' && isdigit(name[i+1])) 650 return (0); 651 while (isdigit(name[i])) { 652 u *= 10; 653 u += name[i++] - '0'; 654 } 655 if (u > 0xffffff) 656 return (0); 657 *unit = u; 658 if (namep) 659 *namep = &name[i]; 660 if (name[i]) 661 return (2); 662 return (1); 663} 664 665/* 666 * Helper functions for cloning device drivers. 667 * 668 * The objective here is to make it unnecessary for the device drivers to 669 * use rman or similar to manage their unit number space. Due to the way 670 * we do "on-demand" devices, using rman or other "private" methods 671 * will be very tricky to lock down properly once we lock down this file. 672 * 673 * Instead we give the drivers these routines which puts the struct cdev *'s 674 * that are to be managed on their own list, and gives the driver the ability 675 * to ask for the first free unit number or a given specified unit number. 676 * 677 * In addition these routines support paired devices (pty, nmdm and similar) 678 * by respecting a number of "flag" bits in the minor number. 679 * 680 */ 681 682struct clonedevs { 683 LIST_HEAD(,cdev) head; 684}; 685 686void 687clone_setup(struct clonedevs **cdp) 688{ 689 690 *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 691 LIST_INIT(&(*cdp)->head); 692} 693 694int 695clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 696{ 697 struct clonedevs *cd; 698 struct cdev *dev, *dl, *de; 699 int unit, low, u; 700 701 KASSERT(*cdp != NULL, 702 ("clone_setup() not called in driver \"%s\"", csw->d_name)); 703 KASSERT(!(extra & CLONE_UNITMASK), 704 ("Illegal extra bits (0x%x) in clone_create", extra)); 705 KASSERT(*up <= CLONE_UNITMASK, 706 ("Too high unit (0x%x) in clone_create", *up)); 707 708 if (csw->d_maj == MAJOR_AUTO) 709 find_major(csw); 710 711 /* 712 * Search the list for a lot of things in one go: 713 * A preexisting match is returned immediately. 714 * The lowest free unit number if we are passed -1, and the place 715 * in the list where we should insert that new element. 716 * The place to insert a specified unit number, if applicable 717 * the end of the list. 718 */ 719 unit = *up; 720 low = extra; 721 de = dl = NULL; 722 cd = *cdp; 723 LIST_FOREACH(dev, &cd->head, si_clone) { 724 u = dev2unit(dev); 725 if (u == (unit | extra)) { 726 *dp = dev; 727 return (0); 728 } 729 if (unit == -1 && u == low) { 730 low++; 731 de = dev; 732 continue; 733 } 734 if (u > (unit | extra)) { 735 dl = dev; 736 break; 737 } 738 de = dev; 739 } 740 if (unit == -1) 741 unit = low & CLONE_UNITMASK; 742 dev = newdev(csw->d_maj, unit2minor(unit | extra)); 743 KASSERT(!(dev->si_flags & SI_CLONELIST), 744 ("Dev %p should not be on clonelist", dev)); 745 if (dl != NULL) 746 LIST_INSERT_BEFORE(dl, dev, si_clone); 747 else if (de != NULL) 748 LIST_INSERT_AFTER(de, dev, si_clone); 749 else 750 LIST_INSERT_HEAD(&cd->head, dev, si_clone); 751 dev->si_flags |= SI_CLONELIST; 752 *up = unit; 753 return (1); 754} 755 756/* 757 * Kill everything still on the list. The driver should already have 758 * disposed of any softc hung of the struct cdev *'s at this time. 759 */ 760void 761clone_cleanup(struct clonedevs **cdp) 762{ 763 struct cdev *dev, *tdev; 764 struct clonedevs *cd; 765 766 cd = *cdp; 767 if (cd == NULL) 768 return; 769 LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 770 KASSERT(dev->si_flags & SI_NAMED, 771 ("Driver has goofed in cloning underways udev %x", dev->si_udev)); 772 destroy_dev(dev); 773 } 774 free(cd, M_DEVBUF); 775 *cdp = NULL; 776} 777 778/* 779 * Helper sysctl for devname(3). We're given a struct cdev * and return 780 * the name, if any, registered by the device driver. 781 */ 782static int 783sysctl_devname(SYSCTL_HANDLER_ARGS) 784{ 785 int error; 786 dev_t ud; 787 struct cdev *dev; 788 789 error = SYSCTL_IN(req, &ud, sizeof (ud)); 790 if (error) 791 return (error); 792 if (ud == NODEV) 793 return(EINVAL); 794 dev = findcdev(ud); 795 if (dev == NULL) 796 error = ENOENT; 797 else 798 error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 799 return (error); 800} 801 802SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 803 NULL, 0, sysctl_devname, "", "devname(3) handler"); 804