kern_conf.c revision 154029
111126Sjulian/*- 2103722Sphk * Copyright (c) 1999-2002 Poul-Henning Kamp 311126Sjulian * All rights reserved. 411126Sjulian * 511126Sjulian * Redistribution and use in source and binary forms, with or without 611126Sjulian * modification, are permitted provided that the following conditions 711126Sjulian * are met: 811126Sjulian * 1. Redistributions of source code must retain the above copyright 911126Sjulian * notice, this list of conditions and the following disclaimer. 1011126Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1111126Sjulian * notice, this list of conditions and the following disclaimer in the 1211126Sjulian * documentation and/or other materials provided with the distribution. 1311126Sjulian * 14103722Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15103722Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1611126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17103722Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1811126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1911126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2011126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2111126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2211126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2311126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2411126Sjulian * SUCH DAMAGE. 2511126Sjulian */ 2611126Sjulian 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 154029 2006-01-04 17:40:54Z bz $"); 29116182Sobrien 3011126Sjulian#include <sys/param.h> 3148936Sphk#include <sys/kernel.h> 3283366Sjulian#include <sys/systm.h> 33111179Sphk#include <sys/bio.h> 3490737Sgreen#include <sys/lock.h> 3590737Sgreen#include <sys/mutex.h> 3636735Sdfr#include <sys/module.h> 3748936Sphk#include <sys/malloc.h> 3811126Sjulian#include <sys/conf.h> 3912954Sjulian#include <sys/vnode.h> 4048936Sphk#include <sys/queue.h> 41120514Sphk#include <sys/poll.h> 4265374Sphk#include <sys/ctype.h> 43126078Sphk#include <sys/tty.h> 44147982Srwatson#include <sys/ucred.h> 4549535Sphk#include <machine/stdarg.h> 4611126Sjulian 47149144Sphk#include <fs/devfs/devfs_int.h> 48149144Sphk 49131996Sphkstatic MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 5048936Sphk 51150342Sphkstruct mtx devmtx; 52142242Sphkstatic void destroy_devl(struct cdev *dev); 53147982Srwatsonstatic struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr, 54147982Srwatson struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 55147982Srwatson va_list ap); 56126082Sphk 57135600Sphkvoid 58135600Sphkdev_lock(void) 59126082Sphk{ 60151450Sjhb 61126082Sphk mtx_lock(&devmtx); 62126082Sphk} 63126082Sphk 64135600Sphkvoid 65135600Sphkdev_unlock(void) 66126082Sphk{ 67135704Sphk 68126082Sphk mtx_unlock(&devmtx); 69126082Sphk} 70126082Sphk 71126082Sphkvoid 72144385Sphkdev_ref(struct cdev *dev) 73144385Sphk{ 74144385Sphk 75144385Sphk mtx_assert(&devmtx, MA_NOTOWNED); 76144385Sphk mtx_lock(&devmtx); 77144385Sphk dev->si_refcount++; 78144385Sphk mtx_unlock(&devmtx); 79144385Sphk} 80144385Sphk 81144385Sphkvoid 82144384Sphkdev_refl(struct cdev *dev) 83126082Sphk{ 84135704Sphk 85142232Sphk mtx_assert(&devmtx, MA_OWNED); 86126082Sphk dev->si_refcount++; 87126082Sphk} 88126082Sphk 89126082Sphkvoid 90142242Sphkdev_rel(struct cdev *dev) 91126082Sphk{ 92142242Sphk int flag = 0; 93135600Sphk 94136014Sphk mtx_assert(&devmtx, MA_NOTOWNED); 95136014Sphk dev_lock(); 96126082Sphk dev->si_refcount--; 97126082Sphk KASSERT(dev->si_refcount >= 0, 98126082Sphk ("dev_rel(%s) gave negative count", devtoname(dev))); 99150342Sphk#if 0 100142242Sphk if (dev->si_usecount == 0 && 101142242Sphk (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 102150342Sphk ; 103150342Sphk else 104150342Sphk#endif 105154029Sbz if (dev->si_devsw == NULL && dev->si_refcount == 0) { 106126082Sphk LIST_REMOVE(dev, si_list); 107136014Sphk flag = 1; 108136014Sphk } 109136014Sphk dev_unlock(); 110136014Sphk if (flag) 111150342Sphk devfs_free(dev); 112126082Sphk} 113136014Sphk 114135704Sphkstruct cdevsw * 115135704Sphkdev_refthread(struct cdev *dev) 116135704Sphk{ 117135704Sphk struct cdevsw *csw; 118126082Sphk 119135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 120135704Sphk dev_lock(); 121135704Sphk csw = dev->si_devsw; 122135704Sphk if (csw != NULL) 123135704Sphk dev->si_threadcount++; 124135704Sphk dev_unlock(); 125135704Sphk return (csw); 126135704Sphk} 127135704Sphk 128135704Sphkvoid 129135704Sphkdev_relthread(struct cdev *dev) 130135704Sphk{ 131135704Sphk 132135704Sphk mtx_assert(&devmtx, MA_NOTOWNED); 133135704Sphk dev_lock(); 134135704Sphk dev->si_threadcount--; 135135704Sphk dev_unlock(); 136135704Sphk} 137135704Sphk 138120514Sphkint 139120514Sphknullop(void) 140120514Sphk{ 14185603Sphk 142120514Sphk return (0); 143120514Sphk} 144120514Sphk 145120514Sphkint 146120514Sphkeopnotsupp(void) 147120514Sphk{ 148120514Sphk 149120514Sphk return (EOPNOTSUPP); 150120514Sphk} 151120514Sphk 152111179Sphkstatic int 153111179Sphkenxio(void) 154111179Sphk{ 155111179Sphk return (ENXIO); 156111179Sphk} 157111179Sphk 158120514Sphkstatic int 159120514Sphkenodev(void) 160120514Sphk{ 161120514Sphk return (ENODEV); 162120514Sphk} 163120514Sphk 164120514Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 165120514Sphk 166111179Sphk#define dead_open (d_open_t *)enxio 167111179Sphk#define dead_close (d_close_t *)enxio 168111179Sphk#define dead_read (d_read_t *)enxio 169111179Sphk#define dead_write (d_write_t *)enxio 170111179Sphk#define dead_ioctl (d_ioctl_t *)enxio 171120514Sphk#define dead_poll (d_poll_t *)enodev 172120514Sphk#define dead_mmap (d_mmap_t *)enodev 173111179Sphk 174111179Sphkstatic void 175111179Sphkdead_strategy(struct bio *bp) 176111179Sphk{ 177111179Sphk 178111179Sphk biofinish(bp, NULL, ENXIO); 179111179Sphk} 180111179Sphk 181111220Sphk#define dead_dump (dumper_t *)enxio 182111179Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 183111179Sphk 184111179Sphkstatic struct cdevsw dead_cdevsw = { 185126080Sphk .d_version = D_VERSION, 186126080Sphk .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 187111815Sphk .d_open = dead_open, 188111815Sphk .d_close = dead_close, 189111815Sphk .d_read = dead_read, 190111815Sphk .d_write = dead_write, 191111815Sphk .d_ioctl = dead_ioctl, 192111815Sphk .d_poll = dead_poll, 193111815Sphk .d_mmap = dead_mmap, 194111815Sphk .d_strategy = dead_strategy, 195111815Sphk .d_name = "dead", 196111815Sphk .d_dump = dead_dump, 197111815Sphk .d_kqfilter = dead_kqfilter 198111179Sphk}; 199111179Sphk 200120514Sphk/* Default methods if driver does not specify method */ 201111179Sphk 202120514Sphk#define null_open (d_open_t *)nullop 203120514Sphk#define null_close (d_close_t *)nullop 204120514Sphk#define no_read (d_read_t *)enodev 205120514Sphk#define no_write (d_write_t *)enodev 206120514Sphk#define no_ioctl (d_ioctl_t *)enodev 207120514Sphk#define no_mmap (d_mmap_t *)enodev 208133741Sjmg#define no_kqfilter (d_kqfilter_t *)enodev 209120514Sphk 210120514Sphkstatic void 211120514Sphkno_strategy(struct bio *bp) 212120514Sphk{ 213120514Sphk 214120514Sphk biofinish(bp, NULL, ENODEV); 215120514Sphk} 216120514Sphk 217120514Sphkstatic int 218130585Sphkno_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 219120514Sphk{ 220120514Sphk /* 221120514Sphk * Return true for read/write. If the user asked for something 222120514Sphk * special, return POLLNVAL, so that clients have a way of 223120514Sphk * determining reliably whether or not the extended 224120514Sphk * functionality is present without hard-coding knowledge 225120514Sphk * of specific filesystem implementations. 226120514Sphk * Stay in sync with vop_nopoll(). 227120514Sphk */ 228120514Sphk if (events & ~POLLSTANDARD) 229120514Sphk return (POLLNVAL); 230120514Sphk 231120514Sphk return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 232120514Sphk} 233120514Sphk 234120514Sphk#define no_dump (dumper_t *)enodev 235120514Sphk 236149177Sphkstatic int 237149177Sphkgiant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 238149177Sphk{ 239149177Sphk int retval; 240149177Sphk 241149177Sphk mtx_lock(&Giant); 242149177Sphk retval = dev->si_devsw->d_gianttrick-> 243149177Sphk d_open(dev, oflags, devtype, td); 244149177Sphk mtx_unlock(&Giant); 245149177Sphk return (retval); 246149177Sphk} 247149177Sphk 248149177Sphkstatic int 249149177Sphkgiant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx) 250149177Sphk{ 251149177Sphk int retval; 252149177Sphk 253149177Sphk mtx_lock(&Giant); 254149177Sphk retval = dev->si_devsw->d_gianttrick-> 255149177Sphk d_fdopen(dev, oflags, td, fdidx); 256149177Sphk mtx_unlock(&Giant); 257149177Sphk return (retval); 258149177Sphk} 259149177Sphk 260149177Sphkstatic int 261149177Sphkgiant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 262149177Sphk{ 263149177Sphk int retval; 264149177Sphk 265149177Sphk mtx_lock(&Giant); 266149177Sphk retval = dev->si_devsw->d_gianttrick-> 267149177Sphk d_close(dev, fflag, devtype, td); 268149177Sphk mtx_unlock(&Giant); 269149177Sphk return (retval); 270149177Sphk} 271149177Sphk 272149177Sphkstatic void 273149177Sphkgiant_strategy(struct bio *bp) 274149177Sphk{ 275149177Sphk 276149177Sphk mtx_lock(&Giant); 277149177Sphk bp->bio_dev->si_devsw->d_gianttrick-> 278149177Sphk d_strategy(bp); 279149177Sphk mtx_unlock(&Giant); 280149177Sphk} 281149177Sphk 282149177Sphkstatic int 283149177Sphkgiant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 284149177Sphk{ 285149177Sphk int retval; 286149177Sphk 287149177Sphk mtx_lock(&Giant); 288149177Sphk retval = dev->si_devsw->d_gianttrick-> 289149177Sphk d_ioctl(dev, cmd, data, fflag, td); 290149177Sphk mtx_unlock(&Giant); 291149177Sphk return (retval); 292149177Sphk} 293149177Sphk 294149177Sphkstatic int 295149177Sphkgiant_read(struct cdev *dev, struct uio *uio, int ioflag) 296149177Sphk{ 297149177Sphk int retval; 298149177Sphk 299149177Sphk mtx_lock(&Giant); 300149177Sphk retval = dev->si_devsw->d_gianttrick-> 301149177Sphk d_read(dev, uio, ioflag); 302149177Sphk mtx_unlock(&Giant); 303149177Sphk return (retval); 304149177Sphk} 305149177Sphk 306149177Sphkstatic int 307149177Sphkgiant_write(struct cdev *dev, struct uio *uio, int ioflag) 308149177Sphk{ 309149177Sphk int retval; 310149177Sphk 311149177Sphk mtx_lock(&Giant); 312149177Sphk retval = dev->si_devsw->d_gianttrick-> 313149177Sphk d_write(dev, uio, ioflag); 314149177Sphk mtx_unlock(&Giant); 315149177Sphk return (retval); 316149177Sphk} 317149177Sphk 318149177Sphkstatic int 319149177Sphkgiant_poll(struct cdev *dev, int events, struct thread *td) 320149177Sphk{ 321149177Sphk int retval; 322149177Sphk 323149177Sphk mtx_lock(&Giant); 324149177Sphk retval = dev->si_devsw->d_gianttrick-> 325149177Sphk d_poll(dev, events, td); 326149177Sphk mtx_unlock(&Giant); 327149177Sphk return (retval); 328149177Sphk} 329149177Sphk 330149177Sphkstatic int 331149177Sphkgiant_kqfilter(struct cdev *dev, struct knote *kn) 332149177Sphk{ 333149177Sphk int retval; 334149177Sphk 335149177Sphk mtx_lock(&Giant); 336149177Sphk retval = dev->si_devsw->d_gianttrick-> 337149177Sphk d_kqfilter(dev, kn); 338149177Sphk mtx_unlock(&Giant); 339149177Sphk return (retval); 340149177Sphk} 341149177Sphk 342149177Sphkstatic int 343149177Sphkgiant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 344149177Sphk{ 345149177Sphk int retval; 346149177Sphk 347149177Sphk mtx_lock(&Giant); 348149177Sphk retval = dev->si_devsw->d_gianttrick-> 349149177Sphk d_mmap(dev, offset, paddr, nprot); 350149177Sphk mtx_unlock(&Giant); 351149177Sphk return (retval); 352149177Sphk} 353149177Sphk 354149177Sphk 35547640Sphk/* 356130936Sle * struct cdev * and u_dev_t primitives 35747028Sphk */ 35847028Sphk 35947028Sphkint 360130585Sphkminor(struct cdev *x) 36147028Sphk{ 362130640Sphk if (x == NULL) 363130640Sphk return NODEV; 364143631Sphk return(x->si_drv0 & MAXMINOR); 36547028Sphk} 36647028Sphk 36749826Sphkint 368130585Sphkdev2unit(struct cdev *x) 36949826Sphk{ 37049826Sphk 371130640Sphk if (x == NULL) 372130640Sphk return NODEV; 373140964Sphk return (minor2unit(minor(x))); 37449826Sphk} 37549826Sphk 376143282Sphku_int 377143282Sphkminor2unit(u_int _minor) 378140963Sphk{ 379140963Sphk 380140969Sphk KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 381143282Sphk return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 382140963Sphk} 383140963Sphk 384140963Sphkint 38566067Sphkunit2minor(int unit) 38666067Sphk{ 38766067Sphk 38874522Sphk KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 38966067Sphk return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 39066067Sphk} 39166067Sphk 392130585Sphkstatic struct cdev * 393144281Sphknewdev(struct cdevsw *csw, int y, struct cdev *si) 39447028Sphk{ 395140733Sphk struct cdev *si2; 396130640Sphk dev_t udev; 39748936Sphk 398140733Sphk mtx_assert(&devmtx, MA_OWNED); 399144292Sphk udev = y; 400144281Sphk LIST_FOREACH(si2, &csw->d_devs, si_list) { 401143631Sphk if (si2->si_drv0 == udev) { 402150342Sphk devfs_free(si); 403140733Sphk return (si2); 404140733Sphk } 40548936Sphk } 406143631Sphk si->si_drv0 = udev; 407150342Sphk si->si_devsw = csw; 408144281Sphk LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 409125850Sbde return (si); 41047028Sphk} 41147028Sphk 41247028Sphkint 413130640Sphkuminor(dev_t dev) 41447028Sphk{ 415140969Sphk return (dev & MAXMINOR); 41647028Sphk} 41747028Sphk 41847028Sphkint 419130640Sphkumajor(dev_t dev) 42047028Sphk{ 421140969Sphk return ((dev & ~MAXMINOR) >> 8); 42247028Sphk} 42347028Sphk 424125846Sphkstatic void 425144292Sphkfini_cdevsw(struct cdevsw *devsw) 42649535Sphk{ 427149324Sphk struct cdevsw *gt; 42849535Sphk 429149324Sphk if (devsw->d_gianttrick != NULL) { 430149324Sphk gt = devsw->d_gianttrick; 431149324Sphk memcpy(devsw, gt, sizeof *devsw); 432149324Sphk free(gt, M_DEVT); 433149324Sphk devsw->d_gianttrick = NULL; 434149324Sphk } 435126156Sphk devsw->d_flags &= ~D_INIT; 436126082Sphk} 437126082Sphk 438126082Sphkstatic void 439126077Sphkprep_cdevsw(struct cdevsw *devsw) 440126077Sphk{ 441149177Sphk struct cdevsw *dsw2; 442126077Sphk 443149177Sphk if (devsw->d_flags & D_NEEDGIANT) 444149177Sphk dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 445149177Sphk else 446149177Sphk dsw2 = NULL; 447135600Sphk dev_lock(); 448126082Sphk 449143746Sphk if (devsw->d_version != D_VERSION_01) { 450126082Sphk printf( 451126082Sphk "WARNING: Device driver \"%s\" has wrong version %s\n", 452126082Sphk devsw->d_name, "and is disabled. Recompile KLD module."); 453126082Sphk devsw->d_open = dead_open; 454126082Sphk devsw->d_close = dead_close; 455126082Sphk devsw->d_read = dead_read; 456126082Sphk devsw->d_write = dead_write; 457126082Sphk devsw->d_ioctl = dead_ioctl; 458126082Sphk devsw->d_poll = dead_poll; 459126082Sphk devsw->d_mmap = dead_mmap; 460126082Sphk devsw->d_strategy = dead_strategy; 461126082Sphk devsw->d_dump = dead_dump; 462126082Sphk devsw->d_kqfilter = dead_kqfilter; 463126082Sphk } 464126082Sphk 465126078Sphk if (devsw->d_flags & D_TTY) { 466129943Sphk if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 467126078Sphk if (devsw->d_read == NULL) devsw->d_read = ttyread; 468126078Sphk if (devsw->d_write == NULL) devsw->d_write = ttywrite; 469126078Sphk if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 470126078Sphk if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 471126078Sphk } 472126078Sphk 473149177Sphk if (devsw->d_flags & D_NEEDGIANT) { 474149177Sphk if (devsw->d_gianttrick == NULL) { 475149177Sphk memcpy(dsw2, devsw, sizeof *dsw2); 476149177Sphk devsw->d_gianttrick = dsw2; 477149177Sphk } else 478149177Sphk free(dsw2, M_DEVT); 479149177Sphk } 480149177Sphk 481149177Sphk#define FIXUP(member, noop, giant) \ 482149177Sphk do { \ 483149177Sphk if (devsw->member == NULL) { \ 484149177Sphk devsw->member = noop; \ 485149177Sphk } else if (devsw->d_flags & D_NEEDGIANT) \ 486149177Sphk devsw->member = giant; \ 487149177Sphk } \ 488149177Sphk while (0) 489149177Sphk 490149177Sphk FIXUP(d_open, null_open, giant_open); 491149177Sphk FIXUP(d_fdopen, NULL, giant_fdopen); 492149177Sphk FIXUP(d_close, null_close, giant_close); 493149177Sphk FIXUP(d_read, no_read, giant_read); 494149177Sphk FIXUP(d_write, no_write, giant_write); 495149177Sphk FIXUP(d_ioctl, no_ioctl, giant_ioctl); 496149177Sphk FIXUP(d_poll, no_poll, giant_poll); 497149177Sphk FIXUP(d_mmap, no_mmap, giant_mmap); 498149177Sphk FIXUP(d_strategy, no_strategy, giant_strategy); 499149177Sphk FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 500149177Sphk 501120514Sphk if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 502126082Sphk 503126082Sphk LIST_INIT(&devsw->d_devs); 504126082Sphk 505126082Sphk devsw->d_flags |= D_INIT; 506126082Sphk 507135600Sphk dev_unlock(); 508125846Sphk} 509111622Sphk 510147982Srwatsonstatic struct cdev * 511147982Srwatsonmake_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 512147982Srwatson gid_t gid, int mode, const char *fmt, va_list ap) 513125846Sphk{ 514130585Sphk struct cdev *dev; 515125846Sphk int i; 516125846Sphk 517140969Sphk KASSERT((minornr & ~MAXMINOR) == 0, 518126082Sphk ("Invalid minor (0x%x) in make_dev", minornr)); 519126082Sphk 520144385Sphk if (!(devsw->d_flags & D_INIT)) 521126082Sphk prep_cdevsw(devsw); 522150342Sphk dev = devfs_alloc(); 523140733Sphk dev_lock(); 524144281Sphk dev = newdev(devsw, minornr, dev); 525120529Sphk if (dev->si_flags & SI_CHEAPCLONE && 526150342Sphk dev->si_flags & SI_NAMED) { 527120529Sphk /* 528120529Sphk * This is allowed as it removes races and generally 529120529Sphk * simplifies cloning devices. 530126082Sphk * XXX: still ?? 531120529Sphk */ 532140733Sphk dev_unlock(); 533120529Sphk return (dev); 534120529Sphk } 535126082Sphk KASSERT(!(dev->si_flags & SI_NAMED), 536144281Sphk ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 537144281Sphk devsw->d_name, minor(dev), devtoname(dev))); 538126082Sphk 539110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 540110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 541134501Spjd printf("WARNING: Device name truncated! (%s)\n", 542110318Sphk dev->__si_namebuf); 543110318Sphk } 544136947Sphk 54565747Sphk dev->si_flags |= SI_NAMED; 546147982Srwatson if (cr != NULL) 547147982Srwatson dev->si_cred = crhold(cr); 548147982Srwatson else 549147982Srwatson dev->si_cred = NULL; 550144385Sphk dev->si_uid = uid; 551144385Sphk dev->si_gid = gid; 552144385Sphk dev->si_mode = mode; 55350092Sjulian 554111730Sphk devfs_create(dev); 555135600Sphk dev_unlock(); 55649535Sphk return (dev); 55749535Sphk} 55849535Sphk 559147982Srwatsonstruct cdev * 560147982Srwatsonmake_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, 561147982Srwatson const char *fmt, ...) 562147982Srwatson{ 563147982Srwatson struct cdev *dev; 564147982Srwatson va_list ap; 565147982Srwatson 566147982Srwatson va_start(ap, fmt); 567147982Srwatson dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap); 568147982Srwatson va_end(ap); 569147982Srwatson return (dev); 570147982Srwatson} 571147982Srwatson 572147982Srwatsonstruct cdev * 573147982Srwatsonmake_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 574147982Srwatson gid_t gid, int mode, const char *fmt, ...) 575147982Srwatson{ 576147982Srwatson struct cdev *dev; 577147982Srwatson va_list ap; 578147982Srwatson 579147982Srwatson va_start(ap, fmt); 580147982Srwatson dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap); 581147982Srwatson va_end(ap); 582147982Srwatson 583147982Srwatson return (dev); 584147982Srwatson} 585147982Srwatson 586150342Sphkstatic void 587150342Sphkdev_dependsl(struct cdev *pdev, struct cdev *cdev) 588150342Sphk{ 589150342Sphk 590150342Sphk cdev->si_parent = pdev; 591150342Sphk cdev->si_flags |= SI_CHILD; 592150342Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 593150342Sphk} 594150342Sphk 595150342Sphk 59677215Sphkvoid 597130585Sphkdev_depends(struct cdev *pdev, struct cdev *cdev) 59877215Sphk{ 59977215Sphk 600135600Sphk dev_lock(); 601150342Sphk dev_dependsl(pdev, cdev); 602135600Sphk dev_unlock(); 60377215Sphk} 60477215Sphk 605130585Sphkstruct cdev * 606130585Sphkmake_dev_alias(struct cdev *pdev, const char *fmt, ...) 60764880Sphk{ 608130585Sphk struct cdev *dev; 60964880Sphk va_list ap; 61064880Sphk int i; 61164880Sphk 612150342Sphk dev = devfs_alloc(); 613135600Sphk dev_lock(); 61464880Sphk dev->si_flags |= SI_ALIAS; 61565747Sphk dev->si_flags |= SI_NAMED; 61664880Sphk va_start(ap, fmt); 617110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 618110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 619134501Spjd printf("WARNING: Device name truncated! (%s)\n", 620110318Sphk dev->__si_namebuf); 621110318Sphk } 62264880Sphk va_end(ap); 62364880Sphk 624111730Sphk devfs_create(dev); 625135600Sphk dev_unlock(); 626126082Sphk dev_depends(pdev, dev); 62764880Sphk return (dev); 62864880Sphk} 62964880Sphk 630126082Sphkstatic void 631142242Sphkdestroy_devl(struct cdev *dev) 63250549Sphk{ 633135843Sphk struct cdevsw *csw; 634135843Sphk 635142242Sphk mtx_assert(&devmtx, MA_OWNED); 636135843Sphk KASSERT(dev->si_flags & SI_NAMED, 637144281Sphk ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 638154029Sbz 639111730Sphk devfs_destroy(dev); 640126082Sphk 641126082Sphk /* Remove name marking */ 642126077Sphk dev->si_flags &= ~SI_NAMED; 643126077Sphk 644126082Sphk /* If we are a child, remove us from the parents list */ 64577215Sphk if (dev->si_flags & SI_CHILD) { 64677215Sphk LIST_REMOVE(dev, si_siblings); 64777215Sphk dev->si_flags &= ~SI_CHILD; 64877215Sphk } 649126082Sphk 650126082Sphk /* Kill our children */ 65177215Sphk while (!LIST_EMPTY(&dev->si_children)) 652142242Sphk destroy_devl(LIST_FIRST(&dev->si_children)); 653126082Sphk 654126082Sphk /* Remove from clone list */ 655126077Sphk if (dev->si_flags & SI_CLONELIST) { 656126077Sphk LIST_REMOVE(dev, si_clone); 657126077Sphk dev->si_flags &= ~SI_CLONELIST; 658126077Sphk } 659126082Sphk 660135843Sphk csw = dev->si_devsw; 661135934Sgreen dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 662135934Sgreen while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 663135843Sphk printf("Purging %lu threads from %s\n", 664135843Sphk dev->si_threadcount, devtoname(dev)); 665135843Sphk csw->d_purge(dev); 666135843Sphk msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 667135843Sphk } 668135934Sgreen if (csw != NULL && csw->d_purge != NULL) 669135844Sphk printf("All threads purged from %s\n", devtoname(dev)); 670135843Sphk 671135843Sphk dev->si_drv1 = 0; 672135843Sphk dev->si_drv2 = 0; 673135843Sphk bzero(&dev->__si_u, sizeof(dev->__si_u)); 674135843Sphk 675126082Sphk if (!(dev->si_flags & SI_ALIAS)) { 676126082Sphk /* Remove from cdevsw list */ 677126082Sphk LIST_REMOVE(dev, si_list); 678126082Sphk 679150342Sphk /* If cdevsw has no more struct cdev *'s, clean it */ 680135844Sphk if (LIST_EMPTY(&csw->d_devs)) 681135844Sphk fini_cdevsw(csw); 682126082Sphk } 68365747Sphk dev->si_flags &= ~SI_ALIAS; 684135843Sphk 685126082Sphk if (dev->si_refcount > 0) { 686126082Sphk LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 687126082Sphk } else { 688150342Sphk devfs_free(dev); 689126082Sphk } 69050549Sphk} 69150549Sphk 692126082Sphkvoid 693130585Sphkdestroy_dev(struct cdev *dev) 694126082Sphk{ 695126082Sphk 696135600Sphk dev_lock(); 697142242Sphk destroy_devl(dev); 698135600Sphk dev_unlock(); 699126082Sphk} 700126082Sphk 70151225Sbdeconst char * 702130585Sphkdevtoname(struct cdev *dev) 70349982Sbillf{ 70450549Sphk char *p; 705135712Sphk struct cdevsw *csw; 70651225Sbde int mynor; 70749982Sbillf 70850549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 70950549Sphk p = dev->si_name; 710135712Sphk csw = dev_refthread(dev); 711135712Sphk if (csw != NULL) { 712135712Sphk sprintf(p, "(%s)", csw->d_name); 713135712Sphk dev_relthread(dev); 714135712Sphk } 715135712Sphk p += strlen(p); 71651225Sbde mynor = minor(dev); 71751225Sbde if (mynor < 0 || mynor > 255) 718135712Sphk sprintf(p, "/%#x", (u_int)mynor); 71951225Sbde else 720135712Sphk sprintf(p, "/%d", mynor); 72150549Sphk } 72249982Sbillf return (dev->si_name); 72349982Sbillf} 72465374Sphk 72565374Sphkint 72691998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 72765374Sphk{ 72865374Sphk int u, i; 72965374Sphk 73075519Sbrian i = strlen(stem); 73175519Sbrian if (bcmp(stem, name, i) != 0) 73265374Sphk return (0); 73365374Sphk if (!isdigit(name[i])) 73465374Sphk return (0); 73565374Sphk u = 0; 73686461Sphk if (name[i] == '0' && isdigit(name[i+1])) 73786461Sphk return (0); 73865374Sphk while (isdigit(name[i])) { 73965374Sphk u *= 10; 74065374Sphk u += name[i++] - '0'; 74165374Sphk } 742104523Sgreen if (u > 0xffffff) 743104523Sgreen return (0); 74465374Sphk *unit = u; 74565374Sphk if (namep) 74665374Sphk *namep = &name[i]; 74765374Sphk if (name[i]) 74865374Sphk return (2); 74965374Sphk return (1); 75065374Sphk} 75165632Sphk 75265632Sphk/* 753126077Sphk * Helper functions for cloning device drivers. 754126077Sphk * 755126077Sphk * The objective here is to make it unnecessary for the device drivers to 756126077Sphk * use rman or similar to manage their unit number space. Due to the way 757126077Sphk * we do "on-demand" devices, using rman or other "private" methods 758126077Sphk * will be very tricky to lock down properly once we lock down this file. 759126077Sphk * 760130936Sle * Instead we give the drivers these routines which puts the struct cdev *'s 761130936Sle * that are to be managed on their own list, and gives the driver the ability 762126077Sphk * to ask for the first free unit number or a given specified unit number. 763126077Sphk * 764126077Sphk * In addition these routines support paired devices (pty, nmdm and similar) 765126077Sphk * by respecting a number of "flag" bits in the minor number. 766126077Sphk * 767126077Sphk */ 768126077Sphk 769126077Sphkstruct clonedevs { 770126077Sphk LIST_HEAD(,cdev) head; 771126077Sphk}; 772126077Sphk 773126845Sphkvoid 774126845Sphkclone_setup(struct clonedevs **cdp) 775126845Sphk{ 776126845Sphk 777126845Sphk *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 778126845Sphk LIST_INIT(&(*cdp)->head); 779126845Sphk} 780126845Sphk 781126077Sphkint 782130585Sphkclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 783126077Sphk{ 784126077Sphk struct clonedevs *cd; 785140733Sphk struct cdev *dev, *ndev, *dl, *de; 786126077Sphk int unit, low, u; 787126077Sphk 788126845Sphk KASSERT(*cdp != NULL, 789126845Sphk ("clone_setup() not called in driver \"%s\"", csw->d_name)); 790126077Sphk KASSERT(!(extra & CLONE_UNITMASK), 791126845Sphk ("Illegal extra bits (0x%x) in clone_create", extra)); 792126077Sphk KASSERT(*up <= CLONE_UNITMASK, 793126845Sphk ("Too high unit (0x%x) in clone_create", *up)); 794126077Sphk 795142726Sphk if (!(csw->d_flags & D_INIT)) 796142726Sphk prep_cdevsw(csw); 797126077Sphk 798126077Sphk /* 799126077Sphk * Search the list for a lot of things in one go: 800126077Sphk * A preexisting match is returned immediately. 801126077Sphk * The lowest free unit number if we are passed -1, and the place 802126077Sphk * in the list where we should insert that new element. 803126077Sphk * The place to insert a specified unit number, if applicable 804126077Sphk * the end of the list. 805126077Sphk */ 806126077Sphk unit = *up; 807150342Sphk ndev = devfs_alloc(); 808140733Sphk dev_lock(); 809126849Sphk low = extra; 810126077Sphk de = dl = NULL; 811126845Sphk cd = *cdp; 812126077Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 813140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 814140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 815126077Sphk u = dev2unit(dev); 816126077Sphk if (u == (unit | extra)) { 817126077Sphk *dp = dev; 818150342Sphk devfs_free(ndev); 819140733Sphk dev_unlock(); 820126077Sphk return (0); 821126077Sphk } 822126077Sphk if (unit == -1 && u == low) { 823126077Sphk low++; 824126077Sphk de = dev; 825126077Sphk continue; 826150793Sphk } else if (u < (unit | extra)) { 827150793Sphk de = dev; 828150793Sphk continue; 829150793Sphk } else if (u > (unit | extra)) { 830126077Sphk dl = dev; 831126077Sphk break; 832126077Sphk } 833126077Sphk } 834126077Sphk if (unit == -1) 835126849Sphk unit = low & CLONE_UNITMASK; 836144281Sphk dev = newdev(csw, unit2minor(unit | extra), ndev); 837140733Sphk if (dev->si_flags & SI_CLONELIST) { 838140733Sphk printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 839150793Sphk printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 840140733Sphk LIST_FOREACH(dev, &cd->head, si_clone) { 841140733Sphk printf("\t%p %s\n", dev, dev->si_name); 842140733Sphk } 843140733Sphk panic("foo"); 844140733Sphk } 845126077Sphk KASSERT(!(dev->si_flags & SI_CLONELIST), 846140733Sphk ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 847126077Sphk if (dl != NULL) 848126077Sphk LIST_INSERT_BEFORE(dl, dev, si_clone); 849126077Sphk else if (de != NULL) 850126077Sphk LIST_INSERT_AFTER(de, dev, si_clone); 851126077Sphk else 852126077Sphk LIST_INSERT_HEAD(&cd->head, dev, si_clone); 853126077Sphk dev->si_flags |= SI_CLONELIST; 854126077Sphk *up = unit; 855140733Sphk dev_unlock(); 856126077Sphk return (1); 857126077Sphk} 858126077Sphk 859126077Sphk/* 860126077Sphk * Kill everything still on the list. The driver should already have 861130585Sphk * disposed of any softc hung of the struct cdev *'s at this time. 862126077Sphk */ 863126077Sphkvoid 864126077Sphkclone_cleanup(struct clonedevs **cdp) 865126077Sphk{ 866130585Sphk struct cdev *dev, *tdev; 867126077Sphk struct clonedevs *cd; 868126077Sphk 869126077Sphk cd = *cdp; 870126077Sphk if (cd == NULL) 871126077Sphk return; 872140733Sphk dev_lock(); 873126077Sphk LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 874140733Sphk KASSERT(dev->si_flags & SI_CLONELIST, 875140733Sphk ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 876126077Sphk KASSERT(dev->si_flags & SI_NAMED, 877143631Sphk ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 878142242Sphk destroy_devl(dev); 879126077Sphk } 880140733Sphk dev_unlock(); 881126077Sphk free(cd, M_DEVBUF); 882126077Sphk *cdp = NULL; 883126077Sphk} 884