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 */ 35 36 #include <sys/param.h> 37 #include <sys/kernel.h> 38 #include <sys/sysctl.h> 39 #include <sys/systm.h> 40 #include <sys/module.h> 41 #include <sys/conf.h> 42 #include <sys/vnode.h> 43 #include <sys/queue.h> 44 #include <sys/device.h> 45 #include <sys/disk.h> 46 #include <machine/stdarg.h> 47 48 #include <sys/sysref2.h> 49 50 #include <sys/devfs.h> 51 52 int dev_ref_debug = 0; 53 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, 54 "Toggle device reference debug output"); 55 56 /* 57 * cdev_t and u_dev_t primitives. Note that the major number is always 58 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced 59 * when a device is destroyed. 60 */ 61 int 62 major(cdev_t dev) 63 { 64 if (dev == NULL) 65 return NOUDEV; 66 return(dev->si_umajor); 67 } 68 69 int 70 minor(cdev_t dev) 71 { 72 if (dev == NULL) 73 return NOUDEV; 74 return(dev->si_uminor); 75 } 76 77 /* 78 * Compatibility function with old udev_t format to convert the 79 * non-consecutive minor space into a consecutive minor space. 80 */ 81 int 82 lminor(cdev_t dev) 83 { 84 int y; 85 86 if (dev == NULL) 87 return NOUDEV; 88 y = dev->si_uminor; 89 if (y & 0x0000ff00) 90 return NOUDEV; 91 return ((y & 0xff) | (y >> 8)); 92 } 93 94 /* 95 * Convert a device pointer to an old style device number. Return NOUDEV 96 * if the device is invalid or if the device (maj,min) cannot be converted 97 * to an old style udev_t. 98 */ 99 udev_t 100 dev2udev(cdev_t dev) 101 { 102 if (dev == NULL) 103 return NOUDEV; 104 105 return (udev_t)dev->si_inode; 106 } 107 108 /* 109 * Convert a device number to a device pointer. The device is referenced 110 * ad-hoc, meaning that the caller should call reference_dev() if it wishes 111 * to keep ahold of the returned structure long term. 112 * 113 * The returned device is associated with the currently installed cdevsw 114 * for the requested major number. NULL is returned if the major number 115 * has not been registered. 116 */ 117 cdev_t 118 udev2dev(udev_t x, int b) 119 { 120 if (x == NOUDEV || b != 0) 121 return(NULL); 122 123 return devfs_find_device_by_udev(x); 124 } 125 126 int 127 dev_is_good(cdev_t dev) 128 { 129 if (dev != NULL && dev->si_ops != &dead_dev_ops) 130 return(1); 131 return(0); 132 } 133 134 /* 135 * Various user device number extraction and conversion routines 136 */ 137 int 138 uminor(udev_t dev) 139 { 140 if (dev == NOUDEV) 141 return(-1); 142 return(dev & 0xffff00ff); 143 } 144 145 int 146 umajor(udev_t dev) 147 { 148 if (dev == NOUDEV) 149 return(-1); 150 return((dev & 0xff00) >> 8); 151 } 152 153 udev_t 154 makeudev(int x, int y) 155 { 156 if ((x & 0xffffff00) || (y & 0x0000ff00)) 157 return NOUDEV; 158 return ((x << 8) | y); 159 } 160 161 /* 162 * Create an internal or external device. 163 * 164 * This routine creates and returns an unreferenced ad-hoc entry for the 165 * device which will remain intact until the device is destroyed. If the 166 * caller intends to store the device pointer it must call reference_dev() 167 * to retain a real reference to the device. 168 * 169 * If an entry already exists, this function will set (or override) 170 * its cred requirements and name (XXX DEVFS interface). 171 */ 172 cdev_t 173 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 174 int perms, const char *fmt, ...) 175 { 176 cdev_t devfs_dev; 177 __va_list ap; 178 179 /* 180 * compile the cdevsw and install the device 181 */ 182 compile_dev_ops(ops); 183 184 devfs_dev = devfs_new_cdev(ops, minor, NULL); 185 __va_start(ap, fmt); 186 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 187 32, fmt, ap); 188 __va_end(ap); 189 190 devfs_debug(DEVFS_DEBUG_INFO, 191 "make_dev called for %s\n", 192 devfs_dev->si_name); 193 devfs_create_dev(devfs_dev, uid, gid, perms); 194 195 return (devfs_dev); 196 } 197 198 /* 199 * make_dev_covering has equivalent functionality to make_dev, except that it 200 * also takes the dev_ops of the underlying device. Hence this function should 201 * only be used by systems and drivers which create devices covering others 202 */ 203 cdev_t 204 make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 205 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 206 { 207 cdev_t devfs_dev; 208 __va_list ap; 209 210 /* 211 * compile the cdevsw and install the device 212 */ 213 compile_dev_ops(ops); 214 215 devfs_dev = devfs_new_cdev(ops, minor, bops); 216 __va_start(ap, fmt); 217 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 218 32, fmt, ap); 219 __va_end(ap); 220 221 devfs_debug(DEVFS_DEBUG_INFO, 222 "make_dev called for %s\n", 223 devfs_dev->si_name); 224 devfs_create_dev(devfs_dev, uid, gid, perms); 225 226 return (devfs_dev); 227 } 228 229 230 231 cdev_t 232 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 233 int perms, const char *fmt, ...) 234 { 235 cdev_t devfs_dev; 236 __va_list ap; 237 238 /* 239 * compile the cdevsw and install the device 240 */ 241 compile_dev_ops(ops); 242 devfs_dev = devfs_new_cdev(ops, minor, NULL); 243 244 /* 245 * Set additional fields (XXX DEVFS interface goes here) 246 */ 247 __va_start(ap, fmt); 248 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 249 32, fmt, ap); 250 __va_end(ap); 251 252 devfs_create_dev(devfs_dev, uid, gid, perms); 253 254 return (devfs_dev); 255 } 256 257 cdev_t 258 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 259 int perms, const char *fmt, ...) 260 { 261 cdev_t devfs_dev; 262 __va_list ap; 263 264 /* 265 * compile the cdevsw and install the device 266 */ 267 compile_dev_ops(ops); 268 devfs_dev = devfs_new_cdev(ops, minor, NULL); 269 devfs_dev->si_perms = perms; 270 devfs_dev->si_uid = uid; 271 devfs_dev->si_gid = gid; 272 273 /* 274 * Set additional fields (XXX DEVFS interface goes here) 275 */ 276 __va_start(ap, fmt); 277 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 278 32, fmt, ap); 279 __va_end(ap); 280 281 reference_dev(devfs_dev); 282 283 return (devfs_dev); 284 } 285 286 cdev_t 287 make_only_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 288 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 289 { 290 cdev_t devfs_dev; 291 __va_list ap; 292 293 /* 294 * compile the cdevsw and install the device 295 */ 296 compile_dev_ops(ops); 297 devfs_dev = devfs_new_cdev(ops, minor, bops); 298 devfs_dev->si_perms = perms; 299 devfs_dev->si_uid = uid; 300 devfs_dev->si_gid = gid; 301 302 /* 303 * Set additional fields (XXX DEVFS interface goes here) 304 */ 305 __va_start(ap, fmt); 306 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 307 32, fmt, ap); 308 __va_end(ap); 309 310 reference_dev(devfs_dev); 311 312 return (devfs_dev); 313 } 314 315 void 316 destroy_only_dev(cdev_t dev) 317 { 318 release_dev(dev); 319 release_dev(dev); 320 release_dev(dev); 321 } 322 323 /* 324 * destroy_dev() removes the adhoc association for a device and revectors 325 * its ops to &dead_dev_ops. 326 * 327 * This routine releases the reference count associated with the ADHOC 328 * entry, plus releases the reference count held by the caller. What this 329 * means is that you should not call destroy_dev(make_dev(...)), because 330 * make_dev() does not bump the reference count (beyond what it needs to 331 * create the ad-hoc association). Any procedure that intends to destroy 332 * a device must have its own reference to it first. 333 */ 334 void 335 destroy_dev(cdev_t dev) 336 { 337 if (dev) { 338 devfs_debug(DEVFS_DEBUG_DEBUG, 339 "destroy_dev called for %s\n", 340 dev->si_name); 341 devfs_destroy_dev(dev); 342 } 343 } 344 345 /* 346 * Make sure all asynchronous disk and devfs related operations have 347 * completed. 348 * 349 * Typically called prior to mountroot to ensure that all disks have 350 * been completely probed and on module unload to ensure that ops 351 * structures have been dereferenced. 352 */ 353 void 354 sync_devs(void) 355 { 356 disk_config(NULL); 357 devfs_config(); 358 disk_config(NULL); 359 devfs_config(); 360 } 361 362 int 363 make_dev_alias(cdev_t target, const char *fmt, ...) 364 { 365 __va_list ap; 366 char *name; 367 368 __va_start(ap, fmt); 369 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 370 __va_end(ap); 371 372 devfs_make_alias(name, target); 373 kvasfree(&name); 374 375 return 0; 376 } 377 378 int 379 destroy_dev_alias(cdev_t target, const char *fmt, ...) 380 { 381 __va_list ap; 382 char *name; 383 384 __va_start(ap, fmt); 385 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 386 __va_end(ap); 387 388 devfs_destroy_alias(name, target); 389 kvasfree(&name); 390 391 return 0; 392 } 393 394 extern struct dev_ops default_dev_ops; 395 396 cdev_t 397 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap, 398 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 399 { 400 __va_list ap; 401 cdev_t dev; 402 char *name; 403 404 __va_start(ap, fmt); 405 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 406 __va_end(ap); 407 408 if (bitmap != NULL) 409 devfs_clone_bitmap_init(bitmap); 410 411 devfs_clone_handler_add(name, nhandler); 412 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff, 413 uid, gid, perms, "%s", name); 414 kvasfree(&name); 415 return dev; 416 } 417 418 void 419 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap) 420 { 421 if (dev == NULL) 422 return; 423 424 devfs_clone_handler_del(dev->si_name); 425 426 if (bitmap != NULL) 427 devfs_clone_bitmap_uninit(bitmap); 428 429 destroy_dev(dev); 430 } 431 432 433 /* 434 * Add a reference to a device. Callers generally add their own references 435 * when they are going to store a device node in a variable for long periods 436 * of time, to prevent a disassociation from free()ing the node. 437 * 438 * Also note that a caller that intends to call destroy_dev() must first 439 * obtain a reference on the device. The ad-hoc reference you get with 440 * make_dev() and friends is NOT sufficient to be able to call destroy_dev(). 441 */ 442 cdev_t 443 reference_dev(cdev_t dev) 444 { 445 //kprintf("reference_dev\n"); 446 447 if (dev != NULL) { 448 sysref_get(&dev->si_sysref); 449 if (dev_ref_debug & 2) { 450 kprintf("reference dev %p %s(minor=%08x) refs=%d\n", 451 dev, devtoname(dev), dev->si_uminor, 452 dev->si_sysref.refcnt); 453 } 454 } 455 return(dev); 456 } 457 458 /* 459 * release a reference on a device. The device will be terminated when the 460 * last reference has been released. 461 * 462 * NOTE: we must use si_umajor to figure out the original major number, 463 * because si_ops could already be pointing at dead_dev_ops. 464 */ 465 void 466 release_dev(cdev_t dev) 467 { 468 //kprintf("release_dev\n"); 469 470 if (dev == NULL) 471 return; 472 sysref_put(&dev->si_sysref); 473 } 474 475 const char * 476 devtoname(cdev_t dev) 477 { 478 int mynor; 479 int len; 480 char *p; 481 const char *dname; 482 483 if (dev == NULL) 484 return("#nodev"); 485 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 486 p = dev->si_name; 487 len = sizeof(dev->si_name); 488 if ((dname = dev_dname(dev)) != NULL) 489 ksnprintf(p, len, "#%s/", dname); 490 else 491 ksnprintf(p, len, "#%d/", major(dev)); 492 len -= strlen(p); 493 p += strlen(p); 494 mynor = minor(dev); 495 if (mynor < 0 || mynor > 255) 496 ksnprintf(p, len, "%#x", (u_int)mynor); 497 else 498 ksnprintf(p, len, "%d", mynor); 499 } 500 return (dev->si_name); 501 } 502 503