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 { 608c4b6380SJohn Baldwin 61cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 62cd690b60SPoul-Henning Kamp } 63cd690b60SPoul-Henning Kamp 64a0e78d2eSPoul-Henning Kamp void 65a0e78d2eSPoul-Henning Kamp dev_unlock(void) 66cd690b60SPoul-Henning Kamp { 672c15afd8SPoul-Henning Kamp 68cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 69cd690b60SPoul-Henning Kamp } 70cd690b60SPoul-Henning Kamp 71cd690b60SPoul-Henning Kamp void 729477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 739477d73eSPoul-Henning Kamp { 749477d73eSPoul-Henning Kamp 759477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 769477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 779477d73eSPoul-Henning Kamp dev->si_refcount++; 789477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 799477d73eSPoul-Henning Kamp } 809477d73eSPoul-Henning Kamp 819477d73eSPoul-Henning Kamp void 82eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 83cd690b60SPoul-Henning Kamp { 842c15afd8SPoul-Henning Kamp 851a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 86cd690b60SPoul-Henning Kamp dev->si_refcount++; 87cd690b60SPoul-Henning Kamp } 88cd690b60SPoul-Henning Kamp 89cd690b60SPoul-Henning Kamp void 90aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 91cd690b60SPoul-Henning Kamp { 92aa2f6ddcSPoul-Henning Kamp int flag = 0; 93a0e78d2eSPoul-Henning Kamp 94ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 95ba285125SPoul-Henning Kamp dev_lock(); 96cd690b60SPoul-Henning Kamp dev->si_refcount--; 97cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 98cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 99e606a3c6SPoul-Henning Kamp #if 0 100aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 101aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 102e606a3c6SPoul-Henning Kamp ; 103e606a3c6SPoul-Henning Kamp else 104e606a3c6SPoul-Henning Kamp #endif 105cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 106cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 107ba285125SPoul-Henning Kamp flag = 1; 108ba285125SPoul-Henning Kamp } 109ba285125SPoul-Henning Kamp dev_unlock(); 110ba285125SPoul-Henning Kamp if (flag) 111e606a3c6SPoul-Henning Kamp devfs_free(dev); 112cd690b60SPoul-Henning Kamp } 113ba285125SPoul-Henning Kamp 1142c15afd8SPoul-Henning Kamp struct cdevsw * 1152c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev) 1162c15afd8SPoul-Henning Kamp { 1172c15afd8SPoul-Henning Kamp struct cdevsw *csw; 1182c15afd8SPoul-Henning Kamp 1192c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1202c15afd8SPoul-Henning Kamp dev_lock(); 1212c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 1222c15afd8SPoul-Henning Kamp if (csw != NULL) 1232c15afd8SPoul-Henning Kamp dev->si_threadcount++; 1242c15afd8SPoul-Henning Kamp dev_unlock(); 1252c15afd8SPoul-Henning Kamp return (csw); 1262c15afd8SPoul-Henning Kamp } 1272c15afd8SPoul-Henning Kamp 1282c15afd8SPoul-Henning Kamp void 1292c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 1302c15afd8SPoul-Henning Kamp { 1312c15afd8SPoul-Henning Kamp 1322c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1332c15afd8SPoul-Henning Kamp dev_lock(); 1342c15afd8SPoul-Henning Kamp dev->si_threadcount--; 1352c15afd8SPoul-Henning Kamp dev_unlock(); 1362c15afd8SPoul-Henning Kamp } 137cd690b60SPoul-Henning Kamp 138b2941431SPoul-Henning Kamp int 139b2941431SPoul-Henning Kamp nullop(void) 140b2941431SPoul-Henning Kamp { 141b2941431SPoul-Henning Kamp 142b2941431SPoul-Henning Kamp return (0); 143b2941431SPoul-Henning Kamp } 144b2941431SPoul-Henning Kamp 145b2941431SPoul-Henning Kamp int 146b2941431SPoul-Henning Kamp eopnotsupp(void) 147b2941431SPoul-Henning Kamp { 148b2941431SPoul-Henning Kamp 149b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 150b2941431SPoul-Henning Kamp } 15102574b19SPoul-Henning Kamp 15202574b19SPoul-Henning Kamp static int 15302574b19SPoul-Henning Kamp enxio(void) 15402574b19SPoul-Henning Kamp { 15502574b19SPoul-Henning Kamp return (ENXIO); 15602574b19SPoul-Henning Kamp } 15702574b19SPoul-Henning Kamp 158b2941431SPoul-Henning Kamp static int 159b2941431SPoul-Henning Kamp enodev(void) 160b2941431SPoul-Henning Kamp { 161b2941431SPoul-Henning Kamp return (ENODEV); 162b2941431SPoul-Henning Kamp } 163b2941431SPoul-Henning Kamp 164b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 165b2941431SPoul-Henning Kamp 16602574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 16702574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 16802574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 16902574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 17002574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 171b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 172b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 17302574b19SPoul-Henning Kamp 17402574b19SPoul-Henning Kamp static void 17502574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 17602574b19SPoul-Henning Kamp { 17702574b19SPoul-Henning Kamp 17802574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 17902574b19SPoul-Henning Kamp } 18002574b19SPoul-Henning Kamp 1812c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 18202574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 18302574b19SPoul-Henning Kamp 18402574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 185dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 186dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 1877ac40f5fSPoul-Henning Kamp .d_open = dead_open, 1887ac40f5fSPoul-Henning Kamp .d_close = dead_close, 1897ac40f5fSPoul-Henning Kamp .d_read = dead_read, 1907ac40f5fSPoul-Henning Kamp .d_write = dead_write, 1917ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 1927ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 1937ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 1947ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 1957ac40f5fSPoul-Henning Kamp .d_name = "dead", 1967ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 1977ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 19802574b19SPoul-Henning Kamp }; 19902574b19SPoul-Henning Kamp 200b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 201b2941431SPoul-Henning Kamp 202b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 203b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 204b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 205b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 206b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 207b2941431SPoul-Henning Kamp #define no_mmap (d_mmap_t *)enodev 208ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 209b2941431SPoul-Henning Kamp 210b2941431SPoul-Henning Kamp static void 211b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 212b2941431SPoul-Henning Kamp { 213b2941431SPoul-Henning Kamp 214b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 215b2941431SPoul-Henning Kamp } 216b2941431SPoul-Henning Kamp 217b2941431SPoul-Henning Kamp static int 21889c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 219b2941431SPoul-Henning Kamp { 220b2941431SPoul-Henning Kamp /* 221b2941431SPoul-Henning Kamp * Return true for read/write. If the user asked for something 222b2941431SPoul-Henning Kamp * special, return POLLNVAL, so that clients have a way of 223b2941431SPoul-Henning Kamp * determining reliably whether or not the extended 224b2941431SPoul-Henning Kamp * functionality is present without hard-coding knowledge 225b2941431SPoul-Henning Kamp * of specific filesystem implementations. 226b2941431SPoul-Henning Kamp * Stay in sync with vop_nopoll(). 227b2941431SPoul-Henning Kamp */ 228b2941431SPoul-Henning Kamp if (events & ~POLLSTANDARD) 229b2941431SPoul-Henning Kamp return (POLLNVAL); 230b2941431SPoul-Henning Kamp 231b2941431SPoul-Henning Kamp return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 232b2941431SPoul-Henning Kamp } 233b2941431SPoul-Henning Kamp 234b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 2354e4a7663SPoul-Henning Kamp 236516ad423SPoul-Henning Kamp static int 237516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 238516ad423SPoul-Henning Kamp { 239516ad423SPoul-Henning Kamp int retval; 240516ad423SPoul-Henning Kamp 241516ad423SPoul-Henning Kamp mtx_lock(&Giant); 242516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 243516ad423SPoul-Henning Kamp d_open(dev, oflags, devtype, td); 244516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 245516ad423SPoul-Henning Kamp return (retval); 246516ad423SPoul-Henning Kamp } 247516ad423SPoul-Henning Kamp 248516ad423SPoul-Henning Kamp static int 249516ad423SPoul-Henning Kamp giant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx) 250516ad423SPoul-Henning Kamp { 251516ad423SPoul-Henning Kamp int retval; 252516ad423SPoul-Henning Kamp 253516ad423SPoul-Henning Kamp mtx_lock(&Giant); 254516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 255516ad423SPoul-Henning Kamp d_fdopen(dev, oflags, td, fdidx); 256516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 257516ad423SPoul-Henning Kamp return (retval); 258516ad423SPoul-Henning Kamp } 259516ad423SPoul-Henning Kamp 260516ad423SPoul-Henning Kamp static int 261516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 262516ad423SPoul-Henning Kamp { 263516ad423SPoul-Henning Kamp int retval; 264516ad423SPoul-Henning Kamp 265516ad423SPoul-Henning Kamp mtx_lock(&Giant); 266516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 267516ad423SPoul-Henning Kamp d_close(dev, fflag, devtype, td); 268516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 269516ad423SPoul-Henning Kamp return (retval); 270516ad423SPoul-Henning Kamp } 271516ad423SPoul-Henning Kamp 272516ad423SPoul-Henning Kamp static void 273516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 274516ad423SPoul-Henning Kamp { 275516ad423SPoul-Henning Kamp 276516ad423SPoul-Henning Kamp mtx_lock(&Giant); 277516ad423SPoul-Henning Kamp bp->bio_dev->si_devsw->d_gianttrick-> 278516ad423SPoul-Henning Kamp d_strategy(bp); 279516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 280516ad423SPoul-Henning Kamp } 281516ad423SPoul-Henning Kamp 282516ad423SPoul-Henning Kamp static int 283516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 284516ad423SPoul-Henning Kamp { 285516ad423SPoul-Henning Kamp int retval; 286516ad423SPoul-Henning Kamp 287516ad423SPoul-Henning Kamp mtx_lock(&Giant); 288516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 289516ad423SPoul-Henning Kamp d_ioctl(dev, cmd, data, fflag, td); 290516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 291516ad423SPoul-Henning Kamp return (retval); 292516ad423SPoul-Henning Kamp } 293516ad423SPoul-Henning Kamp 294516ad423SPoul-Henning Kamp static int 295516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 296516ad423SPoul-Henning Kamp { 297516ad423SPoul-Henning Kamp int retval; 298516ad423SPoul-Henning Kamp 299516ad423SPoul-Henning Kamp mtx_lock(&Giant); 300516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 301516ad423SPoul-Henning Kamp d_read(dev, uio, ioflag); 302516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 303516ad423SPoul-Henning Kamp return (retval); 304516ad423SPoul-Henning Kamp } 305516ad423SPoul-Henning Kamp 306516ad423SPoul-Henning Kamp static int 307516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 308516ad423SPoul-Henning Kamp { 309516ad423SPoul-Henning Kamp int retval; 310516ad423SPoul-Henning Kamp 311516ad423SPoul-Henning Kamp mtx_lock(&Giant); 312516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 313516ad423SPoul-Henning Kamp d_write(dev, uio, ioflag); 314516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 315516ad423SPoul-Henning Kamp return (retval); 316516ad423SPoul-Henning Kamp } 317516ad423SPoul-Henning Kamp 318516ad423SPoul-Henning Kamp static int 319516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 320516ad423SPoul-Henning Kamp { 321516ad423SPoul-Henning Kamp int retval; 322516ad423SPoul-Henning Kamp 323516ad423SPoul-Henning Kamp mtx_lock(&Giant); 324516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 325516ad423SPoul-Henning Kamp d_poll(dev, events, td); 326516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 327516ad423SPoul-Henning Kamp return (retval); 328516ad423SPoul-Henning Kamp } 329516ad423SPoul-Henning Kamp 330516ad423SPoul-Henning Kamp static int 331516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 332516ad423SPoul-Henning Kamp { 333516ad423SPoul-Henning Kamp int retval; 334516ad423SPoul-Henning Kamp 335516ad423SPoul-Henning Kamp mtx_lock(&Giant); 336516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 337516ad423SPoul-Henning Kamp d_kqfilter(dev, kn); 338516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 339516ad423SPoul-Henning Kamp return (retval); 340516ad423SPoul-Henning Kamp } 341516ad423SPoul-Henning Kamp 342516ad423SPoul-Henning Kamp static int 343516ad423SPoul-Henning Kamp giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 344516ad423SPoul-Henning Kamp { 345516ad423SPoul-Henning Kamp int retval; 346516ad423SPoul-Henning Kamp 347516ad423SPoul-Henning Kamp mtx_lock(&Giant); 348516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 349516ad423SPoul-Henning Kamp d_mmap(dev, offset, paddr, nprot); 350516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 351516ad423SPoul-Henning Kamp return (retval); 352516ad423SPoul-Henning Kamp } 353516ad423SPoul-Henning Kamp 354516ad423SPoul-Henning Kamp 3552447bec8SPoul-Henning Kamp /* 35689c9c53dSPoul-Henning Kamp * struct cdev * and u_dev_t primitives 357bfbb9ce6SPoul-Henning Kamp */ 358bfbb9ce6SPoul-Henning Kamp 359bfbb9ce6SPoul-Henning Kamp int 36089c9c53dSPoul-Henning Kamp minor(struct cdev *x) 361bfbb9ce6SPoul-Henning Kamp { 362f3732fd1SPoul-Henning Kamp if (x == NULL) 363f3732fd1SPoul-Henning Kamp return NODEV; 3640a2e49f1SPoul-Henning Kamp return(x->si_drv0 & MAXMINOR); 365bfbb9ce6SPoul-Henning Kamp } 366bfbb9ce6SPoul-Henning Kamp 3679a27d579SPoul-Henning Kamp int 36889c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x) 3699a27d579SPoul-Henning Kamp { 3709a27d579SPoul-Henning Kamp 371f3732fd1SPoul-Henning Kamp if (x == NULL) 372f3732fd1SPoul-Henning Kamp return NODEV; 37337085a39SPoul-Henning Kamp return (minor2unit(minor(x))); 3743a85fd26SPoul-Henning Kamp } 3753a85fd26SPoul-Henning Kamp 3763238ec33SPoul-Henning Kamp u_int 3773238ec33SPoul-Henning Kamp minor2unit(u_int _minor) 3783a85fd26SPoul-Henning Kamp { 3793a85fd26SPoul-Henning Kamp 380d9aaa28fSPoul-Henning Kamp KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 3813238ec33SPoul-Henning Kamp return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 3829a27d579SPoul-Henning Kamp } 3839a27d579SPoul-Henning Kamp 384b0d17ba6SPoul-Henning Kamp int 385b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 386b0d17ba6SPoul-Henning Kamp { 387b0d17ba6SPoul-Henning Kamp 38815b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 389b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 390b0d17ba6SPoul-Henning Kamp } 391b0d17ba6SPoul-Henning Kamp 39289c9c53dSPoul-Henning Kamp static struct cdev * 393ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si) 3943f54a085SPoul-Henning Kamp { 395027b1f71SPoul-Henning Kamp struct cdev *si2; 396f3732fd1SPoul-Henning Kamp dev_t udev; 3973f54a085SPoul-Henning Kamp 398027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 399b3d82c03SPoul-Henning Kamp udev = y; 400ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 4010a2e49f1SPoul-Henning Kamp if (si2->si_drv0 == udev) { 402e606a3c6SPoul-Henning Kamp devfs_free(si); 403027b1f71SPoul-Henning Kamp return (si2); 4043f54a085SPoul-Henning Kamp } 405027b1f71SPoul-Henning Kamp } 4060a2e49f1SPoul-Henning Kamp si->si_drv0 = udev; 407e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 408ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 409698bfad7SPoul-Henning Kamp return (si); 410bfbb9ce6SPoul-Henning Kamp } 411bfbb9ce6SPoul-Henning Kamp 412bfbb9ce6SPoul-Henning Kamp int 413f3732fd1SPoul-Henning Kamp uminor(dev_t dev) 414bfbb9ce6SPoul-Henning Kamp { 415d9aaa28fSPoul-Henning Kamp return (dev & MAXMINOR); 416bfbb9ce6SPoul-Henning Kamp } 417bfbb9ce6SPoul-Henning Kamp 418bfbb9ce6SPoul-Henning Kamp int 419f3732fd1SPoul-Henning Kamp umajor(dev_t dev) 420bfbb9ce6SPoul-Henning Kamp { 421d9aaa28fSPoul-Henning Kamp return ((dev & ~MAXMINOR) >> 8); 422bfbb9ce6SPoul-Henning Kamp } 423bfbb9ce6SPoul-Henning Kamp 4242a3faf2fSPoul-Henning Kamp static void 425cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 426cd690b60SPoul-Henning Kamp { 4271d45c50eSPoul-Henning Kamp struct cdevsw *gt; 428b3d82c03SPoul-Henning Kamp 4291d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 4301d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 4311d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 4321d45c50eSPoul-Henning Kamp free(gt, M_DEVT); 433516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 4341d45c50eSPoul-Henning Kamp } 435652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 436b0b03348SPoul-Henning Kamp } 437b0b03348SPoul-Henning Kamp 438b0b03348SPoul-Henning Kamp static void 439b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw) 440b0b03348SPoul-Henning Kamp { 441516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 442b0b03348SPoul-Henning Kamp 443516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) 444516ad423SPoul-Henning Kamp dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 445516ad423SPoul-Henning Kamp else 446516ad423SPoul-Henning Kamp dsw2 = NULL; 447a0e78d2eSPoul-Henning Kamp dev_lock(); 448cd690b60SPoul-Henning Kamp 449800b42bdSPoul-Henning Kamp if (devsw->d_version != D_VERSION_01) { 450cd690b60SPoul-Henning Kamp printf( 451cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 4527d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 4537d7e053cSAlfred Perlstein "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 csw->d_purge(dev); 665743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 666d595182fSPoul-Henning Kamp if (dev->si_threadcount) 667d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 668d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 669743cd76aSPoul-Henning Kamp } 670743cd76aSPoul-Henning Kamp 671743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 672743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 673743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 674743cd76aSPoul-Henning Kamp 675cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 676cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 677cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 678cd690b60SPoul-Henning Kamp 679e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 680a5993c33SPoul-Henning Kamp if (LIST_EMPTY(&csw->d_devs)) 681a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 682cd690b60SPoul-Henning Kamp } 6835ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 684743cd76aSPoul-Henning Kamp 685cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 686cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 687cd690b60SPoul-Henning Kamp } else { 688e606a3c6SPoul-Henning Kamp devfs_free(dev); 689d137acccSPoul-Henning Kamp } 690cd690b60SPoul-Henning Kamp } 691cd690b60SPoul-Henning Kamp 692cd690b60SPoul-Henning Kamp void 69389c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 694cd690b60SPoul-Henning Kamp { 695cd690b60SPoul-Henning Kamp 696a0e78d2eSPoul-Henning Kamp dev_lock(); 697aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 698a0e78d2eSPoul-Henning Kamp dev_unlock(); 699cd690b60SPoul-Henning Kamp } 700d137acccSPoul-Henning Kamp 701c32cc149SBruce Evans const char * 70289c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 703b8e49f68SBill Fumerola { 704d137acccSPoul-Henning Kamp char *p; 7058ff33adbSPoul-Henning Kamp struct cdevsw *csw; 706c32cc149SBruce Evans int mynor; 707b8e49f68SBill Fumerola 708d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 709d137acccSPoul-Henning Kamp p = dev->si_name; 7108ff33adbSPoul-Henning Kamp csw = dev_refthread(dev); 7118ff33adbSPoul-Henning Kamp if (csw != NULL) { 7128ff33adbSPoul-Henning Kamp sprintf(p, "(%s)", csw->d_name); 7138ff33adbSPoul-Henning Kamp dev_relthread(dev); 7148ff33adbSPoul-Henning Kamp } 715d137acccSPoul-Henning Kamp p += strlen(p); 716c32cc149SBruce Evans mynor = minor(dev); 717c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 7188ff33adbSPoul-Henning Kamp sprintf(p, "/%#x", (u_int)mynor); 719c32cc149SBruce Evans else 7208ff33adbSPoul-Henning Kamp sprintf(p, "/%d", mynor); 721d137acccSPoul-Henning Kamp } 722b8e49f68SBill Fumerola return (dev->si_name); 723b8e49f68SBill Fumerola } 724db901281SPoul-Henning Kamp 725db901281SPoul-Henning Kamp int 72601de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 727db901281SPoul-Henning Kamp { 728db901281SPoul-Henning Kamp int u, i; 729db901281SPoul-Henning Kamp 730db901281SPoul-Henning Kamp i = strlen(stem); 73156700d46SBrian Somers if (bcmp(stem, name, i) != 0) 73256700d46SBrian Somers return (0); 733db901281SPoul-Henning Kamp if (!isdigit(name[i])) 734db901281SPoul-Henning Kamp return (0); 735db901281SPoul-Henning Kamp u = 0; 73610786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 73710786074SPoul-Henning Kamp return (0); 738db901281SPoul-Henning Kamp while (isdigit(name[i])) { 739db901281SPoul-Henning Kamp u *= 10; 740db901281SPoul-Henning Kamp u += name[i++] - '0'; 741db901281SPoul-Henning Kamp } 742dab3d85fSBrian Feldman if (u > 0xffffff) 743dab3d85fSBrian Feldman return (0); 744db901281SPoul-Henning Kamp *unit = u; 745db901281SPoul-Henning Kamp if (namep) 746db901281SPoul-Henning Kamp *namep = &name[i]; 747db901281SPoul-Henning Kamp if (name[i]) 748db901281SPoul-Henning Kamp return (2); 749db901281SPoul-Henning Kamp return (1); 750db901281SPoul-Henning Kamp } 7518d25eb2cSPoul-Henning Kamp 7528d25eb2cSPoul-Henning Kamp /* 753b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 754b0b03348SPoul-Henning Kamp * 755b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 756b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 757b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 758b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 759b0b03348SPoul-Henning Kamp * 7609a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 7619a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 762b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 763b0b03348SPoul-Henning Kamp * 764b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 765b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 766b0b03348SPoul-Henning Kamp * 767b0b03348SPoul-Henning Kamp */ 768b0b03348SPoul-Henning Kamp 769b0b03348SPoul-Henning Kamp struct clonedevs { 770b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 771b0b03348SPoul-Henning Kamp }; 772b0b03348SPoul-Henning Kamp 7739397290eSPoul-Henning Kamp void 7749397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 7759397290eSPoul-Henning Kamp { 7769397290eSPoul-Henning Kamp 7779397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 7789397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 7799397290eSPoul-Henning Kamp } 7809397290eSPoul-Henning Kamp 781b0b03348SPoul-Henning Kamp int 78289c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 783b0b03348SPoul-Henning Kamp { 784b0b03348SPoul-Henning Kamp struct clonedevs *cd; 785027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 786b0b03348SPoul-Henning Kamp int unit, low, u; 787b0b03348SPoul-Henning Kamp 7889397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 7899397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 790b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 791b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 792b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 793b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 794b0b03348SPoul-Henning Kamp 7958045ce21SPoul-Henning Kamp if (!(csw->d_flags & D_INIT)) 7968045ce21SPoul-Henning Kamp prep_cdevsw(csw); 797b0b03348SPoul-Henning Kamp 798b0b03348SPoul-Henning Kamp /* 799b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 800b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 801b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 802b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 803b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 804b0b03348SPoul-Henning Kamp * the end of the list. 805b0b03348SPoul-Henning Kamp */ 806b0b03348SPoul-Henning Kamp unit = *up; 807e606a3c6SPoul-Henning Kamp ndev = devfs_alloc(); 808027b1f71SPoul-Henning Kamp dev_lock(); 8098666b655SPoul-Henning Kamp low = extra; 810b0b03348SPoul-Henning Kamp de = dl = NULL; 8119397290eSPoul-Henning Kamp cd = *cdp; 812b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 813027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 814027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 815b0b03348SPoul-Henning Kamp u = dev2unit(dev); 816b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 817b0b03348SPoul-Henning Kamp *dp = dev; 818e606a3c6SPoul-Henning Kamp devfs_free(ndev); 819027b1f71SPoul-Henning Kamp dev_unlock(); 820b0b03348SPoul-Henning Kamp return (0); 821b0b03348SPoul-Henning Kamp } 822b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 823b0b03348SPoul-Henning Kamp low++; 824b0b03348SPoul-Henning Kamp de = dev; 825b0b03348SPoul-Henning Kamp continue; 8267bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 8277bbb3a26SPoul-Henning Kamp de = dev; 8287bbb3a26SPoul-Henning Kamp continue; 8297bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 830b0b03348SPoul-Henning Kamp dl = dev; 831b0b03348SPoul-Henning Kamp break; 832b0b03348SPoul-Henning Kamp } 833b0b03348SPoul-Henning Kamp } 834b0b03348SPoul-Henning Kamp if (unit == -1) 8358666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 836ff7284eeSPoul-Henning Kamp dev = newdev(csw, unit2minor(unit | extra), ndev); 837027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 838027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 8397bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 840027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 841027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 842027b1f71SPoul-Henning Kamp } 843027b1f71SPoul-Henning Kamp panic("foo"); 844027b1f71SPoul-Henning Kamp } 845b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 846027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 847b0b03348SPoul-Henning Kamp if (dl != NULL) 848b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 849b0b03348SPoul-Henning Kamp else if (de != NULL) 850b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 851b0b03348SPoul-Henning Kamp else 852b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 853b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 854b0b03348SPoul-Henning Kamp *up = unit; 855027b1f71SPoul-Henning Kamp dev_unlock(); 856b0b03348SPoul-Henning Kamp return (1); 857b0b03348SPoul-Henning Kamp } 858b0b03348SPoul-Henning Kamp 859b0b03348SPoul-Henning Kamp /* 860b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 86189c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 862b0b03348SPoul-Henning Kamp */ 863b0b03348SPoul-Henning Kamp void 864b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 865b0b03348SPoul-Henning Kamp { 86689c9c53dSPoul-Henning Kamp struct cdev *dev, *tdev; 867b0b03348SPoul-Henning Kamp struct clonedevs *cd; 868b0b03348SPoul-Henning Kamp 869b0b03348SPoul-Henning Kamp cd = *cdp; 870b0b03348SPoul-Henning Kamp if (cd == NULL) 871b0b03348SPoul-Henning Kamp return; 872027b1f71SPoul-Henning Kamp dev_lock(); 873b0b03348SPoul-Henning Kamp LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 874027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 875027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 876b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 8770a2e49f1SPoul-Henning Kamp ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 878aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 879b0b03348SPoul-Henning Kamp } 880027b1f71SPoul-Henning Kamp dev_unlock(); 881b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 882b0b03348SPoul-Henning Kamp *cdp = NULL; 883b0b03348SPoul-Henning Kamp } 884