kern_conf.c revision 129943
190075Sobrien/*- 2169689Skan * Copyright (c) 1999-2002 Poul-Henning Kamp 3169689Skan * All rights reserved. 490075Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer. 1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1190075Sobrien * notice, this list of conditions and the following disclaimer in the 1290075Sobrien * documentation and/or other materials provided with the distribution. 1390075Sobrien * 1490075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1990075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2090075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2490075Sobrien * SUCH DAMAGE. 2590075Sobrien */ 2690075Sobrien 2790075Sobrien#include <sys/cdefs.h> 2890075Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 129943 2004-06-01 13:39:02Z phk $"); 2990075Sobrien 3090075Sobrien#include <sys/param.h> 3190075Sobrien#include <sys/kernel.h> 3290075Sobrien#include <sys/systm.h> 3390075Sobrien#include <sys/bio.h> 3490075Sobrien#include <sys/lock.h> 3590075Sobrien#include <sys/mutex.h> 3690075Sobrien#include <sys/sysctl.h> 3790075Sobrien#include <sys/module.h> 3890075Sobrien#include <sys/malloc.h> 3990075Sobrien#include <sys/conf.h> 4090075Sobrien#include <sys/vnode.h> 4190075Sobrien#include <sys/queue.h> 4290075Sobrien#include <sys/poll.h> 4390075Sobrien#include <sys/ctype.h> 4490075Sobrien#include <sys/tty.h> 4590075Sobrien#include <machine/stdarg.h> 4690075Sobrien 4790075Sobrienstatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 48169689Skan 49169689Skan/* Built at compile time from sys/conf/majors */ 50169689Skanextern unsigned char reserved_majors[256]; 51132718Skan 52169689Skan/* 53132718Skan * This is the number of hash-buckets. Experiements with 'real-life' 54169689Skan * udev_t's show that a prime halfway between two powers of two works 55169689Skan * best. 56169689Skan */ 57169689Skan#define DEVT_HASH 83 58169689Skan 59169689Skan/* The number of dev_t's we can create before malloc(9) kick in. */ 60169689Skan#define DEVT_STASH 50 61169689Skan 62169689Skanstatic struct cdev devt_stash[DEVT_STASH]; 63169689Skan 64169689Skanstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 65169689Skan 66169689Skanstatic LIST_HEAD(, cdev) dev_free; 67169689Skan 68169689Skanstatic int free_devt; 69169689SkanSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 70169689Skan 71169689Skanstatic struct mtx devmtx; 7290075Sobrienstatic void freedev(dev_t dev); 7390075Sobrien 7490075Sobrienstatic void 7590075Sobriendevlock(void) 7690075Sobrien{ 7790075Sobrien if (!mtx_initialized(&devmtx)) 7890075Sobrien mtx_init(&devmtx, "dev_t", NULL, MTX_DEF); 7990075Sobrien mtx_lock(&devmtx); 8090075Sobrien} 8190075Sobrien 8290075Sobrienstatic void 8390075Sobriendevunlock(void) 8490075Sobrien{ 8590075Sobrien mtx_unlock(&devmtx); 8690075Sobrien} 8790075Sobrien 8890075Sobrienvoid 8990075Sobriendev_ref(dev_t dev) 9090075Sobrien{ 9190075Sobrien devlock(); 9290075Sobrien dev->si_refcount++; 9390075Sobrien devunlock(); 9490075Sobrien} 95132718Skan 9690075Sobrienvoid 97117395Skandev_rel(dev_t dev) 98132718Skan{ 99117395Skan devlock(); 100169689Skan dev->si_refcount--; 101169689Skan KASSERT(dev->si_refcount >= 0, 102169689Skan ("dev_rel(%s) gave negative count", devtoname(dev))); 103169689Skan if (dev->si_devsw == NULL && dev->si_refcount == 0) { 104169689Skan LIST_REMOVE(dev, si_list); 105169689Skan freedev(dev); 106169689Skan } 107169689Skan devunlock(); 108169689Skan} 109169689Skan 110169689Skanvoid 111169689Skancdevsw_ref(struct cdevsw *csw) 112169689Skan{ 113169689Skan devlock(); 114132718Skan csw->d_refcount++; 115132718Skan devunlock(); 116132718Skan} 117169689Skan 118169689Skanvoid 119169689Skancdevsw_rel(struct cdevsw *csw) 120117395Skan{ 121117395Skan devlock(); 122132718Skan csw->d_refcount--; 123117395Skan KASSERT(csw->d_refcount >= 0, 12490075Sobrien ("cdevsw_vrel(%s) gave negative count", csw->d_name)); 125132718Skan devunlock(); 12690075Sobrien} 12790075Sobrien 128132718Skanstatic dev_t makedev(int x, int y); 12990075Sobrien 13090075Sobrienint 131132718Skannullop(void) 13290075Sobrien{ 13390075Sobrien 134132718Skan return (0); 13590075Sobrien} 136169689Skan 137169689Skanint 13890075Sobrieneopnotsupp(void) 139169689Skan{ 140169689Skan 141169689Skan return (EOPNOTSUPP); 142169689Skan} 14390075Sobrien 144169689Skanstatic int 145169689Skanenxio(void) 146169689Skan{ 147169689Skan return (ENXIO); 148169689Skan} 14990075Sobrien 150169689Skanstatic int 151169689Skanenodev(void) 152169689Skan{ 153169689Skan return (ENODEV); 154169689Skan} 155117395Skan 156169689Skan/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 157169689Skan 158169689Skan#define dead_open (d_open_t *)enxio 159169689Skan#define dead_close (d_close_t *)enxio 160117395Skan#define dead_read (d_read_t *)enxio 161117395Skan#define dead_write (d_write_t *)enxio 162117395Skan#define dead_ioctl (d_ioctl_t *)enxio 163132718Skan#define dead_poll (d_poll_t *)enodev 164117395Skan#define dead_mmap (d_mmap_t *)enodev 165169689Skan 166169689Skanstatic void 167169689Skandead_strategy(struct bio *bp) 16890075Sobrien{ 169132718Skan 17090075Sobrien biofinish(bp, NULL, ENXIO); 17190075Sobrien} 172132718Skan 173117395Skan#define dead_dump (dumper_t *)enxio 174117395Skan#define dead_kqfilter (d_kqfilter_t *)enxio 175117395Skan 176117395Skanstatic struct cdevsw dead_cdevsw = { 177117395Skan .d_version = D_VERSION, 178117395Skan .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 179132718Skan .d_open = dead_open, 180132718Skan .d_close = dead_close, 181132718Skan .d_read = dead_read, 182117395Skan .d_write = dead_write, 183117395Skan .d_ioctl = dead_ioctl, 184117395Skan .d_poll = dead_poll, 185117395Skan .d_mmap = dead_mmap, 186117395Skan .d_strategy = dead_strategy, 187117395Skan .d_name = "dead", 188117395Skan .d_maj = 255, 189132718Skan .d_dump = dead_dump, 190132718Skan .d_kqfilter = dead_kqfilter 191132718Skan}; 192132718Skan 193132718Skan/* Default methods if driver does not specify method */ 194132718Skan 195132718Skan#define null_open (d_open_t *)nullop 196132718Skan#define null_close (d_close_t *)nullop 197132718Skan#define no_read (d_read_t *)enodev 198132718Skan#define no_write (d_write_t *)enodev 199132718Skan#define no_ioctl (d_ioctl_t *)enodev 200132718Skan#define no_mmap (d_mmap_t *)enodev 201132718Skan 202132718Skanstatic int 203132718Skanno_kqfilter(dev_t dev __unused, struct knote *kn __unused) 204169689Skan{ 205169689Skan 206169689Skan return (1); 207169689Skan} 208169689Skan 209169689Skanstatic void 210169689Skanno_strategy(struct bio *bp) 211169689Skan{ 212169689Skan 213169689Skan biofinish(bp, NULL, ENODEV); 214169689Skan} 21590075Sobrien 21690075Sobrienstatic int 21790075Sobrienno_poll(dev_t dev __unused, int events, struct thread *td __unused) 21890075Sobrien{ 21990075Sobrien /* 22090075Sobrien * Return true for read/write. If the user asked for something 22190075Sobrien * special, return POLLNVAL, so that clients have a way of 22290075Sobrien * determining reliably whether or not the extended 223132718Skan * functionality is present without hard-coding knowledge 22490075Sobrien * of specific filesystem implementations. 22590075Sobrien * Stay in sync with vop_nopoll(). 22690075Sobrien */ 227132718Skan if (events & ~POLLSTANDARD) 22890075Sobrien return (POLLNVAL); 22990075Sobrien 23090075Sobrien return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 23190075Sobrien} 232132718Skan 23390075Sobrien#define no_dump (dumper_t *)enodev 23490075Sobrien 23590075Sobrienstruct cdevsw * 236132718Skandevsw(dev_t dev) 237117395Skan{ 23890075Sobrien if (dev->si_devsw != NULL) 239132718Skan return (dev->si_devsw); 24090075Sobrien return (&dead_cdevsw); 24190075Sobrien} 242132718Skan 24390075Sobrien/* 244169689Skan * dev_t and u_dev_t primitives 245169689Skan */ 246169689Skan 247169689Skanint 248169689Skanmajor(dev_t x) 249169689Skan{ 25090075Sobrien if (x == NODEV) 25190075Sobrien return NOUDEV; 252132718Skan return((x->si_udev >> 8) & 0xff); 253132718Skan} 25490075Sobrien 255132718Skanint 256132718Skanminor(dev_t x) 257132718Skan{ 258132718Skan if (x == NODEV) 259132718Skan return NOUDEV; 260117395Skan return(x->si_udev & 0xffff00ff); 261117395Skan} 262117395Skan 263117395Skanint 264117395Skandev2unit(dev_t x) 265117395Skan{ 266117395Skan int i; 267117395Skan 268132718Skan if (x == NODEV) 269117395Skan return NOUDEV; 270117395Skan i = minor(x); 271132718Skan return ((i & 0xff) | (i >> 8)); 272132718Skan} 273132718Skan 274132718Skanint 275169689Skanunit2minor(int unit) 276117395Skan{ 277117395Skan 278169689Skan KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 279117395Skan return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 280117395Skan} 281117395Skan 282117395Skanstatic dev_t 283132718Skanallocdev(void) 284169689Skan{ 285132718Skan static int stashed; 286132718Skan struct cdev *si; 287132718Skan 288132718Skan if (LIST_FIRST(&dev_free)) { 289132718Skan si = LIST_FIRST(&dev_free); 290132718Skan LIST_REMOVE(si, si_hash); 291169689Skan } else if (stashed >= DEVT_STASH) { 292132718Skan MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 293132718Skan M_USE_RESERVE | M_ZERO | M_WAITOK); 294132718Skan } else { 295132718Skan si = devt_stash + stashed++; 296132718Skan bzero(si, sizeof *si); 297132718Skan si->si_flags |= SI_STASHED; 298132718Skan } 299132718Skan si->__si_namebuf[0] = '\0'; 300132718Skan si->si_name = si->__si_namebuf; 301132718Skan LIST_INIT(&si->si_children); 302132718Skan TAILQ_INIT(&si->si_snapshots); 303132718Skan return (si); 304132718Skan} 305169689Skan 306132718Skanstatic dev_t 307132718Skanmakedev(int x, int y) 308169689Skan{ 309169689Skan struct cdev *si; 310169689Skan udev_t udev; 311132718Skan int hash; 312132718Skan 313169689Skan if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 314132718Skan panic("makedev of NOUDEV"); 315132718Skan udev = (x << 8) | y; 316132718Skan hash = udev % DEVT_HASH; 317169689Skan LIST_FOREACH(si, &dev_hash[hash], si_hash) { 318169689Skan if (si->si_udev == udev) 319169689Skan return (si); 320169689Skan } 321169689Skan si = allocdev(); 322169689Skan si->si_udev = udev; 323169689Skan LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 324169689Skan return (si); 325169689Skan} 326169689Skan 327169689Skanstatic void 328169689Skanfreedev(dev_t dev) 329169689Skan{ 330169689Skan 331169689Skan if (dev->si_flags & SI_STASHED) { 332169689Skan bzero(dev, sizeof(*dev)); 333169689Skan dev->si_flags |= SI_STASHED; 334169689Skan LIST_INSERT_HEAD(&dev_free, dev, si_hash); 335169689Skan } else { 336169689Skan FREE(dev, M_DEVT); 337169689Skan } 338169689Skan} 339169689Skan 340169689Skanudev_t 341169689Skandev2udev(dev_t x) 342169689Skan{ 343169689Skan if (x == NODEV) 344169689Skan return (NOUDEV); 345169689Skan return (x->si_udev); 346169689Skan} 347169689Skan 348169689Skandev_t 349169689Skanudev2dev(udev_t udev) 350169689Skan{ 351169689Skan struct cdev *si; 352169689Skan int hash; 353169689Skan 354169689Skan if (udev == NOUDEV) 355169689Skan return (NODEV); 356169689Skan hash = udev % DEVT_HASH; 357169689Skan LIST_FOREACH(si, &dev_hash[hash], si_hash) { 358169689Skan if (si->si_udev == udev) 359169689Skan return (si); 360169689Skan } 361169689Skan return (NODEV); 362169689Skan} 363169689Skan 364169689Skanint 365169689Skanuminor(udev_t dev) 366169689Skan{ 367169689Skan return (dev & 0xffff00ff); 368169689Skan} 36990075Sobrien 37090075Sobrienint 371169689Skanumajor(udev_t dev) 372169689Skan{ 373169689Skan return ((dev & 0xff00) >> 8); 374169689Skan} 375169689Skan 376169689Skanudev_t 377169689Skanmakeudev(int x, int y) 378220150Smm{ 379220150Smm return ((x << 8) | y); 380220150Smm} 381220150Smm 382169689Skanstatic void 383169689Skanfind_major(struct cdevsw *devsw) 384169689Skan{ 385169689Skan int i; 386169689Skan 387169689Skan for (i = NUMCDEVSW - 1; i > 0; i--) 388169689Skan if (reserved_majors[i] != i) 389169689Skan break; 390169689Skan KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 391169689Skan devsw->d_maj = i; 392169689Skan reserved_majors[i] = i; 393169689Skan devsw->d_flags |= D_ALLOCMAJ; 394169689Skan} 395169689Skan 396169689Skanstatic void 39790075Sobrienfini_cdevsw(struct cdevsw *devsw) 398132718Skan{ 39990075Sobrien if (devsw->d_flags & D_ALLOCMAJ) { 40090075Sobrien reserved_majors[devsw->d_maj] = 0; 401132718Skan devsw->d_maj = MAJOR_AUTO; 40290075Sobrien devsw->d_flags &= ~D_ALLOCMAJ; 403117395Skan } else if (devsw->d_maj == 0) 404117395Skan devsw->d_maj = 256; 40590075Sobrien devsw->d_flags &= ~D_INIT; 40690075Sobrien} 40790075Sobrien 40890075Sobrienstatic void 40990075Sobrienprep_cdevsw(struct cdevsw *devsw) 410132718Skan{ 41190075Sobrien 41290075Sobrien devlock(); 413132718Skan 41490075Sobrien if (devsw->d_version != D_VERSION_00) { 41590075Sobrien printf( 416132718Skan "WARNING: Device driver \"%s\" has wrong version %s\n", 41790075Sobrien devsw->d_name, "and is disabled. Recompile KLD module."); 41890075Sobrien devsw->d_open = dead_open; 41990075Sobrien devsw->d_close = dead_close; 420132718Skan devsw->d_read = dead_read; 42190075Sobrien devsw->d_write = dead_write; 42296263Sobrien devsw->d_ioctl = dead_ioctl; 42396263Sobrien devsw->d_poll = dead_poll; 424132718Skan devsw->d_mmap = dead_mmap; 42596263Sobrien devsw->d_strategy = dead_strategy; 426169689Skan devsw->d_dump = dead_dump; 427169689Skan devsw->d_kqfilter = dead_kqfilter; 428169689Skan } 429169689Skan 430169689Skan if (devsw->d_flags & D_TTY) { 431169689Skan if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 432169689Skan if (devsw->d_read == NULL) devsw->d_read = ttyread; 433169689Skan if (devsw->d_write == NULL) devsw->d_write = ttywrite; 434169689Skan if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 435169689Skan if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 43690075Sobrien } 437132718Skan 43890075Sobrien if (devsw->d_open == NULL) devsw->d_open = null_open; 43990075Sobrien if (devsw->d_close == NULL) devsw->d_close = null_close; 440132718Skan if (devsw->d_read == NULL) devsw->d_read = no_read; 441132718Skan if (devsw->d_write == NULL) devsw->d_write = no_write; 44290075Sobrien if (devsw->d_ioctl == NULL) devsw->d_ioctl = no_ioctl; 443169689Skan if (devsw->d_poll == NULL) devsw->d_poll = no_poll; 444169689Skan if (devsw->d_mmap == NULL) devsw->d_mmap = no_mmap; 445169689Skan if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy; 446169689Skan if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 447169689Skan if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter; 448169689Skan 449169689Skan LIST_INIT(&devsw->d_devs); 450169689Skan 451169689Skan devsw->d_flags |= D_INIT; 452146895Skan 453146895Skan if (devsw->d_maj == MAJOR_AUTO) { 454146895Skan find_major(devsw); 455146895Skan } else { 456146895Skan if (devsw->d_maj == 256) /* XXX: tty_cons.c is magic */ 457132718Skan devsw->d_maj = 0; 458132718Skan KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256, 459132718Skan ("Invalid major (%d) in make_dev", devsw->d_maj)); 46090075Sobrien if (reserved_majors[devsw->d_maj] != devsw->d_maj) { 46190075Sobrien printf("WARNING: driver \"%s\" used %s %d\n", 46290075Sobrien devsw->d_name, "unreserved major device number", 463132718Skan devsw->d_maj); 46490075Sobrien reserved_majors[devsw->d_maj] = devsw->d_maj; 465117395Skan } 466117395Skan } 467132718Skan devunlock(); 468117395Skan} 469132718Skan 470132718Skandev_t 471132718Skanmake_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 472132718Skan{ 473132718Skan dev_t dev; 474132718Skan va_list ap; 475132718Skan int i; 476132718Skan 477132718Skan KASSERT((minornr & ~0xffff00ff) == 0, 478132718Skan ("Invalid minor (0x%x) in make_dev", minornr)); 479117395Skan 480132718Skan if (!(devsw->d_flags & D_INIT)) 481117395Skan prep_cdevsw(devsw); 482132718Skan dev = makedev(devsw->d_maj, minornr); 483132718Skan if (dev->si_flags & SI_CHEAPCLONE && 484132718Skan dev->si_flags & SI_NAMED && 485169689Skan dev->si_devsw == devsw) { 486169689Skan /* 487169689Skan * This is allowed as it removes races and generally 488132718Skan * simplifies cloning devices. 489132718Skan * XXX: still ?? 490132718Skan */ 491169689Skan return (dev); 492169689Skan } 493169689Skan devlock(); 494169689Skan KASSERT(!(dev->si_flags & SI_NAMED), 495169689Skan ("make_dev() by driver %s on pre-existing device (maj=%d, min=%d, name=%s)", 496169689Skan devsw->d_name, major(dev), minor(dev), devtoname(dev))); 497169689Skan 498169689Skan va_start(ap, fmt); 499169689Skan i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 500169689Skan if (i > (sizeof dev->__si_namebuf - 1)) { 501132718Skan printf("WARNING: Device name truncated! (%s)", 502132718Skan dev->__si_namebuf); 503132718Skan } 504132718Skan va_end(ap); 505132718Skan dev->si_devsw = devsw; 506117395Skan dev->si_uid = uid; 507132718Skan dev->si_gid = gid; 508117395Skan dev->si_mode = perms; 509117395Skan dev->si_flags |= SI_NAMED; 510117395Skan 511132718Skan LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list); 512117395Skan devfs_create(dev); 513117395Skan devunlock(); 514117395Skan return (dev); 515132718Skan} 516117395Skan 517117395Skanint 518132718Skandev_named(dev_t pdev, const char *name) 519117395Skan{ 520169689Skan dev_t cdev; 521169689Skan 522169689Skan if (strcmp(devtoname(pdev), name) == 0) 523169689Skan return (1); 524169689Skan LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 525169689Skan if (strcmp(devtoname(cdev), name) == 0) 526169689Skan return (1); 527169689Skan return (0); 528169689Skan} 529169689Skan 530169689Skanvoid 531169689Skandev_depends(dev_t pdev, dev_t cdev) 532169689Skan{ 533169689Skan 534169689Skan devlock(); 535169689Skan cdev->si_parent = pdev; 536169689Skan cdev->si_flags |= SI_CHILD; 537132718Skan LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 538132718Skan devunlock(); 539132718Skan} 540169689Skan 541169689Skandev_t 542169689Skanmake_dev_alias(dev_t pdev, const char *fmt, ...) 543169689Skan{ 544169689Skan dev_t dev; 545169689Skan va_list ap; 546169689Skan int i; 547169689Skan 548169689Skan dev = allocdev(); 549169689Skan devlock(); 550132718Skan dev->si_flags |= SI_ALIAS; 551132718Skan dev->si_flags |= SI_NAMED; 552132718Skan va_start(ap, fmt); 553132718Skan i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 554132718Skan if (i > (sizeof dev->__si_namebuf - 1)) { 555132718Skan printf("WARNING: Device name truncated! (%s)", 556132718Skan dev->__si_namebuf); 557132718Skan } 558132718Skan va_end(ap); 559132718Skan 560132718Skan devfs_create(dev); 561132718Skan devunlock(); 562132718Skan dev_depends(pdev, dev); 563132718Skan return (dev); 564169689Skan} 565169689Skan 566169689Skanstatic void 567169689Skanidestroy_dev(dev_t dev) 568132718Skan{ 569132718Skan if (!(dev->si_flags & SI_NAMED)) { 570132718Skan printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 571132718Skan major(dev), minor(dev)); 572132718Skan panic("don't do that"); 573132718Skan } 574132718Skan 575132718Skan devfs_destroy(dev); 576132718Skan 577132718Skan /* Remove name marking */ 578132718Skan dev->si_flags &= ~SI_NAMED; 579132718Skan 580132718Skan /* If we are a child, remove us from the parents list */ 581132718Skan if (dev->si_flags & SI_CHILD) { 582132718Skan LIST_REMOVE(dev, si_siblings); 583132718Skan dev->si_flags &= ~SI_CHILD; 584132718Skan } 585132718Skan 586132718Skan /* Kill our children */ 587132718Skan while (!LIST_EMPTY(&dev->si_children)) 588132718Skan idestroy_dev(LIST_FIRST(&dev->si_children)); 589132718Skan 590132718Skan /* Remove from clone list */ 591132718Skan if (dev->si_flags & SI_CLONELIST) { 592132718Skan LIST_REMOVE(dev, si_clone); 593132718Skan dev->si_flags &= ~SI_CLONELIST; 594132718Skan } 595132718Skan 596132718Skan if (!(dev->si_flags & SI_ALIAS)) { 597132718Skan /* Remove from cdevsw list */ 598132718Skan LIST_REMOVE(dev, si_list); 599132718Skan 600169689Skan /* If cdevsw has no dev_t's, clean it */ 601169689Skan if (LIST_EMPTY(&dev->si_devsw->d_devs)) 602169689Skan fini_cdevsw(dev->si_devsw); 603169689Skan 604132718Skan LIST_REMOVE(dev, si_hash); 605132718Skan } 606132718Skan dev->si_drv1 = 0; 607132718Skan dev->si_drv2 = 0; 608132718Skan dev->si_devsw = NULL; 609132718Skan bzero(&dev->__si_u, sizeof(dev->__si_u)); 610132718Skan dev->si_flags &= ~SI_ALIAS; 611132718Skan if (dev->si_refcount > 0) { 612132718Skan LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 613169689Skan } else { 614169689Skan freedev(dev); 615169689Skan } 616169689Skan} 617169689Skan 618169689Skanvoid 619169689Skandestroy_dev(dev_t dev) 620169689Skan{ 621169689Skan 622169689Skan devlock(); 623169689Skan idestroy_dev(dev); 624169689Skan devunlock(); 625169689Skan} 626169689Skan 627169689Skanconst char * 628169689Skandevtoname(dev_t dev) 629169689Skan{ 630169689Skan char *p; 631169689Skan int mynor; 632169689Skan 633169689Skan if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 634169689Skan p = dev->si_name; 635169689Skan if (devsw(dev)) 636169689Skan sprintf(p, "#%s/", devsw(dev)->d_name); 637169689Skan else 638169689Skan sprintf(p, "#%d/", major(dev)); 639169689Skan p += strlen(p); 640169689Skan mynor = minor(dev); 641169689Skan if (mynor < 0 || mynor > 255) 642169689Skan sprintf(p, "%#x", (u_int)mynor); 643169689Skan else 644169689Skan sprintf(p, "%d", mynor); 645169689Skan } 646169689Skan return (dev->si_name); 647169689Skan} 648169689Skan 649169689Skanint 650169689Skandev_stdclone(char *name, char **namep, const char *stem, int *unit) 651169689Skan{ 652169689Skan int u, i; 653169689Skan 654169689Skan i = strlen(stem); 655169689Skan if (bcmp(stem, name, i) != 0) 656169689Skan return (0); 657169689Skan if (!isdigit(name[i])) 658169689Skan return (0); 659169689Skan u = 0; 660169689Skan if (name[i] == '0' && isdigit(name[i+1])) 661169689Skan return (0); 662169689Skan while (isdigit(name[i])) { 663169689Skan u *= 10; 664169689Skan u += name[i++] - '0'; 665169689Skan } 666169689Skan if (u > 0xffffff) 667169689Skan return (0); 668169689Skan *unit = u; 669169689Skan if (namep) 670169689Skan *namep = &name[i]; 671132718Skan if (name[i]) 672132718Skan return (2); 673132718Skan return (1); 674132718Skan} 675132718Skan 676132718Skan/* 677132718Skan * Helper functions for cloning device drivers. 678132718Skan * 679169689Skan * The objective here is to make it unnecessary for the device drivers to 680169689Skan * use rman or similar to manage their unit number space. Due to the way 681169689Skan * we do "on-demand" devices, using rman or other "private" methods 682169689Skan * will be very tricky to lock down properly once we lock down this file. 683169689Skan * 684169689Skan * Instead we give the drivers these routines which puts the dev_t's that 685169689Skan * are to be managed on their own list, and gives the driver the ability 686132718Skan * to ask for the first free unit number or a given specified unit number. 687132718Skan * 688132718Skan * In addition these routines support paired devices (pty, nmdm and similar) 689132718Skan * by respecting a number of "flag" bits in the minor number. 690132718Skan * 691132718Skan */ 692169689Skan 693169689Skanstruct clonedevs { 694132718Skan LIST_HEAD(,cdev) head; 695132718Skan}; 696132718Skan 697132718Skanvoid 698132718Skanclone_setup(struct clonedevs **cdp) 699132718Skan{ 700169689Skan 701169689Skan *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 702169689Skan LIST_INIT(&(*cdp)->head); 703169689Skan} 704169689Skan 705169689Skanint 706169689Skanclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, dev_t *dp, u_int extra) 707169689Skan{ 708169689Skan struct clonedevs *cd; 709169689Skan dev_t dev, dl, de; 710169689Skan int unit, low, u; 711169689Skan 712169689Skan KASSERT(*cdp != NULL, 713169689Skan ("clone_setup() not called in driver \"%s\"", csw->d_name)); 714169689Skan KASSERT(!(extra & CLONE_UNITMASK), 715169689Skan ("Illegal extra bits (0x%x) in clone_create", extra)); 716169689Skan KASSERT(*up <= CLONE_UNITMASK, 717169689Skan ("Too high unit (0x%x) in clone_create", *up)); 718169689Skan 719169689Skan if (csw->d_maj == MAJOR_AUTO) 720169689Skan find_major(csw); 721169689Skan 722169689Skan /* 723169689Skan * Search the list for a lot of things in one go: 724169689Skan * A preexisting match is returned immediately. 725169689Skan * The lowest free unit number if we are passed -1, and the place 726169689Skan * in the list where we should insert that new element. 727169689Skan * The place to insert a specified unit number, if applicable 728169689Skan * the end of the list. 729169689Skan */ 730169689Skan unit = *up; 731169689Skan low = extra; 732132718Skan de = dl = NULL; 733132718Skan cd = *cdp; 734169689Skan LIST_FOREACH(dev, &cd->head, si_clone) { 735169689Skan u = dev2unit(dev); 736169689Skan if (u == (unit | extra)) { 737169689Skan *dp = dev; 738169689Skan return (0); 739169689Skan } 740169689Skan if (unit == -1 && u == low) { 741169689Skan low++; 742169689Skan de = dev; 743169689Skan continue; 744169689Skan } 745169689Skan if (u > (unit | extra)) { 746169689Skan dl = dev; 747169689Skan break; 748169689Skan } 749169689Skan de = dev; 750169689Skan } 751169689Skan if (unit == -1) 752169689Skan unit = low & CLONE_UNITMASK; 753169689Skan dev = makedev(csw->d_maj, unit2minor(unit | extra)); 754169689Skan KASSERT(!(dev->si_flags & SI_CLONELIST), 755169689Skan ("Dev %p should not be on clonelist", dev)); 756169689Skan if (dl != NULL) 757169689Skan LIST_INSERT_BEFORE(dl, dev, si_clone); 758169689Skan else if (de != NULL) 759169689Skan LIST_INSERT_AFTER(de, dev, si_clone); 760169689Skan else 761169689Skan LIST_INSERT_HEAD(&cd->head, dev, si_clone); 762169689Skan dev->si_flags |= SI_CLONELIST; 763169689Skan *up = unit; 764169689Skan return (1); 765169689Skan} 766169689Skan 767169689Skan/* 768169689Skan * Kill everything still on the list. The driver should already have 769169689Skan * disposed of any softc hung of the dev_t's at this time. 770169689Skan */ 771169689Skanvoid 772169689Skanclone_cleanup(struct clonedevs **cdp) 773169689Skan{ 774169689Skan dev_t dev, tdev; 775169689Skan struct clonedevs *cd; 776169689Skan 777169689Skan cd = *cdp; 778169689Skan if (cd == NULL) 779169689Skan return; 780169689Skan LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 781169689Skan KASSERT(dev->si_flags & SI_NAMED, 782169689Skan ("Driver has goofed in cloning underways udev %x", dev->si_udev)); 783169689Skan destroy_dev(dev); 784169689Skan } 785169689Skan free(cd, M_DEVBUF); 786259947Spfg *cdp = NULL; 787259947Spfg} 788259947Spfg 789259947Spfg/* 790169689Skan * Helper sysctl for devname(3). We're given a {u}dev_t and return 791169689Skan * the name, if any, registered by the device driver. 792169689Skan */ 793169689Skanstatic int 794169689Skansysctl_devname(SYSCTL_HANDLER_ARGS) 795169689Skan{ 796169689Skan int error; 797169689Skan udev_t ud; 798169689Skan dev_t dev; 799169689Skan 800169689Skan error = SYSCTL_IN(req, &ud, sizeof (ud)); 801169689Skan if (error) 802169689Skan return (error); 803169689Skan if (ud == NOUDEV) 804169689Skan return(EINVAL); 805169689Skan dev = udev2dev(ud); 806169689Skan if (dev == NODEV) 807169689Skan error = ENOENT; 808117395Skan else 809117395Skan error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 81090075Sobrien return (error); 81190075Sobrien} 81290075Sobrien 813169689SkanSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 814169689Skan NULL, 0, sysctl_devname, "", "devname(3) handler"); 815169689Skan