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 * Put a NUL-terminated ASCII number (base == 32) for use as device suffix. 163 * The buffer pointed to by `nbuf' must have length >= MAKEDEV_MINNBUF. 164 */ 165 char * 166 makedev_unit_b32(char *nbuf, uintmax_t num) 167 { 168 char *p = &nbuf[MAKEDEV_MINNBUF - 1]; 169 170 *p = '\0'; 171 do { 172 *--p = hex2ascii(num % 32); 173 } while (num /= 32); 174 return (p); 175 } 176 177 /* 178 * Create an internal or external device. 179 * 180 * This routine creates and returns an unreferenced ad-hoc entry for the 181 * device which will remain intact until the device is destroyed. If the 182 * caller intends to store the device pointer it must call reference_dev() 183 * to retain a real reference to the device. 184 * 185 * If an entry already exists, this function will set (or override) 186 * its cred requirements and name (XXX DEVFS interface). 187 */ 188 cdev_t 189 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 190 int perms, const char *fmt, ...) 191 { 192 cdev_t devfs_dev; 193 __va_list ap; 194 195 /* 196 * compile the cdevsw and install the device 197 */ 198 compile_dev_ops(ops); 199 200 devfs_dev = devfs_new_cdev(ops, minor, NULL); 201 __va_start(ap, fmt); 202 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 203 32, fmt, ap); 204 __va_end(ap); 205 206 devfs_debug(DEVFS_DEBUG_INFO, 207 "make_dev called for %s\n", 208 devfs_dev->si_name); 209 devfs_create_dev(devfs_dev, uid, gid, perms); 210 211 return (devfs_dev); 212 } 213 214 /* 215 * make_dev_covering has equivalent functionality to make_dev, except that it 216 * also takes the dev_ops of the underlying device. Hence this function should 217 * only be used by systems and drivers which create devices covering others 218 */ 219 cdev_t 220 make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 221 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 222 { 223 cdev_t devfs_dev; 224 __va_list ap; 225 226 /* 227 * compile the cdevsw and install the device 228 */ 229 compile_dev_ops(ops); 230 231 devfs_dev = devfs_new_cdev(ops, minor, bops); 232 __va_start(ap, fmt); 233 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 234 32, fmt, ap); 235 __va_end(ap); 236 237 devfs_debug(DEVFS_DEBUG_INFO, 238 "make_dev called for %s\n", 239 devfs_dev->si_name); 240 devfs_create_dev(devfs_dev, uid, gid, perms); 241 242 return (devfs_dev); 243 } 244 245 246 247 cdev_t 248 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 249 int perms, const char *fmt, ...) 250 { 251 cdev_t devfs_dev; 252 __va_list ap; 253 254 /* 255 * compile the cdevsw and install the device 256 */ 257 compile_dev_ops(ops); 258 devfs_dev = devfs_new_cdev(ops, minor, NULL); 259 260 /* 261 * Set additional fields (XXX DEVFS interface goes here) 262 */ 263 __va_start(ap, fmt); 264 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 265 32, fmt, ap); 266 __va_end(ap); 267 268 devfs_create_dev(devfs_dev, uid, gid, perms); 269 270 return (devfs_dev); 271 } 272 273 cdev_t 274 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 275 int perms, const char *fmt, ...) 276 { 277 cdev_t devfs_dev; 278 __va_list ap; 279 280 /* 281 * compile the cdevsw and install the device 282 */ 283 compile_dev_ops(ops); 284 devfs_dev = devfs_new_cdev(ops, minor, NULL); 285 devfs_dev->si_perms = perms; 286 devfs_dev->si_uid = uid; 287 devfs_dev->si_gid = gid; 288 289 /* 290 * Set additional fields (XXX DEVFS interface goes here) 291 */ 292 __va_start(ap, fmt); 293 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 294 32, fmt, ap); 295 __va_end(ap); 296 297 reference_dev(devfs_dev); 298 299 return (devfs_dev); 300 } 301 302 cdev_t 303 make_only_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 304 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 305 { 306 cdev_t devfs_dev; 307 __va_list ap; 308 309 /* 310 * compile the cdevsw and install the device 311 */ 312 compile_dev_ops(ops); 313 devfs_dev = devfs_new_cdev(ops, minor, bops); 314 devfs_dev->si_perms = perms; 315 devfs_dev->si_uid = uid; 316 devfs_dev->si_gid = gid; 317 318 /* 319 * Set additional fields (XXX DEVFS interface goes here) 320 */ 321 __va_start(ap, fmt); 322 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 323 32, fmt, ap); 324 __va_end(ap); 325 326 reference_dev(devfs_dev); 327 328 return (devfs_dev); 329 } 330 331 void 332 destroy_only_dev(cdev_t dev) 333 { 334 release_dev(dev); 335 release_dev(dev); 336 release_dev(dev); 337 } 338 339 /* 340 * destroy_dev() removes the adhoc association for a device and revectors 341 * its ops to &dead_dev_ops. 342 * 343 * This routine releases the reference count associated with the ADHOC 344 * entry, plus releases the reference count held by the caller. What this 345 * means is that you should not call destroy_dev(make_dev(...)), because 346 * make_dev() does not bump the reference count (beyond what it needs to 347 * create the ad-hoc association). Any procedure that intends to destroy 348 * a device must have its own reference to it first. 349 */ 350 void 351 destroy_dev(cdev_t dev) 352 { 353 if (dev) { 354 devfs_debug(DEVFS_DEBUG_DEBUG, 355 "destroy_dev called for %s\n", 356 dev->si_name); 357 devfs_destroy_dev(dev); 358 } 359 } 360 361 /* 362 * Make sure all asynchronous disk and devfs related operations have 363 * completed. 364 * 365 * Typically called prior to mountroot to ensure that all disks have 366 * been completely probed and on module unload to ensure that ops 367 * structures have been dereferenced. 368 */ 369 void 370 sync_devs(void) 371 { 372 disk_config(NULL); 373 devfs_config(); 374 disk_config(NULL); 375 devfs_config(); 376 } 377 378 int 379 make_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_make_alias(name, target); 389 kvasfree(&name); 390 391 return 0; 392 } 393 394 int 395 destroy_dev_alias(cdev_t target, const char *fmt, ...) 396 { 397 __va_list ap; 398 char *name; 399 400 __va_start(ap, fmt); 401 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 402 __va_end(ap); 403 404 devfs_destroy_alias(name, target); 405 kvasfree(&name); 406 407 return 0; 408 } 409 410 extern struct dev_ops default_dev_ops; 411 412 cdev_t 413 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap, 414 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 415 { 416 __va_list ap; 417 cdev_t dev; 418 char *name; 419 420 __va_start(ap, fmt); 421 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 422 __va_end(ap); 423 424 if (bitmap != NULL) 425 devfs_clone_bitmap_init(bitmap); 426 427 devfs_clone_handler_add(name, nhandler); 428 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff, 429 uid, gid, perms, "%s", name); 430 kvasfree(&name); 431 return dev; 432 } 433 434 void 435 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap) 436 { 437 if (dev == NULL) 438 return; 439 440 devfs_clone_handler_del(dev->si_name); 441 442 if (bitmap != NULL) 443 devfs_clone_bitmap_uninit(bitmap); 444 445 destroy_dev(dev); 446 } 447 448 449 /* 450 * Add a reference to a device. Callers generally add their own references 451 * when they are going to store a device node in a variable for long periods 452 * of time, to prevent a disassociation from free()ing the node. 453 * 454 * Also note that a caller that intends to call destroy_dev() must first 455 * obtain a reference on the device. The ad-hoc reference you get with 456 * make_dev() and friends is NOT sufficient to be able to call destroy_dev(). 457 */ 458 cdev_t 459 reference_dev(cdev_t dev) 460 { 461 //kprintf("reference_dev\n"); 462 463 if (dev != NULL) { 464 sysref_get(&dev->si_sysref); 465 if (dev_ref_debug & 2) { 466 kprintf("reference dev %p %s(minor=%08x) refs=%d\n", 467 dev, devtoname(dev), dev->si_uminor, 468 dev->si_sysref.refcnt); 469 } 470 } 471 return(dev); 472 } 473 474 /* 475 * release a reference on a device. The device will be terminated when the 476 * last reference has been released. 477 * 478 * NOTE: we must use si_umajor to figure out the original major number, 479 * because si_ops could already be pointing at dead_dev_ops. 480 */ 481 void 482 release_dev(cdev_t dev) 483 { 484 //kprintf("release_dev\n"); 485 486 if (dev == NULL) 487 return; 488 sysref_put(&dev->si_sysref); 489 } 490 491 const char * 492 devtoname(cdev_t dev) 493 { 494 int mynor; 495 int len; 496 char *p; 497 const char *dname; 498 499 if (dev == NULL) 500 return("#nodev"); 501 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 502 p = dev->si_name; 503 len = sizeof(dev->si_name); 504 if ((dname = dev_dname(dev)) != NULL) 505 ksnprintf(p, len, "#%s/", dname); 506 else 507 ksnprintf(p, len, "#%d/", major(dev)); 508 len -= strlen(p); 509 p += strlen(p); 510 mynor = minor(dev); 511 if (mynor < 0 || mynor > 255) 512 ksnprintf(p, len, "%#x", (u_int)mynor); 513 else 514 ksnprintf(p, len, "%d", mynor); 515 } 516 return (dev->si_name); 517 } 518 519