kern_conf.c revision 71342
1100966Siwasaki/*- 2100966Siwasaki * Parts Copyright (c) 1995 Terrence R. Lambert 3100966Siwasaki * Copyright (c) 1995 Julian R. Elischer 4100966Siwasaki * All rights reserved. 5100966Siwasaki * 6100966Siwasaki * Redistribution and use in source and binary forms, with or without 7217365Sjkim * modification, are permitted provided that the following conditions 8245582Sjkim * are met: 9100966Siwasaki * 1. Redistributions of source code must retain the above copyright 10100966Siwasaki * notice, this list of conditions and the following disclaimer. 11217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright 12217365Sjkim * notice, this list of conditions and the following disclaimer in the 13217365Sjkim * documentation and/or other materials provided with the distribution. 14217365Sjkim * 3. All advertising materials mentioning features or use of this software 15217365Sjkim * must display the following acknowledgement: 16217365Sjkim * This product includes software developed by Terrence R. Lambert. 17217365Sjkim * 4. The name Terrence R. Lambert may not be used to endorse or promote 18217365Sjkim * products derived from this software without specific prior written 19217365Sjkim * permission. 20217365Sjkim * 21217365Sjkim * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 22217365Sjkim * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 25100966Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29100966Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31217365Sjkim * SUCH DAMAGE. 32217365Sjkim * 33217365Sjkim * $FreeBSD: head/sys/kern/kern_conf.c 71342 2001-01-21 21:19:49Z phk $ 34217365Sjkim */ 35217365Sjkim 36217365Sjkim#include <sys/param.h> 37217365Sjkim#include <sys/kernel.h> 38217365Sjkim#include <sys/sysctl.h> 39217365Sjkim#include <sys/systm.h> 40217365Sjkim#include <sys/module.h> 41217365Sjkim#include <sys/malloc.h> 42217365Sjkim#include <sys/conf.h> 43100966Siwasaki#include <sys/vnode.h> 44100966Siwasaki#include <sys/queue.h> 45193341Sjkim#include <sys/ctype.h> 46193341Sjkim#include <machine/stdarg.h> 47193341Sjkim 48100966Siwasaki#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 49100966Siwasaki 50100966Siwasakistruct cdevsw *cdevsw[NUMCDEVSW]; 51100966Siwasaki 52102550Siwasakistatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 53100966Siwasaki 54100966Siwasaki/* 55100966Siwasaki * This is the number of hash-buckets. Experiements with 'real-life' 56151937Sjkim * udev_t's show that a prime halfway between two powers of two works 57151937Sjkim * best. 58151937Sjkim */ 59151937Sjkim#define DEVT_HASH 83 60167802Sjkim 61167802Sjkim/* The number of dev_t's we can create before malloc(9) kick in. */ 62167802Sjkim#define DEVT_STASH 50 63167802Sjkim 64167802Sjkimstatic struct specinfo devt_stash[DEVT_STASH]; 65151937Sjkim 66151937Sjkimstatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 67151937Sjkim 68151937Sjkimstatic LIST_HEAD(, specinfo) dev_free; 69167802Sjkim 70167802Sjkimdevfs_create_t *devfs_create_hook; 71167802Sjkimdevfs_destroy_t *devfs_destroy_hook; 72167802Sjkimint devfs_present; 73151937Sjkim 74151937Sjkimstatic int free_devt; 75151937SjkimSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 76151937Sjkim 77151937Sjkimstruct cdevsw * 78151937Sjkimdevsw(dev_t dev) 79151937Sjkim{ 80151937Sjkim if (dev->si_devsw) 81151937Sjkim return (dev->si_devsw); 82151937Sjkim return(cdevsw[major(dev)]); 83151937Sjkim} 84151937Sjkim 85151937Sjkim/* 86151937Sjkim * Add a cdevsw entry 87151937Sjkim */ 88151937Sjkim 89151937Sjkimint 90151937Sjkimcdevsw_add(struct cdevsw *newentry) 91151937Sjkim{ 92151937Sjkim 93151937Sjkim if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 94151937Sjkim printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 95151937Sjkim newentry->d_name, newentry->d_maj); 96151937Sjkim return (EINVAL); 97151937Sjkim } 98151937Sjkim 99151937Sjkim if (cdevsw[newentry->d_maj]) { 100151937Sjkim printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 101151937Sjkim newentry->d_name, cdevsw[newentry->d_maj]->d_name); 102151937Sjkim } 103151937Sjkim 104151937Sjkim cdevsw[newentry->d_maj] = newentry; 105151937Sjkim 106151937Sjkim return (0); 107151937Sjkim} 108151937Sjkim 109151937Sjkim/* 110151937Sjkim * Remove a cdevsw entry 111151937Sjkim */ 112151937Sjkim 113151937Sjkimint 114151937Sjkimcdevsw_remove(struct cdevsw *oldentry) 115151937Sjkim{ 116151937Sjkim if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 117151937Sjkim printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 118151937Sjkim oldentry->d_name, oldentry->d_maj); 119151937Sjkim return EINVAL; 120151937Sjkim } 121151937Sjkim 122151937Sjkim cdevsw[oldentry->d_maj] = NULL; 123151937Sjkim 124151937Sjkim return 0; 125151937Sjkim} 126100966Siwasaki 127100966Siwasaki/* 128151937Sjkim * dev_t and u_dev_t primitives 129151937Sjkim */ 130151937Sjkim 131151937Sjkimint 132151937Sjkimmajor(dev_t x) 133151937Sjkim{ 134151937Sjkim if (x == NODEV) 135151937Sjkim return NOUDEV; 136151937Sjkim return((x->si_udev >> 8) & 0xff); 137151937Sjkim} 138151937Sjkim 139151937Sjkimint 140151937Sjkimminor(dev_t x) 141151937Sjkim{ 142151937Sjkim if (x == NODEV) 143151937Sjkim return NOUDEV; 144151937Sjkim return(x->si_udev & 0xffff00ff); 145151937Sjkim} 146193267Sjkim 147151937Sjkimint 148151937Sjkimdev2unit(dev_t x) 149151937Sjkim{ 150151937Sjkim int i; 151151937Sjkim 152151937Sjkim if (x == NODEV) 153151937Sjkim return NOUDEV; 154151937Sjkim i = minor(x); 155151937Sjkim return ((i & 0xff) | (i >> 8)); 156250838Sjkim} 157167802Sjkim 158167802Sjkimint 159151937Sjkimunit2minor(int unit) 160151937Sjkim{ 161151937Sjkim 162250838Sjkim return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 163167802Sjkim} 164167802Sjkim 165151937Sjkimstatic dev_t 166151937Sjkimallocdev(void) 167151937Sjkim{ 168250838Sjkim static int stashed; 169151937Sjkim struct specinfo *si; 170151937Sjkim 171151937Sjkim if (stashed >= DEVT_STASH) { 172151937Sjkim MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 173151937Sjkim M_USE_RESERVE | M_ZERO); 174151937Sjkim } else if (LIST_FIRST(&dev_free)) { 175151937Sjkim si = LIST_FIRST(&dev_free); 176151937Sjkim LIST_REMOVE(si, si_hash); 177167802Sjkim } else { 178151937Sjkim si = devt_stash + stashed++; 179151937Sjkim si->si_flags |= SI_STASHED; 180151937Sjkim } 181151937Sjkim LIST_INIT(&si->si_names); 182151937Sjkim return (si); 183151937Sjkim} 184151937Sjkim 185151937Sjkimdev_t 186151937Sjkimmakedev(int x, int y) 187151937Sjkim{ 188151937Sjkim struct specinfo *si; 189151937Sjkim udev_t udev; 190151937Sjkim int hash; 191151937Sjkim 192151937Sjkim if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 193151937Sjkim panic("makedev of NOUDEV"); 194151937Sjkim udev = (x << 8) | y; 195193267Sjkim hash = udev % DEVT_HASH; 196151937Sjkim LIST_FOREACH(si, &dev_hash[hash], si_hash) { 197151937Sjkim if (si->si_udev == udev) 198151937Sjkim return (si); 199151937Sjkim } 200151937Sjkim si = allocdev(); 201151937Sjkim si->si_udev = udev; 202151937Sjkim LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 203151937Sjkim return (si); 204151937Sjkim} 205151937Sjkim 206151937Sjkimvoid 207250838Sjkimfreedev(dev_t dev) 208167802Sjkim{ 209167802Sjkim dev_t adev; 210151937Sjkim 211151937Sjkim if (!free_devt) 212151937Sjkim return; 213250838Sjkim if (SLIST_FIRST(&dev->si_hlist)) 214167802Sjkim return; 215167802Sjkim if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 216151937Sjkim return; 217151937Sjkim while (!LIST_EMPTY(&dev->si_names)) { 218151937Sjkim adev = LIST_FIRST(&dev->si_names); 219250838Sjkim adev->si_drv1 = NULL; 220167802Sjkim freedev(adev); 221167802Sjkim } 222151937Sjkim LIST_REMOVE(dev, si_hash); 223151937Sjkim if (dev->si_flags & SI_STASHED) { 224151937Sjkim bzero(dev, sizeof(*dev)); 225250838Sjkim LIST_INSERT_HEAD(&dev_free, dev, si_hash); 226151937Sjkim } else { 227151937Sjkim FREE(dev, M_DEVT); 228151937Sjkim } 229151937Sjkim} 230151937Sjkim 231151937Sjkimudev_t 232151937Sjkimdev2udev(dev_t x) 233151937Sjkim{ 234151937Sjkim if (x == NODEV) 235151937Sjkim return NOUDEV; 236151937Sjkim return (x->si_udev); 237151937Sjkim} 238151937Sjkim 239151937Sjkimdev_t 240151937Sjkimudev2dev(udev_t x, int b) 241151937Sjkim{ 242151937Sjkim 243151937Sjkim if (x == NOUDEV) 244151937Sjkim return (NODEV); 245151937Sjkim switch (b) { 246151937Sjkim case 0: 247151937Sjkim return makedev(umajor(x), uminor(x)); 248151937Sjkim case 1: 249151937Sjkim return (NODEV); 250151937Sjkim default: 251151937Sjkim Debugger("udev2dev(...,X)"); 252250838Sjkim return NODEV; 253151937Sjkim } 254151937Sjkim} 255151937Sjkim 256151937Sjkimint 257250838Sjkimuminor(udev_t dev) 258151937Sjkim{ 259151937Sjkim return(dev & 0xffff00ff); 260151937Sjkim} 261151937Sjkim 262250838Sjkimint 263151937Sjkimumajor(udev_t dev) 264151937Sjkim{ 265151937Sjkim return((dev & 0xff00) >> 8); 266151937Sjkim} 267250838Sjkim 268151937Sjkimudev_t 269151937Sjkimmakeudev(int x, int y) 270151937Sjkim{ 271151937Sjkim return ((x << 8) | y); 272250838Sjkim} 273151937Sjkim 274151937Sjkimdev_t 275151937Sjkimmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 276151937Sjkim{ 277151937Sjkim dev_t dev; 278151937Sjkim va_list ap; 279151937Sjkim int i; 280151937Sjkim 281151937Sjkim dev = makedev(devsw->d_maj, minor); 282151937Sjkim if (dev->si_flags & SI_NAMED) { 283151937Sjkim printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 284151937Sjkim dev->si_name); 285151937Sjkim return (dev); 286151937Sjkim } 287151937Sjkim va_start(ap, fmt); 288151937Sjkim i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 289151937Sjkim dev->si_name[i] = '\0'; 290151937Sjkim va_end(ap); 291151937Sjkim dev->si_devsw = devsw; 292151937Sjkim dev->si_uid = uid; 293151937Sjkim dev->si_gid = gid; 294151937Sjkim dev->si_mode = perms; 295151937Sjkim dev->si_flags |= SI_NAMED; 296151937Sjkim 297151937Sjkim if (devfs_create_hook) 298151937Sjkim devfs_create_hook(dev); 299151937Sjkim return (dev); 300151937Sjkim} 301151937Sjkim 302151937Sjkimdev_t 303151937Sjkimmake_dev_alias(dev_t pdev, char *fmt, ...) 304151937Sjkim{ 305151937Sjkim dev_t dev; 306151937Sjkim va_list ap; 307151937Sjkim int i; 308151937Sjkim 309151937Sjkim dev = allocdev(); 310151937Sjkim dev->si_flags |= SI_ALIAS; 311151937Sjkim dev->si_flags |= SI_NAMED; 312151937Sjkim dev->si_drv1 = pdev; 313151937Sjkim LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash); 314151937Sjkim 315151937Sjkim va_start(ap, fmt); 316151937Sjkim i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 317151937Sjkim dev->si_name[i] = '\0'; 318151937Sjkim va_end(ap); 319151937Sjkim 320151937Sjkim if (devfs_create_hook) 321151937Sjkim devfs_create_hook(dev); 322151937Sjkim return (dev); 323151937Sjkim} 324151937Sjkim 325151937Sjkimvoid 326151937Sjkimdestroy_dev(dev_t dev) 327151937Sjkim{ 328151937Sjkim 329151937Sjkim if (!(dev->si_flags & SI_NAMED)) { 330151937Sjkim printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 331151937Sjkim major(dev), minor(dev)); 332151937Sjkim return; 333243347Sjkim } 334151937Sjkim 335151937Sjkim if (devfs_destroy_hook) 336151937Sjkim devfs_destroy_hook(dev); 337151937Sjkim dev->si_drv1 = 0; 338151937Sjkim dev->si_drv2 = 0; 339151937Sjkim dev->si_devsw = 0; 340151937Sjkim dev->si_flags &= ~SI_NAMED; 341151937Sjkim dev->si_flags &= ~SI_ALIAS; 342151937Sjkim freedev(dev); 343151937Sjkim} 344151937Sjkim 345151937Sjkimconst char * 346243347Sjkimdevtoname(dev_t dev) 347151937Sjkim{ 348151937Sjkim char *p; 349151937Sjkim int mynor; 350151937Sjkim 351151937Sjkim if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 352151937Sjkim p = dev->si_name; 353151937Sjkim if (devsw(dev)) 354151937Sjkim sprintf(p, "#%s/", devsw(dev)->d_name); 355151937Sjkim else 356151937Sjkim sprintf(p, "#%d/", major(dev)); 357151937Sjkim p += strlen(p); 358151937Sjkim mynor = minor(dev); 359151937Sjkim if (mynor < 0 || mynor > 255) 360151937Sjkim sprintf(p, "%#x", (u_int)mynor); 361151937Sjkim else 362151937Sjkim sprintf(p, "%d", mynor); 363151937Sjkim } 364151937Sjkim return (dev->si_name); 365151937Sjkim} 366151937Sjkim 367151937Sjkimint 368151937Sjkimdev_stdclone(char *name, char **namep, char *stem, int *unit) 369151937Sjkim{ 370151937Sjkim int u, i; 371151937Sjkim 372151937Sjkim if (bcmp(stem, name, strlen(stem)) != 0) 373151937Sjkim return (0); 374151937Sjkim i = strlen(stem); 375151937Sjkim if (!isdigit(name[i])) 376151937Sjkim return (0); 377151937Sjkim u = 0; 378151937Sjkim while (isdigit(name[i])) { 379151937Sjkim u *= 10; 380151937Sjkim u += name[i++] - '0'; 381151937Sjkim } 382151937Sjkim *unit = u; 383151937Sjkim if (namep) 384151937Sjkim *namep = &name[i]; 385151937Sjkim if (name[i]) 386151937Sjkim return (2); 387151937Sjkim return (1); 388151937Sjkim} 389151937Sjkim 390151937Sjkim/* 391151937Sjkim * Helper sysctl for devname(3). We're given a {u}dev_t and return 392151937Sjkim * the name, if any, registered by the device driver. 393151937Sjkim */ 394151937Sjkimstatic int 395151937Sjkimsysctl_devname(SYSCTL_HANDLER_ARGS) 396151937Sjkim{ 397151937Sjkim int error; 398243347Sjkim udev_t ud; 399243347Sjkim dev_t dev; 400243347Sjkim 401243347Sjkim error = SYSCTL_IN(req, &ud, sizeof (ud)); 402151937Sjkim if (error) 403151937Sjkim return (error); 404151937Sjkim if (ud == NOUDEV) 405151937Sjkim return(EINVAL); 406151937Sjkim dev = makedev(umajor(ud), uminor(ud)); 407100966Siwasaki if (dev->si_name[0] == '\0') 408100966Siwasaki error = ENOENT; 409100966Siwasaki else 410100966Siwasaki error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 411100966Siwasaki freedev(dev); 412100966Siwasaki return (error); 413100966Siwasaki} 414100966Siwasaki 415100966SiwasakiSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 416100966Siwasaki NULL, 0, sysctl_devname, "", "devname(3) handler"); 417151937Sjkim 418100966Siwasaki