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 46a87b5350SPoul-Henning Kamp /* 47a87b5350SPoul-Henning Kamp * This is the number of hash-buckets. Experiements with 'real-life' 48a87b5350SPoul-Henning Kamp * udev_t's show that a prime halfway between two powers of two works 49a87b5350SPoul-Henning Kamp * best. 50a87b5350SPoul-Henning Kamp */ 51698bfad7SPoul-Henning Kamp #define DEVT_HASH 83 52a87b5350SPoul-Henning Kamp 53a87b5350SPoul-Henning Kamp /* The number of dev_t's we can create before malloc(9) kick in. */ 54698bfad7SPoul-Henning Kamp #define DEVT_STASH 50 55698bfad7SPoul-Henning Kamp 56ca916247SPoul-Henning Kamp static struct cdev devt_stash[DEVT_STASH]; 57698bfad7SPoul-Henning Kamp 58ca916247SPoul-Henning Kamp static LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 59d137acccSPoul-Henning Kamp 60ca916247SPoul-Henning Kamp static LIST_HEAD(, cdev) dev_free; 6146eede00SPoul-Henning Kamp 629dcbe240SPoul-Henning Kamp devfs_create_t *devfs_create_hook; 63db901281SPoul-Henning Kamp devfs_destroy_t *devfs_destroy_hook; 64d137acccSPoul-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 9302574b19SPoul-Henning Kamp #define dead_dump (d_dump_t *)enxio 9402574b19SPoul-Henning Kamp 9502574b19SPoul-Henning Kamp static int 9602574b19SPoul-Henning Kamp dead_psize(dev_t dev) 9702574b19SPoul-Henning Kamp { 9802574b19SPoul-Henning Kamp 9902574b19SPoul-Henning Kamp return (-1); 10002574b19SPoul-Henning Kamp } 10102574b19SPoul-Henning Kamp 10202574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 10302574b19SPoul-Henning Kamp 10402574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 10502574b19SPoul-Henning Kamp /* open */ dead_open, 10602574b19SPoul-Henning Kamp /* close */ dead_close, 10702574b19SPoul-Henning Kamp /* read */ dead_read, 10802574b19SPoul-Henning Kamp /* write */ dead_write, 10902574b19SPoul-Henning Kamp /* ioctl */ dead_ioctl, 11002574b19SPoul-Henning Kamp /* poll */ dead_poll, 11102574b19SPoul-Henning Kamp /* mmap */ dead_mmap, 11202574b19SPoul-Henning Kamp /* strategy */ dead_strategy, 11302574b19SPoul-Henning Kamp /* name */ "dead", 11402574b19SPoul-Henning Kamp /* maj */ 255, 11502574b19SPoul-Henning Kamp /* dump */ dead_dump, 11602574b19SPoul-Henning Kamp /* psize */ dead_psize, 11702574b19SPoul-Henning Kamp /* flags */ 0, 11802574b19SPoul-Henning Kamp /* kqfilter */ dead_kqfilter 11902574b19SPoul-Henning Kamp }; 12002574b19SPoul-Henning Kamp 1214e4a7663SPoul-Henning Kamp 1222447bec8SPoul-Henning Kamp struct cdevsw * 1232447bec8SPoul-Henning Kamp devsw(dev_t dev) 1242447bec8SPoul-Henning Kamp { 1257dc5cd04SPoul-Henning Kamp if (dev->si_devsw) 1267dc5cd04SPoul-Henning Kamp return (dev->si_devsw); 12702574b19SPoul-Henning Kamp return (&dead_cdevsw); 1282447bec8SPoul-Henning Kamp } 1292447bec8SPoul-Henning Kamp 1302447bec8SPoul-Henning Kamp /* 1312447bec8SPoul-Henning Kamp * Add a cdevsw entry 1322447bec8SPoul-Henning Kamp */ 1332447bec8SPoul-Henning Kamp 134f7ea2f55SJulian Elischer int 1352447bec8SPoul-Henning Kamp cdevsw_add(struct cdevsw *newentry) 136f7ea2f55SJulian Elischer { 137f7ea2f55SJulian Elischer 138662761a7SPoul-Henning Kamp return (0); 139f7ea2f55SJulian Elischer } 140f7ea2f55SJulian Elischer 1419a9eb2b9SGreg Lehey /* 1429a9eb2b9SGreg Lehey * Remove a cdevsw entry 1439a9eb2b9SGreg Lehey */ 1449a9eb2b9SGreg Lehey 1459a9eb2b9SGreg Lehey int 1469a9eb2b9SGreg Lehey cdevsw_remove(struct cdevsw *oldentry) 1479a9eb2b9SGreg Lehey { 1489a9eb2b9SGreg Lehey 1499a9eb2b9SGreg Lehey return 0; 1509a9eb2b9SGreg Lehey } 1519a9eb2b9SGreg Lehey 152bfbb9ce6SPoul-Henning Kamp /* 153bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 154bfbb9ce6SPoul-Henning Kamp */ 155bfbb9ce6SPoul-Henning Kamp 156bfbb9ce6SPoul-Henning Kamp int 157bfbb9ce6SPoul-Henning Kamp major(dev_t x) 158bfbb9ce6SPoul-Henning Kamp { 159698bfad7SPoul-Henning Kamp if (x == NODEV) 160698bfad7SPoul-Henning Kamp return NOUDEV; 161698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 162bfbb9ce6SPoul-Henning Kamp } 163bfbb9ce6SPoul-Henning Kamp 164bfbb9ce6SPoul-Henning Kamp int 165bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 166bfbb9ce6SPoul-Henning Kamp { 167698bfad7SPoul-Henning Kamp if (x == NODEV) 168698bfad7SPoul-Henning Kamp return NOUDEV; 169698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 170bfbb9ce6SPoul-Henning Kamp } 171bfbb9ce6SPoul-Henning Kamp 1729a27d579SPoul-Henning Kamp int 173b0d17ba6SPoul-Henning Kamp dev2unit(dev_t x) 1749a27d579SPoul-Henning Kamp { 1759a27d579SPoul-Henning Kamp int i; 1769a27d579SPoul-Henning Kamp 1779a27d579SPoul-Henning Kamp if (x == NODEV) 1789a27d579SPoul-Henning Kamp return NOUDEV; 1799a27d579SPoul-Henning Kamp i = minor(x); 1809a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 1819a27d579SPoul-Henning Kamp } 1829a27d579SPoul-Henning Kamp 183b0d17ba6SPoul-Henning Kamp int 184b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 185b0d17ba6SPoul-Henning Kamp { 186b0d17ba6SPoul-Henning Kamp 18715b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 188b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 189b0d17ba6SPoul-Henning Kamp } 190b0d17ba6SPoul-Henning Kamp 1913f54a085SPoul-Henning Kamp static dev_t 1923f54a085SPoul-Henning Kamp allocdev(void) 193bfbb9ce6SPoul-Henning Kamp { 194698bfad7SPoul-Henning Kamp static int stashed; 195ca916247SPoul-Henning Kamp struct cdev *si; 196698bfad7SPoul-Henning Kamp 1975ea98f59SPoul-Henning Kamp if (LIST_FIRST(&dev_free)) { 198d137acccSPoul-Henning Kamp si = LIST_FIRST(&dev_free); 199d137acccSPoul-Henning Kamp LIST_REMOVE(si, si_hash); 2005ea98f59SPoul-Henning Kamp } else if (stashed >= DEVT_STASH) { 201ca916247SPoul-Henning Kamp MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 2020c977c9cSPoul-Henning Kamp M_USE_RESERVE | M_ZERO | M_WAITOK); 203698bfad7SPoul-Henning Kamp } else { 204698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 2053344c5a1SPoul-Henning Kamp bzero(si, sizeof *si); 206d137acccSPoul-Henning Kamp si->si_flags |= SI_STASHED; 207698bfad7SPoul-Henning Kamp } 208237d2765SPoul-Henning Kamp si->__si_namebuf[0] = '\0'; 209237d2765SPoul-Henning Kamp si->si_name = si->__si_namebuf; 2103344c5a1SPoul-Henning Kamp LIST_INIT(&si->si_children); 211589c7af9SKirk McKusick TAILQ_INIT(&si->si_snapshots); 2123f54a085SPoul-Henning Kamp return (si); 2133f54a085SPoul-Henning Kamp } 2143f54a085SPoul-Henning Kamp 2153f54a085SPoul-Henning Kamp dev_t 2163f54a085SPoul-Henning Kamp makedev(int x, int y) 2173f54a085SPoul-Henning Kamp { 218ca916247SPoul-Henning Kamp struct cdev *si; 2193f54a085SPoul-Henning Kamp udev_t udev; 2203f54a085SPoul-Henning Kamp int hash; 2213f54a085SPoul-Henning Kamp 2223f54a085SPoul-Henning Kamp if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 2231fd7b93fSPoul-Henning Kamp panic("makedev of NOUDEV"); 2243f54a085SPoul-Henning Kamp udev = (x << 8) | y; 2253f54a085SPoul-Henning Kamp hash = udev % DEVT_HASH; 2263f54a085SPoul-Henning Kamp LIST_FOREACH(si, &dev_hash[hash], si_hash) { 2273f54a085SPoul-Henning Kamp if (si->si_udev == udev) 2283f54a085SPoul-Henning Kamp return (si); 2293f54a085SPoul-Henning Kamp } 2303f54a085SPoul-Henning Kamp si = allocdev(); 231698bfad7SPoul-Henning Kamp si->si_udev = udev; 232d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 233698bfad7SPoul-Henning Kamp return (si); 234bfbb9ce6SPoul-Henning Kamp } 235bfbb9ce6SPoul-Henning Kamp 236d137acccSPoul-Henning Kamp void 237d137acccSPoul-Henning Kamp freedev(dev_t dev) 238d137acccSPoul-Henning Kamp { 239d137acccSPoul-Henning Kamp 240d137acccSPoul-Henning Kamp if (!free_devt) 241d137acccSPoul-Henning Kamp return; 242d137acccSPoul-Henning Kamp if (SLIST_FIRST(&dev->si_hlist)) 243d137acccSPoul-Henning Kamp return; 244d137acccSPoul-Henning Kamp if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 245d137acccSPoul-Henning Kamp return; 246d137acccSPoul-Henning Kamp LIST_REMOVE(dev, si_hash); 247d137acccSPoul-Henning Kamp if (dev->si_flags & SI_STASHED) { 248d137acccSPoul-Henning Kamp bzero(dev, sizeof(*dev)); 2493344c5a1SPoul-Henning Kamp dev->si_flags |= SI_STASHED; 250d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_free, dev, si_hash); 251d137acccSPoul-Henning Kamp } else { 252d137acccSPoul-Henning Kamp FREE(dev, M_DEVT); 253d137acccSPoul-Henning Kamp } 254d137acccSPoul-Henning Kamp } 255d137acccSPoul-Henning Kamp 256bfbb9ce6SPoul-Henning Kamp udev_t 257bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 258bfbb9ce6SPoul-Henning Kamp { 259698bfad7SPoul-Henning Kamp if (x == NODEV) 260698bfad7SPoul-Henning Kamp return NOUDEV; 261698bfad7SPoul-Henning Kamp return (x->si_udev); 262bfbb9ce6SPoul-Henning Kamp } 263bfbb9ce6SPoul-Henning Kamp 264bfbb9ce6SPoul-Henning Kamp dev_t 265bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 266bfbb9ce6SPoul-Henning Kamp { 267fb01c24cSPoul-Henning Kamp 268fb01c24cSPoul-Henning Kamp if (x == NOUDEV) 269fb01c24cSPoul-Henning Kamp return (NODEV); 270d21c632cSPoul-Henning Kamp switch (b) { 271d21c632cSPoul-Henning Kamp case 0: 272bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 273d21c632cSPoul-Henning Kamp case 1: 274a16d0eb2SPoul-Henning Kamp return (NODEV); 275d21c632cSPoul-Henning Kamp default: 276d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 277d21c632cSPoul-Henning Kamp return NODEV; 278d21c632cSPoul-Henning Kamp } 279bfbb9ce6SPoul-Henning Kamp } 280bfbb9ce6SPoul-Henning Kamp 281bfbb9ce6SPoul-Henning Kamp int 282bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 283bfbb9ce6SPoul-Henning Kamp { 284bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 285bfbb9ce6SPoul-Henning Kamp } 286bfbb9ce6SPoul-Henning Kamp 287bfbb9ce6SPoul-Henning Kamp int 288bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 289bfbb9ce6SPoul-Henning Kamp { 290bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 291bfbb9ce6SPoul-Henning Kamp } 292bfbb9ce6SPoul-Henning Kamp 293bfbb9ce6SPoul-Henning Kamp udev_t 294f008cfccSPoul-Henning Kamp makeudev(int x, int y) 295bfbb9ce6SPoul-Henning Kamp { 296bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 297bfbb9ce6SPoul-Henning Kamp } 298bfbb9ce6SPoul-Henning Kamp 2990ef1c826SPoul-Henning Kamp dev_t 300c7021493SWarner Losh make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 3010ef1c826SPoul-Henning Kamp { 3020ef1c826SPoul-Henning Kamp dev_t dev; 3030ef1c826SPoul-Henning Kamp va_list ap; 3040ef1c826SPoul-Henning Kamp int i; 3050ef1c826SPoul-Henning Kamp 30611586717SBrian Somers KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 30711586717SBrian Somers ("Invalid minor (%d) in make_dev", minor)); 30811586717SBrian Somers 309a7489fe5SMike Smith if (!ready_for_devs) { 310a7489fe5SMike Smith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 311a7489fe5SMike Smith fmt); 312a7489fe5SMike Smith /* XXX panic here once drivers are cleaned up */ 313a7489fe5SMike Smith } 314a7489fe5SMike Smith 3150ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 3165ef2707eSPoul-Henning Kamp if (dev->si_flags & SI_NAMED) { 3175ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 3185ef2707eSPoul-Henning Kamp dev->si_name); 3194e4a7663SPoul-Henning Kamp panic("don't do that"); 3205ef2707eSPoul-Henning Kamp return (dev); 3215ef2707eSPoul-Henning Kamp } 3220ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3236334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3246334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3256334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3266334a663SPoul-Henning Kamp dev->__si_namebuf); 3276334a663SPoul-Henning Kamp } 3280ef1c826SPoul-Henning Kamp va_end(ap); 3290ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3303f54a085SPoul-Henning Kamp dev->si_uid = uid; 3313f54a085SPoul-Henning Kamp dev->si_gid = gid; 3323f54a085SPoul-Henning Kamp dev->si_mode = perms; 3335ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3341744fcd0SJulian Elischer 3359dcbe240SPoul-Henning Kamp if (devfs_create_hook) 3363f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3373f54a085SPoul-Henning Kamp return (dev); 3383f54a085SPoul-Henning Kamp } 3393f54a085SPoul-Henning Kamp 3407e7c3f3fSJonathan Lemon int 3417e7c3f3fSJonathan Lemon dev_named(dev_t pdev, const char *name) 3427e7c3f3fSJonathan Lemon { 3437e7c3f3fSJonathan Lemon dev_t cdev; 3447e7c3f3fSJonathan Lemon 3457e7c3f3fSJonathan Lemon if (strcmp(devtoname(pdev), name) == 0) 3467e7c3f3fSJonathan Lemon return (1); 3477e7c3f3fSJonathan Lemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 3487e7c3f3fSJonathan Lemon if (strcmp(devtoname(cdev), name) == 0) 3497e7c3f3fSJonathan Lemon return (1); 3507e7c3f3fSJonathan Lemon return (0); 3517e7c3f3fSJonathan Lemon } 3527e7c3f3fSJonathan Lemon 3533344c5a1SPoul-Henning Kamp void 3543344c5a1SPoul-Henning Kamp dev_depends(dev_t pdev, dev_t cdev) 3553344c5a1SPoul-Henning Kamp { 3563344c5a1SPoul-Henning Kamp 3573344c5a1SPoul-Henning Kamp cdev->si_parent = pdev; 3583344c5a1SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 3593344c5a1SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 3603344c5a1SPoul-Henning Kamp } 3613344c5a1SPoul-Henning Kamp 3623f54a085SPoul-Henning Kamp dev_t 363c7021493SWarner Losh make_dev_alias(dev_t pdev, const char *fmt, ...) 3643f54a085SPoul-Henning Kamp { 3653f54a085SPoul-Henning Kamp dev_t dev; 3663f54a085SPoul-Henning Kamp va_list ap; 3673f54a085SPoul-Henning Kamp int i; 3683f54a085SPoul-Henning Kamp 3693f54a085SPoul-Henning Kamp dev = allocdev(); 3703f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 3715ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3723344c5a1SPoul-Henning Kamp dev_depends(pdev, dev); 3733f54a085SPoul-Henning Kamp va_start(ap, fmt); 3746334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3756334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3766334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3776334a663SPoul-Henning Kamp dev->__si_namebuf); 3786334a663SPoul-Henning Kamp } 3793f54a085SPoul-Henning Kamp va_end(ap); 3803f54a085SPoul-Henning Kamp 3813f54a085SPoul-Henning Kamp if (devfs_create_hook) 3823f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3830ef1c826SPoul-Henning Kamp return (dev); 3840ef1c826SPoul-Henning Kamp } 3850ef1c826SPoul-Henning Kamp 386d137acccSPoul-Henning Kamp void 3871fd9f8f4SBrian Feldman revoke_and_destroy_dev(dev_t dev) 3881fd9f8f4SBrian Feldman { 3891fd9f8f4SBrian Feldman struct vnode *vp; 3901fd9f8f4SBrian Feldman 3911fd9f8f4SBrian Feldman GIANT_REQUIRED; 3921fd9f8f4SBrian Feldman 3931fd9f8f4SBrian Feldman vp = SLIST_FIRST(&dev->si_hlist); 3941fd9f8f4SBrian Feldman if (vp != NULL) 3951fd9f8f4SBrian Feldman VOP_REVOKE(vp, REVOKEALL); 3961fd9f8f4SBrian Feldman destroy_dev(dev); 3971fd9f8f4SBrian Feldman } 3981fd9f8f4SBrian Feldman 3991fd9f8f4SBrian Feldman void 40044d1184eSPoul-Henning Kamp destroy_dev(dev_t dev) 401d137acccSPoul-Henning Kamp { 4025ef2707eSPoul-Henning Kamp 4035ef2707eSPoul-Henning Kamp if (!(dev->si_flags & SI_NAMED)) { 4045ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 4055ef2707eSPoul-Henning Kamp major(dev), minor(dev)); 4064e4a7663SPoul-Henning Kamp panic("don't do that"); 4075ef2707eSPoul-Henning Kamp return; 4085ef2707eSPoul-Henning Kamp } 4095ef2707eSPoul-Henning Kamp 410db901281SPoul-Henning Kamp if (devfs_destroy_hook) 411db901281SPoul-Henning Kamp devfs_destroy_hook(dev); 4123344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 4133344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 4143344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 4153344c5a1SPoul-Henning Kamp } 4163344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 4173344c5a1SPoul-Henning Kamp destroy_dev(LIST_FIRST(&dev->si_children)); 418d137acccSPoul-Henning Kamp dev->si_drv1 = 0; 419d137acccSPoul-Henning Kamp dev->si_drv2 = 0; 420d137acccSPoul-Henning Kamp dev->si_devsw = 0; 421ff557fa1SBruce Evans bzero(&dev->__si_u, sizeof(dev->__si_u)); 4225ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 4235ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 424d137acccSPoul-Henning Kamp freedev(dev); 425d137acccSPoul-Henning Kamp } 426d137acccSPoul-Henning Kamp 427c32cc149SBruce Evans const char * 428b8e49f68SBill Fumerola devtoname(dev_t dev) 429b8e49f68SBill Fumerola { 430d137acccSPoul-Henning Kamp char *p; 431c32cc149SBruce Evans int mynor; 432b8e49f68SBill Fumerola 433d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 434d137acccSPoul-Henning Kamp p = dev->si_name; 435d137acccSPoul-Henning Kamp if (devsw(dev)) 436d137acccSPoul-Henning Kamp sprintf(p, "#%s/", devsw(dev)->d_name); 437d137acccSPoul-Henning Kamp else 438d137acccSPoul-Henning Kamp sprintf(p, "#%d/", major(dev)); 439d137acccSPoul-Henning Kamp p += strlen(p); 440c32cc149SBruce Evans mynor = minor(dev); 441c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 442c32cc149SBruce Evans sprintf(p, "%#x", (u_int)mynor); 443c32cc149SBruce Evans else 444c32cc149SBruce Evans sprintf(p, "%d", mynor); 445d137acccSPoul-Henning Kamp } 446b8e49f68SBill Fumerola return (dev->si_name); 447b8e49f68SBill Fumerola } 448db901281SPoul-Henning Kamp 449db901281SPoul-Henning Kamp int 45001de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 451db901281SPoul-Henning Kamp { 452db901281SPoul-Henning Kamp int u, i; 453db901281SPoul-Henning Kamp 454db901281SPoul-Henning Kamp i = strlen(stem); 45556700d46SBrian Somers if (bcmp(stem, name, i) != 0) 45656700d46SBrian Somers return (0); 457db901281SPoul-Henning Kamp if (!isdigit(name[i])) 458db901281SPoul-Henning Kamp return (0); 459db901281SPoul-Henning Kamp u = 0; 46010786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 46110786074SPoul-Henning Kamp return (0); 462db901281SPoul-Henning Kamp while (isdigit(name[i])) { 463db901281SPoul-Henning Kamp u *= 10; 464db901281SPoul-Henning Kamp u += name[i++] - '0'; 465db901281SPoul-Henning Kamp } 466dab3d85fSBrian Feldman if (u > 0xffffff) 467dab3d85fSBrian Feldman return (0); 468db901281SPoul-Henning Kamp *unit = u; 469db901281SPoul-Henning Kamp if (namep) 470db901281SPoul-Henning Kamp *namep = &name[i]; 471db901281SPoul-Henning Kamp if (name[i]) 472db901281SPoul-Henning Kamp return (2); 473db901281SPoul-Henning Kamp return (1); 474db901281SPoul-Henning Kamp } 4758d25eb2cSPoul-Henning Kamp 4768d25eb2cSPoul-Henning Kamp /* 4778d25eb2cSPoul-Henning Kamp * Helper sysctl for devname(3). We're given a {u}dev_t and return 4788d25eb2cSPoul-Henning Kamp * the name, if any, registered by the device driver. 4798d25eb2cSPoul-Henning Kamp */ 4808d25eb2cSPoul-Henning Kamp static int 4818d25eb2cSPoul-Henning Kamp sysctl_devname(SYSCTL_HANDLER_ARGS) 4828d25eb2cSPoul-Henning Kamp { 4838d25eb2cSPoul-Henning Kamp int error; 4848d25eb2cSPoul-Henning Kamp udev_t ud; 4858d25eb2cSPoul-Henning Kamp dev_t dev; 4868d25eb2cSPoul-Henning Kamp 4878d25eb2cSPoul-Henning Kamp error = SYSCTL_IN(req, &ud, sizeof (ud)); 4888d25eb2cSPoul-Henning Kamp if (error) 4898d25eb2cSPoul-Henning Kamp return (error); 4901fd7b93fSPoul-Henning Kamp if (ud == NOUDEV) 4911fd7b93fSPoul-Henning Kamp return(EINVAL); 4928d25eb2cSPoul-Henning Kamp dev = makedev(umajor(ud), uminor(ud)); 4938d25eb2cSPoul-Henning Kamp if (dev->si_name[0] == '\0') 4948d25eb2cSPoul-Henning Kamp error = ENOENT; 4958d25eb2cSPoul-Henning Kamp else 4968d25eb2cSPoul-Henning Kamp error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 4978d25eb2cSPoul-Henning Kamp freedev(dev); 4988d25eb2cSPoul-Henning Kamp return (error); 4998d25eb2cSPoul-Henning Kamp } 5008d25eb2cSPoul-Henning Kamp 501fe4e3243SPoul-Henning Kamp SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 5028d25eb2cSPoul-Henning Kamp NULL, 0, sysctl_devname, "", "devname(3) handler"); 5038d25eb2cSPoul-Henning Kamp 504a7489fe5SMike Smith /* 505a7489fe5SMike Smith * Set ready_for_devs; prior to this point, device creation is not allowed. 506a7489fe5SMike Smith */ 507a7489fe5SMike Smith static void 508a7489fe5SMike Smith dev_set_ready(void *junk) 509a7489fe5SMike Smith { 510a7489fe5SMike Smith ready_for_devs = 1; 511a7489fe5SMike Smith } 512a7489fe5SMike Smith 513a7489fe5SMike Smith SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 514