1 /*- 2 * Parts Copyright (c) 1995 Terrence R. Lambert 3 * Copyright (c) 1995 Julian R. Elischer 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Terrence R. Lambert. 17 * 4. The name Terrence R. Lambert may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $ 34 * $DragonFly: src/sys/kern/kern_conf.c,v 1.6 2004/01/20 05:04:06 dillon Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/kernel.h> 39 #include <sys/sysctl.h> 40 #include <sys/systm.h> 41 #include <sys/module.h> 42 #include <sys/malloc.h> 43 #include <sys/conf.h> 44 #include <sys/vnode.h> 45 #include <sys/queue.h> 46 #include <sys/device.h> 47 #include <machine/stdarg.h> 48 49 #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 50 51 MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 52 53 /* 54 * This is the number of hash-buckets. Experiements with 'real-life' 55 * udev_t's show that a prime halfway between two powers of two works 56 * best. 57 */ 58 #define DEVT_HASH 83 59 60 /* The number of dev_t's we can create before malloc(9) kick in. */ 61 #define DEVT_STASH 50 62 63 static struct specinfo devt_stash[DEVT_STASH]; 64 65 static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 66 67 static LIST_HEAD(, specinfo) dev_free; 68 69 static int free_devt; 70 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 71 72 /* 73 * dev_t and u_dev_t primitives 74 */ 75 76 int 77 major(dev_t x) 78 { 79 if (x == NODEV) 80 return NOUDEV; 81 return((x->si_udev >> 8) & 0xff); 82 } 83 84 int 85 minor(dev_t x) 86 { 87 if (x == NODEV) 88 return NOUDEV; 89 return(x->si_udev & 0xffff00ff); 90 } 91 92 int 93 lminor(dev_t x) 94 { 95 int i; 96 97 if (x == NODEV) 98 return NOUDEV; 99 i = minor(x); 100 return ((i & 0xff) | (i >> 8)); 101 } 102 103 dev_t 104 makedev(int x, int y) 105 { 106 struct specinfo *si; 107 udev_t udev; 108 int hash; 109 static int stashed; 110 111 if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 112 Debugger("makedev of NOUDEV"); 113 udev = (x << 8) | y; 114 hash = udev % DEVT_HASH; 115 LIST_FOREACH(si, &dev_hash[hash], si_hash) { 116 if (si->si_udev == udev) 117 return (si); 118 } 119 if (stashed >= DEVT_STASH) { 120 MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 121 M_WAITOK|M_USE_RESERVE); 122 bzero(si, sizeof(*si)); 123 } else if (LIST_FIRST(&dev_free)) { 124 si = LIST_FIRST(&dev_free); 125 LIST_REMOVE(si, si_hash); 126 } else { 127 si = devt_stash + stashed++; 128 si->si_flags |= SI_STASHED; 129 } 130 si->si_udev = udev; 131 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 132 return (si); 133 } 134 135 void 136 freedev(dev_t dev) 137 { 138 int hash; 139 140 if (!free_devt) 141 return; 142 if (SLIST_FIRST(&dev->si_hlist)) 143 return; 144 if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 145 return; 146 hash = dev->si_udev % DEVT_HASH; 147 LIST_REMOVE(dev, si_hash); 148 if (dev->si_flags & SI_STASHED) { 149 bzero(dev, sizeof(*dev)); 150 LIST_INSERT_HEAD(&dev_free, dev, si_hash); 151 } else { 152 FREE(dev, M_DEVT); 153 } 154 } 155 156 udev_t 157 dev2udev(dev_t x) 158 { 159 if (x == NODEV) 160 return NOUDEV; 161 return (x->si_udev); 162 } 163 164 dev_t 165 udev2dev(udev_t x, int b) 166 { 167 168 if (x == NOUDEV) 169 return (NODEV); 170 switch (b) { 171 case 0: 172 return makedev(umajor(x), uminor(x)); 173 case 1: 174 printf("udev2dev: attempt to lookup block dev(%d)", x); 175 return NODEV; 176 default: 177 Debugger("udev2dev(...,X)"); 178 return NODEV; 179 } 180 } 181 182 int 183 uminor(udev_t dev) 184 { 185 return(dev & 0xffff00ff); 186 } 187 188 int 189 umajor(udev_t dev) 190 { 191 return((dev & 0xff00) >> 8); 192 } 193 194 udev_t 195 makeudev(int x, int y) 196 { 197 return ((x << 8) | y); 198 } 199 200 dev_t 201 make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 202 { 203 dev_t dev; 204 __va_list ap; 205 int i; 206 207 compile_devsw(devsw); 208 dev = makedev(devsw->d_maj, minor); 209 __va_start(ap, fmt); 210 i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 211 dev->si_name[i] = '\0'; 212 __va_end(ap); 213 dev->si_devsw = devsw; 214 215 return (dev); 216 } 217 218 void 219 destroy_dev(dev_t dev) 220 { 221 dev->si_drv1 = 0; 222 dev->si_drv2 = 0; 223 dev->si_devsw = 0; 224 freedev(dev); 225 } 226 227 const char * 228 devtoname(dev_t dev) 229 { 230 int mynor; 231 int len; 232 char *p; 233 const char *dname; 234 235 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 236 p = dev->si_name; 237 len = sizeof(dev->si_name); 238 if ((dname = dev_dname(dev)) != NULL) 239 snprintf(p, len, "#%s/", dname); 240 else 241 snprintf(p, len, "#%d/", major(dev)); 242 len -= strlen(p); 243 p += strlen(p); 244 mynor = minor(dev); 245 if (mynor < 0 || mynor > 255) 246 snprintf(p, len, "%#x", (u_int)mynor); 247 else 248 snprintf(p, len, "%d", mynor); 249 } 250 return (dev->si_name); 251 } 252