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