126453f35SJulian Elischer /*- 266cdbc28SPoul-Henning Kamp * Copyright (c) 1999-2002 Poul-Henning Kamp 326453f35SJulian Elischer * All rights reserved. 426453f35SJulian Elischer * 526453f35SJulian Elischer * Redistribution and use in source and binary forms, with or without 626453f35SJulian Elischer * modification, are permitted provided that the following conditions 726453f35SJulian Elischer * are met: 826453f35SJulian Elischer * 1. Redistributions of source code must retain the above copyright 926453f35SJulian Elischer * notice, this list of conditions and the following disclaimer. 1026453f35SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 1126453f35SJulian Elischer * notice, this list of conditions and the following disclaimer in the 1226453f35SJulian Elischer * documentation and/or other materials provided with the distribution. 1326453f35SJulian Elischer * 1466cdbc28SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1566cdbc28SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626453f35SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1766cdbc28SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1826453f35SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926453f35SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026453f35SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126453f35SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226453f35SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326453f35SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426453f35SJulian Elischer * SUCH DAMAGE. 2526453f35SJulian Elischer */ 2626453f35SJulian Elischer 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 3026453f35SJulian Elischer #include <sys/param.h> 31698bfad7SPoul-Henning Kamp #include <sys/kernel.h> 32f8a760b3SJulian Elischer #include <sys/systm.h> 3302574b19SPoul-Henning Kamp #include <sys/bio.h> 341b567820SBrian Feldman #include <sys/lock.h> 351b567820SBrian Feldman #include <sys/mutex.h> 36ecbb00a2SDoug Rabson #include <sys/module.h> 37698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 3826453f35SJulian Elischer #include <sys/conf.h> 391dfcbb0cSJulian Elischer #include <sys/vnode.h> 40698bfad7SPoul-Henning Kamp #include <sys/queue.h> 41b2941431SPoul-Henning Kamp #include <sys/poll.h> 42db901281SPoul-Henning Kamp #include <sys/ctype.h> 438e1f1df0SPoul-Henning Kamp #include <sys/tty.h> 44d26dd2d9SRobert Watson #include <sys/ucred.h> 450ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 461dfcbb0cSJulian Elischer 479c0af131SPoul-Henning Kamp #include <fs/devfs/devfs_int.h> 489c0af131SPoul-Henning Kamp 499ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 50698bfad7SPoul-Henning Kamp 51e606a3c6SPoul-Henning Kamp struct mtx devmtx; 52aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev); 53d26dd2d9SRobert Watson static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr, 54d26dd2d9SRobert Watson struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 55d26dd2d9SRobert Watson va_list ap); 56f3732fd1SPoul-Henning Kamp 57a0e78d2eSPoul-Henning Kamp void 58a0e78d2eSPoul-Henning Kamp dev_lock(void) 59cd690b60SPoul-Henning Kamp { 60cd690b60SPoul-Henning Kamp if (!mtx_initialized(&devmtx)) 619ef295b7SPoul-Henning Kamp mtx_init(&devmtx, "cdev", NULL, MTX_DEF); 62cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 63cd690b60SPoul-Henning Kamp } 64cd690b60SPoul-Henning Kamp 65a0e78d2eSPoul-Henning Kamp void 66a0e78d2eSPoul-Henning Kamp dev_unlock(void) 67cd690b60SPoul-Henning Kamp { 682c15afd8SPoul-Henning Kamp 69cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 70cd690b60SPoul-Henning Kamp } 71cd690b60SPoul-Henning Kamp 72cd690b60SPoul-Henning Kamp void 739477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 749477d73eSPoul-Henning Kamp { 759477d73eSPoul-Henning Kamp 769477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 779477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 789477d73eSPoul-Henning Kamp dev->si_refcount++; 799477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 809477d73eSPoul-Henning Kamp } 819477d73eSPoul-Henning Kamp 829477d73eSPoul-Henning Kamp void 83eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 84cd690b60SPoul-Henning Kamp { 852c15afd8SPoul-Henning Kamp 861a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 87cd690b60SPoul-Henning Kamp dev->si_refcount++; 88cd690b60SPoul-Henning Kamp } 89cd690b60SPoul-Henning Kamp 90cd690b60SPoul-Henning Kamp void 91aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 92cd690b60SPoul-Henning Kamp { 93aa2f6ddcSPoul-Henning Kamp int flag = 0; 94a0e78d2eSPoul-Henning Kamp 95ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 96ba285125SPoul-Henning Kamp dev_lock(); 97cd690b60SPoul-Henning Kamp dev->si_refcount--; 98cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 99cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 100e606a3c6SPoul-Henning Kamp #if 0 101aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 102aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 103e606a3c6SPoul-Henning Kamp ; 104e606a3c6SPoul-Henning Kamp else 105e606a3c6SPoul-Henning Kamp #endif 106cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 107cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 108ba285125SPoul-Henning Kamp flag = 1; 109ba285125SPoul-Henning Kamp } 110ba285125SPoul-Henning Kamp dev_unlock(); 111ba285125SPoul-Henning Kamp if (flag) 112e606a3c6SPoul-Henning Kamp devfs_free(dev); 113cd690b60SPoul-Henning Kamp } 114ba285125SPoul-Henning Kamp 1152c15afd8SPoul-Henning Kamp struct cdevsw * 1162c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev) 1172c15afd8SPoul-Henning Kamp { 1182c15afd8SPoul-Henning Kamp struct cdevsw *csw; 1192c15afd8SPoul-Henning Kamp 1202c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1212c15afd8SPoul-Henning Kamp dev_lock(); 1222c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 1232c15afd8SPoul-Henning Kamp if (csw != NULL) 1242c15afd8SPoul-Henning Kamp dev->si_threadcount++; 1252c15afd8SPoul-Henning Kamp dev_unlock(); 1262c15afd8SPoul-Henning Kamp return (csw); 1272c15afd8SPoul-Henning Kamp } 1282c15afd8SPoul-Henning Kamp 1292c15afd8SPoul-Henning Kamp void 1302c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 1312c15afd8SPoul-Henning Kamp { 1322c15afd8SPoul-Henning Kamp 1332c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1342c15afd8SPoul-Henning Kamp dev_lock(); 1352c15afd8SPoul-Henning Kamp dev->si_threadcount--; 1362c15afd8SPoul-Henning Kamp dev_unlock(); 1372c15afd8SPoul-Henning Kamp } 138cd690b60SPoul-Henning Kamp 139b2941431SPoul-Henning Kamp int 140b2941431SPoul-Henning Kamp nullop(void) 141b2941431SPoul-Henning Kamp { 142b2941431SPoul-Henning Kamp 143b2941431SPoul-Henning Kamp return (0); 144b2941431SPoul-Henning Kamp } 145b2941431SPoul-Henning Kamp 146b2941431SPoul-Henning Kamp int 147b2941431SPoul-Henning Kamp eopnotsupp(void) 148b2941431SPoul-Henning Kamp { 149b2941431SPoul-Henning Kamp 150b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 151b2941431SPoul-Henning Kamp } 15202574b19SPoul-Henning Kamp 15302574b19SPoul-Henning Kamp static int 15402574b19SPoul-Henning Kamp enxio(void) 15502574b19SPoul-Henning Kamp { 15602574b19SPoul-Henning Kamp return (ENXIO); 15702574b19SPoul-Henning Kamp } 15802574b19SPoul-Henning Kamp 159b2941431SPoul-Henning Kamp static int 160b2941431SPoul-Henning Kamp enodev(void) 161b2941431SPoul-Henning Kamp { 162b2941431SPoul-Henning Kamp return (ENODEV); 163b2941431SPoul-Henning Kamp } 164b2941431SPoul-Henning Kamp 165b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 166b2941431SPoul-Henning Kamp 16702574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 16802574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 16902574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 17002574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 17102574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 172b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 173b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 17402574b19SPoul-Henning Kamp 17502574b19SPoul-Henning Kamp static void 17602574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 17702574b19SPoul-Henning Kamp { 17802574b19SPoul-Henning Kamp 17902574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 18002574b19SPoul-Henning Kamp } 18102574b19SPoul-Henning Kamp 1822c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 18302574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 18402574b19SPoul-Henning Kamp 18502574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 186dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 187dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 1887ac40f5fSPoul-Henning Kamp .d_open = dead_open, 1897ac40f5fSPoul-Henning Kamp .d_close = dead_close, 1907ac40f5fSPoul-Henning Kamp .d_read = dead_read, 1917ac40f5fSPoul-Henning Kamp .d_write = dead_write, 1927ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 1937ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 1947ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 1957ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 1967ac40f5fSPoul-Henning Kamp .d_name = "dead", 1977ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 1987ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 19902574b19SPoul-Henning Kamp }; 20002574b19SPoul-Henning Kamp 201b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 202b2941431SPoul-Henning Kamp 203b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 204b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 205b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 206b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 207b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 208b2941431SPoul-Henning Kamp #define no_mmap (d_mmap_t *)enodev 209ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 210b2941431SPoul-Henning Kamp 211b2941431SPoul-Henning Kamp static void 212b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 213b2941431SPoul-Henning Kamp { 214b2941431SPoul-Henning Kamp 215b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 216b2941431SPoul-Henning Kamp } 217b2941431SPoul-Henning Kamp 218b2941431SPoul-Henning Kamp static int 21989c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 220b2941431SPoul-Henning Kamp { 221b2941431SPoul-Henning Kamp /* 222b2941431SPoul-Henning Kamp * Return true for read/write. If the user asked for something 223b2941431SPoul-Henning Kamp * special, return POLLNVAL, so that clients have a way of 224b2941431SPoul-Henning Kamp * determining reliably whether or not the extended 225b2941431SPoul-Henning Kamp * functionality is present without hard-coding knowledge 226b2941431SPoul-Henning Kamp * of specific filesystem implementations. 227b2941431SPoul-Henning Kamp * Stay in sync with vop_nopoll(). 228b2941431SPoul-Henning Kamp */ 229b2941431SPoul-Henning Kamp if (events & ~POLLSTANDARD) 230b2941431SPoul-Henning Kamp return (POLLNVAL); 231b2941431SPoul-Henning Kamp 232b2941431SPoul-Henning Kamp return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 233b2941431SPoul-Henning Kamp } 234b2941431SPoul-Henning Kamp 235b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 2364e4a7663SPoul-Henning Kamp 237516ad423SPoul-Henning Kamp static int 238516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 239516ad423SPoul-Henning Kamp { 240516ad423SPoul-Henning Kamp int retval; 241516ad423SPoul-Henning Kamp 242516ad423SPoul-Henning Kamp mtx_lock(&Giant); 243516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 244516ad423SPoul-Henning Kamp d_open(dev, oflags, devtype, td); 245516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 246516ad423SPoul-Henning Kamp return (retval); 247516ad423SPoul-Henning Kamp } 248516ad423SPoul-Henning Kamp 249516ad423SPoul-Henning Kamp static int 250516ad423SPoul-Henning Kamp giant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx) 251516ad423SPoul-Henning Kamp { 252516ad423SPoul-Henning Kamp int retval; 253516ad423SPoul-Henning Kamp 254516ad423SPoul-Henning Kamp mtx_lock(&Giant); 255516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 256516ad423SPoul-Henning Kamp d_fdopen(dev, oflags, td, fdidx); 257516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 258516ad423SPoul-Henning Kamp return (retval); 259516ad423SPoul-Henning Kamp } 260516ad423SPoul-Henning Kamp 261516ad423SPoul-Henning Kamp static int 262516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 263516ad423SPoul-Henning Kamp { 264516ad423SPoul-Henning Kamp int retval; 265516ad423SPoul-Henning Kamp 266516ad423SPoul-Henning Kamp mtx_lock(&Giant); 267516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 268516ad423SPoul-Henning Kamp d_close(dev, fflag, devtype, td); 269516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 270516ad423SPoul-Henning Kamp return (retval); 271516ad423SPoul-Henning Kamp } 272516ad423SPoul-Henning Kamp 273516ad423SPoul-Henning Kamp static void 274516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 275516ad423SPoul-Henning Kamp { 276516ad423SPoul-Henning Kamp 277516ad423SPoul-Henning Kamp mtx_lock(&Giant); 278516ad423SPoul-Henning Kamp bp->bio_dev->si_devsw->d_gianttrick-> 279516ad423SPoul-Henning Kamp d_strategy(bp); 280516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 281516ad423SPoul-Henning Kamp } 282516ad423SPoul-Henning Kamp 283516ad423SPoul-Henning Kamp static int 284516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 285516ad423SPoul-Henning Kamp { 286516ad423SPoul-Henning Kamp int retval; 287516ad423SPoul-Henning Kamp 288516ad423SPoul-Henning Kamp mtx_lock(&Giant); 289516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 290516ad423SPoul-Henning Kamp d_ioctl(dev, cmd, data, fflag, td); 291516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 292516ad423SPoul-Henning Kamp return (retval); 293516ad423SPoul-Henning Kamp } 294516ad423SPoul-Henning Kamp 295516ad423SPoul-Henning Kamp static int 296516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 297516ad423SPoul-Henning Kamp { 298516ad423SPoul-Henning Kamp int retval; 299516ad423SPoul-Henning Kamp 300516ad423SPoul-Henning Kamp mtx_lock(&Giant); 301516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 302516ad423SPoul-Henning Kamp d_read(dev, uio, ioflag); 303516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 304516ad423SPoul-Henning Kamp return (retval); 305516ad423SPoul-Henning Kamp } 306516ad423SPoul-Henning Kamp 307516ad423SPoul-Henning Kamp static int 308516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 309516ad423SPoul-Henning Kamp { 310516ad423SPoul-Henning Kamp int retval; 311516ad423SPoul-Henning Kamp 312516ad423SPoul-Henning Kamp mtx_lock(&Giant); 313516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 314516ad423SPoul-Henning Kamp d_write(dev, uio, ioflag); 315516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 316516ad423SPoul-Henning Kamp return (retval); 317516ad423SPoul-Henning Kamp } 318516ad423SPoul-Henning Kamp 319516ad423SPoul-Henning Kamp static int 320516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 321516ad423SPoul-Henning Kamp { 322516ad423SPoul-Henning Kamp int retval; 323516ad423SPoul-Henning Kamp 324516ad423SPoul-Henning Kamp mtx_lock(&Giant); 325516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 326516ad423SPoul-Henning Kamp d_poll(dev, events, td); 327516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 328516ad423SPoul-Henning Kamp return (retval); 329516ad423SPoul-Henning Kamp } 330516ad423SPoul-Henning Kamp 331516ad423SPoul-Henning Kamp static int 332516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 333516ad423SPoul-Henning Kamp { 334516ad423SPoul-Henning Kamp int retval; 335516ad423SPoul-Henning Kamp 336516ad423SPoul-Henning Kamp mtx_lock(&Giant); 337516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 338516ad423SPoul-Henning Kamp d_kqfilter(dev, kn); 339516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 340516ad423SPoul-Henning Kamp return (retval); 341516ad423SPoul-Henning Kamp } 342516ad423SPoul-Henning Kamp 343516ad423SPoul-Henning Kamp static int 344516ad423SPoul-Henning Kamp giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 345516ad423SPoul-Henning Kamp { 346516ad423SPoul-Henning Kamp int retval; 347516ad423SPoul-Henning Kamp 348516ad423SPoul-Henning Kamp mtx_lock(&Giant); 349516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 350516ad423SPoul-Henning Kamp d_mmap(dev, offset, paddr, nprot); 351516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 352516ad423SPoul-Henning Kamp return (retval); 353516ad423SPoul-Henning Kamp } 354516ad423SPoul-Henning Kamp 355516ad423SPoul-Henning Kamp 3562447bec8SPoul-Henning Kamp /* 35789c9c53dSPoul-Henning Kamp * struct cdev * and u_dev_t primitives 358bfbb9ce6SPoul-Henning Kamp */ 359bfbb9ce6SPoul-Henning Kamp 360bfbb9ce6SPoul-Henning Kamp int 36189c9c53dSPoul-Henning Kamp minor(struct cdev *x) 362bfbb9ce6SPoul-Henning Kamp { 363f3732fd1SPoul-Henning Kamp if (x == NULL) 364f3732fd1SPoul-Henning Kamp return NODEV; 3650a2e49f1SPoul-Henning Kamp return(x->si_drv0 & MAXMINOR); 366bfbb9ce6SPoul-Henning Kamp } 367bfbb9ce6SPoul-Henning Kamp 3689a27d579SPoul-Henning Kamp int 36989c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x) 3709a27d579SPoul-Henning Kamp { 3719a27d579SPoul-Henning Kamp 372f3732fd1SPoul-Henning Kamp if (x == NULL) 373f3732fd1SPoul-Henning Kamp return NODEV; 37437085a39SPoul-Henning Kamp return (minor2unit(minor(x))); 3753a85fd26SPoul-Henning Kamp } 3763a85fd26SPoul-Henning Kamp 3773238ec33SPoul-Henning Kamp u_int 3783238ec33SPoul-Henning Kamp minor2unit(u_int _minor) 3793a85fd26SPoul-Henning Kamp { 3803a85fd26SPoul-Henning Kamp 381d9aaa28fSPoul-Henning Kamp KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 3823238ec33SPoul-Henning Kamp return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 3839a27d579SPoul-Henning Kamp } 3849a27d579SPoul-Henning Kamp 385b0d17ba6SPoul-Henning Kamp int 386b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 387b0d17ba6SPoul-Henning Kamp { 388b0d17ba6SPoul-Henning Kamp 38915b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 390b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 391b0d17ba6SPoul-Henning Kamp } 392b0d17ba6SPoul-Henning Kamp 39389c9c53dSPoul-Henning Kamp static struct cdev * 394ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si) 3953f54a085SPoul-Henning Kamp { 396027b1f71SPoul-Henning Kamp struct cdev *si2; 397f3732fd1SPoul-Henning Kamp dev_t udev; 3983f54a085SPoul-Henning Kamp 399027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 400b3d82c03SPoul-Henning Kamp udev = y; 401ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 4020a2e49f1SPoul-Henning Kamp if (si2->si_drv0 == udev) { 403e606a3c6SPoul-Henning Kamp devfs_free(si); 404027b1f71SPoul-Henning Kamp return (si2); 4053f54a085SPoul-Henning Kamp } 406027b1f71SPoul-Henning Kamp } 4070a2e49f1SPoul-Henning Kamp si->si_drv0 = udev; 408e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 409ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 410698bfad7SPoul-Henning Kamp return (si); 411bfbb9ce6SPoul-Henning Kamp } 412bfbb9ce6SPoul-Henning Kamp 413bfbb9ce6SPoul-Henning Kamp int 414f3732fd1SPoul-Henning Kamp uminor(dev_t dev) 415bfbb9ce6SPoul-Henning Kamp { 416d9aaa28fSPoul-Henning Kamp return (dev & MAXMINOR); 417bfbb9ce6SPoul-Henning Kamp } 418bfbb9ce6SPoul-Henning Kamp 419bfbb9ce6SPoul-Henning Kamp int 420f3732fd1SPoul-Henning Kamp umajor(dev_t dev) 421bfbb9ce6SPoul-Henning Kamp { 422d9aaa28fSPoul-Henning Kamp return ((dev & ~MAXMINOR) >> 8); 423bfbb9ce6SPoul-Henning Kamp } 424bfbb9ce6SPoul-Henning Kamp 4252a3faf2fSPoul-Henning Kamp static void 426cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 427cd690b60SPoul-Henning Kamp { 4281d45c50eSPoul-Henning Kamp struct cdevsw *gt; 429b3d82c03SPoul-Henning Kamp 4301d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 4311d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 4321d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 4331d45c50eSPoul-Henning Kamp free(gt, M_DEVT); 434516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 4351d45c50eSPoul-Henning Kamp } 436652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 437b0b03348SPoul-Henning Kamp } 438b0b03348SPoul-Henning Kamp 439b0b03348SPoul-Henning Kamp static void 440b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw) 441b0b03348SPoul-Henning Kamp { 442516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 443b0b03348SPoul-Henning Kamp 444516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) 445516ad423SPoul-Henning Kamp dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 446516ad423SPoul-Henning Kamp else 447516ad423SPoul-Henning Kamp dsw2 = NULL; 448a0e78d2eSPoul-Henning Kamp dev_lock(); 449cd690b60SPoul-Henning Kamp 450800b42bdSPoul-Henning Kamp if (devsw->d_version != D_VERSION_01) { 451cd690b60SPoul-Henning Kamp printf( 452cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 453cd690b60SPoul-Henning Kamp devsw->d_name, "and is disabled. Recompile KLD module."); 454cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 455cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 456cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 457cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 458cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 459cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 460cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 461cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 462cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 463cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 464cd690b60SPoul-Henning Kamp } 465cd690b60SPoul-Henning Kamp 4668e1f1df0SPoul-Henning Kamp if (devsw->d_flags & D_TTY) { 4673a95025fSPoul-Henning Kamp if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 4688e1f1df0SPoul-Henning Kamp if (devsw->d_read == NULL) devsw->d_read = ttyread; 4698e1f1df0SPoul-Henning Kamp if (devsw->d_write == NULL) devsw->d_write = ttywrite; 4708e1f1df0SPoul-Henning Kamp if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 4718e1f1df0SPoul-Henning Kamp if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 4728e1f1df0SPoul-Henning Kamp } 4738e1f1df0SPoul-Henning Kamp 474516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 475516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 476516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 477516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 478516ad423SPoul-Henning Kamp } else 479516ad423SPoul-Henning Kamp free(dsw2, M_DEVT); 480516ad423SPoul-Henning Kamp } 481516ad423SPoul-Henning Kamp 482516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 483516ad423SPoul-Henning Kamp do { \ 484516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 485516ad423SPoul-Henning Kamp devsw->member = noop; \ 486516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 487516ad423SPoul-Henning Kamp devsw->member = giant; \ 488516ad423SPoul-Henning Kamp } \ 489516ad423SPoul-Henning Kamp while (0) 490516ad423SPoul-Henning Kamp 491516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 492516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 493516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 494516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 495516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 496516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 497516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 498516ad423SPoul-Henning Kamp FIXUP(d_mmap, no_mmap, giant_mmap); 499516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 500516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 501516ad423SPoul-Henning Kamp 502b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 503cd690b60SPoul-Henning Kamp 504cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 505cd690b60SPoul-Henning Kamp 506cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 507cd690b60SPoul-Henning Kamp 508a0e78d2eSPoul-Henning Kamp dev_unlock(); 5092a3faf2fSPoul-Henning Kamp } 51011586717SBrian Somers 511d26dd2d9SRobert Watson static struct cdev * 512d26dd2d9SRobert Watson make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 513d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, va_list ap) 5142a3faf2fSPoul-Henning Kamp { 51589c9c53dSPoul-Henning Kamp struct cdev *dev; 5162a3faf2fSPoul-Henning Kamp int i; 5172a3faf2fSPoul-Henning Kamp 518d9aaa28fSPoul-Henning Kamp KASSERT((minornr & ~MAXMINOR) == 0, 519cd690b60SPoul-Henning Kamp ("Invalid minor (0x%x) in make_dev", minornr)); 520cd690b60SPoul-Henning Kamp 5219477d73eSPoul-Henning Kamp if (!(devsw->d_flags & D_INIT)) 5222a3faf2fSPoul-Henning Kamp prep_cdevsw(devsw); 523e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 524027b1f71SPoul-Henning Kamp dev_lock(); 525ff7284eeSPoul-Henning Kamp dev = newdev(devsw, minornr, dev); 52698c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 527e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 52898c469d4SPoul-Henning Kamp /* 52998c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 53098c469d4SPoul-Henning Kamp * simplifies cloning devices. 531cd690b60SPoul-Henning Kamp * XXX: still ?? 53298c469d4SPoul-Henning Kamp */ 533027b1f71SPoul-Henning Kamp dev_unlock(); 53498c469d4SPoul-Henning Kamp return (dev); 53598c469d4SPoul-Henning Kamp } 536cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 537ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 538ff7284eeSPoul-Henning Kamp devsw->d_name, minor(dev), devtoname(dev))); 539cd690b60SPoul-Henning Kamp 5406334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 5416334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 5422e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 5436334a663SPoul-Henning Kamp dev->__si_namebuf); 5446334a663SPoul-Henning Kamp } 5451a1b2800SPoul-Henning Kamp 5465ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 547d26dd2d9SRobert Watson if (cr != NULL) 548d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 549d26dd2d9SRobert Watson else 550d26dd2d9SRobert Watson dev->si_cred = NULL; 5519477d73eSPoul-Henning Kamp dev->si_uid = uid; 5529477d73eSPoul-Henning Kamp dev->si_gid = gid; 5539477d73eSPoul-Henning Kamp dev->si_mode = mode; 5541744fcd0SJulian Elischer 5559285a87eSPoul-Henning Kamp devfs_create(dev); 556a0e78d2eSPoul-Henning Kamp dev_unlock(); 5573f54a085SPoul-Henning Kamp return (dev); 5583f54a085SPoul-Henning Kamp } 5593f54a085SPoul-Henning Kamp 560d26dd2d9SRobert Watson struct cdev * 561d26dd2d9SRobert Watson make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, 562d26dd2d9SRobert Watson const char *fmt, ...) 563d26dd2d9SRobert Watson { 564d26dd2d9SRobert Watson struct cdev *dev; 565d26dd2d9SRobert Watson va_list ap; 566d26dd2d9SRobert Watson 567d26dd2d9SRobert Watson va_start(ap, fmt); 568d26dd2d9SRobert Watson dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap); 569d26dd2d9SRobert Watson va_end(ap); 570d26dd2d9SRobert Watson return (dev); 571d26dd2d9SRobert Watson } 572d26dd2d9SRobert Watson 573d26dd2d9SRobert Watson struct cdev * 574d26dd2d9SRobert Watson make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 575d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 576d26dd2d9SRobert Watson { 577d26dd2d9SRobert Watson struct cdev *dev; 578d26dd2d9SRobert Watson va_list ap; 579d26dd2d9SRobert Watson 580d26dd2d9SRobert Watson va_start(ap, fmt); 581d26dd2d9SRobert Watson dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap); 582d26dd2d9SRobert Watson va_end(ap); 583d26dd2d9SRobert Watson 584d26dd2d9SRobert Watson return (dev); 585d26dd2d9SRobert Watson } 586d26dd2d9SRobert Watson 587e606a3c6SPoul-Henning Kamp static void 588e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 589e606a3c6SPoul-Henning Kamp { 590e606a3c6SPoul-Henning Kamp 591e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 592e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 593e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 594e606a3c6SPoul-Henning Kamp } 595e606a3c6SPoul-Henning Kamp 596e606a3c6SPoul-Henning Kamp 5973344c5a1SPoul-Henning Kamp void 59889c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 5993344c5a1SPoul-Henning Kamp { 6003344c5a1SPoul-Henning Kamp 601a0e78d2eSPoul-Henning Kamp dev_lock(); 602e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 603a0e78d2eSPoul-Henning Kamp dev_unlock(); 6043344c5a1SPoul-Henning Kamp } 6053344c5a1SPoul-Henning Kamp 60689c9c53dSPoul-Henning Kamp struct cdev * 60789c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 6083f54a085SPoul-Henning Kamp { 60989c9c53dSPoul-Henning Kamp struct cdev *dev; 6103f54a085SPoul-Henning Kamp va_list ap; 6113f54a085SPoul-Henning Kamp int i; 6123f54a085SPoul-Henning Kamp 613e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 614a0e78d2eSPoul-Henning Kamp dev_lock(); 6153f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 6165ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 6173f54a085SPoul-Henning Kamp va_start(ap, fmt); 6186334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 6196334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 6202e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 6216334a663SPoul-Henning Kamp dev->__si_namebuf); 6226334a663SPoul-Henning Kamp } 6233f54a085SPoul-Henning Kamp va_end(ap); 6243f54a085SPoul-Henning Kamp 6259285a87eSPoul-Henning Kamp devfs_create(dev); 626a0e78d2eSPoul-Henning Kamp dev_unlock(); 627cd690b60SPoul-Henning Kamp dev_depends(pdev, dev); 6280ef1c826SPoul-Henning Kamp return (dev); 6290ef1c826SPoul-Henning Kamp } 6300ef1c826SPoul-Henning Kamp 631cd690b60SPoul-Henning Kamp static void 632aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 633d137acccSPoul-Henning Kamp { 634743cd76aSPoul-Henning Kamp struct cdevsw *csw; 635743cd76aSPoul-Henning Kamp 636aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 637743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 638ff7284eeSPoul-Henning Kamp ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 6395ef2707eSPoul-Henning Kamp 6409285a87eSPoul-Henning Kamp devfs_destroy(dev); 641cd690b60SPoul-Henning Kamp 642cd690b60SPoul-Henning Kamp /* Remove name marking */ 643b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 644b0b03348SPoul-Henning Kamp 645cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 6463344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 6473344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 6483344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 6493344c5a1SPoul-Henning Kamp } 650cd690b60SPoul-Henning Kamp 651cd690b60SPoul-Henning Kamp /* Kill our children */ 6523344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 653aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 654cd690b60SPoul-Henning Kamp 655cd690b60SPoul-Henning Kamp /* Remove from clone list */ 656b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 657b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 658b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 659b0b03348SPoul-Henning Kamp } 660cd690b60SPoul-Henning Kamp 661743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 6621abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 6631abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 664743cd76aSPoul-Henning Kamp printf("Purging %lu threads from %s\n", 665743cd76aSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 666743cd76aSPoul-Henning Kamp csw->d_purge(dev); 667743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 668743cd76aSPoul-Henning Kamp } 6691abf2c36SBrian Feldman if (csw != NULL && csw->d_purge != NULL) 670a5993c33SPoul-Henning Kamp printf("All threads purged from %s\n", devtoname(dev)); 671743cd76aSPoul-Henning Kamp 672743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 673743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 674743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 675743cd76aSPoul-Henning Kamp 676cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 677cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 678cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 679cd690b60SPoul-Henning Kamp 680e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 681a5993c33SPoul-Henning Kamp if (LIST_EMPTY(&csw->d_devs)) 682a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 683cd690b60SPoul-Henning Kamp } 6845ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 685743cd76aSPoul-Henning Kamp 686cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 687cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 688cd690b60SPoul-Henning Kamp } else { 689e606a3c6SPoul-Henning Kamp devfs_free(dev); 690d137acccSPoul-Henning Kamp } 691cd690b60SPoul-Henning Kamp } 692cd690b60SPoul-Henning Kamp 693cd690b60SPoul-Henning Kamp void 69489c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 695cd690b60SPoul-Henning Kamp { 696cd690b60SPoul-Henning Kamp 697a0e78d2eSPoul-Henning Kamp dev_lock(); 698aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 699a0e78d2eSPoul-Henning Kamp dev_unlock(); 700cd690b60SPoul-Henning Kamp } 701d137acccSPoul-Henning Kamp 702c32cc149SBruce Evans const char * 70389c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 704b8e49f68SBill Fumerola { 705d137acccSPoul-Henning Kamp char *p; 7068ff33adbSPoul-Henning Kamp struct cdevsw *csw; 707c32cc149SBruce Evans int mynor; 708b8e49f68SBill Fumerola 709d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 710d137acccSPoul-Henning Kamp p = dev->si_name; 7118ff33adbSPoul-Henning Kamp csw = dev_refthread(dev); 7128ff33adbSPoul-Henning Kamp if (csw != NULL) { 7138ff33adbSPoul-Henning Kamp sprintf(p, "(%s)", csw->d_name); 7148ff33adbSPoul-Henning Kamp dev_relthread(dev); 7158ff33adbSPoul-Henning Kamp } 716d137acccSPoul-Henning Kamp p += strlen(p); 717c32cc149SBruce Evans mynor = minor(dev); 718c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 7198ff33adbSPoul-Henning Kamp sprintf(p, "/%#x", (u_int)mynor); 720c32cc149SBruce Evans else 7218ff33adbSPoul-Henning Kamp sprintf(p, "/%d", mynor); 722d137acccSPoul-Henning Kamp } 723b8e49f68SBill Fumerola return (dev->si_name); 724b8e49f68SBill Fumerola } 725db901281SPoul-Henning Kamp 726db901281SPoul-Henning Kamp int 72701de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 728db901281SPoul-Henning Kamp { 729db901281SPoul-Henning Kamp int u, i; 730db901281SPoul-Henning Kamp 731db901281SPoul-Henning Kamp i = strlen(stem); 73256700d46SBrian Somers if (bcmp(stem, name, i) != 0) 73356700d46SBrian Somers return (0); 734db901281SPoul-Henning Kamp if (!isdigit(name[i])) 735db901281SPoul-Henning Kamp return (0); 736db901281SPoul-Henning Kamp u = 0; 73710786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 73810786074SPoul-Henning Kamp return (0); 739db901281SPoul-Henning Kamp while (isdigit(name[i])) { 740db901281SPoul-Henning Kamp u *= 10; 741db901281SPoul-Henning Kamp u += name[i++] - '0'; 742db901281SPoul-Henning Kamp } 743dab3d85fSBrian Feldman if (u > 0xffffff) 744dab3d85fSBrian Feldman return (0); 745db901281SPoul-Henning Kamp *unit = u; 746db901281SPoul-Henning Kamp if (namep) 747db901281SPoul-Henning Kamp *namep = &name[i]; 748db901281SPoul-Henning Kamp if (name[i]) 749db901281SPoul-Henning Kamp return (2); 750db901281SPoul-Henning Kamp return (1); 751db901281SPoul-Henning Kamp } 7528d25eb2cSPoul-Henning Kamp 7538d25eb2cSPoul-Henning Kamp /* 754b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 755b0b03348SPoul-Henning Kamp * 756b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 757b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 758b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 759b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 760b0b03348SPoul-Henning Kamp * 7619a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 7629a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 763b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 764b0b03348SPoul-Henning Kamp * 765b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 766b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 767b0b03348SPoul-Henning Kamp * 768b0b03348SPoul-Henning Kamp */ 769b0b03348SPoul-Henning Kamp 770b0b03348SPoul-Henning Kamp struct clonedevs { 771b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 772b0b03348SPoul-Henning Kamp }; 773b0b03348SPoul-Henning Kamp 7749397290eSPoul-Henning Kamp void 7759397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 7769397290eSPoul-Henning Kamp { 7779397290eSPoul-Henning Kamp 7789397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 7799397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 7809397290eSPoul-Henning Kamp } 7819397290eSPoul-Henning Kamp 782b0b03348SPoul-Henning Kamp int 78389c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 784b0b03348SPoul-Henning Kamp { 785b0b03348SPoul-Henning Kamp struct clonedevs *cd; 786027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 787b0b03348SPoul-Henning Kamp int unit, low, u; 788b0b03348SPoul-Henning Kamp 7899397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 7909397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 791b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 792b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 793b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 794b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 795b0b03348SPoul-Henning Kamp 7968045ce21SPoul-Henning Kamp if (!(csw->d_flags & D_INIT)) 7978045ce21SPoul-Henning Kamp prep_cdevsw(csw); 798b0b03348SPoul-Henning Kamp 799b0b03348SPoul-Henning Kamp /* 800b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 801b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 802b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 803b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 804b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 805b0b03348SPoul-Henning Kamp * the end of the list. 806b0b03348SPoul-Henning Kamp */ 807b0b03348SPoul-Henning Kamp unit = *up; 808e606a3c6SPoul-Henning Kamp ndev = devfs_alloc(); 809027b1f71SPoul-Henning Kamp dev_lock(); 8108666b655SPoul-Henning Kamp low = extra; 811b0b03348SPoul-Henning Kamp de = dl = NULL; 8129397290eSPoul-Henning Kamp cd = *cdp; 813b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 814027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 815027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 816b0b03348SPoul-Henning Kamp u = dev2unit(dev); 817b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 818b0b03348SPoul-Henning Kamp *dp = dev; 819e606a3c6SPoul-Henning Kamp devfs_free(ndev); 820027b1f71SPoul-Henning Kamp dev_unlock(); 821b0b03348SPoul-Henning Kamp return (0); 822b0b03348SPoul-Henning Kamp } 823b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 824b0b03348SPoul-Henning Kamp low++; 825b0b03348SPoul-Henning Kamp de = dev; 826b0b03348SPoul-Henning Kamp continue; 8277bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 8287bbb3a26SPoul-Henning Kamp de = dev; 8297bbb3a26SPoul-Henning Kamp continue; 8307bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 831b0b03348SPoul-Henning Kamp dl = dev; 832b0b03348SPoul-Henning Kamp break; 833b0b03348SPoul-Henning Kamp } 834b0b03348SPoul-Henning Kamp } 835b0b03348SPoul-Henning Kamp if (unit == -1) 8368666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 837ff7284eeSPoul-Henning Kamp dev = newdev(csw, unit2minor(unit | extra), ndev); 838027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 839027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 8407bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 841027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 842027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 843027b1f71SPoul-Henning Kamp } 844027b1f71SPoul-Henning Kamp panic("foo"); 845027b1f71SPoul-Henning Kamp } 846b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 847027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 848b0b03348SPoul-Henning Kamp if (dl != NULL) 849b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 850b0b03348SPoul-Henning Kamp else if (de != NULL) 851b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 852b0b03348SPoul-Henning Kamp else 853b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 854b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 855b0b03348SPoul-Henning Kamp *up = unit; 856027b1f71SPoul-Henning Kamp dev_unlock(); 857b0b03348SPoul-Henning Kamp return (1); 858b0b03348SPoul-Henning Kamp } 859b0b03348SPoul-Henning Kamp 860b0b03348SPoul-Henning Kamp /* 861b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 86289c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 863b0b03348SPoul-Henning Kamp */ 864b0b03348SPoul-Henning Kamp void 865b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 866b0b03348SPoul-Henning Kamp { 86789c9c53dSPoul-Henning Kamp struct cdev *dev, *tdev; 868b0b03348SPoul-Henning Kamp struct clonedevs *cd; 869b0b03348SPoul-Henning Kamp 870b0b03348SPoul-Henning Kamp cd = *cdp; 871b0b03348SPoul-Henning Kamp if (cd == NULL) 872b0b03348SPoul-Henning Kamp return; 873027b1f71SPoul-Henning Kamp dev_lock(); 874b0b03348SPoul-Henning Kamp LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 875027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 876027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 877b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 8780a2e49f1SPoul-Henning Kamp ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 879aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 880b0b03348SPoul-Henning Kamp } 881027b1f71SPoul-Henning Kamp dev_unlock(); 882b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 883b0b03348SPoul-Henning Kamp *cdp = NULL; 884b0b03348SPoul-Henning Kamp } 885