126453f35SJulian Elischer /*- 226453f35SJulian Elischer * Parts Copyright (c) 1995 Terrence R. Lambert 326453f35SJulian Elischer * Copyright (c) 1995 Julian R. Elischer 426453f35SJulian Elischer * All rights reserved. 526453f35SJulian Elischer * 626453f35SJulian Elischer * Redistribution and use in source and binary forms, with or without 726453f35SJulian Elischer * modification, are permitted provided that the following conditions 826453f35SJulian Elischer * are met: 926453f35SJulian Elischer * 1. Redistributions of source code must retain the above copyright 1026453f35SJulian Elischer * notice, this list of conditions and the following disclaimer. 1126453f35SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1226453f35SJulian Elischer * notice, this list of conditions and the following disclaimer in the 1326453f35SJulian Elischer * documentation and/or other materials provided with the distribution. 1426453f35SJulian Elischer * 3. All advertising materials mentioning features or use of this software 1526453f35SJulian Elischer * must display the following acknowledgement: 1626453f35SJulian Elischer * This product includes software developed by Terrence R. Lambert. 1726453f35SJulian Elischer * 4. The name Terrence R. Lambert may not be used to endorse or promote 1826453f35SJulian Elischer * products derived from this software without specific prior written 1926453f35SJulian Elischer * permission. 2026453f35SJulian Elischer * 2126453f35SJulian Elischer * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 2226453f35SJulian Elischer * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2326453f35SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2426453f35SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 2526453f35SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2626453f35SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2726453f35SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2826453f35SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2926453f35SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3026453f35SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3126453f35SJulian Elischer * SUCH DAMAGE. 3226453f35SJulian Elischer * 33c3aac50fSPeter Wemm * $FreeBSD$ 3426453f35SJulian Elischer */ 3526453f35SJulian Elischer 3626453f35SJulian Elischer #include <sys/param.h> 37698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 38f8a760b3SJulian Elischer #include <sys/systm.h> 391b567820SBrian Feldman #include <sys/lock.h> 401b567820SBrian Feldman #include <sys/mutex.h> 41b40ce416SJulian Elischer #include <sys/sysctl.h> 42ecbb00a2SDoug Rabson #include <sys/module.h> 43698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 4426453f35SJulian Elischer #include <sys/conf.h> 451dfcbb0cSJulian Elischer #include <sys/vnode.h> 46698bfad7SPoul-Henning Kamp #include <sys/queue.h> 47db901281SPoul-Henning Kamp #include <sys/ctype.h> 480ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 491dfcbb0cSJulian Elischer 502447bec8SPoul-Henning Kamp #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 511dfcbb0cSJulian Elischer 525f7806abSPoul-Henning Kamp static struct cdevsw *cdevsw[NUMCDEVSW]; 531dfcbb0cSJulian Elischer 54959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 55698bfad7SPoul-Henning Kamp 56a87b5350SPoul-Henning Kamp /* 57a87b5350SPoul-Henning Kamp * This is the number of hash-buckets. Experiements with 'real-life' 58a87b5350SPoul-Henning Kamp * udev_t's show that a prime halfway between two powers of two works 59a87b5350SPoul-Henning Kamp * best. 60a87b5350SPoul-Henning Kamp */ 61698bfad7SPoul-Henning Kamp #define DEVT_HASH 83 62a87b5350SPoul-Henning Kamp 63a87b5350SPoul-Henning Kamp /* The number of dev_t's we can create before malloc(9) kick in. */ 64698bfad7SPoul-Henning Kamp #define DEVT_STASH 50 65698bfad7SPoul-Henning Kamp 66698bfad7SPoul-Henning Kamp static struct specinfo devt_stash[DEVT_STASH]; 67698bfad7SPoul-Henning Kamp 68e3975643SJake Burkholder static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 69d137acccSPoul-Henning Kamp 70e3975643SJake Burkholder static LIST_HEAD(, specinfo) dev_free; 7146eede00SPoul-Henning Kamp 729dcbe240SPoul-Henning Kamp devfs_create_t *devfs_create_hook; 73db901281SPoul-Henning Kamp devfs_destroy_t *devfs_destroy_hook; 74db901281SPoul-Henning Kamp int devfs_present; 75d137acccSPoul-Henning Kamp 76a7489fe5SMike Smith static int ready_for_devs; 77a7489fe5SMike Smith 78d137acccSPoul-Henning Kamp static int free_devt; 79d137acccSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 809dcbe240SPoul-Henning Kamp 814e4a7663SPoul-Henning Kamp /* XXX: This is a hack */ 824e4a7663SPoul-Henning Kamp void disk_dev_synth(dev_t dev); 834e4a7663SPoul-Henning Kamp 842447bec8SPoul-Henning Kamp struct cdevsw * 852447bec8SPoul-Henning Kamp devsw(dev_t dev) 862447bec8SPoul-Henning Kamp { 877dc5cd04SPoul-Henning Kamp if (dev->si_devsw) 887dc5cd04SPoul-Henning Kamp return (dev->si_devsw); 894e4a7663SPoul-Henning Kamp /* XXX: Hack around our backwards disk code */ 904e4a7663SPoul-Henning Kamp disk_dev_synth(dev); 914e4a7663SPoul-Henning Kamp if (dev->si_devsw) 924e4a7663SPoul-Henning Kamp return (dev->si_devsw); 934e4a7663SPoul-Henning Kamp if (devfs_present) 944e130067SPoul-Henning Kamp return (NULL); 953de280c4SPoul-Henning Kamp return(cdevsw[major(dev)]); 962447bec8SPoul-Henning Kamp } 972447bec8SPoul-Henning Kamp 982447bec8SPoul-Henning Kamp /* 992447bec8SPoul-Henning Kamp * Add a cdevsw entry 1002447bec8SPoul-Henning Kamp */ 1012447bec8SPoul-Henning Kamp 102f7ea2f55SJulian Elischer int 1032447bec8SPoul-Henning Kamp cdevsw_add(struct cdevsw *newentry) 104f7ea2f55SJulian Elischer { 105bfbb9ce6SPoul-Henning Kamp 1062447bec8SPoul-Henning Kamp if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 1072447bec8SPoul-Henning Kamp printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1082447bec8SPoul-Henning Kamp newentry->d_name, newentry->d_maj); 109662761a7SPoul-Henning Kamp return (EINVAL); 110662761a7SPoul-Henning Kamp } 111f7ea2f55SJulian Elischer 112c31558b2SPoul-Henning Kamp if (cdevsw[newentry->d_maj]) { 113c31558b2SPoul-Henning Kamp printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 114c31558b2SPoul-Henning Kamp newentry->d_name, cdevsw[newentry->d_maj]->d_name); 115c31558b2SPoul-Henning Kamp } 116662761a7SPoul-Henning Kamp 1172447bec8SPoul-Henning Kamp cdevsw[newentry->d_maj] = newentry; 118f7ea2f55SJulian Elischer 119662761a7SPoul-Henning Kamp return (0); 120f7ea2f55SJulian Elischer } 121f7ea2f55SJulian Elischer 1229a9eb2b9SGreg Lehey /* 1239a9eb2b9SGreg Lehey * Remove a cdevsw entry 1249a9eb2b9SGreg Lehey */ 1259a9eb2b9SGreg Lehey 1269a9eb2b9SGreg Lehey int 1279a9eb2b9SGreg Lehey cdevsw_remove(struct cdevsw *oldentry) 1289a9eb2b9SGreg Lehey { 1299a9eb2b9SGreg Lehey if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 1309a9eb2b9SGreg Lehey printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1319a9eb2b9SGreg Lehey oldentry->d_name, oldentry->d_maj); 1329a9eb2b9SGreg Lehey return EINVAL; 1339a9eb2b9SGreg Lehey } 1349a9eb2b9SGreg Lehey 1359a9eb2b9SGreg Lehey cdevsw[oldentry->d_maj] = NULL; 1369a9eb2b9SGreg Lehey 1379a9eb2b9SGreg Lehey return 0; 1389a9eb2b9SGreg Lehey } 1399a9eb2b9SGreg Lehey 140bfbb9ce6SPoul-Henning Kamp /* 141bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 142bfbb9ce6SPoul-Henning Kamp */ 143bfbb9ce6SPoul-Henning Kamp 144bfbb9ce6SPoul-Henning Kamp int 145bfbb9ce6SPoul-Henning Kamp major(dev_t x) 146bfbb9ce6SPoul-Henning Kamp { 147698bfad7SPoul-Henning Kamp if (x == NODEV) 148698bfad7SPoul-Henning Kamp return NOUDEV; 149698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 150bfbb9ce6SPoul-Henning Kamp } 151bfbb9ce6SPoul-Henning Kamp 152bfbb9ce6SPoul-Henning Kamp int 153bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 154bfbb9ce6SPoul-Henning Kamp { 155698bfad7SPoul-Henning Kamp if (x == NODEV) 156698bfad7SPoul-Henning Kamp return NOUDEV; 157698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 158bfbb9ce6SPoul-Henning Kamp } 159bfbb9ce6SPoul-Henning Kamp 1609a27d579SPoul-Henning Kamp int 161b0d17ba6SPoul-Henning Kamp dev2unit(dev_t x) 1629a27d579SPoul-Henning Kamp { 1639a27d579SPoul-Henning Kamp int i; 1649a27d579SPoul-Henning Kamp 1659a27d579SPoul-Henning Kamp if (x == NODEV) 1669a27d579SPoul-Henning Kamp return NOUDEV; 1679a27d579SPoul-Henning Kamp i = minor(x); 1689a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 1699a27d579SPoul-Henning Kamp } 1709a27d579SPoul-Henning Kamp 171b0d17ba6SPoul-Henning Kamp int 172b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 173b0d17ba6SPoul-Henning Kamp { 174b0d17ba6SPoul-Henning Kamp 17515b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 176b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 177b0d17ba6SPoul-Henning Kamp } 178b0d17ba6SPoul-Henning Kamp 1793f54a085SPoul-Henning Kamp static dev_t 1803f54a085SPoul-Henning Kamp allocdev(void) 181bfbb9ce6SPoul-Henning Kamp { 182698bfad7SPoul-Henning Kamp static int stashed; 1833f54a085SPoul-Henning Kamp struct specinfo *si; 184698bfad7SPoul-Henning Kamp 185698bfad7SPoul-Henning Kamp if (stashed >= DEVT_STASH) { 186698bfad7SPoul-Henning Kamp MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 1877cc0979fSDavid Malone M_USE_RESERVE | M_ZERO); 188d137acccSPoul-Henning Kamp } else if (LIST_FIRST(&dev_free)) { 189d137acccSPoul-Henning Kamp si = LIST_FIRST(&dev_free); 190d137acccSPoul-Henning Kamp LIST_REMOVE(si, si_hash); 191698bfad7SPoul-Henning Kamp } else { 192698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 1933344c5a1SPoul-Henning Kamp bzero(si, sizeof *si); 194d137acccSPoul-Henning Kamp si->si_flags |= SI_STASHED; 195698bfad7SPoul-Henning Kamp } 1963344c5a1SPoul-Henning Kamp LIST_INIT(&si->si_children); 197589c7af9SKirk McKusick TAILQ_INIT(&si->si_snapshots); 1983f54a085SPoul-Henning Kamp return (si); 1993f54a085SPoul-Henning Kamp } 2003f54a085SPoul-Henning Kamp 2013f54a085SPoul-Henning Kamp dev_t 2023f54a085SPoul-Henning Kamp makedev(int x, int y) 2033f54a085SPoul-Henning Kamp { 2043f54a085SPoul-Henning Kamp struct specinfo *si; 2053f54a085SPoul-Henning Kamp udev_t udev; 2063f54a085SPoul-Henning Kamp int hash; 2073f54a085SPoul-Henning Kamp 2083f54a085SPoul-Henning Kamp if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 2091fd7b93fSPoul-Henning Kamp panic("makedev of NOUDEV"); 2103f54a085SPoul-Henning Kamp udev = (x << 8) | y; 2113f54a085SPoul-Henning Kamp hash = udev % DEVT_HASH; 2123f54a085SPoul-Henning Kamp LIST_FOREACH(si, &dev_hash[hash], si_hash) { 2133f54a085SPoul-Henning Kamp if (si->si_udev == udev) 2143f54a085SPoul-Henning Kamp return (si); 2153f54a085SPoul-Henning Kamp } 2163f54a085SPoul-Henning Kamp si = allocdev(); 217698bfad7SPoul-Henning Kamp si->si_udev = udev; 218d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 219698bfad7SPoul-Henning Kamp return (si); 220bfbb9ce6SPoul-Henning Kamp } 221bfbb9ce6SPoul-Henning Kamp 222d137acccSPoul-Henning Kamp void 223d137acccSPoul-Henning Kamp freedev(dev_t dev) 224d137acccSPoul-Henning Kamp { 225d137acccSPoul-Henning Kamp 226d137acccSPoul-Henning Kamp if (!free_devt) 227d137acccSPoul-Henning Kamp return; 228d137acccSPoul-Henning Kamp if (SLIST_FIRST(&dev->si_hlist)) 229d137acccSPoul-Henning Kamp return; 230d137acccSPoul-Henning Kamp if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 231d137acccSPoul-Henning Kamp return; 232d137acccSPoul-Henning Kamp LIST_REMOVE(dev, si_hash); 233d137acccSPoul-Henning Kamp if (dev->si_flags & SI_STASHED) { 234d137acccSPoul-Henning Kamp bzero(dev, sizeof(*dev)); 2353344c5a1SPoul-Henning Kamp dev->si_flags |= SI_STASHED; 236d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_free, dev, si_hash); 237d137acccSPoul-Henning Kamp } else { 238d137acccSPoul-Henning Kamp FREE(dev, M_DEVT); 239d137acccSPoul-Henning Kamp } 240d137acccSPoul-Henning Kamp } 241d137acccSPoul-Henning Kamp 242bfbb9ce6SPoul-Henning Kamp udev_t 243bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 244bfbb9ce6SPoul-Henning Kamp { 245698bfad7SPoul-Henning Kamp if (x == NODEV) 246698bfad7SPoul-Henning Kamp return NOUDEV; 247698bfad7SPoul-Henning Kamp return (x->si_udev); 248bfbb9ce6SPoul-Henning Kamp } 249bfbb9ce6SPoul-Henning Kamp 250bfbb9ce6SPoul-Henning Kamp dev_t 251bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 252bfbb9ce6SPoul-Henning Kamp { 253fb01c24cSPoul-Henning Kamp 254fb01c24cSPoul-Henning Kamp if (x == NOUDEV) 255fb01c24cSPoul-Henning Kamp return (NODEV); 256d21c632cSPoul-Henning Kamp switch (b) { 257d21c632cSPoul-Henning Kamp case 0: 258bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 259d21c632cSPoul-Henning Kamp case 1: 260a16d0eb2SPoul-Henning Kamp return (NODEV); 261d21c632cSPoul-Henning Kamp default: 262d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 263d21c632cSPoul-Henning Kamp return NODEV; 264d21c632cSPoul-Henning Kamp } 265bfbb9ce6SPoul-Henning Kamp } 266bfbb9ce6SPoul-Henning Kamp 267bfbb9ce6SPoul-Henning Kamp int 268bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 269bfbb9ce6SPoul-Henning Kamp { 270bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 271bfbb9ce6SPoul-Henning Kamp } 272bfbb9ce6SPoul-Henning Kamp 273bfbb9ce6SPoul-Henning Kamp int 274bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 275bfbb9ce6SPoul-Henning Kamp { 276bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 277bfbb9ce6SPoul-Henning Kamp } 278bfbb9ce6SPoul-Henning Kamp 279bfbb9ce6SPoul-Henning Kamp udev_t 280f008cfccSPoul-Henning Kamp makeudev(int x, int y) 281bfbb9ce6SPoul-Henning Kamp { 282bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 283bfbb9ce6SPoul-Henning Kamp } 284bfbb9ce6SPoul-Henning Kamp 2850ef1c826SPoul-Henning Kamp dev_t 286c7021493SWarner Losh make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 2870ef1c826SPoul-Henning Kamp { 2880ef1c826SPoul-Henning Kamp dev_t dev; 2890ef1c826SPoul-Henning Kamp va_list ap; 2900ef1c826SPoul-Henning Kamp int i; 2910ef1c826SPoul-Henning Kamp 29211586717SBrian Somers KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 29311586717SBrian Somers ("Invalid minor (%d) in make_dev", minor)); 29411586717SBrian Somers 295a7489fe5SMike Smith if (!ready_for_devs) { 296a7489fe5SMike Smith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 297a7489fe5SMike Smith fmt); 298a7489fe5SMike Smith /* XXX panic here once drivers are cleaned up */ 299a7489fe5SMike Smith } 300a7489fe5SMike Smith 3010ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 3025ef2707eSPoul-Henning Kamp if (dev->si_flags & SI_NAMED) { 3035ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 3045ef2707eSPoul-Henning Kamp dev->si_name); 3054e4a7663SPoul-Henning Kamp panic("don't do that"); 3065ef2707eSPoul-Henning Kamp return (dev); 3075ef2707eSPoul-Henning Kamp } 3080ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3098dc74b62SBoris Popov i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 3100ef1c826SPoul-Henning Kamp dev->si_name[i] = '\0'; 3110ef1c826SPoul-Henning Kamp va_end(ap); 3120ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3133f54a085SPoul-Henning Kamp dev->si_uid = uid; 3143f54a085SPoul-Henning Kamp dev->si_gid = gid; 3153f54a085SPoul-Henning Kamp dev->si_mode = perms; 3165ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3171744fcd0SJulian Elischer 3189dcbe240SPoul-Henning Kamp if (devfs_create_hook) 3193f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3203f54a085SPoul-Henning Kamp return (dev); 3213f54a085SPoul-Henning Kamp } 3223f54a085SPoul-Henning Kamp 3237e7c3f3fSJonathan Lemon int 3247e7c3f3fSJonathan Lemon dev_named(dev_t pdev, const char *name) 3257e7c3f3fSJonathan Lemon { 3267e7c3f3fSJonathan Lemon dev_t cdev; 3277e7c3f3fSJonathan Lemon 3287e7c3f3fSJonathan Lemon if (strcmp(devtoname(pdev), name) == 0) 3297e7c3f3fSJonathan Lemon return (1); 3307e7c3f3fSJonathan Lemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 3317e7c3f3fSJonathan Lemon if (strcmp(devtoname(cdev), name) == 0) 3327e7c3f3fSJonathan Lemon return (1); 3337e7c3f3fSJonathan Lemon return (0); 3347e7c3f3fSJonathan Lemon } 3357e7c3f3fSJonathan Lemon 3363344c5a1SPoul-Henning Kamp void 3373344c5a1SPoul-Henning Kamp dev_depends(dev_t pdev, dev_t cdev) 3383344c5a1SPoul-Henning Kamp { 3393344c5a1SPoul-Henning Kamp 3403344c5a1SPoul-Henning Kamp cdev->si_parent = pdev; 3413344c5a1SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 3423344c5a1SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 3433344c5a1SPoul-Henning Kamp } 3443344c5a1SPoul-Henning Kamp 3453f54a085SPoul-Henning Kamp dev_t 346c7021493SWarner Losh make_dev_alias(dev_t pdev, const char *fmt, ...) 3473f54a085SPoul-Henning Kamp { 3483f54a085SPoul-Henning Kamp dev_t dev; 3493f54a085SPoul-Henning Kamp va_list ap; 3503f54a085SPoul-Henning Kamp int i; 3513f54a085SPoul-Henning Kamp 3523f54a085SPoul-Henning Kamp dev = allocdev(); 3533f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 3545ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3553344c5a1SPoul-Henning Kamp dev_depends(pdev, dev); 3563f54a085SPoul-Henning Kamp va_start(ap, fmt); 3573f54a085SPoul-Henning Kamp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 3583f54a085SPoul-Henning Kamp dev->si_name[i] = '\0'; 3593f54a085SPoul-Henning Kamp va_end(ap); 3603f54a085SPoul-Henning Kamp 3613f54a085SPoul-Henning Kamp if (devfs_create_hook) 3623f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3630ef1c826SPoul-Henning Kamp return (dev); 3640ef1c826SPoul-Henning Kamp } 3650ef1c826SPoul-Henning Kamp 366d137acccSPoul-Henning Kamp void 3671fd9f8f4SBrian Feldman revoke_and_destroy_dev(dev_t dev) 3681fd9f8f4SBrian Feldman { 3691fd9f8f4SBrian Feldman struct vnode *vp; 3701fd9f8f4SBrian Feldman 3711fd9f8f4SBrian Feldman GIANT_REQUIRED; 3721fd9f8f4SBrian Feldman 3731fd9f8f4SBrian Feldman vp = SLIST_FIRST(&dev->si_hlist); 3741fd9f8f4SBrian Feldman if (vp != NULL) 3751fd9f8f4SBrian Feldman VOP_REVOKE(vp, REVOKEALL); 3761fd9f8f4SBrian Feldman destroy_dev(dev); 3771fd9f8f4SBrian Feldman } 3781fd9f8f4SBrian Feldman 3791fd9f8f4SBrian Feldman void 38044d1184eSPoul-Henning Kamp destroy_dev(dev_t dev) 381d137acccSPoul-Henning Kamp { 3825ef2707eSPoul-Henning Kamp 3835ef2707eSPoul-Henning Kamp if (!(dev->si_flags & SI_NAMED)) { 3845ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 3855ef2707eSPoul-Henning Kamp major(dev), minor(dev)); 3864e4a7663SPoul-Henning Kamp panic("don't do that"); 3875ef2707eSPoul-Henning Kamp return; 3885ef2707eSPoul-Henning Kamp } 3895ef2707eSPoul-Henning Kamp 390db901281SPoul-Henning Kamp if (devfs_destroy_hook) 391db901281SPoul-Henning Kamp devfs_destroy_hook(dev); 3923344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 3933344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 3943344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 3953344c5a1SPoul-Henning Kamp } 3963344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 3973344c5a1SPoul-Henning Kamp destroy_dev(LIST_FIRST(&dev->si_children)); 398d137acccSPoul-Henning Kamp dev->si_drv1 = 0; 399d137acccSPoul-Henning Kamp dev->si_drv2 = 0; 400d137acccSPoul-Henning Kamp dev->si_devsw = 0; 4015ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 4025ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 403d137acccSPoul-Henning Kamp freedev(dev); 404d137acccSPoul-Henning Kamp } 405d137acccSPoul-Henning Kamp 406c32cc149SBruce Evans const char * 407b8e49f68SBill Fumerola devtoname(dev_t dev) 408b8e49f68SBill Fumerola { 409d137acccSPoul-Henning Kamp char *p; 410c32cc149SBruce Evans int mynor; 411b8e49f68SBill Fumerola 412d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 413d137acccSPoul-Henning Kamp p = dev->si_name; 414d137acccSPoul-Henning Kamp if (devsw(dev)) 415d137acccSPoul-Henning Kamp sprintf(p, "#%s/", devsw(dev)->d_name); 416d137acccSPoul-Henning Kamp else 417d137acccSPoul-Henning Kamp sprintf(p, "#%d/", major(dev)); 418d137acccSPoul-Henning Kamp p += strlen(p); 419c32cc149SBruce Evans mynor = minor(dev); 420c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 421c32cc149SBruce Evans sprintf(p, "%#x", (u_int)mynor); 422c32cc149SBruce Evans else 423c32cc149SBruce Evans sprintf(p, "%d", mynor); 424d137acccSPoul-Henning Kamp } 425b8e49f68SBill Fumerola return (dev->si_name); 426b8e49f68SBill Fumerola } 427db901281SPoul-Henning Kamp 428db901281SPoul-Henning Kamp int 429db901281SPoul-Henning Kamp dev_stdclone(char *name, char **namep, char *stem, int *unit) 430db901281SPoul-Henning Kamp { 431db901281SPoul-Henning Kamp int u, i; 432db901281SPoul-Henning Kamp 433db901281SPoul-Henning Kamp i = strlen(stem); 43456700d46SBrian Somers if (bcmp(stem, name, i) != 0) 43556700d46SBrian Somers return (0); 436db901281SPoul-Henning Kamp if (!isdigit(name[i])) 437db901281SPoul-Henning Kamp return (0); 438db901281SPoul-Henning Kamp u = 0; 43910786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 44010786074SPoul-Henning Kamp return (0); 441db901281SPoul-Henning Kamp while (isdigit(name[i])) { 442db901281SPoul-Henning Kamp u *= 10; 443db901281SPoul-Henning Kamp u += name[i++] - '0'; 444db901281SPoul-Henning Kamp } 445db901281SPoul-Henning Kamp *unit = u; 446db901281SPoul-Henning Kamp if (namep) 447db901281SPoul-Henning Kamp *namep = &name[i]; 448db901281SPoul-Henning Kamp if (name[i]) 449db901281SPoul-Henning Kamp return (2); 450db901281SPoul-Henning Kamp return (1); 451db901281SPoul-Henning Kamp } 4528d25eb2cSPoul-Henning Kamp 4538d25eb2cSPoul-Henning Kamp /* 4548d25eb2cSPoul-Henning Kamp * Helper sysctl for devname(3). We're given a {u}dev_t and return 4558d25eb2cSPoul-Henning Kamp * the name, if any, registered by the device driver. 4568d25eb2cSPoul-Henning Kamp */ 4578d25eb2cSPoul-Henning Kamp static int 4588d25eb2cSPoul-Henning Kamp sysctl_devname(SYSCTL_HANDLER_ARGS) 4598d25eb2cSPoul-Henning Kamp { 4608d25eb2cSPoul-Henning Kamp int error; 4618d25eb2cSPoul-Henning Kamp udev_t ud; 4628d25eb2cSPoul-Henning Kamp dev_t dev; 4638d25eb2cSPoul-Henning Kamp 4648d25eb2cSPoul-Henning Kamp error = SYSCTL_IN(req, &ud, sizeof (ud)); 4658d25eb2cSPoul-Henning Kamp if (error) 4668d25eb2cSPoul-Henning Kamp return (error); 4671fd7b93fSPoul-Henning Kamp if (ud == NOUDEV) 4681fd7b93fSPoul-Henning Kamp return(EINVAL); 4698d25eb2cSPoul-Henning Kamp dev = makedev(umajor(ud), uminor(ud)); 4708d25eb2cSPoul-Henning Kamp if (dev->si_name[0] == '\0') 4718d25eb2cSPoul-Henning Kamp error = ENOENT; 4728d25eb2cSPoul-Henning Kamp else 4738d25eb2cSPoul-Henning Kamp error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 4748d25eb2cSPoul-Henning Kamp freedev(dev); 4758d25eb2cSPoul-Henning Kamp return (error); 4768d25eb2cSPoul-Henning Kamp } 4778d25eb2cSPoul-Henning Kamp 478fe4e3243SPoul-Henning Kamp SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 4798d25eb2cSPoul-Henning Kamp NULL, 0, sysctl_devname, "", "devname(3) handler"); 4808d25eb2cSPoul-Henning Kamp 481a7489fe5SMike Smith /* 482a7489fe5SMike Smith * Set ready_for_devs; prior to this point, device creation is not allowed. 483a7489fe5SMike Smith */ 484a7489fe5SMike Smith static void 485a7489fe5SMike Smith dev_set_ready(void *junk) 486a7489fe5SMike Smith { 487a7489fe5SMike Smith ready_for_devs = 1; 488a7489fe5SMike Smith } 489a7489fe5SMike Smith 490a7489fe5SMike Smith SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 491