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> 321b567820SBrian Feldman #include <sys/lock.h> 331b567820SBrian Feldman #include <sys/mutex.h> 34b40ce416SJulian Elischer #include <sys/sysctl.h> 35ecbb00a2SDoug Rabson #include <sys/module.h> 36698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 3726453f35SJulian Elischer #include <sys/conf.h> 381dfcbb0cSJulian Elischer #include <sys/vnode.h> 39698bfad7SPoul-Henning Kamp #include <sys/queue.h> 40db901281SPoul-Henning Kamp #include <sys/ctype.h> 410ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 421dfcbb0cSJulian Elischer 432447bec8SPoul-Henning Kamp #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 441dfcbb0cSJulian Elischer 455f7806abSPoul-Henning Kamp static struct cdevsw *cdevsw[NUMCDEVSW]; 461dfcbb0cSJulian Elischer 47959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 48698bfad7SPoul-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 59698bfad7SPoul-Henning Kamp static struct specinfo devt_stash[DEVT_STASH]; 60698bfad7SPoul-Henning Kamp 61e3975643SJake Burkholder static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 62d137acccSPoul-Henning Kamp 63e3975643SJake Burkholder static LIST_HEAD(, specinfo) dev_free; 6446eede00SPoul-Henning Kamp 659dcbe240SPoul-Henning Kamp devfs_create_t *devfs_create_hook; 66db901281SPoul-Henning Kamp devfs_destroy_t *devfs_destroy_hook; 67db901281SPoul-Henning Kamp int devfs_present; 68d137acccSPoul-Henning Kamp 69a7489fe5SMike Smith static int ready_for_devs; 70a7489fe5SMike Smith 71d137acccSPoul-Henning Kamp static int free_devt; 72d137acccSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 739dcbe240SPoul-Henning Kamp 744e4a7663SPoul-Henning Kamp /* XXX: This is a hack */ 754e4a7663SPoul-Henning Kamp void disk_dev_synth(dev_t dev); 764e4a7663SPoul-Henning Kamp 772447bec8SPoul-Henning Kamp struct cdevsw * 782447bec8SPoul-Henning Kamp devsw(dev_t dev) 792447bec8SPoul-Henning Kamp { 807dc5cd04SPoul-Henning Kamp if (dev->si_devsw) 817dc5cd04SPoul-Henning Kamp return (dev->si_devsw); 824e4a7663SPoul-Henning Kamp /* XXX: Hack around our backwards disk code */ 834e4a7663SPoul-Henning Kamp disk_dev_synth(dev); 844e4a7663SPoul-Henning Kamp if (dev->si_devsw) 854e4a7663SPoul-Henning Kamp return (dev->si_devsw); 864e4a7663SPoul-Henning Kamp if (devfs_present) 874e130067SPoul-Henning Kamp return (NULL); 883de280c4SPoul-Henning Kamp return(cdevsw[major(dev)]); 892447bec8SPoul-Henning Kamp } 902447bec8SPoul-Henning Kamp 912447bec8SPoul-Henning Kamp /* 922447bec8SPoul-Henning Kamp * Add a cdevsw entry 932447bec8SPoul-Henning Kamp */ 942447bec8SPoul-Henning Kamp 95f7ea2f55SJulian Elischer int 962447bec8SPoul-Henning Kamp cdevsw_add(struct cdevsw *newentry) 97f7ea2f55SJulian Elischer { 98bfbb9ce6SPoul-Henning Kamp 992447bec8SPoul-Henning Kamp if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 1002447bec8SPoul-Henning Kamp printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1012447bec8SPoul-Henning Kamp newentry->d_name, newentry->d_maj); 102662761a7SPoul-Henning Kamp return (EINVAL); 103662761a7SPoul-Henning Kamp } 104f7ea2f55SJulian Elischer 105c31558b2SPoul-Henning Kamp if (cdevsw[newentry->d_maj]) { 106c31558b2SPoul-Henning Kamp printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 107c31558b2SPoul-Henning Kamp newentry->d_name, cdevsw[newentry->d_maj]->d_name); 108c31558b2SPoul-Henning Kamp } 109662761a7SPoul-Henning Kamp 1102447bec8SPoul-Henning Kamp cdevsw[newentry->d_maj] = newentry; 111f7ea2f55SJulian Elischer 112662761a7SPoul-Henning Kamp return (0); 113f7ea2f55SJulian Elischer } 114f7ea2f55SJulian Elischer 1159a9eb2b9SGreg Lehey /* 1169a9eb2b9SGreg Lehey * Remove a cdevsw entry 1179a9eb2b9SGreg Lehey */ 1189a9eb2b9SGreg Lehey 1199a9eb2b9SGreg Lehey int 1209a9eb2b9SGreg Lehey cdevsw_remove(struct cdevsw *oldentry) 1219a9eb2b9SGreg Lehey { 1229a9eb2b9SGreg Lehey if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 1239a9eb2b9SGreg Lehey printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1249a9eb2b9SGreg Lehey oldentry->d_name, oldentry->d_maj); 1259a9eb2b9SGreg Lehey return EINVAL; 1269a9eb2b9SGreg Lehey } 1279a9eb2b9SGreg Lehey 1289a9eb2b9SGreg Lehey cdevsw[oldentry->d_maj] = NULL; 1299a9eb2b9SGreg Lehey 1309a9eb2b9SGreg Lehey return 0; 1319a9eb2b9SGreg Lehey } 1329a9eb2b9SGreg Lehey 133bfbb9ce6SPoul-Henning Kamp /* 134bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 135bfbb9ce6SPoul-Henning Kamp */ 136bfbb9ce6SPoul-Henning Kamp 137bfbb9ce6SPoul-Henning Kamp int 138bfbb9ce6SPoul-Henning Kamp major(dev_t x) 139bfbb9ce6SPoul-Henning Kamp { 140698bfad7SPoul-Henning Kamp if (x == NODEV) 141698bfad7SPoul-Henning Kamp return NOUDEV; 142698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 143bfbb9ce6SPoul-Henning Kamp } 144bfbb9ce6SPoul-Henning Kamp 145bfbb9ce6SPoul-Henning Kamp int 146bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 147bfbb9ce6SPoul-Henning Kamp { 148698bfad7SPoul-Henning Kamp if (x == NODEV) 149698bfad7SPoul-Henning Kamp return NOUDEV; 150698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 151bfbb9ce6SPoul-Henning Kamp } 152bfbb9ce6SPoul-Henning Kamp 1539a27d579SPoul-Henning Kamp int 154b0d17ba6SPoul-Henning Kamp dev2unit(dev_t x) 1559a27d579SPoul-Henning Kamp { 1569a27d579SPoul-Henning Kamp int i; 1579a27d579SPoul-Henning Kamp 1589a27d579SPoul-Henning Kamp if (x == NODEV) 1599a27d579SPoul-Henning Kamp return NOUDEV; 1609a27d579SPoul-Henning Kamp i = minor(x); 1619a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 1629a27d579SPoul-Henning Kamp } 1639a27d579SPoul-Henning Kamp 164b0d17ba6SPoul-Henning Kamp int 165b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 166b0d17ba6SPoul-Henning Kamp { 167b0d17ba6SPoul-Henning Kamp 16815b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 169b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 170b0d17ba6SPoul-Henning Kamp } 171b0d17ba6SPoul-Henning Kamp 1723f54a085SPoul-Henning Kamp static dev_t 1733f54a085SPoul-Henning Kamp allocdev(void) 174bfbb9ce6SPoul-Henning Kamp { 175698bfad7SPoul-Henning Kamp static int stashed; 1763f54a085SPoul-Henning Kamp struct specinfo *si; 177698bfad7SPoul-Henning Kamp 1785ea98f59SPoul-Henning Kamp if (LIST_FIRST(&dev_free)) { 179d137acccSPoul-Henning Kamp si = LIST_FIRST(&dev_free); 180d137acccSPoul-Henning Kamp LIST_REMOVE(si, si_hash); 1815ea98f59SPoul-Henning Kamp } else if (stashed >= DEVT_STASH) { 1825ea98f59SPoul-Henning Kamp MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 1835ea98f59SPoul-Henning Kamp M_USE_RESERVE | M_ZERO); 184698bfad7SPoul-Henning Kamp } else { 185698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 1863344c5a1SPoul-Henning Kamp bzero(si, sizeof *si); 187d137acccSPoul-Henning Kamp si->si_flags |= SI_STASHED; 188698bfad7SPoul-Henning Kamp } 1893344c5a1SPoul-Henning Kamp LIST_INIT(&si->si_children); 190589c7af9SKirk McKusick TAILQ_INIT(&si->si_snapshots); 1913f54a085SPoul-Henning Kamp return (si); 1923f54a085SPoul-Henning Kamp } 1933f54a085SPoul-Henning Kamp 1943f54a085SPoul-Henning Kamp dev_t 1953f54a085SPoul-Henning Kamp makedev(int x, int y) 1963f54a085SPoul-Henning Kamp { 1973f54a085SPoul-Henning Kamp struct specinfo *si; 1983f54a085SPoul-Henning Kamp udev_t udev; 1993f54a085SPoul-Henning Kamp int hash; 2003f54a085SPoul-Henning Kamp 2013f54a085SPoul-Henning Kamp if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 2021fd7b93fSPoul-Henning Kamp panic("makedev of NOUDEV"); 2033f54a085SPoul-Henning Kamp udev = (x << 8) | y; 2043f54a085SPoul-Henning Kamp hash = udev % DEVT_HASH; 2053f54a085SPoul-Henning Kamp LIST_FOREACH(si, &dev_hash[hash], si_hash) { 2063f54a085SPoul-Henning Kamp if (si->si_udev == udev) 2073f54a085SPoul-Henning Kamp return (si); 2083f54a085SPoul-Henning Kamp } 2093f54a085SPoul-Henning Kamp si = allocdev(); 210698bfad7SPoul-Henning Kamp si->si_udev = udev; 211d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 212698bfad7SPoul-Henning Kamp return (si); 213bfbb9ce6SPoul-Henning Kamp } 214bfbb9ce6SPoul-Henning Kamp 215d137acccSPoul-Henning Kamp void 216d137acccSPoul-Henning Kamp freedev(dev_t dev) 217d137acccSPoul-Henning Kamp { 218d137acccSPoul-Henning Kamp 219d137acccSPoul-Henning Kamp if (!free_devt) 220d137acccSPoul-Henning Kamp return; 221d137acccSPoul-Henning Kamp if (SLIST_FIRST(&dev->si_hlist)) 222d137acccSPoul-Henning Kamp return; 223d137acccSPoul-Henning Kamp if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 224d137acccSPoul-Henning Kamp return; 225d137acccSPoul-Henning Kamp LIST_REMOVE(dev, si_hash); 226d137acccSPoul-Henning Kamp if (dev->si_flags & SI_STASHED) { 227d137acccSPoul-Henning Kamp bzero(dev, sizeof(*dev)); 2283344c5a1SPoul-Henning Kamp dev->si_flags |= SI_STASHED; 229d137acccSPoul-Henning Kamp LIST_INSERT_HEAD(&dev_free, dev, si_hash); 230d137acccSPoul-Henning Kamp } else { 231d137acccSPoul-Henning Kamp FREE(dev, M_DEVT); 232d137acccSPoul-Henning Kamp } 233d137acccSPoul-Henning Kamp } 234d137acccSPoul-Henning Kamp 235bfbb9ce6SPoul-Henning Kamp udev_t 236bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 237bfbb9ce6SPoul-Henning Kamp { 238698bfad7SPoul-Henning Kamp if (x == NODEV) 239698bfad7SPoul-Henning Kamp return NOUDEV; 240698bfad7SPoul-Henning Kamp return (x->si_udev); 241bfbb9ce6SPoul-Henning Kamp } 242bfbb9ce6SPoul-Henning Kamp 243bfbb9ce6SPoul-Henning Kamp dev_t 244bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 245bfbb9ce6SPoul-Henning Kamp { 246fb01c24cSPoul-Henning Kamp 247fb01c24cSPoul-Henning Kamp if (x == NOUDEV) 248fb01c24cSPoul-Henning Kamp return (NODEV); 249d21c632cSPoul-Henning Kamp switch (b) { 250d21c632cSPoul-Henning Kamp case 0: 251bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 252d21c632cSPoul-Henning Kamp case 1: 253a16d0eb2SPoul-Henning Kamp return (NODEV); 254d21c632cSPoul-Henning Kamp default: 255d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 256d21c632cSPoul-Henning Kamp return NODEV; 257d21c632cSPoul-Henning Kamp } 258bfbb9ce6SPoul-Henning Kamp } 259bfbb9ce6SPoul-Henning Kamp 260bfbb9ce6SPoul-Henning Kamp int 261bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 262bfbb9ce6SPoul-Henning Kamp { 263bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 264bfbb9ce6SPoul-Henning Kamp } 265bfbb9ce6SPoul-Henning Kamp 266bfbb9ce6SPoul-Henning Kamp int 267bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 268bfbb9ce6SPoul-Henning Kamp { 269bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 270bfbb9ce6SPoul-Henning Kamp } 271bfbb9ce6SPoul-Henning Kamp 272bfbb9ce6SPoul-Henning Kamp udev_t 273f008cfccSPoul-Henning Kamp makeudev(int x, int y) 274bfbb9ce6SPoul-Henning Kamp { 275bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 276bfbb9ce6SPoul-Henning Kamp } 277bfbb9ce6SPoul-Henning Kamp 2780ef1c826SPoul-Henning Kamp dev_t 279c7021493SWarner Losh make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 2800ef1c826SPoul-Henning Kamp { 2810ef1c826SPoul-Henning Kamp dev_t dev; 2820ef1c826SPoul-Henning Kamp va_list ap; 2830ef1c826SPoul-Henning Kamp int i; 2840ef1c826SPoul-Henning Kamp 28511586717SBrian Somers KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 28611586717SBrian Somers ("Invalid minor (%d) in make_dev", minor)); 28711586717SBrian Somers 288a7489fe5SMike Smith if (!ready_for_devs) { 289a7489fe5SMike Smith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 290a7489fe5SMike Smith fmt); 291a7489fe5SMike Smith /* XXX panic here once drivers are cleaned up */ 292a7489fe5SMike Smith } 293a7489fe5SMike Smith 2940ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 2955ef2707eSPoul-Henning Kamp if (dev->si_flags & SI_NAMED) { 2965ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 2975ef2707eSPoul-Henning Kamp dev->si_name); 2984e4a7663SPoul-Henning Kamp panic("don't do that"); 2995ef2707eSPoul-Henning Kamp return (dev); 3005ef2707eSPoul-Henning Kamp } 3010ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3028dc74b62SBoris Popov i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 3030ef1c826SPoul-Henning Kamp dev->si_name[i] = '\0'; 3040ef1c826SPoul-Henning Kamp va_end(ap); 3050ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3063f54a085SPoul-Henning Kamp dev->si_uid = uid; 3073f54a085SPoul-Henning Kamp dev->si_gid = gid; 3083f54a085SPoul-Henning Kamp dev->si_mode = perms; 3095ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3101744fcd0SJulian Elischer 3119dcbe240SPoul-Henning Kamp if (devfs_create_hook) 3123f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3133f54a085SPoul-Henning Kamp return (dev); 3143f54a085SPoul-Henning Kamp } 3153f54a085SPoul-Henning Kamp 3167e7c3f3fSJonathan Lemon int 3177e7c3f3fSJonathan Lemon dev_named(dev_t pdev, const char *name) 3187e7c3f3fSJonathan Lemon { 3197e7c3f3fSJonathan Lemon dev_t cdev; 3207e7c3f3fSJonathan Lemon 3217e7c3f3fSJonathan Lemon if (strcmp(devtoname(pdev), name) == 0) 3227e7c3f3fSJonathan Lemon return (1); 3237e7c3f3fSJonathan Lemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 3247e7c3f3fSJonathan Lemon if (strcmp(devtoname(cdev), name) == 0) 3257e7c3f3fSJonathan Lemon return (1); 3267e7c3f3fSJonathan Lemon return (0); 3277e7c3f3fSJonathan Lemon } 3287e7c3f3fSJonathan Lemon 3293344c5a1SPoul-Henning Kamp void 3303344c5a1SPoul-Henning Kamp dev_depends(dev_t pdev, dev_t cdev) 3313344c5a1SPoul-Henning Kamp { 3323344c5a1SPoul-Henning Kamp 3333344c5a1SPoul-Henning Kamp cdev->si_parent = pdev; 3343344c5a1SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 3353344c5a1SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 3363344c5a1SPoul-Henning Kamp } 3373344c5a1SPoul-Henning Kamp 3383f54a085SPoul-Henning Kamp dev_t 339c7021493SWarner Losh make_dev_alias(dev_t pdev, const char *fmt, ...) 3403f54a085SPoul-Henning Kamp { 3413f54a085SPoul-Henning Kamp dev_t dev; 3423f54a085SPoul-Henning Kamp va_list ap; 3433f54a085SPoul-Henning Kamp int i; 3443f54a085SPoul-Henning Kamp 3453f54a085SPoul-Henning Kamp dev = allocdev(); 3463f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 3475ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 3483344c5a1SPoul-Henning Kamp dev_depends(pdev, dev); 3493f54a085SPoul-Henning Kamp va_start(ap, fmt); 3503f54a085SPoul-Henning Kamp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 3513f54a085SPoul-Henning Kamp dev->si_name[i] = '\0'; 3523f54a085SPoul-Henning Kamp va_end(ap); 3533f54a085SPoul-Henning Kamp 3543f54a085SPoul-Henning Kamp if (devfs_create_hook) 3553f54a085SPoul-Henning Kamp devfs_create_hook(dev); 3560ef1c826SPoul-Henning Kamp return (dev); 3570ef1c826SPoul-Henning Kamp } 3580ef1c826SPoul-Henning Kamp 359d137acccSPoul-Henning Kamp void 3601fd9f8f4SBrian Feldman revoke_and_destroy_dev(dev_t dev) 3611fd9f8f4SBrian Feldman { 3621fd9f8f4SBrian Feldman struct vnode *vp; 3631fd9f8f4SBrian Feldman 3641fd9f8f4SBrian Feldman GIANT_REQUIRED; 3651fd9f8f4SBrian Feldman 3661fd9f8f4SBrian Feldman vp = SLIST_FIRST(&dev->si_hlist); 3671fd9f8f4SBrian Feldman if (vp != NULL) 3681fd9f8f4SBrian Feldman VOP_REVOKE(vp, REVOKEALL); 3691fd9f8f4SBrian Feldman destroy_dev(dev); 3701fd9f8f4SBrian Feldman } 3711fd9f8f4SBrian Feldman 3721fd9f8f4SBrian Feldman void 37344d1184eSPoul-Henning Kamp destroy_dev(dev_t dev) 374d137acccSPoul-Henning Kamp { 3755ef2707eSPoul-Henning Kamp 3765ef2707eSPoul-Henning Kamp if (!(dev->si_flags & SI_NAMED)) { 3775ef2707eSPoul-Henning Kamp printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 3785ef2707eSPoul-Henning Kamp major(dev), minor(dev)); 3794e4a7663SPoul-Henning Kamp panic("don't do that"); 3805ef2707eSPoul-Henning Kamp return; 3815ef2707eSPoul-Henning Kamp } 3825ef2707eSPoul-Henning Kamp 383db901281SPoul-Henning Kamp if (devfs_destroy_hook) 384db901281SPoul-Henning Kamp devfs_destroy_hook(dev); 3853344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 3863344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 3873344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 3883344c5a1SPoul-Henning Kamp } 3893344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 3903344c5a1SPoul-Henning Kamp destroy_dev(LIST_FIRST(&dev->si_children)); 391d137acccSPoul-Henning Kamp dev->si_drv1 = 0; 392d137acccSPoul-Henning Kamp dev->si_drv2 = 0; 393d137acccSPoul-Henning Kamp dev->si_devsw = 0; 394ff557fa1SBruce Evans bzero(&dev->__si_u, sizeof(dev->__si_u)); 3955ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 3965ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 397d137acccSPoul-Henning Kamp freedev(dev); 398d137acccSPoul-Henning Kamp } 399d137acccSPoul-Henning Kamp 400c32cc149SBruce Evans const char * 401b8e49f68SBill Fumerola devtoname(dev_t dev) 402b8e49f68SBill Fumerola { 403d137acccSPoul-Henning Kamp char *p; 404c32cc149SBruce Evans int mynor; 405b8e49f68SBill Fumerola 406d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 407d137acccSPoul-Henning Kamp p = dev->si_name; 408d137acccSPoul-Henning Kamp if (devsw(dev)) 409d137acccSPoul-Henning Kamp sprintf(p, "#%s/", devsw(dev)->d_name); 410d137acccSPoul-Henning Kamp else 411d137acccSPoul-Henning Kamp sprintf(p, "#%d/", major(dev)); 412d137acccSPoul-Henning Kamp p += strlen(p); 413c32cc149SBruce Evans mynor = minor(dev); 414c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 415c32cc149SBruce Evans sprintf(p, "%#x", (u_int)mynor); 416c32cc149SBruce Evans else 417c32cc149SBruce Evans sprintf(p, "%d", mynor); 418d137acccSPoul-Henning Kamp } 419b8e49f68SBill Fumerola return (dev->si_name); 420b8e49f68SBill Fumerola } 421db901281SPoul-Henning Kamp 422db901281SPoul-Henning Kamp int 42301de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 424db901281SPoul-Henning Kamp { 425db901281SPoul-Henning Kamp int u, i; 426db901281SPoul-Henning Kamp 427db901281SPoul-Henning Kamp i = strlen(stem); 42856700d46SBrian Somers if (bcmp(stem, name, i) != 0) 42956700d46SBrian Somers return (0); 430db901281SPoul-Henning Kamp if (!isdigit(name[i])) 431db901281SPoul-Henning Kamp return (0); 432db901281SPoul-Henning Kamp u = 0; 43310786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 43410786074SPoul-Henning Kamp return (0); 435db901281SPoul-Henning Kamp while (isdigit(name[i])) { 436db901281SPoul-Henning Kamp u *= 10; 437db901281SPoul-Henning Kamp u += name[i++] - '0'; 438db901281SPoul-Henning Kamp } 439db901281SPoul-Henning Kamp *unit = u; 440db901281SPoul-Henning Kamp if (namep) 441db901281SPoul-Henning Kamp *namep = &name[i]; 442db901281SPoul-Henning Kamp if (name[i]) 443db901281SPoul-Henning Kamp return (2); 444db901281SPoul-Henning Kamp return (1); 445db901281SPoul-Henning Kamp } 4468d25eb2cSPoul-Henning Kamp 4478d25eb2cSPoul-Henning Kamp /* 4488d25eb2cSPoul-Henning Kamp * Helper sysctl for devname(3). We're given a {u}dev_t and return 4498d25eb2cSPoul-Henning Kamp * the name, if any, registered by the device driver. 4508d25eb2cSPoul-Henning Kamp */ 4518d25eb2cSPoul-Henning Kamp static int 4528d25eb2cSPoul-Henning Kamp sysctl_devname(SYSCTL_HANDLER_ARGS) 4538d25eb2cSPoul-Henning Kamp { 4548d25eb2cSPoul-Henning Kamp int error; 4558d25eb2cSPoul-Henning Kamp udev_t ud; 4568d25eb2cSPoul-Henning Kamp dev_t dev; 4578d25eb2cSPoul-Henning Kamp 4588d25eb2cSPoul-Henning Kamp error = SYSCTL_IN(req, &ud, sizeof (ud)); 4598d25eb2cSPoul-Henning Kamp if (error) 4608d25eb2cSPoul-Henning Kamp return (error); 4611fd7b93fSPoul-Henning Kamp if (ud == NOUDEV) 4621fd7b93fSPoul-Henning Kamp return(EINVAL); 4638d25eb2cSPoul-Henning Kamp dev = makedev(umajor(ud), uminor(ud)); 4648d25eb2cSPoul-Henning Kamp if (dev->si_name[0] == '\0') 4658d25eb2cSPoul-Henning Kamp error = ENOENT; 4668d25eb2cSPoul-Henning Kamp else 4678d25eb2cSPoul-Henning Kamp error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 4688d25eb2cSPoul-Henning Kamp freedev(dev); 4698d25eb2cSPoul-Henning Kamp return (error); 4708d25eb2cSPoul-Henning Kamp } 4718d25eb2cSPoul-Henning Kamp 472fe4e3243SPoul-Henning Kamp SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 4738d25eb2cSPoul-Henning Kamp NULL, 0, sysctl_devname, "", "devname(3) handler"); 4748d25eb2cSPoul-Henning Kamp 475a7489fe5SMike Smith /* 476a7489fe5SMike Smith * Set ready_for_devs; prior to this point, device creation is not allowed. 477a7489fe5SMike Smith */ 478a7489fe5SMike Smith static void 479a7489fe5SMike Smith dev_set_ready(void *junk) 480a7489fe5SMike Smith { 481a7489fe5SMike Smith ready_for_devs = 1; 482a7489fe5SMike Smith } 483a7489fe5SMike Smith 484a7489fe5SMike Smith SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 485