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 1281663075cSKonstantin Belousov struct cdevsw * 1291663075cSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp) 1301663075cSKonstantin Belousov { 1311663075cSKonstantin Belousov struct cdevsw *csw; 1321663075cSKonstantin Belousov 1331663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 1341663075cSKonstantin Belousov csw = NULL; 1351663075cSKonstantin Belousov dev_lock(); 1361663075cSKonstantin Belousov *devp = vp->v_rdev; 1371663075cSKonstantin Belousov if (*devp != NULL) { 1381663075cSKonstantin Belousov csw = (*devp)->si_devsw; 1391663075cSKonstantin Belousov if (csw != NULL) 1401663075cSKonstantin Belousov (*devp)->si_threadcount++; 1411663075cSKonstantin Belousov } 1421663075cSKonstantin Belousov dev_unlock(); 1431663075cSKonstantin Belousov return (csw); 1441663075cSKonstantin Belousov } 1451663075cSKonstantin Belousov 1462c15afd8SPoul-Henning Kamp void 1472c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 1482c15afd8SPoul-Henning Kamp { 1492c15afd8SPoul-Henning Kamp 1502c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1512c15afd8SPoul-Henning Kamp dev_lock(); 1522c15afd8SPoul-Henning Kamp dev->si_threadcount--; 1532c15afd8SPoul-Henning Kamp dev_unlock(); 1542c15afd8SPoul-Henning Kamp } 155cd690b60SPoul-Henning Kamp 156b2941431SPoul-Henning Kamp int 157b2941431SPoul-Henning Kamp nullop(void) 158b2941431SPoul-Henning Kamp { 159b2941431SPoul-Henning Kamp 160b2941431SPoul-Henning Kamp return (0); 161b2941431SPoul-Henning Kamp } 162b2941431SPoul-Henning Kamp 163b2941431SPoul-Henning Kamp int 164b2941431SPoul-Henning Kamp eopnotsupp(void) 165b2941431SPoul-Henning Kamp { 166b2941431SPoul-Henning Kamp 167b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 168b2941431SPoul-Henning Kamp } 16902574b19SPoul-Henning Kamp 17002574b19SPoul-Henning Kamp static int 17102574b19SPoul-Henning Kamp enxio(void) 17202574b19SPoul-Henning Kamp { 17302574b19SPoul-Henning Kamp return (ENXIO); 17402574b19SPoul-Henning Kamp } 17502574b19SPoul-Henning Kamp 176b2941431SPoul-Henning Kamp static int 177b2941431SPoul-Henning Kamp enodev(void) 178b2941431SPoul-Henning Kamp { 179b2941431SPoul-Henning Kamp return (ENODEV); 180b2941431SPoul-Henning Kamp } 181b2941431SPoul-Henning Kamp 182b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 183b2941431SPoul-Henning Kamp 18402574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 18502574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 18602574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 18702574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 18802574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 189b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 190b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 19102574b19SPoul-Henning Kamp 19202574b19SPoul-Henning Kamp static void 19302574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 19402574b19SPoul-Henning Kamp { 19502574b19SPoul-Henning Kamp 19602574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 19702574b19SPoul-Henning Kamp } 19802574b19SPoul-Henning Kamp 1992c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 20002574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 20102574b19SPoul-Henning Kamp 20202574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 203dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 204dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 2057ac40f5fSPoul-Henning Kamp .d_open = dead_open, 2067ac40f5fSPoul-Henning Kamp .d_close = dead_close, 2077ac40f5fSPoul-Henning Kamp .d_read = dead_read, 2087ac40f5fSPoul-Henning Kamp .d_write = dead_write, 2097ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 2107ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 2117ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 2127ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 2137ac40f5fSPoul-Henning Kamp .d_name = "dead", 2147ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 2157ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 21602574b19SPoul-Henning Kamp }; 21702574b19SPoul-Henning Kamp 218b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 219b2941431SPoul-Henning Kamp 220b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 221b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 222b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 223b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 224b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 225b2941431SPoul-Henning Kamp #define no_mmap (d_mmap_t *)enodev 226ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 227b2941431SPoul-Henning Kamp 228b2941431SPoul-Henning Kamp static void 229b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 230b2941431SPoul-Henning Kamp { 231b2941431SPoul-Henning Kamp 232b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 233b2941431SPoul-Henning Kamp } 234b2941431SPoul-Henning Kamp 235b2941431SPoul-Henning Kamp static int 23689c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 237b2941431SPoul-Henning Kamp { 238b2941431SPoul-Henning Kamp /* 239b2941431SPoul-Henning Kamp * Return true for read/write. If the user asked for something 240b2941431SPoul-Henning Kamp * special, return POLLNVAL, so that clients have a way of 241b2941431SPoul-Henning Kamp * determining reliably whether or not the extended 242b2941431SPoul-Henning Kamp * functionality is present without hard-coding knowledge 243b2941431SPoul-Henning Kamp * of specific filesystem implementations. 244b2941431SPoul-Henning Kamp * Stay in sync with vop_nopoll(). 245b2941431SPoul-Henning Kamp */ 246b2941431SPoul-Henning Kamp if (events & ~POLLSTANDARD) 247b2941431SPoul-Henning Kamp return (POLLNVAL); 248b2941431SPoul-Henning Kamp 249b2941431SPoul-Henning Kamp return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 250b2941431SPoul-Henning Kamp } 251b2941431SPoul-Henning Kamp 252b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 2534e4a7663SPoul-Henning Kamp 254516ad423SPoul-Henning Kamp static int 255516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 256516ad423SPoul-Henning Kamp { 257516ad423SPoul-Henning Kamp int retval; 258516ad423SPoul-Henning Kamp 259516ad423SPoul-Henning Kamp mtx_lock(&Giant); 260516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 261516ad423SPoul-Henning Kamp d_open(dev, oflags, devtype, td); 262516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 263516ad423SPoul-Henning Kamp return (retval); 264516ad423SPoul-Henning Kamp } 265516ad423SPoul-Henning Kamp 266516ad423SPoul-Henning Kamp static int 267516ad423SPoul-Henning Kamp giant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx) 268516ad423SPoul-Henning Kamp { 269516ad423SPoul-Henning Kamp int retval; 270516ad423SPoul-Henning Kamp 271516ad423SPoul-Henning Kamp mtx_lock(&Giant); 272516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 273516ad423SPoul-Henning Kamp d_fdopen(dev, oflags, td, fdidx); 274516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 275516ad423SPoul-Henning Kamp return (retval); 276516ad423SPoul-Henning Kamp } 277516ad423SPoul-Henning Kamp 278516ad423SPoul-Henning Kamp static int 279516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 280516ad423SPoul-Henning Kamp { 281516ad423SPoul-Henning Kamp int retval; 282516ad423SPoul-Henning Kamp 283516ad423SPoul-Henning Kamp mtx_lock(&Giant); 284516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 285516ad423SPoul-Henning Kamp d_close(dev, fflag, devtype, td); 286516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 287516ad423SPoul-Henning Kamp return (retval); 288516ad423SPoul-Henning Kamp } 289516ad423SPoul-Henning Kamp 290516ad423SPoul-Henning Kamp static void 291516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 292516ad423SPoul-Henning Kamp { 293516ad423SPoul-Henning Kamp 294516ad423SPoul-Henning Kamp mtx_lock(&Giant); 295516ad423SPoul-Henning Kamp bp->bio_dev->si_devsw->d_gianttrick-> 296516ad423SPoul-Henning Kamp d_strategy(bp); 297516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 298516ad423SPoul-Henning Kamp } 299516ad423SPoul-Henning Kamp 300516ad423SPoul-Henning Kamp static int 301516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 302516ad423SPoul-Henning Kamp { 303516ad423SPoul-Henning Kamp int retval; 304516ad423SPoul-Henning Kamp 305516ad423SPoul-Henning Kamp mtx_lock(&Giant); 306516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 307516ad423SPoul-Henning Kamp d_ioctl(dev, cmd, data, fflag, td); 308516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 309516ad423SPoul-Henning Kamp return (retval); 310516ad423SPoul-Henning Kamp } 311516ad423SPoul-Henning Kamp 312516ad423SPoul-Henning Kamp static int 313516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 314516ad423SPoul-Henning Kamp { 315516ad423SPoul-Henning Kamp int retval; 316516ad423SPoul-Henning Kamp 317516ad423SPoul-Henning Kamp mtx_lock(&Giant); 318516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 319516ad423SPoul-Henning Kamp d_read(dev, uio, ioflag); 320516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 321516ad423SPoul-Henning Kamp return (retval); 322516ad423SPoul-Henning Kamp } 323516ad423SPoul-Henning Kamp 324516ad423SPoul-Henning Kamp static int 325516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 326516ad423SPoul-Henning Kamp { 327516ad423SPoul-Henning Kamp int retval; 328516ad423SPoul-Henning Kamp 329516ad423SPoul-Henning Kamp mtx_lock(&Giant); 330516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 331516ad423SPoul-Henning Kamp d_write(dev, uio, ioflag); 332516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 333516ad423SPoul-Henning Kamp return (retval); 334516ad423SPoul-Henning Kamp } 335516ad423SPoul-Henning Kamp 336516ad423SPoul-Henning Kamp static int 337516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 338516ad423SPoul-Henning Kamp { 339516ad423SPoul-Henning Kamp int retval; 340516ad423SPoul-Henning Kamp 341516ad423SPoul-Henning Kamp mtx_lock(&Giant); 342516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 343516ad423SPoul-Henning Kamp d_poll(dev, events, td); 344516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 345516ad423SPoul-Henning Kamp return (retval); 346516ad423SPoul-Henning Kamp } 347516ad423SPoul-Henning Kamp 348516ad423SPoul-Henning Kamp static int 349516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 350516ad423SPoul-Henning Kamp { 351516ad423SPoul-Henning Kamp int retval; 352516ad423SPoul-Henning Kamp 353516ad423SPoul-Henning Kamp mtx_lock(&Giant); 354516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 355516ad423SPoul-Henning Kamp d_kqfilter(dev, kn); 356516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 357516ad423SPoul-Henning Kamp return (retval); 358516ad423SPoul-Henning Kamp } 359516ad423SPoul-Henning Kamp 360516ad423SPoul-Henning Kamp static int 361516ad423SPoul-Henning Kamp giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 362516ad423SPoul-Henning Kamp { 363516ad423SPoul-Henning Kamp int retval; 364516ad423SPoul-Henning Kamp 365516ad423SPoul-Henning Kamp mtx_lock(&Giant); 366516ad423SPoul-Henning Kamp retval = dev->si_devsw->d_gianttrick-> 367516ad423SPoul-Henning Kamp d_mmap(dev, offset, paddr, nprot); 368516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 369516ad423SPoul-Henning Kamp return (retval); 370516ad423SPoul-Henning Kamp } 371516ad423SPoul-Henning Kamp 372516ad423SPoul-Henning Kamp 3732447bec8SPoul-Henning Kamp /* 37489c9c53dSPoul-Henning Kamp * struct cdev * and u_dev_t primitives 375bfbb9ce6SPoul-Henning Kamp */ 376bfbb9ce6SPoul-Henning Kamp 377bfbb9ce6SPoul-Henning Kamp int 37889c9c53dSPoul-Henning Kamp minor(struct cdev *x) 379bfbb9ce6SPoul-Henning Kamp { 380f3732fd1SPoul-Henning Kamp if (x == NULL) 381f3732fd1SPoul-Henning Kamp return NODEV; 3820a2e49f1SPoul-Henning Kamp return(x->si_drv0 & MAXMINOR); 383bfbb9ce6SPoul-Henning Kamp } 384bfbb9ce6SPoul-Henning Kamp 3859a27d579SPoul-Henning Kamp int 38689c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x) 3879a27d579SPoul-Henning Kamp { 3889a27d579SPoul-Henning Kamp 389f3732fd1SPoul-Henning Kamp if (x == NULL) 390f3732fd1SPoul-Henning Kamp return NODEV; 39137085a39SPoul-Henning Kamp return (minor2unit(minor(x))); 3923a85fd26SPoul-Henning Kamp } 3933a85fd26SPoul-Henning Kamp 3943238ec33SPoul-Henning Kamp u_int 3953238ec33SPoul-Henning Kamp minor2unit(u_int _minor) 3963a85fd26SPoul-Henning Kamp { 3973a85fd26SPoul-Henning Kamp 398d9aaa28fSPoul-Henning Kamp KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 3993238ec33SPoul-Henning Kamp return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 4009a27d579SPoul-Henning Kamp } 4019a27d579SPoul-Henning Kamp 402b0d17ba6SPoul-Henning Kamp int 403b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 404b0d17ba6SPoul-Henning Kamp { 405b0d17ba6SPoul-Henning Kamp 40615b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 407b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 408b0d17ba6SPoul-Henning Kamp } 409b0d17ba6SPoul-Henning Kamp 41089c9c53dSPoul-Henning Kamp static struct cdev * 411ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si) 4123f54a085SPoul-Henning Kamp { 413027b1f71SPoul-Henning Kamp struct cdev *si2; 414f3732fd1SPoul-Henning Kamp dev_t udev; 4153f54a085SPoul-Henning Kamp 416027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 417b3d82c03SPoul-Henning Kamp udev = y; 418ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 4190a2e49f1SPoul-Henning Kamp if (si2->si_drv0 == udev) { 420e606a3c6SPoul-Henning Kamp devfs_free(si); 421027b1f71SPoul-Henning Kamp return (si2); 4223f54a085SPoul-Henning Kamp } 423027b1f71SPoul-Henning Kamp } 4240a2e49f1SPoul-Henning Kamp si->si_drv0 = udev; 425e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 426ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 427698bfad7SPoul-Henning Kamp return (si); 428bfbb9ce6SPoul-Henning Kamp } 429bfbb9ce6SPoul-Henning Kamp 430bfbb9ce6SPoul-Henning Kamp int 431f3732fd1SPoul-Henning Kamp uminor(dev_t dev) 432bfbb9ce6SPoul-Henning Kamp { 433d9aaa28fSPoul-Henning Kamp return (dev & MAXMINOR); 434bfbb9ce6SPoul-Henning Kamp } 435bfbb9ce6SPoul-Henning Kamp 436bfbb9ce6SPoul-Henning Kamp int 437f3732fd1SPoul-Henning Kamp umajor(dev_t dev) 438bfbb9ce6SPoul-Henning Kamp { 439d9aaa28fSPoul-Henning Kamp return ((dev & ~MAXMINOR) >> 8); 440bfbb9ce6SPoul-Henning Kamp } 441bfbb9ce6SPoul-Henning Kamp 4422a3faf2fSPoul-Henning Kamp static void 443cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 444cd690b60SPoul-Henning Kamp { 4451d45c50eSPoul-Henning Kamp struct cdevsw *gt; 446b3d82c03SPoul-Henning Kamp 4471d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 4481d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 4491d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 4501d45c50eSPoul-Henning Kamp free(gt, M_DEVT); 451516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 4521d45c50eSPoul-Henning Kamp } 453652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 454b0b03348SPoul-Henning Kamp } 455b0b03348SPoul-Henning Kamp 456b0b03348SPoul-Henning Kamp static void 457b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw) 458b0b03348SPoul-Henning Kamp { 459516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 460b0b03348SPoul-Henning Kamp 461516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) 462516ad423SPoul-Henning Kamp dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 463516ad423SPoul-Henning Kamp else 464516ad423SPoul-Henning Kamp dsw2 = NULL; 465a0e78d2eSPoul-Henning Kamp dev_lock(); 466cd690b60SPoul-Henning Kamp 467800b42bdSPoul-Henning Kamp if (devsw->d_version != D_VERSION_01) { 468cd690b60SPoul-Henning Kamp printf( 469cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 4707d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 4717d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 472cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 473cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 474cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 475cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 476cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 477cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 478cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 479cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 480cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 481cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 482cd690b60SPoul-Henning Kamp } 483cd690b60SPoul-Henning Kamp 4848e1f1df0SPoul-Henning Kamp if (devsw->d_flags & D_TTY) { 4853a95025fSPoul-Henning Kamp if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 4868e1f1df0SPoul-Henning Kamp if (devsw->d_read == NULL) devsw->d_read = ttyread; 4878e1f1df0SPoul-Henning Kamp if (devsw->d_write == NULL) devsw->d_write = ttywrite; 4888e1f1df0SPoul-Henning Kamp if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 4898e1f1df0SPoul-Henning Kamp if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 4908e1f1df0SPoul-Henning Kamp } 4918e1f1df0SPoul-Henning Kamp 492516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 493516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 494516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 495516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 496516ad423SPoul-Henning Kamp } else 497516ad423SPoul-Henning Kamp free(dsw2, M_DEVT); 498516ad423SPoul-Henning Kamp } 499516ad423SPoul-Henning Kamp 500516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 501516ad423SPoul-Henning Kamp do { \ 502516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 503516ad423SPoul-Henning Kamp devsw->member = noop; \ 504516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 505516ad423SPoul-Henning Kamp devsw->member = giant; \ 506516ad423SPoul-Henning Kamp } \ 507516ad423SPoul-Henning Kamp while (0) 508516ad423SPoul-Henning Kamp 509516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 510516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 511516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 512516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 513516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 514516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 515516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 516516ad423SPoul-Henning Kamp FIXUP(d_mmap, no_mmap, giant_mmap); 517516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 518516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 519516ad423SPoul-Henning Kamp 520b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 521cd690b60SPoul-Henning Kamp 522cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 523cd690b60SPoul-Henning Kamp 524cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 525cd690b60SPoul-Henning Kamp 526a0e78d2eSPoul-Henning Kamp dev_unlock(); 5272a3faf2fSPoul-Henning Kamp } 52811586717SBrian Somers 529d26dd2d9SRobert Watson static struct cdev * 530d26dd2d9SRobert Watson make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 531d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, va_list ap) 5322a3faf2fSPoul-Henning Kamp { 53389c9c53dSPoul-Henning Kamp struct cdev *dev; 5342a3faf2fSPoul-Henning Kamp int i; 5352a3faf2fSPoul-Henning Kamp 536d9aaa28fSPoul-Henning Kamp KASSERT((minornr & ~MAXMINOR) == 0, 537cd690b60SPoul-Henning Kamp ("Invalid minor (0x%x) in make_dev", minornr)); 538cd690b60SPoul-Henning Kamp 5399477d73eSPoul-Henning Kamp if (!(devsw->d_flags & D_INIT)) 5402a3faf2fSPoul-Henning Kamp prep_cdevsw(devsw); 541e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 542027b1f71SPoul-Henning Kamp dev_lock(); 543ff7284eeSPoul-Henning Kamp dev = newdev(devsw, minornr, dev); 54498c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 545e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 54698c469d4SPoul-Henning Kamp /* 54798c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 54898c469d4SPoul-Henning Kamp * simplifies cloning devices. 549cd690b60SPoul-Henning Kamp * XXX: still ?? 55098c469d4SPoul-Henning Kamp */ 551027b1f71SPoul-Henning Kamp dev_unlock(); 55298c469d4SPoul-Henning Kamp return (dev); 55398c469d4SPoul-Henning Kamp } 554cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 555ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 556ff7284eeSPoul-Henning Kamp devsw->d_name, minor(dev), devtoname(dev))); 557cd690b60SPoul-Henning Kamp 5586334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 5596334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 5602e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 5616334a663SPoul-Henning Kamp dev->__si_namebuf); 5626334a663SPoul-Henning Kamp } 5631a1b2800SPoul-Henning Kamp 5645ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 565d26dd2d9SRobert Watson if (cr != NULL) 566d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 567d26dd2d9SRobert Watson else 568d26dd2d9SRobert Watson dev->si_cred = NULL; 5699477d73eSPoul-Henning Kamp dev->si_uid = uid; 5709477d73eSPoul-Henning Kamp dev->si_gid = gid; 5719477d73eSPoul-Henning Kamp dev->si_mode = mode; 5721744fcd0SJulian Elischer 5739285a87eSPoul-Henning Kamp devfs_create(dev); 574a0e78d2eSPoul-Henning Kamp dev_unlock(); 5753f54a085SPoul-Henning Kamp return (dev); 5763f54a085SPoul-Henning Kamp } 5773f54a085SPoul-Henning Kamp 578d26dd2d9SRobert Watson struct cdev * 579d26dd2d9SRobert Watson make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, 580d26dd2d9SRobert Watson const char *fmt, ...) 581d26dd2d9SRobert Watson { 582d26dd2d9SRobert Watson struct cdev *dev; 583d26dd2d9SRobert Watson va_list ap; 584d26dd2d9SRobert Watson 585d26dd2d9SRobert Watson va_start(ap, fmt); 586d26dd2d9SRobert Watson dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap); 587d26dd2d9SRobert Watson va_end(ap); 588d26dd2d9SRobert Watson return (dev); 589d26dd2d9SRobert Watson } 590d26dd2d9SRobert Watson 591d26dd2d9SRobert Watson struct cdev * 592d26dd2d9SRobert Watson make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 593d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 594d26dd2d9SRobert Watson { 595d26dd2d9SRobert Watson struct cdev *dev; 596d26dd2d9SRobert Watson va_list ap; 597d26dd2d9SRobert Watson 598d26dd2d9SRobert Watson va_start(ap, fmt); 599d26dd2d9SRobert Watson dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap); 600d26dd2d9SRobert Watson va_end(ap); 601d26dd2d9SRobert Watson 602d26dd2d9SRobert Watson return (dev); 603d26dd2d9SRobert Watson } 604d26dd2d9SRobert Watson 605e606a3c6SPoul-Henning Kamp static void 606e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 607e606a3c6SPoul-Henning Kamp { 608e606a3c6SPoul-Henning Kamp 609e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 610e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 611e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 612e606a3c6SPoul-Henning Kamp } 613e606a3c6SPoul-Henning Kamp 614e606a3c6SPoul-Henning Kamp 6153344c5a1SPoul-Henning Kamp void 61689c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 6173344c5a1SPoul-Henning Kamp { 6183344c5a1SPoul-Henning Kamp 619a0e78d2eSPoul-Henning Kamp dev_lock(); 620e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 621a0e78d2eSPoul-Henning Kamp dev_unlock(); 6223344c5a1SPoul-Henning Kamp } 6233344c5a1SPoul-Henning Kamp 62489c9c53dSPoul-Henning Kamp struct cdev * 62589c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 6263f54a085SPoul-Henning Kamp { 62789c9c53dSPoul-Henning Kamp struct cdev *dev; 6283f54a085SPoul-Henning Kamp va_list ap; 6293f54a085SPoul-Henning Kamp int i; 6303f54a085SPoul-Henning Kamp 631e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 632a0e78d2eSPoul-Henning Kamp dev_lock(); 6333f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 6345ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 6353f54a085SPoul-Henning Kamp va_start(ap, fmt); 6366334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 6376334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 6382e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 6396334a663SPoul-Henning Kamp dev->__si_namebuf); 6406334a663SPoul-Henning Kamp } 6413f54a085SPoul-Henning Kamp va_end(ap); 6423f54a085SPoul-Henning Kamp 6439285a87eSPoul-Henning Kamp devfs_create(dev); 644a0e78d2eSPoul-Henning Kamp dev_unlock(); 645cd690b60SPoul-Henning Kamp dev_depends(pdev, dev); 6460ef1c826SPoul-Henning Kamp return (dev); 6470ef1c826SPoul-Henning Kamp } 6480ef1c826SPoul-Henning Kamp 649cd690b60SPoul-Henning Kamp static void 650aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 651d137acccSPoul-Henning Kamp { 652743cd76aSPoul-Henning Kamp struct cdevsw *csw; 653743cd76aSPoul-Henning Kamp 654aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 655743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 656ff7284eeSPoul-Henning Kamp ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 6575ef2707eSPoul-Henning Kamp 6589285a87eSPoul-Henning Kamp devfs_destroy(dev); 659cd690b60SPoul-Henning Kamp 660cd690b60SPoul-Henning Kamp /* Remove name marking */ 661b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 662b0b03348SPoul-Henning Kamp 663cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 6643344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 6653344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 6663344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 6673344c5a1SPoul-Henning Kamp } 668cd690b60SPoul-Henning Kamp 669cd690b60SPoul-Henning Kamp /* Kill our children */ 6703344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 671aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 672cd690b60SPoul-Henning Kamp 673cd690b60SPoul-Henning Kamp /* Remove from clone list */ 674b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 675b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 676b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 677b0b03348SPoul-Henning Kamp } 678cd690b60SPoul-Henning Kamp 679e0c33ad5STor Egge dev->si_refcount++; /* Avoid race with dev_rel() */ 680743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 6811abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 6821abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 683743cd76aSPoul-Henning Kamp csw->d_purge(dev); 684743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 685d595182fSPoul-Henning Kamp if (dev->si_threadcount) 686d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 687d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 688743cd76aSPoul-Henning Kamp } 689e0c33ad5STor Egge while (dev->si_threadcount != 0) { 690e0c33ad5STor Egge /* Use unique dummy wait ident */ 691e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 692e0c33ad5STor Egge } 693743cd76aSPoul-Henning Kamp 694743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 695743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 696743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 697743cd76aSPoul-Henning Kamp 698cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 699cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 700cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 701cd690b60SPoul-Henning Kamp 702e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 703a5993c33SPoul-Henning Kamp if (LIST_EMPTY(&csw->d_devs)) 704a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 705cd690b60SPoul-Henning Kamp } 7065ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 707e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 708743cd76aSPoul-Henning Kamp 709cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 710cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 711cd690b60SPoul-Henning Kamp } else { 712e606a3c6SPoul-Henning Kamp devfs_free(dev); 713d137acccSPoul-Henning Kamp } 714cd690b60SPoul-Henning Kamp } 715cd690b60SPoul-Henning Kamp 716cd690b60SPoul-Henning Kamp void 71789c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 718cd690b60SPoul-Henning Kamp { 719cd690b60SPoul-Henning Kamp 720a0e78d2eSPoul-Henning Kamp dev_lock(); 721aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 722a0e78d2eSPoul-Henning Kamp dev_unlock(); 723cd690b60SPoul-Henning Kamp } 724d137acccSPoul-Henning Kamp 725c32cc149SBruce Evans const char * 72689c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 727b8e49f68SBill Fumerola { 728d137acccSPoul-Henning Kamp char *p; 7298ff33adbSPoul-Henning Kamp struct cdevsw *csw; 730c32cc149SBruce Evans int mynor; 731b8e49f68SBill Fumerola 732d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 733d137acccSPoul-Henning Kamp p = dev->si_name; 7348ff33adbSPoul-Henning Kamp csw = dev_refthread(dev); 7358ff33adbSPoul-Henning Kamp if (csw != NULL) { 7368ff33adbSPoul-Henning Kamp sprintf(p, "(%s)", csw->d_name); 7378ff33adbSPoul-Henning Kamp dev_relthread(dev); 7388ff33adbSPoul-Henning Kamp } 739d137acccSPoul-Henning Kamp p += strlen(p); 740c32cc149SBruce Evans mynor = minor(dev); 741c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 7428ff33adbSPoul-Henning Kamp sprintf(p, "/%#x", (u_int)mynor); 743c32cc149SBruce Evans else 7448ff33adbSPoul-Henning Kamp sprintf(p, "/%d", mynor); 745d137acccSPoul-Henning Kamp } 746b8e49f68SBill Fumerola return (dev->si_name); 747b8e49f68SBill Fumerola } 748db901281SPoul-Henning Kamp 749db901281SPoul-Henning Kamp int 75001de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 751db901281SPoul-Henning Kamp { 752db901281SPoul-Henning Kamp int u, i; 753db901281SPoul-Henning Kamp 754db901281SPoul-Henning Kamp i = strlen(stem); 75556700d46SBrian Somers if (bcmp(stem, name, i) != 0) 75656700d46SBrian Somers return (0); 757db901281SPoul-Henning Kamp if (!isdigit(name[i])) 758db901281SPoul-Henning Kamp return (0); 759db901281SPoul-Henning Kamp u = 0; 76010786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 76110786074SPoul-Henning Kamp return (0); 762db901281SPoul-Henning Kamp while (isdigit(name[i])) { 763db901281SPoul-Henning Kamp u *= 10; 764db901281SPoul-Henning Kamp u += name[i++] - '0'; 765db901281SPoul-Henning Kamp } 766dab3d85fSBrian Feldman if (u > 0xffffff) 767dab3d85fSBrian Feldman return (0); 768db901281SPoul-Henning Kamp *unit = u; 769db901281SPoul-Henning Kamp if (namep) 770db901281SPoul-Henning Kamp *namep = &name[i]; 771db901281SPoul-Henning Kamp if (name[i]) 772db901281SPoul-Henning Kamp return (2); 773db901281SPoul-Henning Kamp return (1); 774db901281SPoul-Henning Kamp } 7758d25eb2cSPoul-Henning Kamp 7768d25eb2cSPoul-Henning Kamp /* 777b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 778b0b03348SPoul-Henning Kamp * 779b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 780b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 781b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 782b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 783b0b03348SPoul-Henning Kamp * 7849a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 7859a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 786b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 787b0b03348SPoul-Henning Kamp * 788b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 789b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 790b0b03348SPoul-Henning Kamp * 791b0b03348SPoul-Henning Kamp */ 792b0b03348SPoul-Henning Kamp 793b0b03348SPoul-Henning Kamp struct clonedevs { 794b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 795b0b03348SPoul-Henning Kamp }; 796b0b03348SPoul-Henning Kamp 7979397290eSPoul-Henning Kamp void 7989397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 7999397290eSPoul-Henning Kamp { 8009397290eSPoul-Henning Kamp 8019397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 8029397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 8039397290eSPoul-Henning Kamp } 8049397290eSPoul-Henning Kamp 805b0b03348SPoul-Henning Kamp int 80689c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 807b0b03348SPoul-Henning Kamp { 808b0b03348SPoul-Henning Kamp struct clonedevs *cd; 809027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 810b0b03348SPoul-Henning Kamp int unit, low, u; 811b0b03348SPoul-Henning Kamp 8129397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 8139397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 814b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 815b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 816b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 817b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 818b0b03348SPoul-Henning Kamp 8198045ce21SPoul-Henning Kamp if (!(csw->d_flags & D_INIT)) 8208045ce21SPoul-Henning Kamp prep_cdevsw(csw); 821b0b03348SPoul-Henning Kamp 822b0b03348SPoul-Henning Kamp /* 823b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 824b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 825b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 826b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 827b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 828b0b03348SPoul-Henning Kamp * the end of the list. 829b0b03348SPoul-Henning Kamp */ 830b0b03348SPoul-Henning Kamp unit = *up; 831e606a3c6SPoul-Henning Kamp ndev = devfs_alloc(); 832027b1f71SPoul-Henning Kamp dev_lock(); 8338666b655SPoul-Henning Kamp low = extra; 834b0b03348SPoul-Henning Kamp de = dl = NULL; 8359397290eSPoul-Henning Kamp cd = *cdp; 836b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 837027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 838027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 839b0b03348SPoul-Henning Kamp u = dev2unit(dev); 840b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 841b0b03348SPoul-Henning Kamp *dp = dev; 842e606a3c6SPoul-Henning Kamp devfs_free(ndev); 843027b1f71SPoul-Henning Kamp dev_unlock(); 844b0b03348SPoul-Henning Kamp return (0); 845b0b03348SPoul-Henning Kamp } 846b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 847b0b03348SPoul-Henning Kamp low++; 848b0b03348SPoul-Henning Kamp de = dev; 849b0b03348SPoul-Henning Kamp continue; 8507bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 8517bbb3a26SPoul-Henning Kamp de = dev; 8527bbb3a26SPoul-Henning Kamp continue; 8537bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 854b0b03348SPoul-Henning Kamp dl = dev; 855b0b03348SPoul-Henning Kamp break; 856b0b03348SPoul-Henning Kamp } 857b0b03348SPoul-Henning Kamp } 858b0b03348SPoul-Henning Kamp if (unit == -1) 8598666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 860ff7284eeSPoul-Henning Kamp dev = newdev(csw, unit2minor(unit | extra), ndev); 861027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 862027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 8637bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 864027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 865027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 866027b1f71SPoul-Henning Kamp } 867027b1f71SPoul-Henning Kamp panic("foo"); 868027b1f71SPoul-Henning Kamp } 869b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 870027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 871b0b03348SPoul-Henning Kamp if (dl != NULL) 872b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 873b0b03348SPoul-Henning Kamp else if (de != NULL) 874b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 875b0b03348SPoul-Henning Kamp else 876b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 877b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 878b0b03348SPoul-Henning Kamp *up = unit; 879027b1f71SPoul-Henning Kamp dev_unlock(); 880b0b03348SPoul-Henning Kamp return (1); 881b0b03348SPoul-Henning Kamp } 882b0b03348SPoul-Henning Kamp 883b0b03348SPoul-Henning Kamp /* 884b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 88589c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 886b0b03348SPoul-Henning Kamp */ 887b0b03348SPoul-Henning Kamp void 888b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 889b0b03348SPoul-Henning Kamp { 89089c9c53dSPoul-Henning Kamp struct cdev *dev, *tdev; 891b0b03348SPoul-Henning Kamp struct clonedevs *cd; 892b0b03348SPoul-Henning Kamp 893b0b03348SPoul-Henning Kamp cd = *cdp; 894b0b03348SPoul-Henning Kamp if (cd == NULL) 895b0b03348SPoul-Henning Kamp return; 896027b1f71SPoul-Henning Kamp dev_lock(); 897b0b03348SPoul-Henning Kamp LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 898027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 899027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 900b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 9010a2e49f1SPoul-Henning Kamp ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 902aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 903b0b03348SPoul-Henning Kamp } 904027b1f71SPoul-Henning Kamp dev_unlock(); 905b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 906b0b03348SPoul-Henning Kamp *cdp = NULL; 907b0b03348SPoul-Henning Kamp } 908