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 * 331744fcd0SJulian Elischer * $Id: kern_conf.c,v 1.58 1999/08/17 20:25:50 billf Exp $ 3426453f35SJulian Elischer */ 3526453f35SJulian Elischer 361744fcd0SJulian Elischer #include "opt_devfs.h" 371744fcd0SJulian Elischer 3826453f35SJulian Elischer #include <sys/param.h> 39698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 40f8a760b3SJulian Elischer #include <sys/systm.h> 41ecbb00a2SDoug Rabson #include <sys/module.h> 42698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 4326453f35SJulian Elischer #include <sys/conf.h> 441dfcbb0cSJulian Elischer #include <sys/vnode.h> 45698bfad7SPoul-Henning Kamp #include <sys/queue.h> 460ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 471744fcd0SJulian Elischer #ifdef DEVFS 481744fcd0SJulian Elischer #include <sys/devfsext.h> 491744fcd0SJulian Elischer #endif /* DEVFS */ 501744fcd0SJulian Elischer 511dfcbb0cSJulian Elischer 522447bec8SPoul-Henning Kamp #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 531dfcbb0cSJulian Elischer 542447bec8SPoul-Henning Kamp struct cdevsw *cdevsw[NUMCDEVSW]; 551dfcbb0cSJulian Elischer 56698bfad7SPoul-Henning Kamp static int bmaj2cmaj[NUMCDEVSW]; 57698bfad7SPoul-Henning Kamp 58698bfad7SPoul-Henning Kamp MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 59698bfad7SPoul-Henning Kamp 60698bfad7SPoul-Henning Kamp #define DEVT_HASH 83 61698bfad7SPoul-Henning Kamp #define DEVT_STASH 50 62698bfad7SPoul-Henning Kamp 63698bfad7SPoul-Henning Kamp static struct specinfo devt_stash[DEVT_STASH]; 64698bfad7SPoul-Henning Kamp 65698bfad7SPoul-Henning Kamp static SLIST_HEAD(devt_hash_head, specinfo) dev_hash[DEVT_HASH]; 6646eede00SPoul-Henning Kamp 671dfcbb0cSJulian Elischer /* 681dfcbb0cSJulian Elischer * Routine to convert from character to block device number. 691dfcbb0cSJulian Elischer * 701dfcbb0cSJulian Elischer * A minimal stub routine can always return NODEV. 711dfcbb0cSJulian Elischer */ 721dfcbb0cSJulian Elischer dev_t 731dfcbb0cSJulian Elischer chrtoblk(dev_t dev) 741dfcbb0cSJulian Elischer { 751dfcbb0cSJulian Elischer struct cdevsw *cd; 761dfcbb0cSJulian Elischer 774be2eb8cSPoul-Henning Kamp if((cd = devsw(dev)) != NULL) { 78f7ea2f55SJulian Elischer if (cd->d_bmaj != -1) 79d21c632cSPoul-Henning Kamp return(makebdev(cd->d_bmaj,minor(dev))); 801dfcbb0cSJulian Elischer } 811dfcbb0cSJulian Elischer return(NODEV); 821dfcbb0cSJulian Elischer } 8326453f35SJulian Elischer 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); 893de280c4SPoul-Henning Kamp return(cdevsw[major(dev)]); 902447bec8SPoul-Henning Kamp } 912447bec8SPoul-Henning Kamp 922447bec8SPoul-Henning Kamp /* 932447bec8SPoul-Henning Kamp * Add a cdevsw entry 942447bec8SPoul-Henning Kamp */ 952447bec8SPoul-Henning Kamp 96f7ea2f55SJulian Elischer int 972447bec8SPoul-Henning Kamp cdevsw_add(struct cdevsw *newentry) 98f7ea2f55SJulian Elischer { 99f7ea2f55SJulian Elischer int i; 100bfbb9ce6SPoul-Henning Kamp static int setup; 101bfbb9ce6SPoul-Henning Kamp 102bfbb9ce6SPoul-Henning Kamp if (!setup) { 1032447bec8SPoul-Henning Kamp for (i = 0; i < NUMCDEVSW; i++) 104bfbb9ce6SPoul-Henning Kamp if (!bmaj2cmaj[i]) 105698bfad7SPoul-Henning Kamp bmaj2cmaj[i] = 254; 106bfbb9ce6SPoul-Henning Kamp setup++; 107bfbb9ce6SPoul-Henning Kamp } 108f7ea2f55SJulian Elischer 1092447bec8SPoul-Henning Kamp if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 1102447bec8SPoul-Henning Kamp printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1112447bec8SPoul-Henning Kamp newentry->d_name, newentry->d_maj); 112f7ea2f55SJulian Elischer return EINVAL; 113f7ea2f55SJulian Elischer } 114f7ea2f55SJulian Elischer 115c31558b2SPoul-Henning Kamp if (cdevsw[newentry->d_maj]) { 116c31558b2SPoul-Henning Kamp printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 117c31558b2SPoul-Henning Kamp newentry->d_name, cdevsw[newentry->d_maj]->d_name); 118c31558b2SPoul-Henning Kamp } 1192447bec8SPoul-Henning Kamp cdevsw[newentry->d_maj] = newentry; 120f7ea2f55SJulian Elischer 121c31558b2SPoul-Henning Kamp if (newentry->d_bmaj >= 0 && newentry->d_bmaj < NUMCDEVSW) { 122698bfad7SPoul-Henning Kamp if (bmaj2cmaj[newentry->d_bmaj] != 254) { 123c31558b2SPoul-Henning Kamp printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 124c31558b2SPoul-Henning Kamp newentry->d_name, 125c31558b2SPoul-Henning Kamp cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 126c31558b2SPoul-Henning Kamp } 1272447bec8SPoul-Henning Kamp bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 128c31558b2SPoul-Henning Kamp } 1292447bec8SPoul-Henning Kamp 130f7ea2f55SJulian Elischer return 0; 131f7ea2f55SJulian Elischer } 132f7ea2f55SJulian Elischer 1339a9eb2b9SGreg Lehey /* 1349a9eb2b9SGreg Lehey * Remove a cdevsw entry 1359a9eb2b9SGreg Lehey */ 1369a9eb2b9SGreg Lehey 1379a9eb2b9SGreg Lehey int 1389a9eb2b9SGreg Lehey cdevsw_remove(struct cdevsw *oldentry) 1399a9eb2b9SGreg Lehey { 1409a9eb2b9SGreg Lehey if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 1419a9eb2b9SGreg Lehey printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 1429a9eb2b9SGreg Lehey oldentry->d_name, oldentry->d_maj); 1439a9eb2b9SGreg Lehey return EINVAL; 1449a9eb2b9SGreg Lehey } 1459a9eb2b9SGreg Lehey 1469a9eb2b9SGreg Lehey cdevsw[oldentry->d_maj] = NULL; 1479a9eb2b9SGreg Lehey 1489a9eb2b9SGreg Lehey if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 14932c0c324SGreg Lehey bmaj2cmaj[oldentry->d_bmaj] = 254; 1509a9eb2b9SGreg Lehey 1519a9eb2b9SGreg Lehey return 0; 1529a9eb2b9SGreg Lehey } 1539a9eb2b9SGreg Lehey 154ecbb00a2SDoug Rabson int 15546eede00SPoul-Henning Kamp devsw_module_handler(module_t mod, int what, void* arg) 156ecbb00a2SDoug Rabson { 15746eede00SPoul-Henning Kamp struct devsw_module_data* data = (struct devsw_module_data*) arg; 1586d4ce7aaSDoug Rabson int error = 0; 159ecbb00a2SDoug Rabson 160ecbb00a2SDoug Rabson switch (what) { 161ecbb00a2SDoug Rabson case MOD_LOAD: 1622447bec8SPoul-Henning Kamp error = cdevsw_add(data->cdevsw); 1636ca34d85SDoug Rabson if (!error && data->chainevh) 1646ca34d85SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 165ecbb00a2SDoug Rabson return error; 166ecbb00a2SDoug Rabson 167ecbb00a2SDoug Rabson case MOD_UNLOAD: 1686ca34d85SDoug Rabson if (data->chainevh) { 1696ca34d85SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 1706ca34d85SDoug Rabson if (error) 171ecbb00a2SDoug Rabson return error; 1726ca34d85SDoug Rabson } 1736d4ce7aaSDoug Rabson cdevsw_remove(data->cdevsw); 174f7ea2f55SJulian Elischer return error; 175ecbb00a2SDoug Rabson } 176ecbb00a2SDoug Rabson 177ecbb00a2SDoug Rabson if (data->chainevh) 178ecbb00a2SDoug Rabson return data->chainevh(mod, what, data->chainarg); 179ecbb00a2SDoug Rabson else 180ecbb00a2SDoug Rabson return 0; 181ecbb00a2SDoug Rabson } 182bfbb9ce6SPoul-Henning Kamp 183bfbb9ce6SPoul-Henning Kamp /* 184bfbb9ce6SPoul-Henning Kamp * dev_t and u_dev_t primitives 185bfbb9ce6SPoul-Henning Kamp */ 186bfbb9ce6SPoul-Henning Kamp 187bfbb9ce6SPoul-Henning Kamp int 188bfbb9ce6SPoul-Henning Kamp major(dev_t x) 189bfbb9ce6SPoul-Henning Kamp { 190698bfad7SPoul-Henning Kamp if (x == NODEV) 191698bfad7SPoul-Henning Kamp return NOUDEV; 192698bfad7SPoul-Henning Kamp return((x->si_udev >> 8) & 0xff); 193bfbb9ce6SPoul-Henning Kamp } 194bfbb9ce6SPoul-Henning Kamp 195bfbb9ce6SPoul-Henning Kamp int 196bfbb9ce6SPoul-Henning Kamp minor(dev_t x) 197bfbb9ce6SPoul-Henning Kamp { 198698bfad7SPoul-Henning Kamp if (x == NODEV) 199698bfad7SPoul-Henning Kamp return NOUDEV; 200698bfad7SPoul-Henning Kamp return(x->si_udev & 0xffff00ff); 201bfbb9ce6SPoul-Henning Kamp } 202bfbb9ce6SPoul-Henning Kamp 2039a27d579SPoul-Henning Kamp int 2049a27d579SPoul-Henning Kamp lminor(dev_t x) 2059a27d579SPoul-Henning Kamp { 2069a27d579SPoul-Henning Kamp int i; 2079a27d579SPoul-Henning Kamp 2089a27d579SPoul-Henning Kamp if (x == NODEV) 2099a27d579SPoul-Henning Kamp return NOUDEV; 2109a27d579SPoul-Henning Kamp i = minor(x); 2119a27d579SPoul-Henning Kamp return ((i & 0xff) | (i >> 8)); 2129a27d579SPoul-Henning Kamp } 2139a27d579SPoul-Henning Kamp 214bfbb9ce6SPoul-Henning Kamp dev_t 2156fcd8a7cSPoul-Henning Kamp makebdev(int x, int y) 2166fcd8a7cSPoul-Henning Kamp { 2173de280c4SPoul-Henning Kamp return (makedev(bmaj2cmaj[x], y)); 2186fcd8a7cSPoul-Henning Kamp } 2196fcd8a7cSPoul-Henning Kamp 2206fcd8a7cSPoul-Henning Kamp dev_t 221bfbb9ce6SPoul-Henning Kamp makedev(int x, int y) 222bfbb9ce6SPoul-Henning Kamp { 223698bfad7SPoul-Henning Kamp struct specinfo *si; 224698bfad7SPoul-Henning Kamp udev_t udev; 225698bfad7SPoul-Henning Kamp int hash; 226698bfad7SPoul-Henning Kamp static int stashed; 227698bfad7SPoul-Henning Kamp 228698bfad7SPoul-Henning Kamp udev = (x << 8) | y; 229698bfad7SPoul-Henning Kamp hash = udev % DEVT_HASH; 230698bfad7SPoul-Henning Kamp SLIST_FOREACH(si, &dev_hash[hash], si_hash) { 231698bfad7SPoul-Henning Kamp if (si->si_udev == udev) 232698bfad7SPoul-Henning Kamp return (si); 233698bfad7SPoul-Henning Kamp } 234698bfad7SPoul-Henning Kamp if (stashed >= DEVT_STASH) { 235698bfad7SPoul-Henning Kamp MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 236698bfad7SPoul-Henning Kamp M_USE_RESERVE); 237698bfad7SPoul-Henning Kamp } else { 238698bfad7SPoul-Henning Kamp si = devt_stash + stashed++; 239698bfad7SPoul-Henning Kamp } 240698bfad7SPoul-Henning Kamp bzero(si, sizeof(*si)); 241698bfad7SPoul-Henning Kamp si->si_udev = udev; 242698bfad7SPoul-Henning Kamp si->si_bsize_phys = DEV_BSIZE; 243698bfad7SPoul-Henning Kamp si->si_bsize_best = BLKDEV_IOSIZE; 244698bfad7SPoul-Henning Kamp si->si_bsize_max = MAXBSIZE; 2450ef1c826SPoul-Henning Kamp if (y > 256) 2460ef1c826SPoul-Henning Kamp sprintf(si->si_name, "#%d/0x%x", x, y); 2470ef1c826SPoul-Henning Kamp else 2480ef1c826SPoul-Henning Kamp sprintf(si->si_name, "#%d/%d", x, y); 249698bfad7SPoul-Henning Kamp SLIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 250698bfad7SPoul-Henning Kamp return (si); 251bfbb9ce6SPoul-Henning Kamp } 252bfbb9ce6SPoul-Henning Kamp 253bfbb9ce6SPoul-Henning Kamp udev_t 254bfbb9ce6SPoul-Henning Kamp dev2udev(dev_t x) 255bfbb9ce6SPoul-Henning Kamp { 256698bfad7SPoul-Henning Kamp if (x == NODEV) 257698bfad7SPoul-Henning Kamp return NOUDEV; 258698bfad7SPoul-Henning Kamp return (x->si_udev); 259bfbb9ce6SPoul-Henning Kamp } 260bfbb9ce6SPoul-Henning Kamp 261fb30b5bdSBrian Feldman udev_t 262fb30b5bdSBrian Feldman dev2budev(dev_t x) 263fb30b5bdSBrian Feldman { 26457d86fc6SBrian Feldman if (x == NODEV) 265fb30b5bdSBrian Feldman return NOUDEV; 266fb30b5bdSBrian Feldman else 267fb30b5bdSBrian Feldman return makeudev(devsw(x)->d_bmaj, minor(x)); 268fb30b5bdSBrian Feldman } 269fb30b5bdSBrian Feldman 270bfbb9ce6SPoul-Henning Kamp dev_t 271bfbb9ce6SPoul-Henning Kamp udev2dev(udev_t x, int b) 272bfbb9ce6SPoul-Henning Kamp { 273d21c632cSPoul-Henning Kamp switch (b) { 274d21c632cSPoul-Henning Kamp case 0: 275bfbb9ce6SPoul-Henning Kamp return makedev(umajor(x), uminor(x)); 276d21c632cSPoul-Henning Kamp case 1: 277d21c632cSPoul-Henning Kamp return makebdev(umajor(x), uminor(x)); 278d21c632cSPoul-Henning Kamp default: 279d21c632cSPoul-Henning Kamp Debugger("udev2dev(...,X)"); 280d21c632cSPoul-Henning Kamp return NODEV; 281d21c632cSPoul-Henning Kamp } 282bfbb9ce6SPoul-Henning Kamp } 283bfbb9ce6SPoul-Henning Kamp 284bfbb9ce6SPoul-Henning Kamp int 285bfbb9ce6SPoul-Henning Kamp uminor(udev_t dev) 286bfbb9ce6SPoul-Henning Kamp { 287bfbb9ce6SPoul-Henning Kamp return(dev & 0xffff00ff); 288bfbb9ce6SPoul-Henning Kamp } 289bfbb9ce6SPoul-Henning Kamp 290bfbb9ce6SPoul-Henning Kamp int 291bfbb9ce6SPoul-Henning Kamp umajor(udev_t dev) 292bfbb9ce6SPoul-Henning Kamp { 293bfbb9ce6SPoul-Henning Kamp return((dev & 0xff00) >> 8); 294bfbb9ce6SPoul-Henning Kamp } 295bfbb9ce6SPoul-Henning Kamp 296bfbb9ce6SPoul-Henning Kamp udev_t 297f008cfccSPoul-Henning Kamp makeudev(int x, int y) 298bfbb9ce6SPoul-Henning Kamp { 299bfbb9ce6SPoul-Henning Kamp return ((x << 8) | y); 300bfbb9ce6SPoul-Henning Kamp } 301bfbb9ce6SPoul-Henning Kamp 3020ef1c826SPoul-Henning Kamp dev_t 3030ef1c826SPoul-Henning Kamp make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 3040ef1c826SPoul-Henning Kamp { 3050ef1c826SPoul-Henning Kamp dev_t dev; 3060ef1c826SPoul-Henning Kamp va_list ap; 3070ef1c826SPoul-Henning Kamp int i; 3080ef1c826SPoul-Henning Kamp 3090ef1c826SPoul-Henning Kamp dev = makedev(devsw->d_maj, minor); 3100ef1c826SPoul-Henning Kamp va_start(ap, fmt); 3110ef1c826SPoul-Henning Kamp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 3120ef1c826SPoul-Henning Kamp dev->si_name[i] = '\0'; 3130ef1c826SPoul-Henning Kamp va_end(ap); 3140ef1c826SPoul-Henning Kamp dev->si_devsw = devsw; 3151744fcd0SJulian Elischer 3161744fcd0SJulian Elischer #ifdef DEVFS 3171744fcd0SJulian Elischer dev->si_devfs = devfs_add_devswf(devsw, minor, DV_CHR, 3181744fcd0SJulian Elischer uid, gid, perms, dev->si_name); 3191744fcd0SJulian Elischer /* XXX HACK .. name may not start in 'r' */ 3201744fcd0SJulian Elischer if ((devsw->d_bmaj != -1) 3211744fcd0SJulian Elischer && (*dev->si_name == 'r') 3221744fcd0SJulian Elischer && ((devsw->d_flags & D_TYPEMASK) == D_DISK)) { 3231744fcd0SJulian Elischer dev->si_devfs = devfs_add_devswf(devsw, minor, DV_BLK, 3241744fcd0SJulian Elischer uid, gid, perms, dev->si_name + 1); 3251744fcd0SJulian Elischer } 3261744fcd0SJulian Elischer #endif /* DEVFS */ 3270ef1c826SPoul-Henning Kamp return (dev); 3280ef1c826SPoul-Henning Kamp } 3290ef1c826SPoul-Henning Kamp 330b8e49f68SBill Fumerola char * 331b8e49f68SBill Fumerola devtoname(dev_t dev) 332b8e49f68SBill Fumerola { 333b8e49f68SBill Fumerola 334b8e49f68SBill Fumerola return (dev->si_name); 335b8e49f68SBill Fumerola } 336b8e49f68SBill Fumerola 337