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 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 /* 131bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 132bfbb9ce6SPoul-Henning Kamp */ 133bfbb9ce6SPoul-Henning Kamp 134bfbb9ce6SPoul-Henning Kamp int 135bfbb9ce6SPoul-Henning Kamp major(dev_t x) 136bfbb9ce6SPoul-Henning Kamp { 137698bfad7SPoul-Henning Kamp if (x == NODEV) 138698bfad7SPoul-Henning Kamp return NOUDEV; 139698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 140bfbb9ce6SPoul-Henning Kamp } 141bfbb9ce6SPoul-Henning Kamp 142bfbb9ce6SPoul-Henning Kamp int 143bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 144bfbb9ce6SPoul-Henning Kamp { 145698bfad7SPoul-Henning Kamp if (x == NODEV) 146698bfad7SPoul-Henning Kamp return NOUDEV; 147698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 148bfbb9ce6SPoul-Henning Kamp } 149bfbb9ce6SPoul-Henning Kamp 1509a27d579SPoul-Henning Kamp int 151b0d17ba6SPoul-Henning Kamp dev2unit(dev_t x) 1529a27d579SPoul-Henning Kamp { 1539a27d579SPoul-Henning Kamp int i; 1549a27d579SPoul-Henning Kamp 1559a27d579SPoul-Henning Kamp if (x == NODEV) 1569a27d579SPoul-Henning Kamp return NOUDEV; 1579a27d579SPoul-Henning Kamp i = minor(x); 1589a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 1599a27d579SPoul-Henning Kamp } 1609a27d579SPoul-Henning Kamp 161b0d17ba6SPoul-Henning Kamp int 162b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 163b0d17ba6SPoul-Henning Kamp { 164b0d17ba6SPoul-Henning Kamp 16515b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 166b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 167b0d17ba6SPoul-Henning Kamp } 168b0d17ba6SPoul-Henning Kamp 1693f54a085SPoul-Henning Kamp static dev_t 1703f54a085SPoul-Henning Kamp allocdev(void) 171bfbb9ce6SPoul-Henning Kamp { 172698bfad7SPoul-Henning Kamp static int stashed; 173ca916247SPoul-Henning Kamp struct cdev *si; 174698bfad7SPoul-Henning Kamp 1755ea98f59SPoul-Henning Kamp if (LIST_FIRST(&dev_free)) { 176d137acccSPoul-Henning Kamp si = LIST_FIRST(&dev_free); 177d137acccSPoul-Henning Kamp LIST_REMOVE(si, si_hash); 1785ea98f59SPoul-Henning Kamp } else if (stashed >= DEVT_STASH) { 179ca916247SPoul-Henning Kamp MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 1800c977c9cSPoul-Henning Kamp M_USE_RESERVE | M_ZERO | M_WAITOK); 181698bfad7SPoul-Henning Kamp } else { 182698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 1833344c5a1SPoul-Henning Kamp bzero(si, sizeof *si); 184d137acccSPoul-Henning Kamp si->si_flags |= SI_STASHED; 185698bfad7SPoul-Henning Kamp } 186237d2765SPoul-Henning Kamp si->__si_namebuf[0] = '\0'; 187237d2765SPoul-Henning Kamp si->si_name = si->__si_namebuf; 1883344c5a1SPoul-Henning Kamp LIST_INIT(&si->si_children); 189589c7af9SKirk McKusick TAILQ_INIT(&si->si_snapshots); 1903f54a085SPoul-Henning Kamp return (si); 1913f54a085SPoul-Henning Kamp } 1923f54a085SPoul-Henning Kamp 1933f54a085SPoul-Henning Kamp dev_t 1943f54a085SPoul-Henning Kamp makedev(int x, int y) 1953f54a085SPoul-Henning Kamp { 196ca916247SPoul-Henning Kamp struct cdev *si; 1973f54a085SPoul-Henning Kamp udev_t udev; 1983f54a085SPoul-Henning Kamp int hash; 1993f54a085SPoul-Henning Kamp 2003f54a085SPoul-Henning Kamp if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 2011fd7b93fSPoul-Henning Kamp panic("makedev of NOUDEV"); 2023f54a085SPoul-Henning Kamp udev = (x << 8) | y; 2033f54a085SPoul-Henning Kamp hash = udev % DEVT_HASH; 2043f54a085SPoul-Henning Kamp LIST_FOREACH(si, &dev_hash[hash], si_hash) { 2053f54a085SPoul-Henning Kamp if (si->si_udev == udev) 2063f54a085SPoul-Henning Kamp return (si); 2073f54a085SPoul-Henning Kamp } 2083f54a085SPoul-Henning Kamp si = allocdev(); 209698bfad7SPoul-Henning Kamp si->si_udev = udev; 210d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 211698bfad7SPoul-Henning Kamp return (si); 212bfbb9ce6SPoul-Henning Kamp } 213bfbb9ce6SPoul-Henning Kamp 214d137acccSPoul-Henning Kamp void 215d137acccSPoul-Henning Kamp freedev(dev_t dev) 216d137acccSPoul-Henning Kamp { 217d137acccSPoul-Henning Kamp 218d137acccSPoul-Henning Kamp if (!free_devt) 219d137acccSPoul-Henning Kamp return; 220d137acccSPoul-Henning Kamp if (SLIST_FIRST(&dev->si_hlist)) 221d137acccSPoul-Henning Kamp return; 222d137acccSPoul-Henning Kamp if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 223d137acccSPoul-Henning Kamp return; 224d137acccSPoul-Henning Kamp LIST_REMOVE(dev, si_hash); 225d137acccSPoul-Henning Kamp if (dev->si_flags & SI_STASHED) { 226d137acccSPoul-Henning Kamp bzero(dev, sizeof(*dev)); 2273344c5a1SPoul-Henning Kamp dev->si_flags |= SI_STASHED; 228d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_free, dev, si_hash); 229d137acccSPoul-Henning Kamp } else { 230d137acccSPoul-Henning Kamp FREE(dev, M_DEVT); 231d137acccSPoul-Henning Kamp } 232d137acccSPoul-Henning Kamp } 233d137acccSPoul-Henning Kamp 234bfbb9ce6SPoul-Henning Kamp udev_t 235bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 236bfbb9ce6SPoul-Henning Kamp { 237698bfad7SPoul-Henning Kamp if (x == NODEV) 238698bfad7SPoul-Henning Kamp return NOUDEV; 239698bfad7SPoul-Henning Kamp return (x->si_udev); 240bfbb9ce6SPoul-Henning Kamp } 241bfbb9ce6SPoul-Henning Kamp 242bfbb9ce6SPoul-Henning Kamp dev_t 243bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 244bfbb9ce6SPoul-Henning Kamp { 245fb01c24cSPoul-Henning Kamp 246fb01c24cSPoul-Henning Kamp if (x == NOUDEV) 247fb01c24cSPoul-Henning Kamp return (NODEV); 248d21c632cSPoul-Henning Kamp switch (b) { 249d21c632cSPoul-Henning Kamp case 0: 250bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 251d21c632cSPoul-Henning Kamp case 1: 252a16d0eb2SPoul-Henning Kamp return (NODEV); 253d21c632cSPoul-Henning Kamp default: 254d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 255d21c632cSPoul-Henning Kamp return NODEV; 256d21c632cSPoul-Henning Kamp } 257bfbb9ce6SPoul-Henning Kamp } 258bfbb9ce6SPoul-Henning Kamp 259bfbb9ce6SPoul-Henning Kamp int 260bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 261bfbb9ce6SPoul-Henning Kamp { 262bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 263bfbb9ce6SPoul-Henning Kamp } 264bfbb9ce6SPoul-Henning Kamp 265bfbb9ce6SPoul-Henning Kamp int 266bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 267bfbb9ce6SPoul-Henning Kamp { 268bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 269bfbb9ce6SPoul-Henning Kamp } 270bfbb9ce6SPoul-Henning Kamp 271bfbb9ce6SPoul-Henning Kamp udev_t 272f008cfccSPoul-Henning Kamp makeudev(int x, int y) 273bfbb9ce6SPoul-Henning Kamp { 274bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 275bfbb9ce6SPoul-Henning Kamp } 276bfbb9ce6SPoul-Henning Kamp 2770ef1c826SPoul-Henning Kamp dev_t 278c7021493SWarner Losh make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 2790ef1c826SPoul-Henning Kamp { 2800ef1c826SPoul-Henning Kamp dev_t dev; 2810ef1c826SPoul-Henning Kamp va_list ap; 2820ef1c826SPoul-Henning Kamp int i; 2830ef1c826SPoul-Henning Kamp 284beea48b2SPoul-Henning Kamp KASSERT((minor & ~0xffff00ff) == 0, 285beea48b2SPoul-Henning Kamp ("Invalid minor (0x%x) in make_dev", minor)); 286beea48b2SPoul-Henning Kamp 287beea48b2SPoul-Henning Kamp if (devsw->d_maj == MAJOR_AUTO) { 288beea48b2SPoul-Henning Kamp for (i = NUMCDEVSW - 1; i > 0; i--) 289beea48b2SPoul-Henning Kamp if (reserved_majors[i] != i) 290beea48b2SPoul-Henning Kamp break; 291beea48b2SPoul-Henning Kamp KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 292beea48b2SPoul-Henning Kamp printf("Allocating major#%d to \"%s\"\n", i, devsw->d_name); 293beea48b2SPoul-Henning Kamp devsw->d_maj = i; 294beea48b2SPoul-Henning Kamp reserved_majors[i] = i; 29585f19dccSPoul-Henning Kamp } else { 29685f19dccSPoul-Henning Kamp KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256, 29785f19dccSPoul-Henning Kamp ("Invalid major (%d) in make_dev", devsw->d_maj)); 29885f19dccSPoul-Henning Kamp if (reserved_majors[devsw->d_maj] != devsw->d_maj) { 29985f19dccSPoul-Henning Kamp printf("WARNING: driver \"%s\" used %s %d\n", 30085f19dccSPoul-Henning Kamp devsw->d_name, "unreserved major device number", 30185f19dccSPoul-Henning Kamp devsw->d_maj); 30285f19dccSPoul-Henning Kamp reserved_majors[devsw->d_maj] = devsw->d_maj; 30385f19dccSPoul-Henning Kamp } 304beea48b2SPoul-Henning Kamp } 30511586717SBrian Somers 306a7489fe5SMike Smith if (!ready_for_devs) { 307a7489fe5SMike Smith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 308a7489fe5SMike Smith fmt); 309a7489fe5SMike Smith /* XXX panic here once drivers are cleaned up */ 310a7489fe5SMike Smith } 311a7489fe5SMike Smith 3120ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 3135ef2707eSPoul-Henning Kamp if (dev->si_flags & SI_NAMED) { 3145ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 3155ef2707eSPoul-Henning Kamp dev->si_name); 3164e4a7663SPoul-Henning Kamp panic("don't do that"); 3175ef2707eSPoul-Henning Kamp return (dev); 3185ef2707eSPoul-Henning Kamp } 3190ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3206334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3216334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3226334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3236334a663SPoul-Henning Kamp dev->__si_namebuf); 3246334a663SPoul-Henning Kamp } 3250ef1c826SPoul-Henning Kamp va_end(ap); 3260ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3273f54a085SPoul-Henning Kamp dev->si_uid = uid; 3283f54a085SPoul-Henning Kamp dev->si_gid = gid; 3293f54a085SPoul-Henning Kamp dev->si_mode = perms; 3305ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3311744fcd0SJulian Elischer 3329285a87eSPoul-Henning Kamp devfs_create(dev); 3333f54a085SPoul-Henning Kamp return (dev); 3343f54a085SPoul-Henning Kamp } 3353f54a085SPoul-Henning Kamp 3367e7c3f3fSJonathan Lemon int 3377e7c3f3fSJonathan Lemon dev_named(dev_t pdev, const char *name) 3387e7c3f3fSJonathan Lemon { 3397e7c3f3fSJonathan Lemon dev_t cdev; 3407e7c3f3fSJonathan Lemon 3417e7c3f3fSJonathan Lemon if (strcmp(devtoname(pdev), name) == 0) 3427e7c3f3fSJonathan Lemon return (1); 3437e7c3f3fSJonathan Lemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 3447e7c3f3fSJonathan Lemon if (strcmp(devtoname(cdev), name) == 0) 3457e7c3f3fSJonathan Lemon return (1); 3467e7c3f3fSJonathan Lemon return (0); 3477e7c3f3fSJonathan Lemon } 3487e7c3f3fSJonathan Lemon 3493344c5a1SPoul-Henning Kamp void 3503344c5a1SPoul-Henning Kamp dev_depends(dev_t pdev, dev_t cdev) 3513344c5a1SPoul-Henning Kamp { 3523344c5a1SPoul-Henning Kamp 3533344c5a1SPoul-Henning Kamp cdev->si_parent = pdev; 3543344c5a1SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 3553344c5a1SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 3563344c5a1SPoul-Henning Kamp } 3573344c5a1SPoul-Henning Kamp 3583f54a085SPoul-Henning Kamp dev_t 359c7021493SWarner Losh make_dev_alias(dev_t pdev, const char *fmt, ...) 3603f54a085SPoul-Henning Kamp { 3613f54a085SPoul-Henning Kamp dev_t dev; 3623f54a085SPoul-Henning Kamp va_list ap; 3633f54a085SPoul-Henning Kamp int i; 3643f54a085SPoul-Henning Kamp 3653f54a085SPoul-Henning Kamp dev = allocdev(); 3663f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 3675ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3683344c5a1SPoul-Henning Kamp dev_depends(pdev, dev); 3693f54a085SPoul-Henning Kamp va_start(ap, fmt); 3706334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 3716334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 3726334a663SPoul-Henning Kamp printf("WARNING: Device name truncated! (%s)", 3736334a663SPoul-Henning Kamp dev->__si_namebuf); 3746334a663SPoul-Henning Kamp } 3753f54a085SPoul-Henning Kamp va_end(ap); 3763f54a085SPoul-Henning Kamp 3779285a87eSPoul-Henning Kamp devfs_create(dev); 3780ef1c826SPoul-Henning Kamp return (dev); 3790ef1c826SPoul-Henning Kamp } 3800ef1c826SPoul-Henning Kamp 381d137acccSPoul-Henning Kamp void 3821fd9f8f4SBrian Feldman revoke_and_destroy_dev(dev_t dev) 3831fd9f8f4SBrian Feldman { 3841fd9f8f4SBrian Feldman struct vnode *vp; 3851fd9f8f4SBrian Feldman 3861fd9f8f4SBrian Feldman GIANT_REQUIRED; 3871fd9f8f4SBrian Feldman 3881fd9f8f4SBrian Feldman vp = SLIST_FIRST(&dev->si_hlist); 3891fd9f8f4SBrian Feldman if (vp != NULL) 3901fd9f8f4SBrian Feldman VOP_REVOKE(vp, REVOKEALL); 3911fd9f8f4SBrian Feldman destroy_dev(dev); 3921fd9f8f4SBrian Feldman } 3931fd9f8f4SBrian Feldman 3941fd9f8f4SBrian Feldman void 39544d1184eSPoul-Henning Kamp destroy_dev(dev_t dev) 396d137acccSPoul-Henning Kamp { 3975ef2707eSPoul-Henning Kamp 3985ef2707eSPoul-Henning Kamp if (!(dev->si_flags & SI_NAMED)) { 3995ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 4005ef2707eSPoul-Henning Kamp major(dev), minor(dev)); 4014e4a7663SPoul-Henning Kamp panic("don't do that"); 4025ef2707eSPoul-Henning Kamp return; 4035ef2707eSPoul-Henning Kamp } 4045ef2707eSPoul-Henning Kamp 4059285a87eSPoul-Henning Kamp devfs_destroy(dev); 4063344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 4073344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 4083344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 4093344c5a1SPoul-Henning Kamp } 4103344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 4113344c5a1SPoul-Henning Kamp destroy_dev(LIST_FIRST(&dev->si_children)); 412d137acccSPoul-Henning Kamp dev->si_drv1 = 0; 413d137acccSPoul-Henning Kamp dev->si_drv2 = 0; 414d137acccSPoul-Henning Kamp dev->si_devsw = 0; 415ff557fa1SBruce Evans bzero(&dev->__si_u, sizeof(dev->__si_u)); 4165ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 4175ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 418d137acccSPoul-Henning Kamp freedev(dev); 419d137acccSPoul-Henning Kamp } 420d137acccSPoul-Henning Kamp 421c32cc149SBruce Evans const char * 422b8e49f68SBill Fumerola devtoname(dev_t dev) 423b8e49f68SBill Fumerola { 424d137acccSPoul-Henning Kamp char *p; 425c32cc149SBruce Evans int mynor; 426b8e49f68SBill Fumerola 427d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 428d137acccSPoul-Henning Kamp p = dev->si_name; 429d137acccSPoul-Henning Kamp if (devsw(dev)) 430d137acccSPoul-Henning Kamp sprintf(p, "#%s/", devsw(dev)->d_name); 431d137acccSPoul-Henning Kamp else 432d137acccSPoul-Henning Kamp sprintf(p, "#%d/", major(dev)); 433d137acccSPoul-Henning Kamp p += strlen(p); 434c32cc149SBruce Evans mynor = minor(dev); 435c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 436c32cc149SBruce Evans sprintf(p, "%#x", (u_int)mynor); 437c32cc149SBruce Evans else 438c32cc149SBruce Evans sprintf(p, "%d", mynor); 439d137acccSPoul-Henning Kamp } 440b8e49f68SBill Fumerola return (dev->si_name); 441b8e49f68SBill Fumerola } 442db901281SPoul-Henning Kamp 443db901281SPoul-Henning Kamp int 44401de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 445db901281SPoul-Henning Kamp { 446db901281SPoul-Henning Kamp int u, i; 447db901281SPoul-Henning Kamp 448db901281SPoul-Henning Kamp i = strlen(stem); 44956700d46SBrian Somers if (bcmp(stem, name, i) != 0) 45056700d46SBrian Somers return (0); 451db901281SPoul-Henning Kamp if (!isdigit(name[i])) 452db901281SPoul-Henning Kamp return (0); 453db901281SPoul-Henning Kamp u = 0; 45410786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 45510786074SPoul-Henning Kamp return (0); 456db901281SPoul-Henning Kamp while (isdigit(name[i])) { 457db901281SPoul-Henning Kamp u *= 10; 458db901281SPoul-Henning Kamp u += name[i++] - '0'; 459db901281SPoul-Henning Kamp } 460dab3d85fSBrian Feldman if (u > 0xffffff) 461dab3d85fSBrian Feldman return (0); 462db901281SPoul-Henning Kamp *unit = u; 463db901281SPoul-Henning Kamp if (namep) 464db901281SPoul-Henning Kamp *namep = &name[i]; 465db901281SPoul-Henning Kamp if (name[i]) 466db901281SPoul-Henning Kamp return (2); 467db901281SPoul-Henning Kamp return (1); 468db901281SPoul-Henning Kamp } 4698d25eb2cSPoul-Henning Kamp 4708d25eb2cSPoul-Henning Kamp /* 4718d25eb2cSPoul-Henning Kamp * Helper sysctl for devname(3). We're given a {u}dev_t and return 4728d25eb2cSPoul-Henning Kamp * the name, if any, registered by the device driver. 4738d25eb2cSPoul-Henning Kamp */ 4748d25eb2cSPoul-Henning Kamp static int 4758d25eb2cSPoul-Henning Kamp sysctl_devname(SYSCTL_HANDLER_ARGS) 4768d25eb2cSPoul-Henning Kamp { 4778d25eb2cSPoul-Henning Kamp int error; 4788d25eb2cSPoul-Henning Kamp udev_t ud; 4798d25eb2cSPoul-Henning Kamp dev_t dev; 4808d25eb2cSPoul-Henning Kamp 4818d25eb2cSPoul-Henning Kamp error = SYSCTL_IN(req, &ud, sizeof (ud)); 4828d25eb2cSPoul-Henning Kamp if (error) 4838d25eb2cSPoul-Henning Kamp return (error); 4841fd7b93fSPoul-Henning Kamp if (ud == NOUDEV) 4851fd7b93fSPoul-Henning Kamp return(EINVAL); 4868d25eb2cSPoul-Henning Kamp dev = makedev(umajor(ud), uminor(ud)); 4878d25eb2cSPoul-Henning Kamp if (dev->si_name[0] == '\0') 4888d25eb2cSPoul-Henning Kamp error = ENOENT; 4898d25eb2cSPoul-Henning Kamp else 4908d25eb2cSPoul-Henning Kamp error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 4918d25eb2cSPoul-Henning Kamp freedev(dev); 4928d25eb2cSPoul-Henning Kamp return (error); 4938d25eb2cSPoul-Henning Kamp } 4948d25eb2cSPoul-Henning Kamp 495fe4e3243SPoul-Henning Kamp SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 4968d25eb2cSPoul-Henning Kamp NULL, 0, sysctl_devname, "", "devname(3) handler"); 4978d25eb2cSPoul-Henning Kamp 498a7489fe5SMike Smith /* 499a7489fe5SMike Smith * Set ready_for_devs; prior to this point, device creation is not allowed. 500a7489fe5SMike Smith */ 501a7489fe5SMike Smith static void 502a7489fe5SMike Smith dev_set_ready(void *junk) 503a7489fe5SMike Smith { 504a7489fe5SMike Smith ready_for_devs = 1; 505a7489fe5SMike Smith } 506a7489fe5SMike Smith 507a7489fe5SMike Smith SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 508