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.2 2003/06/17 04:28:41 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 <machine/stdarg.h> 47 48 #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 49 50 struct cdevsw *cdevsw[NUMCDEVSW]; 51 52 static int bmaj2cmaj[NUMCDEVSW]; 53 54 MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 55 56 /* 57 * This is the number of hash-buckets. Experiements with 'real-life' 58 * udev_t's show that a prime halfway between two powers of two works 59 * best. 60 */ 61 #define DEVT_HASH 83 62 63 /* The number of dev_t's we can create before malloc(9) kick in. */ 64 #define DEVT_STASH 50 65 66 static struct specinfo devt_stash[DEVT_STASH]; 67 68 static LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 69 70 static LIST_HEAD(, specinfo) dev_free; 71 72 static int free_devt; 73 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 74 75 struct cdevsw * 76 devsw(dev_t dev) 77 { 78 if (dev->si_devsw) 79 return (dev->si_devsw); 80 return(cdevsw[major(dev)]); 81 } 82 83 static void 84 compile_devsw(struct cdevsw *devsw) 85 { 86 if (devsw->d_open == NULL) 87 devsw->d_open = noopen; 88 if (devsw->d_close == NULL) 89 devsw->d_close = noclose; 90 if (devsw->d_read == NULL) 91 devsw->d_read = noread; 92 if (devsw->d_write == NULL) 93 devsw->d_write = nowrite; 94 if (devsw->d_ioctl == NULL) 95 devsw->d_ioctl = noioctl; 96 if (devsw->d_poll == NULL) 97 devsw->d_poll = nopoll; 98 if (devsw->d_mmap == NULL) 99 devsw->d_mmap = nommap; 100 if (devsw->d_strategy == NULL) 101 devsw->d_strategy = nostrategy; 102 if (devsw->d_dump == NULL) 103 devsw->d_dump = nodump; 104 if (devsw->d_psize == NULL) 105 devsw->d_psize = nopsize; 106 if (devsw->d_kqfilter == NULL) 107 devsw->d_kqfilter = nokqfilter; 108 } 109 110 /* 111 * Add a cdevsw entry 112 */ 113 114 int 115 cdevsw_add(struct cdevsw *newentry) 116 { 117 int i; 118 static int setup; 119 120 if (!setup) { 121 for (i = 0; i < NUMCDEVSW; i++) 122 if (!bmaj2cmaj[i]) 123 bmaj2cmaj[i] = 254; 124 setup++; 125 } 126 127 compile_devsw(newentry); 128 if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 129 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 130 newentry->d_name, newentry->d_maj); 131 return (EINVAL); 132 } 133 if (newentry->d_bmaj >= NUMCDEVSW) { 134 printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n", 135 newentry->d_name, newentry->d_bmaj); 136 return (EINVAL); 137 } 138 if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) { 139 printf("ERROR: \"%s\" bmaj but is not a disk\n", 140 newentry->d_name); 141 return (EINVAL); 142 } 143 144 if (cdevsw[newentry->d_maj]) { 145 printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 146 newentry->d_name, cdevsw[newentry->d_maj]->d_name); 147 } 148 149 cdevsw[newentry->d_maj] = newentry; 150 151 if (newentry->d_bmaj < 0) 152 return (0); 153 154 if (bmaj2cmaj[newentry->d_bmaj] != 254) { 155 printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 156 newentry->d_name, 157 cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 158 } 159 bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 160 return (0); 161 } 162 163 /* 164 * Remove a cdevsw entry 165 */ 166 167 int 168 cdevsw_remove(struct cdevsw *oldentry) 169 { 170 if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 171 printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 172 oldentry->d_name, oldentry->d_maj); 173 return EINVAL; 174 } 175 176 cdevsw[oldentry->d_maj] = NULL; 177 178 if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 179 bmaj2cmaj[oldentry->d_bmaj] = 254; 180 181 return 0; 182 } 183 184 /* 185 * dev_t and u_dev_t primitives 186 */ 187 188 int 189 major(dev_t x) 190 { 191 if (x == NODEV) 192 return NOUDEV; 193 return((x->si_udev >> 8) & 0xff); 194 } 195 196 int 197 minor(dev_t x) 198 { 199 if (x == NODEV) 200 return NOUDEV; 201 return(x->si_udev & 0xffff00ff); 202 } 203 204 int 205 lminor(dev_t x) 206 { 207 int i; 208 209 if (x == NODEV) 210 return NOUDEV; 211 i = minor(x); 212 return ((i & 0xff) | (i >> 8)); 213 } 214 215 dev_t 216 makebdev(int x, int y) 217 { 218 219 if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 220 Debugger("makebdev of NOUDEV"); 221 return (makedev(bmaj2cmaj[x], y)); 222 } 223 224 dev_t 225 makedev(int x, int y) 226 { 227 struct specinfo *si; 228 udev_t udev; 229 int hash; 230 static int stashed; 231 232 if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 233 Debugger("makedev of NOUDEV"); 234 udev = (x << 8) | y; 235 hash = udev % DEVT_HASH; 236 LIST_FOREACH(si, &dev_hash[hash], si_hash) { 237 if (si->si_udev == udev) 238 return (si); 239 } 240 if (stashed >= DEVT_STASH) { 241 MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 242 M_USE_RESERVE); 243 bzero(si, sizeof(*si)); 244 } else if (LIST_FIRST(&dev_free)) { 245 si = LIST_FIRST(&dev_free); 246 LIST_REMOVE(si, si_hash); 247 } else { 248 si = devt_stash + stashed++; 249 si->si_flags |= SI_STASHED; 250 } 251 si->si_udev = udev; 252 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 253 return (si); 254 } 255 256 void 257 freedev(dev_t dev) 258 { 259 int hash; 260 261 if (!free_devt) 262 return; 263 if (SLIST_FIRST(&dev->si_hlist)) 264 return; 265 if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 266 return; 267 hash = dev->si_udev % DEVT_HASH; 268 LIST_REMOVE(dev, si_hash); 269 if (dev->si_flags & SI_STASHED) { 270 bzero(dev, sizeof(*dev)); 271 LIST_INSERT_HEAD(&dev_free, dev, si_hash); 272 } else { 273 FREE(dev, M_DEVT); 274 } 275 } 276 277 udev_t 278 dev2udev(dev_t x) 279 { 280 if (x == NODEV) 281 return NOUDEV; 282 return (x->si_udev); 283 } 284 285 dev_t 286 udev2dev(udev_t x, int b) 287 { 288 289 if (x == NOUDEV) 290 return (NODEV); 291 switch (b) { 292 case 0: 293 return makedev(umajor(x), uminor(x)); 294 case 1: 295 return makebdev(umajor(x), uminor(x)); 296 default: 297 Debugger("udev2dev(...,X)"); 298 return NODEV; 299 } 300 } 301 302 int 303 uminor(udev_t dev) 304 { 305 return(dev & 0xffff00ff); 306 } 307 308 int 309 umajor(udev_t dev) 310 { 311 return((dev & 0xff00) >> 8); 312 } 313 314 udev_t 315 makeudev(int x, int y) 316 { 317 return ((x << 8) | y); 318 } 319 320 dev_t 321 make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 322 { 323 dev_t dev; 324 va_list ap; 325 int i; 326 327 compile_devsw(devsw); 328 dev = makedev(devsw->d_maj, minor); 329 va_start(ap, fmt); 330 i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 331 dev->si_name[i] = '\0'; 332 va_end(ap); 333 dev->si_devsw = devsw; 334 335 return (dev); 336 } 337 338 void 339 destroy_dev(dev_t dev) 340 { 341 dev->si_drv1 = 0; 342 dev->si_drv2 = 0; 343 dev->si_devsw = 0; 344 freedev(dev); 345 } 346 347 const char * 348 devtoname(dev_t dev) 349 { 350 char *p; 351 int mynor; 352 353 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 354 p = dev->si_name; 355 if (devsw(dev)) 356 sprintf(p, "#%s/", devsw(dev)->d_name); 357 else 358 sprintf(p, "#%d/", major(dev)); 359 p += strlen(p); 360 mynor = minor(dev); 361 if (mynor < 0 || mynor > 255) 362 sprintf(p, "%#x", (u_int)mynor); 363 else 364 sprintf(p, "%d", mynor); 365 } 366 return (dev->si_name); 367 } 368