126453f35SJulian Elischer /*- 266cdbc28SPoul-Henning Kamp * Copyright (c) 1999-2002 Poul-Henning Kamp 326453f35SJulian Elischer * All rights reserved. 426453f35SJulian Elischer * 526453f35SJulian Elischer * Redistribution and use in source and binary forms, with or without 626453f35SJulian Elischer * modification, are permitted provided that the following conditions 726453f35SJulian Elischer * are met: 826453f35SJulian Elischer * 1. Redistributions of source code must retain the above copyright 926453f35SJulian Elischer * notice, this list of conditions and the following disclaimer. 1026453f35SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1126453f35SJulian Elischer * notice, this list of conditions and the following disclaimer in the 1226453f35SJulian Elischer * documentation and/or other materials provided with the distribution. 1326453f35SJulian Elischer * 1466cdbc28SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1566cdbc28SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626453f35SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1766cdbc28SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826453f35SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926453f35SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026453f35SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126453f35SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226453f35SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326453f35SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426453f35SJulian Elischer * SUCH DAMAGE. 2526453f35SJulian Elischer * 26c3aac50fSPeter Wemm * $FreeBSD$ 2726453f35SJulian Elischer */ 2826453f35SJulian Elischer 2926453f35SJulian Elischer #include <sys/param.h> 30698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 31f8a760b3SJulian Elischer #include <sys/systm.h> 3202574b19SPoul-Henning Kamp #include <sys/bio.h> 331b567820SBrian Feldman #include <sys/lock.h> 341b567820SBrian Feldman #include <sys/mutex.h> 35b40ce416SJulian Elischer #include <sys/sysctl.h> 36ecbb00a2SDoug Rabson #include <sys/module.h> 37698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 3826453f35SJulian Elischer #include <sys/conf.h> 391dfcbb0cSJulian Elischer #include <sys/vnode.h> 40698bfad7SPoul-Henning Kamp #include <sys/queue.h> 41db901281SPoul-Henning Kamp #include <sys/ctype.h> 420ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 431dfcbb0cSJulian Elischer 44959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 45698bfad7SPoul-Henning Kamp 46beea48b2SPoul-Henning Kamp /* Built at compile time from sys/conf/majors */ 47beea48b2SPoul-Henning Kamp extern unsigned char reserved_majors[256]; 48beea48b2SPoul-Henning Kamp 49a87b5350SPoul-Henning Kamp /* 50a87b5350SPoul-Henning Kamp * This is the number of hash-buckets. Experiements with 'real-life' 51a87b5350SPoul-Henning Kamp * udev_t's show that a prime halfway between two powers of two works 52a87b5350SPoul-Henning Kamp * best. 53a87b5350SPoul-Henning Kamp */ 54698bfad7SPoul-Henning Kamp #define DEVT_HASH 83 55a87b5350SPoul-Henning Kamp 56a87b5350SPoul-Henning Kamp /* The number of dev_t's we can create before malloc(9) kick in. */ 57698bfad7SPoul-Henning Kamp #define DEVT_STASH 50 58698bfad7SPoul-Henning Kamp 59ca916247SPoul-Henning Kamp static struct cdev devt_stash[DEVT_STASH]; 60698bfad7SPoul-Henning Kamp 61ca916247SPoul-Henning Kamp static LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 62d137acccSPoul-Henning Kamp 63ca916247SPoul-Henning Kamp static LIST_HEAD(, cdev) dev_free; 6446eede00SPoul-Henning Kamp 65a7489fe5SMike Smith static int ready_for_devs; 66a7489fe5SMike Smith 67d137acccSPoul-Henning Kamp static int free_devt; 68d137acccSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 699dcbe240SPoul-Henning Kamp 7002574b19SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 7102574b19SPoul-Henning Kamp 7202574b19SPoul-Henning Kamp static int 7302574b19SPoul-Henning Kamp enxio(void) 7402574b19SPoul-Henning Kamp { 7502574b19SPoul-Henning Kamp return (ENXIO); 7602574b19SPoul-Henning Kamp } 7702574b19SPoul-Henning Kamp 7802574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 7902574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 8002574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 8102574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 8202574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 8302574b19SPoul-Henning Kamp #define dead_poll nopoll 8402574b19SPoul-Henning Kamp #define dead_mmap nommap 8502574b19SPoul-Henning Kamp 8602574b19SPoul-Henning Kamp static void 8702574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 8802574b19SPoul-Henning Kamp { 8902574b19SPoul-Henning Kamp 9002574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 9102574b19SPoul-Henning Kamp } 9202574b19SPoul-Henning Kamp 932c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 9402574b19SPoul-Henning Kamp 9502574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 9602574b19SPoul-Henning Kamp 9702574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 987ac40f5fSPoul-Henning Kamp .d_open = dead_open, 997ac40f5fSPoul-Henning Kamp .d_close = dead_close, 1007ac40f5fSPoul-Henning Kamp .d_read = dead_read, 1017ac40f5fSPoul-Henning Kamp .d_write = dead_write, 1027ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 1037ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 1047ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 1057ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 1067ac40f5fSPoul-Henning Kamp .d_name = "dead", 1077ac40f5fSPoul-Henning Kamp .d_maj = 255, 1087ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 1097ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 11002574b19SPoul-Henning Kamp }; 11102574b19SPoul-Henning Kamp 1124e4a7663SPoul-Henning Kamp 1132447bec8SPoul-Henning Kamp struct cdevsw * 1142447bec8SPoul-Henning Kamp devsw(dev_t dev) 1152447bec8SPoul-Henning Kamp { 1167dc5cd04SPoul-Henning Kamp if (dev->si_devsw) 1177dc5cd04SPoul-Henning Kamp return (dev->si_devsw); 11802574b19SPoul-Henning Kamp return (&dead_cdevsw); 1192447bec8SPoul-Henning Kamp } 1202447bec8SPoul-Henning Kamp 1212447bec8SPoul-Henning Kamp /* 122bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 123bfbb9ce6SPoul-Henning Kamp */ 124bfbb9ce6SPoul-Henning Kamp 125bfbb9ce6SPoul-Henning Kamp int 126bfbb9ce6SPoul-Henning Kamp major(dev_t x) 127bfbb9ce6SPoul-Henning Kamp { 128698bfad7SPoul-Henning Kamp if (x == NODEV) 129698bfad7SPoul-Henning Kamp return NOUDEV; 130698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 131bfbb9ce6SPoul-Henning Kamp } 132bfbb9ce6SPoul-Henning Kamp 133bfbb9ce6SPoul-Henning Kamp int 134bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 135bfbb9ce6SPoul-Henning Kamp { 136698bfad7SPoul-Henning Kamp if (x == NODEV) 137698bfad7SPoul-Henning Kamp return NOUDEV; 138698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 139bfbb9ce6SPoul-Henning Kamp } 140bfbb9ce6SPoul-Henning Kamp 1419a27d579SPoul-Henning Kamp int 142b0d17ba6SPoul-Henning Kamp dev2unit(dev_t x) 1439a27d579SPoul-Henning Kamp { 1449a27d579SPoul-Henning Kamp int i; 1459a27d579SPoul-Henning Kamp 1469a27d579SPoul-Henning Kamp if (x == NODEV) 1479a27d579SPoul-Henning Kamp return NOUDEV; 1489a27d579SPoul-Henning Kamp i = minor(x); 1499a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 1509a27d579SPoul-Henning Kamp } 1519a27d579SPoul-Henning Kamp 152b0d17ba6SPoul-Henning Kamp int 153b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 154b0d17ba6SPoul-Henning Kamp { 155b0d17ba6SPoul-Henning Kamp 15615b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 157b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 158b0d17ba6SPoul-Henning Kamp } 159b0d17ba6SPoul-Henning Kamp 1603f54a085SPoul-Henning Kamp static dev_t 1613f54a085SPoul-Henning Kamp allocdev(void) 162bfbb9ce6SPoul-Henning Kamp { 163698bfad7SPoul-Henning Kamp static int stashed; 164ca916247SPoul-Henning Kamp struct cdev *si; 165698bfad7SPoul-Henning Kamp 1665ea98f59SPoul-Henning Kamp if (LIST_FIRST(&dev_free)) { 167d137acccSPoul-Henning Kamp si = LIST_FIRST(&dev_free); 168d137acccSPoul-Henning Kamp LIST_REMOVE(si, si_hash); 1695ea98f59SPoul-Henning Kamp } else if (stashed >= DEVT_STASH) { 170ca916247SPoul-Henning Kamp MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 1710c977c9cSPoul-Henning Kamp M_USE_RESERVE | M_ZERO | M_WAITOK); 172698bfad7SPoul-Henning Kamp } else { 173698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 1743344c5a1SPoul-Henning Kamp bzero(si, sizeof *si); 175d137acccSPoul-Henning Kamp si->si_flags |= SI_STASHED; 176698bfad7SPoul-Henning Kamp } 177237d2765SPoul-Henning Kamp si->__si_namebuf[0] = '\0'; 178237d2765SPoul-Henning Kamp si->si_name = si->__si_namebuf; 1793344c5a1SPoul-Henning Kamp LIST_INIT(&si->si_children); 180589c7af9SKirk McKusick TAILQ_INIT(&si->si_snapshots); 1813f54a085SPoul-Henning Kamp return (si); 1823f54a085SPoul-Henning Kamp } 1833f54a085SPoul-Henning Kamp 1843f54a085SPoul-Henning Kamp dev_t 1853f54a085SPoul-Henning Kamp makedev(int x, int y) 1863f54a085SPoul-Henning Kamp { 187ca916247SPoul-Henning Kamp struct cdev *si; 1883f54a085SPoul-Henning Kamp udev_t udev; 1893f54a085SPoul-Henning Kamp int hash; 1903f54a085SPoul-Henning Kamp 1913f54a085SPoul-Henning Kamp if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 1921fd7b93fSPoul-Henning Kamp panic("makedev of NOUDEV"); 1933f54a085SPoul-Henning Kamp udev = (x << 8) | y; 1943f54a085SPoul-Henning Kamp hash = udev % DEVT_HASH; 1953f54a085SPoul-Henning Kamp LIST_FOREACH(si, &dev_hash[hash], si_hash) { 1963f54a085SPoul-Henning Kamp if (si->si_udev == udev) 1973f54a085SPoul-Henning Kamp return (si); 1983f54a085SPoul-Henning Kamp } 1993f54a085SPoul-Henning Kamp si = allocdev(); 200698bfad7SPoul-Henning Kamp si->si_udev = udev; 201d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 202698bfad7SPoul-Henning Kamp return (si); 203bfbb9ce6SPoul-Henning Kamp } 204bfbb9ce6SPoul-Henning Kamp 205d137acccSPoul-Henning Kamp void 206d137acccSPoul-Henning Kamp freedev(dev_t dev) 207d137acccSPoul-Henning Kamp { 208d137acccSPoul-Henning Kamp 209d137acccSPoul-Henning Kamp if (!free_devt) 210d137acccSPoul-Henning Kamp return; 211d137acccSPoul-Henning Kamp if (SLIST_FIRST(&dev->si_hlist)) 212d137acccSPoul-Henning Kamp return; 213d137acccSPoul-Henning Kamp if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 214d137acccSPoul-Henning Kamp return; 215d137acccSPoul-Henning Kamp LIST_REMOVE(dev, si_hash); 216d137acccSPoul-Henning Kamp if (dev->si_flags & SI_STASHED) { 217d137acccSPoul-Henning Kamp bzero(dev, sizeof(*dev)); 2183344c5a1SPoul-Henning Kamp dev->si_flags |= SI_STASHED; 219d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_free, dev, si_hash); 220d137acccSPoul-Henning Kamp } else { 221d137acccSPoul-Henning Kamp FREE(dev, M_DEVT); 222d137acccSPoul-Henning Kamp } 223d137acccSPoul-Henning Kamp } 224d137acccSPoul-Henning Kamp 225bfbb9ce6SPoul-Henning Kamp udev_t 226bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 227bfbb9ce6SPoul-Henning Kamp { 228698bfad7SPoul-Henning Kamp if (x == NODEV) 229698bfad7SPoul-Henning Kamp return NOUDEV; 230698bfad7SPoul-Henning Kamp return (x->si_udev); 231bfbb9ce6SPoul-Henning Kamp } 232bfbb9ce6SPoul-Henning Kamp 233bfbb9ce6SPoul-Henning Kamp dev_t 234bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 235bfbb9ce6SPoul-Henning Kamp { 236fb01c24cSPoul-Henning Kamp 237fb01c24cSPoul-Henning Kamp if (x == NOUDEV) 238fb01c24cSPoul-Henning Kamp return (NODEV); 239d21c632cSPoul-Henning Kamp switch (b) { 240d21c632cSPoul-Henning Kamp case 0: 241bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 242d21c632cSPoul-Henning Kamp case 1: 243a16d0eb2SPoul-Henning Kamp return (NODEV); 244d21c632cSPoul-Henning Kamp default: 245d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 246d21c632cSPoul-Henning Kamp return NODEV; 247d21c632cSPoul-Henning Kamp } 248bfbb9ce6SPoul-Henning Kamp } 249bfbb9ce6SPoul-Henning Kamp 250bfbb9ce6SPoul-Henning Kamp int 251bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 252bfbb9ce6SPoul-Henning Kamp { 253bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 254bfbb9ce6SPoul-Henning Kamp } 255bfbb9ce6SPoul-Henning Kamp 256bfbb9ce6SPoul-Henning Kamp int 257bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 258bfbb9ce6SPoul-Henning Kamp { 259bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 260bfbb9ce6SPoul-Henning Kamp } 261bfbb9ce6SPoul-Henning Kamp 262bfbb9ce6SPoul-Henning Kamp udev_t 263f008cfccSPoul-Henning Kamp makeudev(int x, int y) 264bfbb9ce6SPoul-Henning Kamp { 265bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 266bfbb9ce6SPoul-Henning Kamp } 267bfbb9ce6SPoul-Henning Kamp 2680ef1c826SPoul-Henning Kamp dev_t 269c7021493SWarner Losh make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 2700ef1c826SPoul-Henning Kamp { 2710ef1c826SPoul-Henning Kamp dev_t dev; 2720ef1c826SPoul-Henning Kamp va_list ap; 2730ef1c826SPoul-Henning Kamp int i; 2740ef1c826SPoul-Henning Kamp 275beea48b2SPoul-Henning Kamp KASSERT((minor & ~0xffff00ff) == 0, 276beea48b2SPoul-Henning Kamp ("Invalid minor (0x%x) in make_dev", minor)); 277beea48b2SPoul-Henning Kamp 278f16304aaSPoul-Henning Kamp if (devsw->d_open == NULL) devsw->d_open = noopen; 279f16304aaSPoul-Henning Kamp if (devsw->d_close == NULL) devsw->d_close = noclose; 280f16304aaSPoul-Henning Kamp if (devsw->d_read == NULL) devsw->d_read = noread; 281f16304aaSPoul-Henning Kamp if (devsw->d_write == NULL) devsw->d_write = nowrite; 282f16304aaSPoul-Henning Kamp if (devsw->d_ioctl == NULL) devsw->d_ioctl = noioctl; 283f16304aaSPoul-Henning Kamp if (devsw->d_poll == NULL) devsw->d_poll = nopoll; 284f16304aaSPoul-Henning Kamp if (devsw->d_mmap == NULL) devsw->d_mmap = nommap; 285f16304aaSPoul-Henning Kamp if (devsw->d_strategy == NULL) devsw->d_strategy = nostrategy; 286f16304aaSPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = nodump; 287f16304aaSPoul-Henning Kamp if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = nokqfilter; 288f16304aaSPoul-Henning Kamp 289beea48b2SPoul-Henning Kamp if (devsw->d_maj == MAJOR_AUTO) { 290beea48b2SPoul-Henning Kamp for (i = NUMCDEVSW - 1; i > 0; i--) 291beea48b2SPoul-Henning Kamp if (reserved_majors[i] != i) 292beea48b2SPoul-Henning Kamp break; 293beea48b2SPoul-Henning Kamp KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 294beea48b2SPoul-Henning Kamp printf("Allocating major#%d to \"%s\"\n", i, devsw->d_name); 295beea48b2SPoul-Henning Kamp devsw->d_maj = i; 296beea48b2SPoul-Henning Kamp reserved_majors[i] = i; 29785f19dccSPoul-Henning Kamp } else { 29885f19dccSPoul-Henning Kamp KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256, 29985f19dccSPoul-Henning Kamp ("Invalid major (%d) in make_dev", devsw->d_maj)); 30085f19dccSPoul-Henning Kamp if (reserved_majors[devsw->d_maj] != devsw->d_maj) { 30185f19dccSPoul-Henning Kamp printf("WARNING: driver \"%s\" used %s %d\n", 30285f19dccSPoul-Henning Kamp devsw->d_name, "unreserved major device number", 30385f19dccSPoul-Henning Kamp devsw->d_maj); 30485f19dccSPoul-Henning Kamp reserved_majors[devsw->d_maj] = devsw->d_maj; 30585f19dccSPoul-Henning Kamp } 306beea48b2SPoul-Henning Kamp } 30711586717SBrian Somers 308a7489fe5SMike Smith if (!ready_for_devs) { 309a7489fe5SMike Smith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 310a7489fe5SMike Smith fmt); 311a7489fe5SMike Smith /* XXX panic here once drivers are cleaned up */ 312a7489fe5SMike Smith } 313a7489fe5SMike Smith 3140ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 3155ef2707eSPoul-Henning Kamp if (dev->si_flags & SI_NAMED) { 3165ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 3175ef2707eSPoul-Henning Kamp dev->si_name); 3184e4a7663SPoul-Henning Kamp panic("don't do that"); 3195ef2707eSPoul-Henning Kamp return (dev); 3205ef2707eSPoul-Henning Kamp } 3210ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3226334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3236334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3246334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3256334a663SPoul-Henning Kamp dev->__si_namebuf); 3266334a663SPoul-Henning Kamp } 3270ef1c826SPoul-Henning Kamp va_end(ap); 3280ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3293f54a085SPoul-Henning Kamp dev->si_uid = uid; 3303f54a085SPoul-Henning Kamp dev->si_gid = gid; 3313f54a085SPoul-Henning Kamp dev->si_mode = perms; 3325ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3331744fcd0SJulian Elischer 3349285a87eSPoul-Henning Kamp devfs_create(dev); 3353f54a085SPoul-Henning Kamp return (dev); 3363f54a085SPoul-Henning Kamp } 3373f54a085SPoul-Henning Kamp 3387e7c3f3fSJonathan Lemon int 3397e7c3f3fSJonathan Lemon dev_named(dev_t pdev, const char *name) 3407e7c3f3fSJonathan Lemon { 3417e7c3f3fSJonathan Lemon dev_t cdev; 3427e7c3f3fSJonathan Lemon 3437e7c3f3fSJonathan Lemon if (strcmp(devtoname(pdev), name) == 0) 3447e7c3f3fSJonathan Lemon return (1); 3457e7c3f3fSJonathan Lemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 3467e7c3f3fSJonathan Lemon if (strcmp(devtoname(cdev), name) == 0) 3477e7c3f3fSJonathan Lemon return (1); 3487e7c3f3fSJonathan Lemon return (0); 3497e7c3f3fSJonathan Lemon } 3507e7c3f3fSJonathan Lemon 3513344c5a1SPoul-Henning Kamp void 3523344c5a1SPoul-Henning Kamp dev_depends(dev_t pdev, dev_t cdev) 3533344c5a1SPoul-Henning Kamp { 3543344c5a1SPoul-Henning Kamp 3553344c5a1SPoul-Henning Kamp cdev->si_parent = pdev; 3563344c5a1SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 3573344c5a1SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 3583344c5a1SPoul-Henning Kamp } 3593344c5a1SPoul-Henning Kamp 3603f54a085SPoul-Henning Kamp dev_t 361c7021493SWarner Losh make_dev_alias(dev_t pdev, const char *fmt, ...) 3623f54a085SPoul-Henning Kamp { 3633f54a085SPoul-Henning Kamp dev_t dev; 3643f54a085SPoul-Henning Kamp va_list ap; 3653f54a085SPoul-Henning Kamp int i; 3663f54a085SPoul-Henning Kamp 3673f54a085SPoul-Henning Kamp dev = allocdev(); 3683f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 3695ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3703344c5a1SPoul-Henning Kamp dev_depends(pdev, dev); 3713f54a085SPoul-Henning Kamp va_start(ap, fmt); 3726334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3736334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3746334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3756334a663SPoul-Henning Kamp dev->__si_namebuf); 3766334a663SPoul-Henning Kamp } 3773f54a085SPoul-Henning Kamp va_end(ap); 3783f54a085SPoul-Henning Kamp 3799285a87eSPoul-Henning Kamp devfs_create(dev); 3800ef1c826SPoul-Henning Kamp return (dev); 3810ef1c826SPoul-Henning Kamp } 3820ef1c826SPoul-Henning Kamp 383d137acccSPoul-Henning Kamp void 3841fd9f8f4SBrian Feldman revoke_and_destroy_dev(dev_t dev) 3851fd9f8f4SBrian Feldman { 3861fd9f8f4SBrian Feldman struct vnode *vp; 3871fd9f8f4SBrian Feldman 3881fd9f8f4SBrian Feldman GIANT_REQUIRED; 3891fd9f8f4SBrian Feldman 3901fd9f8f4SBrian Feldman vp = SLIST_FIRST(&dev->si_hlist); 3911fd9f8f4SBrian Feldman if (vp != NULL) 3921fd9f8f4SBrian Feldman VOP_REVOKE(vp, REVOKEALL); 3931fd9f8f4SBrian Feldman destroy_dev(dev); 3941fd9f8f4SBrian Feldman } 3951fd9f8f4SBrian Feldman 3961fd9f8f4SBrian Feldman void 39744d1184eSPoul-Henning Kamp destroy_dev(dev_t dev) 398d137acccSPoul-Henning Kamp { 3995ef2707eSPoul-Henning Kamp 4005ef2707eSPoul-Henning Kamp if (!(dev->si_flags & SI_NAMED)) { 4015ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 4025ef2707eSPoul-Henning Kamp major(dev), minor(dev)); 4034e4a7663SPoul-Henning Kamp panic("don't do that"); 4045ef2707eSPoul-Henning Kamp return; 4055ef2707eSPoul-Henning Kamp } 4065ef2707eSPoul-Henning Kamp 4079285a87eSPoul-Henning Kamp devfs_destroy(dev); 4083344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 4093344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 4103344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 4113344c5a1SPoul-Henning Kamp } 4123344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 4133344c5a1SPoul-Henning Kamp destroy_dev(LIST_FIRST(&dev->si_children)); 414d137acccSPoul-Henning Kamp dev->si_drv1 = 0; 415d137acccSPoul-Henning Kamp dev->si_drv2 = 0; 416d137acccSPoul-Henning Kamp dev->si_devsw = 0; 417ff557fa1SBruce Evans bzero(&dev->__si_u, sizeof(dev->__si_u)); 4185ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 4195ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 420d137acccSPoul-Henning Kamp freedev(dev); 421d137acccSPoul-Henning Kamp } 422d137acccSPoul-Henning Kamp 423c32cc149SBruce Evans const char * 424b8e49f68SBill Fumerola devtoname(dev_t dev) 425b8e49f68SBill Fumerola { 426d137acccSPoul-Henning Kamp char *p; 427c32cc149SBruce Evans int mynor; 428b8e49f68SBill Fumerola 429d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 430d137acccSPoul-Henning Kamp p = dev->si_name; 431d137acccSPoul-Henning Kamp if (devsw(dev)) 432d137acccSPoul-Henning Kamp sprintf(p, "#%s/", devsw(dev)->d_name); 433d137acccSPoul-Henning Kamp else 434d137acccSPoul-Henning Kamp sprintf(p, "#%d/", major(dev)); 435d137acccSPoul-Henning Kamp p += strlen(p); 436c32cc149SBruce Evans mynor = minor(dev); 437c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 438c32cc149SBruce Evans sprintf(p, "%#x", (u_int)mynor); 439c32cc149SBruce Evans else 440c32cc149SBruce Evans sprintf(p, "%d", mynor); 441d137acccSPoul-Henning Kamp } 442b8e49f68SBill Fumerola return (dev->si_name); 443b8e49f68SBill Fumerola } 444db901281SPoul-Henning Kamp 445db901281SPoul-Henning Kamp int 44601de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 447db901281SPoul-Henning Kamp { 448db901281SPoul-Henning Kamp int u, i; 449db901281SPoul-Henning Kamp 450db901281SPoul-Henning Kamp i = strlen(stem); 45156700d46SBrian Somers if (bcmp(stem, name, i) != 0) 45256700d46SBrian Somers return (0); 453db901281SPoul-Henning Kamp if (!isdigit(name[i])) 454db901281SPoul-Henning Kamp return (0); 455db901281SPoul-Henning Kamp u = 0; 45610786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 45710786074SPoul-Henning Kamp return (0); 458db901281SPoul-Henning Kamp while (isdigit(name[i])) { 459db901281SPoul-Henning Kamp u *= 10; 460db901281SPoul-Henning Kamp u += name[i++] - '0'; 461db901281SPoul-Henning Kamp } 462dab3d85fSBrian Feldman if (u > 0xffffff) 463dab3d85fSBrian Feldman return (0); 464db901281SPoul-Henning Kamp *unit = u; 465db901281SPoul-Henning Kamp if (namep) 466db901281SPoul-Henning Kamp *namep = &name[i]; 467db901281SPoul-Henning Kamp if (name[i]) 468db901281SPoul-Henning Kamp return (2); 469db901281SPoul-Henning Kamp return (1); 470db901281SPoul-Henning Kamp } 4718d25eb2cSPoul-Henning Kamp 4728d25eb2cSPoul-Henning Kamp /* 4738d25eb2cSPoul-Henning Kamp * Helper sysctl for devname(3). We're given a {u}dev_t and return 4748d25eb2cSPoul-Henning Kamp * the name, if any, registered by the device driver. 4758d25eb2cSPoul-Henning Kamp */ 4768d25eb2cSPoul-Henning Kamp static int 4778d25eb2cSPoul-Henning Kamp sysctl_devname(SYSCTL_HANDLER_ARGS) 4788d25eb2cSPoul-Henning Kamp { 4798d25eb2cSPoul-Henning Kamp int error; 4808d25eb2cSPoul-Henning Kamp udev_t ud; 4818d25eb2cSPoul-Henning Kamp dev_t dev; 4828d25eb2cSPoul-Henning Kamp 4838d25eb2cSPoul-Henning Kamp error = SYSCTL_IN(req, &ud, sizeof (ud)); 4848d25eb2cSPoul-Henning Kamp if (error) 4858d25eb2cSPoul-Henning Kamp return (error); 4861fd7b93fSPoul-Henning Kamp if (ud == NOUDEV) 4871fd7b93fSPoul-Henning Kamp return(EINVAL); 4888d25eb2cSPoul-Henning Kamp dev = makedev(umajor(ud), uminor(ud)); 4898d25eb2cSPoul-Henning Kamp if (dev->si_name[0] == '\0') 4908d25eb2cSPoul-Henning Kamp error = ENOENT; 4918d25eb2cSPoul-Henning Kamp else 4928d25eb2cSPoul-Henning Kamp error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 4938d25eb2cSPoul-Henning Kamp freedev(dev); 4948d25eb2cSPoul-Henning Kamp return (error); 4958d25eb2cSPoul-Henning Kamp } 4968d25eb2cSPoul-Henning Kamp 497fe4e3243SPoul-Henning Kamp SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 4988d25eb2cSPoul-Henning Kamp NULL, 0, sysctl_devname, "", "devname(3) handler"); 4998d25eb2cSPoul-Henning Kamp 500a7489fe5SMike Smith /* 501a7489fe5SMike Smith * Set ready_for_devs; prior to this point, device creation is not allowed. 502a7489fe5SMike Smith */ 503a7489fe5SMike Smith static void 504a7489fe5SMike Smith dev_set_ready(void *junk) 505a7489fe5SMike Smith { 506a7489fe5SMike Smith ready_for_devs = 1; 507a7489fe5SMike Smith } 508a7489fe5SMike Smith 509a7489fe5SMike Smith SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 510