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> 3348504cc2SKonstantin Belousov #include <sys/bus.h> 3402574b19SPoul-Henning Kamp #include <sys/bio.h> 351b567820SBrian Feldman #include <sys/lock.h> 361b567820SBrian Feldman #include <sys/mutex.h> 37ecbb00a2SDoug Rabson #include <sys/module.h> 38698bfad7SPoul-Henning Kamp #include <sys/malloc.h> 3926453f35SJulian Elischer #include <sys/conf.h> 401dfcbb0cSJulian Elischer #include <sys/vnode.h> 41698bfad7SPoul-Henning Kamp #include <sys/queue.h> 42b2941431SPoul-Henning Kamp #include <sys/poll.h> 43de10ffa5SKonstantin Belousov #include <sys/sx.h> 44db901281SPoul-Henning Kamp #include <sys/ctype.h> 458e1f1df0SPoul-Henning Kamp #include <sys/tty.h> 46d26dd2d9SRobert Watson #include <sys/ucred.h> 47de10ffa5SKonstantin Belousov #include <sys/taskqueue.h> 480ef1c826SPoul-Henning Kamp #include <machine/stdarg.h> 491dfcbb0cSJulian Elischer 509c0af131SPoul-Henning Kamp #include <fs/devfs/devfs_int.h> 519c0af131SPoul-Henning Kamp 529ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 53698bfad7SPoul-Henning Kamp 54e606a3c6SPoul-Henning Kamp struct mtx devmtx; 55aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev); 569d53363bSKonstantin Belousov static int destroy_dev_sched_cbl(struct cdev *dev, 579d53363bSKonstantin Belousov void (*cb)(void *), void *arg); 58de10ffa5SKonstantin Belousov static struct cdev *make_dev_credv(int flags, 59de10ffa5SKonstantin Belousov struct cdevsw *devsw, int minornr, 60d26dd2d9SRobert Watson struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 61d26dd2d9SRobert Watson va_list ap); 62f3732fd1SPoul-Henning Kamp 639bc911d4SKonstantin Belousov static struct cdev_priv_list cdevp_free_list = 649bc911d4SKonstantin Belousov TAILQ_HEAD_INITIALIZER(cdevp_free_list); 65aeeb4202SKonstantin Belousov static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list = 66aeeb4202SKonstantin Belousov SLIST_HEAD_INITIALIZER(); 679bc911d4SKonstantin Belousov 68a0e78d2eSPoul-Henning Kamp void 69a0e78d2eSPoul-Henning Kamp dev_lock(void) 70cd690b60SPoul-Henning Kamp { 718c4b6380SJohn Baldwin 72cd690b60SPoul-Henning Kamp mtx_lock(&devmtx); 73cd690b60SPoul-Henning Kamp } 74cd690b60SPoul-Henning Kamp 75aeeb4202SKonstantin Belousov /* 76aeeb4202SKonstantin Belousov * Free all the memory collected while the cdev mutex was 77aeeb4202SKonstantin Belousov * locked. Since devmtx is after the system map mutex, free() cannot 78aeeb4202SKonstantin Belousov * be called immediately and is postponed until cdev mutex can be 79aeeb4202SKonstantin Belousov * dropped. 80aeeb4202SKonstantin Belousov */ 819bc911d4SKonstantin Belousov static void 829bc911d4SKonstantin Belousov dev_unlock_and_free(void) 839bc911d4SKonstantin Belousov { 84aeeb4202SKonstantin Belousov struct cdev_priv_list cdp_free; 85aeeb4202SKonstantin Belousov struct free_cdevsw csw_free; 869bc911d4SKonstantin Belousov struct cdev_priv *cdp; 87aeeb4202SKonstantin Belousov struct cdevsw *csw; 889bc911d4SKonstantin Belousov 899bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 90aeeb4202SKonstantin Belousov 91aeeb4202SKonstantin Belousov /* 92aeeb4202SKonstantin Belousov * Make the local copy of the list heads while the dev_mtx is 93aeeb4202SKonstantin Belousov * held. Free it later. 94aeeb4202SKonstantin Belousov */ 95aeeb4202SKonstantin Belousov TAILQ_INIT(&cdp_free); 96aeeb4202SKonstantin Belousov TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list); 97aeeb4202SKonstantin Belousov csw_free = cdevsw_gt_post_list; 98aeeb4202SKonstantin Belousov SLIST_INIT(&cdevsw_gt_post_list); 99aeeb4202SKonstantin Belousov 1009bc911d4SKonstantin Belousov mtx_unlock(&devmtx); 101aeeb4202SKonstantin Belousov 102aeeb4202SKonstantin Belousov while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) { 103aeeb4202SKonstantin Belousov TAILQ_REMOVE(&cdp_free, cdp, cdp_list); 1049bc911d4SKonstantin Belousov devfs_free(&cdp->cdp_c); 1059bc911d4SKonstantin Belousov } 106aeeb4202SKonstantin Belousov while ((csw = SLIST_FIRST(&csw_free)) != NULL) { 107aeeb4202SKonstantin Belousov SLIST_REMOVE_HEAD(&csw_free, d_postfree_list); 108aeeb4202SKonstantin Belousov free(csw, M_DEVT); 109aeeb4202SKonstantin Belousov } 1109bc911d4SKonstantin Belousov } 1119bc911d4SKonstantin Belousov 1129bc911d4SKonstantin Belousov static void 1139bc911d4SKonstantin Belousov dev_free_devlocked(struct cdev *cdev) 1149bc911d4SKonstantin Belousov { 1159bc911d4SKonstantin Belousov struct cdev_priv *cdp; 1169bc911d4SKonstantin Belousov 1179bc911d4SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 1189bc911d4SKonstantin Belousov cdp = cdev->si_priv; 1199bc911d4SKonstantin Belousov TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list); 1209bc911d4SKonstantin Belousov } 1219bc911d4SKonstantin Belousov 122aeeb4202SKonstantin Belousov static void 123aeeb4202SKonstantin Belousov cdevsw_free_devlocked(struct cdevsw *csw) 124aeeb4202SKonstantin Belousov { 125aeeb4202SKonstantin Belousov 126aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 127aeeb4202SKonstantin Belousov SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list); 128aeeb4202SKonstantin Belousov } 129aeeb4202SKonstantin Belousov 130a0e78d2eSPoul-Henning Kamp void 131a0e78d2eSPoul-Henning Kamp dev_unlock(void) 132cd690b60SPoul-Henning Kamp { 1332c15afd8SPoul-Henning Kamp 134cd690b60SPoul-Henning Kamp mtx_unlock(&devmtx); 135cd690b60SPoul-Henning Kamp } 136cd690b60SPoul-Henning Kamp 137cd690b60SPoul-Henning Kamp void 1389477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev) 1399477d73eSPoul-Henning Kamp { 1409477d73eSPoul-Henning Kamp 1419477d73eSPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1429477d73eSPoul-Henning Kamp mtx_lock(&devmtx); 1439477d73eSPoul-Henning Kamp dev->si_refcount++; 1449477d73eSPoul-Henning Kamp mtx_unlock(&devmtx); 1459477d73eSPoul-Henning Kamp } 1469477d73eSPoul-Henning Kamp 1479477d73eSPoul-Henning Kamp void 148eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev) 149cd690b60SPoul-Henning Kamp { 1502c15afd8SPoul-Henning Kamp 1511a1457d4SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 152cd690b60SPoul-Henning Kamp dev->si_refcount++; 153cd690b60SPoul-Henning Kamp } 154cd690b60SPoul-Henning Kamp 155cd690b60SPoul-Henning Kamp void 156aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev) 157cd690b60SPoul-Henning Kamp { 158aa2f6ddcSPoul-Henning Kamp int flag = 0; 159a0e78d2eSPoul-Henning Kamp 160ba285125SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 161ba285125SPoul-Henning Kamp dev_lock(); 162cd690b60SPoul-Henning Kamp dev->si_refcount--; 163cd690b60SPoul-Henning Kamp KASSERT(dev->si_refcount >= 0, 164cd690b60SPoul-Henning Kamp ("dev_rel(%s) gave negative count", devtoname(dev))); 165e606a3c6SPoul-Henning Kamp #if 0 166aa2f6ddcSPoul-Henning Kamp if (dev->si_usecount == 0 && 167aa2f6ddcSPoul-Henning Kamp (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 168e606a3c6SPoul-Henning Kamp ; 169e606a3c6SPoul-Henning Kamp else 170e606a3c6SPoul-Henning Kamp #endif 171cd690b60SPoul-Henning Kamp if (dev->si_devsw == NULL && dev->si_refcount == 0) { 172cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 173ba285125SPoul-Henning Kamp flag = 1; 174ba285125SPoul-Henning Kamp } 175ba285125SPoul-Henning Kamp dev_unlock(); 176ba285125SPoul-Henning Kamp if (flag) 177e606a3c6SPoul-Henning Kamp devfs_free(dev); 178cd690b60SPoul-Henning Kamp } 179ba285125SPoul-Henning Kamp 1802c15afd8SPoul-Henning Kamp struct cdevsw * 1812c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev) 1822c15afd8SPoul-Henning Kamp { 1832c15afd8SPoul-Henning Kamp struct cdevsw *csw; 184de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 1852c15afd8SPoul-Henning Kamp 1862c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 1872c15afd8SPoul-Henning Kamp dev_lock(); 1882c15afd8SPoul-Henning Kamp csw = dev->si_devsw; 189de10ffa5SKonstantin Belousov if (csw != NULL) { 190de10ffa5SKonstantin Belousov cdp = dev->si_priv; 191de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) 1922c15afd8SPoul-Henning Kamp dev->si_threadcount++; 193de10ffa5SKonstantin Belousov else 194de10ffa5SKonstantin Belousov csw = NULL; 195de10ffa5SKonstantin Belousov } 1962c15afd8SPoul-Henning Kamp dev_unlock(); 1972c15afd8SPoul-Henning Kamp return (csw); 1982c15afd8SPoul-Henning Kamp } 1992c15afd8SPoul-Henning Kamp 2001663075cSKonstantin Belousov struct cdevsw * 2011663075cSKonstantin Belousov devvn_refthread(struct vnode *vp, struct cdev **devp) 2021663075cSKonstantin Belousov { 2031663075cSKonstantin Belousov struct cdevsw *csw; 204de10ffa5SKonstantin Belousov struct cdev_priv *cdp; 2051663075cSKonstantin Belousov 2061663075cSKonstantin Belousov mtx_assert(&devmtx, MA_NOTOWNED); 2071663075cSKonstantin Belousov csw = NULL; 2081663075cSKonstantin Belousov dev_lock(); 2091663075cSKonstantin Belousov *devp = vp->v_rdev; 2101663075cSKonstantin Belousov if (*devp != NULL) { 211de10ffa5SKonstantin Belousov cdp = (*devp)->si_priv; 212de10ffa5SKonstantin Belousov if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) { 2131663075cSKonstantin Belousov csw = (*devp)->si_devsw; 2141663075cSKonstantin Belousov if (csw != NULL) 2151663075cSKonstantin Belousov (*devp)->si_threadcount++; 2161663075cSKonstantin Belousov } 217de10ffa5SKonstantin Belousov } 2181663075cSKonstantin Belousov dev_unlock(); 2191663075cSKonstantin Belousov return (csw); 2201663075cSKonstantin Belousov } 2211663075cSKonstantin Belousov 2222c15afd8SPoul-Henning Kamp void 2232c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev) 2242c15afd8SPoul-Henning Kamp { 2252c15afd8SPoul-Henning Kamp 2262c15afd8SPoul-Henning Kamp mtx_assert(&devmtx, MA_NOTOWNED); 2272c15afd8SPoul-Henning Kamp dev_lock(); 2282c15afd8SPoul-Henning Kamp dev->si_threadcount--; 2292c15afd8SPoul-Henning Kamp dev_unlock(); 2302c15afd8SPoul-Henning Kamp } 231cd690b60SPoul-Henning Kamp 232b2941431SPoul-Henning Kamp int 233b2941431SPoul-Henning Kamp nullop(void) 234b2941431SPoul-Henning Kamp { 235b2941431SPoul-Henning Kamp 236b2941431SPoul-Henning Kamp return (0); 237b2941431SPoul-Henning Kamp } 238b2941431SPoul-Henning Kamp 239b2941431SPoul-Henning Kamp int 240b2941431SPoul-Henning Kamp eopnotsupp(void) 241b2941431SPoul-Henning Kamp { 242b2941431SPoul-Henning Kamp 243b2941431SPoul-Henning Kamp return (EOPNOTSUPP); 244b2941431SPoul-Henning Kamp } 24502574b19SPoul-Henning Kamp 24602574b19SPoul-Henning Kamp static int 24702574b19SPoul-Henning Kamp enxio(void) 24802574b19SPoul-Henning Kamp { 24902574b19SPoul-Henning Kamp return (ENXIO); 25002574b19SPoul-Henning Kamp } 25102574b19SPoul-Henning Kamp 252b2941431SPoul-Henning Kamp static int 253b2941431SPoul-Henning Kamp enodev(void) 254b2941431SPoul-Henning Kamp { 255b2941431SPoul-Henning Kamp return (ENODEV); 256b2941431SPoul-Henning Kamp } 257b2941431SPoul-Henning Kamp 258b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */ 259b2941431SPoul-Henning Kamp 26002574b19SPoul-Henning Kamp #define dead_open (d_open_t *)enxio 26102574b19SPoul-Henning Kamp #define dead_close (d_close_t *)enxio 26202574b19SPoul-Henning Kamp #define dead_read (d_read_t *)enxio 26302574b19SPoul-Henning Kamp #define dead_write (d_write_t *)enxio 26402574b19SPoul-Henning Kamp #define dead_ioctl (d_ioctl_t *)enxio 265b2941431SPoul-Henning Kamp #define dead_poll (d_poll_t *)enodev 266b2941431SPoul-Henning Kamp #define dead_mmap (d_mmap_t *)enodev 26702574b19SPoul-Henning Kamp 26802574b19SPoul-Henning Kamp static void 26902574b19SPoul-Henning Kamp dead_strategy(struct bio *bp) 27002574b19SPoul-Henning Kamp { 27102574b19SPoul-Henning Kamp 27202574b19SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 27302574b19SPoul-Henning Kamp } 27402574b19SPoul-Henning Kamp 2752c6b49f6SPoul-Henning Kamp #define dead_dump (dumper_t *)enxio 27602574b19SPoul-Henning Kamp #define dead_kqfilter (d_kqfilter_t *)enxio 27702574b19SPoul-Henning Kamp 27802574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = { 279dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 280dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 2817ac40f5fSPoul-Henning Kamp .d_open = dead_open, 2827ac40f5fSPoul-Henning Kamp .d_close = dead_close, 2837ac40f5fSPoul-Henning Kamp .d_read = dead_read, 2847ac40f5fSPoul-Henning Kamp .d_write = dead_write, 2857ac40f5fSPoul-Henning Kamp .d_ioctl = dead_ioctl, 2867ac40f5fSPoul-Henning Kamp .d_poll = dead_poll, 2877ac40f5fSPoul-Henning Kamp .d_mmap = dead_mmap, 2887ac40f5fSPoul-Henning Kamp .d_strategy = dead_strategy, 2897ac40f5fSPoul-Henning Kamp .d_name = "dead", 2907ac40f5fSPoul-Henning Kamp .d_dump = dead_dump, 2917ac40f5fSPoul-Henning Kamp .d_kqfilter = dead_kqfilter 29202574b19SPoul-Henning Kamp }; 29302574b19SPoul-Henning Kamp 294b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */ 295b2941431SPoul-Henning Kamp 296b2941431SPoul-Henning Kamp #define null_open (d_open_t *)nullop 297b2941431SPoul-Henning Kamp #define null_close (d_close_t *)nullop 298b2941431SPoul-Henning Kamp #define no_read (d_read_t *)enodev 299b2941431SPoul-Henning Kamp #define no_write (d_write_t *)enodev 300b2941431SPoul-Henning Kamp #define no_ioctl (d_ioctl_t *)enodev 301b2941431SPoul-Henning Kamp #define no_mmap (d_mmap_t *)enodev 302ad3b9257SJohn-Mark Gurney #define no_kqfilter (d_kqfilter_t *)enodev 303b2941431SPoul-Henning Kamp 304b2941431SPoul-Henning Kamp static void 305b2941431SPoul-Henning Kamp no_strategy(struct bio *bp) 306b2941431SPoul-Henning Kamp { 307b2941431SPoul-Henning Kamp 308b2941431SPoul-Henning Kamp biofinish(bp, NULL, ENODEV); 309b2941431SPoul-Henning Kamp } 310b2941431SPoul-Henning Kamp 311b2941431SPoul-Henning Kamp static int 31289c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 313b2941431SPoul-Henning Kamp { 314b2941431SPoul-Henning Kamp /* 315b2941431SPoul-Henning Kamp * Return true for read/write. If the user asked for something 316b2941431SPoul-Henning Kamp * special, return POLLNVAL, so that clients have a way of 317b2941431SPoul-Henning Kamp * determining reliably whether or not the extended 318b2941431SPoul-Henning Kamp * functionality is present without hard-coding knowledge 319b2941431SPoul-Henning Kamp * of specific filesystem implementations. 320b2941431SPoul-Henning Kamp * Stay in sync with vop_nopoll(). 321b2941431SPoul-Henning Kamp */ 322b2941431SPoul-Henning Kamp if (events & ~POLLSTANDARD) 323b2941431SPoul-Henning Kamp return (POLLNVAL); 324b2941431SPoul-Henning Kamp 325b2941431SPoul-Henning Kamp return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 326b2941431SPoul-Henning Kamp } 327b2941431SPoul-Henning Kamp 328b2941431SPoul-Henning Kamp #define no_dump (dumper_t *)enodev 3294e4a7663SPoul-Henning Kamp 330516ad423SPoul-Henning Kamp static int 331516ad423SPoul-Henning Kamp giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 332516ad423SPoul-Henning Kamp { 333aeeb4202SKonstantin Belousov struct cdevsw *dsw; 334516ad423SPoul-Henning Kamp int retval; 335516ad423SPoul-Henning Kamp 336aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 337aeeb4202SKonstantin Belousov if (dsw == NULL) 338aeeb4202SKonstantin Belousov return (ENXIO); 339516ad423SPoul-Henning Kamp mtx_lock(&Giant); 340aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td); 341516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 342aeeb4202SKonstantin Belousov dev_relthread(dev); 343516ad423SPoul-Henning Kamp return (retval); 344516ad423SPoul-Henning Kamp } 345516ad423SPoul-Henning Kamp 346516ad423SPoul-Henning Kamp static int 3479e223287SKonstantin Belousov giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 348516ad423SPoul-Henning Kamp { 349aeeb4202SKonstantin Belousov struct cdevsw *dsw; 350516ad423SPoul-Henning Kamp int retval; 351516ad423SPoul-Henning Kamp 352aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 353aeeb4202SKonstantin Belousov if (dsw == NULL) 354aeeb4202SKonstantin Belousov return (ENXIO); 355516ad423SPoul-Henning Kamp mtx_lock(&Giant); 356aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp); 357516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 358aeeb4202SKonstantin Belousov dev_relthread(dev); 359516ad423SPoul-Henning Kamp return (retval); 360516ad423SPoul-Henning Kamp } 361516ad423SPoul-Henning Kamp 362516ad423SPoul-Henning Kamp static int 363516ad423SPoul-Henning Kamp giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 364516ad423SPoul-Henning Kamp { 365aeeb4202SKonstantin Belousov struct cdevsw *dsw; 366516ad423SPoul-Henning Kamp int retval; 367516ad423SPoul-Henning Kamp 368aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 369aeeb4202SKonstantin Belousov if (dsw == NULL) 370aeeb4202SKonstantin Belousov return (ENXIO); 371516ad423SPoul-Henning Kamp mtx_lock(&Giant); 372aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td); 373516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 374aeeb4202SKonstantin Belousov dev_relthread(dev); 375516ad423SPoul-Henning Kamp return (retval); 376516ad423SPoul-Henning Kamp } 377516ad423SPoul-Henning Kamp 378516ad423SPoul-Henning Kamp static void 379516ad423SPoul-Henning Kamp giant_strategy(struct bio *bp) 380516ad423SPoul-Henning Kamp { 381aeeb4202SKonstantin Belousov struct cdevsw *dsw; 382aeeb4202SKonstantin Belousov struct cdev *dev; 383516ad423SPoul-Henning Kamp 384aeeb4202SKonstantin Belousov dev = bp->bio_dev; 385aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 386aeeb4202SKonstantin Belousov if (dsw == NULL) { 387aeeb4202SKonstantin Belousov biofinish(bp, NULL, ENXIO); 388aeeb4202SKonstantin Belousov return; 389aeeb4202SKonstantin Belousov } 390516ad423SPoul-Henning Kamp mtx_lock(&Giant); 391aeeb4202SKonstantin Belousov dsw->d_gianttrick->d_strategy(bp); 392516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 393aeeb4202SKonstantin Belousov dev_relthread(dev); 394516ad423SPoul-Henning Kamp } 395516ad423SPoul-Henning Kamp 396516ad423SPoul-Henning Kamp static int 397516ad423SPoul-Henning Kamp giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 398516ad423SPoul-Henning Kamp { 399aeeb4202SKonstantin Belousov struct cdevsw *dsw; 400516ad423SPoul-Henning Kamp int retval; 401516ad423SPoul-Henning Kamp 402aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 403aeeb4202SKonstantin Belousov if (dsw == NULL) 404aeeb4202SKonstantin Belousov return (ENXIO); 405516ad423SPoul-Henning Kamp mtx_lock(&Giant); 40635b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td); 407516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 408aeeb4202SKonstantin Belousov dev_relthread(dev); 409516ad423SPoul-Henning Kamp return (retval); 410516ad423SPoul-Henning Kamp } 411516ad423SPoul-Henning Kamp 412516ad423SPoul-Henning Kamp static int 413516ad423SPoul-Henning Kamp giant_read(struct cdev *dev, struct uio *uio, int ioflag) 414516ad423SPoul-Henning Kamp { 415aeeb4202SKonstantin Belousov struct cdevsw *dsw; 416516ad423SPoul-Henning Kamp int retval; 417516ad423SPoul-Henning Kamp 418aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 419aeeb4202SKonstantin Belousov if (dsw == NULL) 420aeeb4202SKonstantin Belousov return (ENXIO); 421516ad423SPoul-Henning Kamp mtx_lock(&Giant); 42235b45029SKonstantin Belousov retval = dsw->d_gianttrick->d_read(dev, uio, ioflag); 423516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 424aeeb4202SKonstantin Belousov dev_relthread(dev); 425516ad423SPoul-Henning Kamp return (retval); 426516ad423SPoul-Henning Kamp } 427516ad423SPoul-Henning Kamp 428516ad423SPoul-Henning Kamp static int 429516ad423SPoul-Henning Kamp giant_write(struct cdev *dev, struct uio *uio, int ioflag) 430516ad423SPoul-Henning Kamp { 431aeeb4202SKonstantin Belousov struct cdevsw *dsw; 432516ad423SPoul-Henning Kamp int retval; 433516ad423SPoul-Henning Kamp 434aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 435aeeb4202SKonstantin Belousov if (dsw == NULL) 436aeeb4202SKonstantin Belousov return (ENXIO); 437516ad423SPoul-Henning Kamp mtx_lock(&Giant); 438aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_write(dev, uio, ioflag); 439516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 440aeeb4202SKonstantin Belousov dev_relthread(dev); 441516ad423SPoul-Henning Kamp return (retval); 442516ad423SPoul-Henning Kamp } 443516ad423SPoul-Henning Kamp 444516ad423SPoul-Henning Kamp static int 445516ad423SPoul-Henning Kamp giant_poll(struct cdev *dev, int events, struct thread *td) 446516ad423SPoul-Henning Kamp { 447aeeb4202SKonstantin Belousov struct cdevsw *dsw; 448516ad423SPoul-Henning Kamp int retval; 449516ad423SPoul-Henning Kamp 450aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 451aeeb4202SKonstantin Belousov if (dsw == NULL) 452aeeb4202SKonstantin Belousov return (ENXIO); 453516ad423SPoul-Henning Kamp mtx_lock(&Giant); 454aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_poll(dev, events, td); 455516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 456aeeb4202SKonstantin Belousov dev_relthread(dev); 457516ad423SPoul-Henning Kamp return (retval); 458516ad423SPoul-Henning Kamp } 459516ad423SPoul-Henning Kamp 460516ad423SPoul-Henning Kamp static int 461516ad423SPoul-Henning Kamp giant_kqfilter(struct cdev *dev, struct knote *kn) 462516ad423SPoul-Henning Kamp { 463aeeb4202SKonstantin Belousov struct cdevsw *dsw; 464516ad423SPoul-Henning Kamp int retval; 465516ad423SPoul-Henning Kamp 466aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 467aeeb4202SKonstantin Belousov if (dsw == NULL) 468aeeb4202SKonstantin Belousov return (ENXIO); 469516ad423SPoul-Henning Kamp mtx_lock(&Giant); 470aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_kqfilter(dev, kn); 471516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 472aeeb4202SKonstantin Belousov dev_relthread(dev); 473516ad423SPoul-Henning Kamp return (retval); 474516ad423SPoul-Henning Kamp } 475516ad423SPoul-Henning Kamp 476516ad423SPoul-Henning Kamp static int 477516ad423SPoul-Henning Kamp giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 478516ad423SPoul-Henning Kamp { 479aeeb4202SKonstantin Belousov struct cdevsw *dsw; 480516ad423SPoul-Henning Kamp int retval; 481516ad423SPoul-Henning Kamp 482aeeb4202SKonstantin Belousov dsw = dev_refthread(dev); 483aeeb4202SKonstantin Belousov if (dsw == NULL) 484aeeb4202SKonstantin Belousov return (ENXIO); 485516ad423SPoul-Henning Kamp mtx_lock(&Giant); 486aeeb4202SKonstantin Belousov retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot); 487516ad423SPoul-Henning Kamp mtx_unlock(&Giant); 488aeeb4202SKonstantin Belousov dev_relthread(dev); 489516ad423SPoul-Henning Kamp return (retval); 490516ad423SPoul-Henning Kamp } 491516ad423SPoul-Henning Kamp 492516ad423SPoul-Henning Kamp 4932447bec8SPoul-Henning Kamp /* 49489c9c53dSPoul-Henning Kamp * struct cdev * and u_dev_t primitives 495bfbb9ce6SPoul-Henning Kamp */ 496bfbb9ce6SPoul-Henning Kamp 497bfbb9ce6SPoul-Henning Kamp int 49889c9c53dSPoul-Henning Kamp minor(struct cdev *x) 499bfbb9ce6SPoul-Henning Kamp { 500f3732fd1SPoul-Henning Kamp if (x == NULL) 501f3732fd1SPoul-Henning Kamp return NODEV; 5020a2e49f1SPoul-Henning Kamp return(x->si_drv0 & MAXMINOR); 503bfbb9ce6SPoul-Henning Kamp } 504bfbb9ce6SPoul-Henning Kamp 5059a27d579SPoul-Henning Kamp int 50689c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x) 5079a27d579SPoul-Henning Kamp { 5089a27d579SPoul-Henning Kamp 509f3732fd1SPoul-Henning Kamp if (x == NULL) 510f3732fd1SPoul-Henning Kamp return NODEV; 51137085a39SPoul-Henning Kamp return (minor2unit(minor(x))); 5123a85fd26SPoul-Henning Kamp } 5133a85fd26SPoul-Henning Kamp 5143238ec33SPoul-Henning Kamp u_int 5153238ec33SPoul-Henning Kamp minor2unit(u_int _minor) 5163a85fd26SPoul-Henning Kamp { 5173a85fd26SPoul-Henning Kamp 518d9aaa28fSPoul-Henning Kamp KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 5193238ec33SPoul-Henning Kamp return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 5209a27d579SPoul-Henning Kamp } 5219a27d579SPoul-Henning Kamp 522b0d17ba6SPoul-Henning Kamp int 523b0d17ba6SPoul-Henning Kamp unit2minor(int unit) 524b0d17ba6SPoul-Henning Kamp { 525b0d17ba6SPoul-Henning Kamp 52615b6f00fSPoul-Henning Kamp KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 527b0d17ba6SPoul-Henning Kamp return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 528b0d17ba6SPoul-Henning Kamp } 529b0d17ba6SPoul-Henning Kamp 53048504cc2SKonstantin Belousov static void 53148504cc2SKonstantin Belousov notify(struct cdev *dev, const char *ev) 53248504cc2SKonstantin Belousov { 53348504cc2SKonstantin Belousov static const char prefix[] = "cdev="; 53448504cc2SKonstantin Belousov char *data; 53548504cc2SKonstantin Belousov int namelen; 53648504cc2SKonstantin Belousov 53748504cc2SKonstantin Belousov if (cold) 53848504cc2SKonstantin Belousov return; 53948504cc2SKonstantin Belousov namelen = strlen(dev->si_name); 54048504cc2SKonstantin Belousov data = malloc(namelen + sizeof(prefix), M_TEMP, M_WAITOK); 54148504cc2SKonstantin Belousov memcpy(data, prefix, sizeof(prefix) - 1); 54248504cc2SKonstantin Belousov memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1); 54348504cc2SKonstantin Belousov devctl_notify("DEVFS", "CDEV", ev, data); 54448504cc2SKonstantin Belousov free(data, M_TEMP); 54548504cc2SKonstantin Belousov } 54648504cc2SKonstantin Belousov 54748504cc2SKonstantin Belousov static void 54848504cc2SKonstantin Belousov notify_create(struct cdev *dev) 54948504cc2SKonstantin Belousov { 55048504cc2SKonstantin Belousov 55148504cc2SKonstantin Belousov notify(dev, "CREATE"); 55248504cc2SKonstantin Belousov } 55348504cc2SKonstantin Belousov 55448504cc2SKonstantin Belousov static void 55548504cc2SKonstantin Belousov notify_destroy(struct cdev *dev) 55648504cc2SKonstantin Belousov { 55748504cc2SKonstantin Belousov 55848504cc2SKonstantin Belousov notify(dev, "DESTROY"); 55948504cc2SKonstantin Belousov } 56048504cc2SKonstantin Belousov 56189c9c53dSPoul-Henning Kamp static struct cdev * 562ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si) 5633f54a085SPoul-Henning Kamp { 564027b1f71SPoul-Henning Kamp struct cdev *si2; 565f3732fd1SPoul-Henning Kamp dev_t udev; 5663f54a085SPoul-Henning Kamp 567027b1f71SPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 568b3d82c03SPoul-Henning Kamp udev = y; 569ff7284eeSPoul-Henning Kamp LIST_FOREACH(si2, &csw->d_devs, si_list) { 5700a2e49f1SPoul-Henning Kamp if (si2->si_drv0 == udev) { 5719bc911d4SKonstantin Belousov dev_free_devlocked(si); 572027b1f71SPoul-Henning Kamp return (si2); 5733f54a085SPoul-Henning Kamp } 574027b1f71SPoul-Henning Kamp } 5750a2e49f1SPoul-Henning Kamp si->si_drv0 = udev; 576e606a3c6SPoul-Henning Kamp si->si_devsw = csw; 577ff7284eeSPoul-Henning Kamp LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 578698bfad7SPoul-Henning Kamp return (si); 579bfbb9ce6SPoul-Henning Kamp } 580bfbb9ce6SPoul-Henning Kamp 581bfbb9ce6SPoul-Henning Kamp int 582f3732fd1SPoul-Henning Kamp uminor(dev_t dev) 583bfbb9ce6SPoul-Henning Kamp { 584d9aaa28fSPoul-Henning Kamp return (dev & MAXMINOR); 585bfbb9ce6SPoul-Henning Kamp } 586bfbb9ce6SPoul-Henning Kamp 587bfbb9ce6SPoul-Henning Kamp int 588f3732fd1SPoul-Henning Kamp umajor(dev_t dev) 589bfbb9ce6SPoul-Henning Kamp { 590d9aaa28fSPoul-Henning Kamp return ((dev & ~MAXMINOR) >> 8); 591bfbb9ce6SPoul-Henning Kamp } 592bfbb9ce6SPoul-Henning Kamp 5932a3faf2fSPoul-Henning Kamp static void 594cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw) 595cd690b60SPoul-Henning Kamp { 5961d45c50eSPoul-Henning Kamp struct cdevsw *gt; 597b3d82c03SPoul-Henning Kamp 5981d45c50eSPoul-Henning Kamp if (devsw->d_gianttrick != NULL) { 5991d45c50eSPoul-Henning Kamp gt = devsw->d_gianttrick; 6001d45c50eSPoul-Henning Kamp memcpy(devsw, gt, sizeof *devsw); 601aeeb4202SKonstantin Belousov cdevsw_free_devlocked(gt); 602516ad423SPoul-Henning Kamp devsw->d_gianttrick = NULL; 6031d45c50eSPoul-Henning Kamp } 604652d0472SPoul-Henning Kamp devsw->d_flags &= ~D_INIT; 605b0b03348SPoul-Henning Kamp } 606b0b03348SPoul-Henning Kamp 607b0b03348SPoul-Henning Kamp static void 608b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw) 609b0b03348SPoul-Henning Kamp { 610516ad423SPoul-Henning Kamp struct cdevsw *dsw2; 611b0b03348SPoul-Henning Kamp 612aeeb4202SKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 613aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) 614aeeb4202SKonstantin Belousov return; 615aeeb4202SKonstantin Belousov if (devsw->d_flags & D_NEEDGIANT) { 616aeeb4202SKonstantin Belousov dev_unlock(); 617516ad423SPoul-Henning Kamp dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 618a0e78d2eSPoul-Henning Kamp dev_lock(); 619aeeb4202SKonstantin Belousov } else 620aeeb4202SKonstantin Belousov dsw2 = NULL; 621aeeb4202SKonstantin Belousov if (devsw->d_flags & D_INIT) { 622aeeb4202SKonstantin Belousov if (dsw2 != NULL) 623aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 624aeeb4202SKonstantin Belousov return; 625aeeb4202SKonstantin Belousov } 626cd690b60SPoul-Henning Kamp 627800b42bdSPoul-Henning Kamp if (devsw->d_version != D_VERSION_01) { 628cd690b60SPoul-Henning Kamp printf( 629cd690b60SPoul-Henning Kamp "WARNING: Device driver \"%s\" has wrong version %s\n", 6307d7e053cSAlfred Perlstein devsw->d_name == NULL ? "???" : devsw->d_name, 6317d7e053cSAlfred Perlstein "and is disabled. Recompile KLD module."); 632cd690b60SPoul-Henning Kamp devsw->d_open = dead_open; 633cd690b60SPoul-Henning Kamp devsw->d_close = dead_close; 634cd690b60SPoul-Henning Kamp devsw->d_read = dead_read; 635cd690b60SPoul-Henning Kamp devsw->d_write = dead_write; 636cd690b60SPoul-Henning Kamp devsw->d_ioctl = dead_ioctl; 637cd690b60SPoul-Henning Kamp devsw->d_poll = dead_poll; 638cd690b60SPoul-Henning Kamp devsw->d_mmap = dead_mmap; 639cd690b60SPoul-Henning Kamp devsw->d_strategy = dead_strategy; 640cd690b60SPoul-Henning Kamp devsw->d_dump = dead_dump; 641cd690b60SPoul-Henning Kamp devsw->d_kqfilter = dead_kqfilter; 642cd690b60SPoul-Henning Kamp } 643cd690b60SPoul-Henning Kamp 6448e1f1df0SPoul-Henning Kamp if (devsw->d_flags & D_TTY) { 6453a95025fSPoul-Henning Kamp if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 6468e1f1df0SPoul-Henning Kamp if (devsw->d_read == NULL) devsw->d_read = ttyread; 6478e1f1df0SPoul-Henning Kamp if (devsw->d_write == NULL) devsw->d_write = ttywrite; 6488e1f1df0SPoul-Henning Kamp if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 6498e1f1df0SPoul-Henning Kamp if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 6508e1f1df0SPoul-Henning Kamp } 6518e1f1df0SPoul-Henning Kamp 652516ad423SPoul-Henning Kamp if (devsw->d_flags & D_NEEDGIANT) { 653516ad423SPoul-Henning Kamp if (devsw->d_gianttrick == NULL) { 654516ad423SPoul-Henning Kamp memcpy(dsw2, devsw, sizeof *dsw2); 655516ad423SPoul-Henning Kamp devsw->d_gianttrick = dsw2; 656aeeb4202SKonstantin Belousov dsw2 = NULL; 657aeeb4202SKonstantin Belousov } 658516ad423SPoul-Henning Kamp } 659516ad423SPoul-Henning Kamp 660516ad423SPoul-Henning Kamp #define FIXUP(member, noop, giant) \ 661516ad423SPoul-Henning Kamp do { \ 662516ad423SPoul-Henning Kamp if (devsw->member == NULL) { \ 663516ad423SPoul-Henning Kamp devsw->member = noop; \ 664516ad423SPoul-Henning Kamp } else if (devsw->d_flags & D_NEEDGIANT) \ 665516ad423SPoul-Henning Kamp devsw->member = giant; \ 666516ad423SPoul-Henning Kamp } \ 667516ad423SPoul-Henning Kamp while (0) 668516ad423SPoul-Henning Kamp 669516ad423SPoul-Henning Kamp FIXUP(d_open, null_open, giant_open); 670516ad423SPoul-Henning Kamp FIXUP(d_fdopen, NULL, giant_fdopen); 671516ad423SPoul-Henning Kamp FIXUP(d_close, null_close, giant_close); 672516ad423SPoul-Henning Kamp FIXUP(d_read, no_read, giant_read); 673516ad423SPoul-Henning Kamp FIXUP(d_write, no_write, giant_write); 674516ad423SPoul-Henning Kamp FIXUP(d_ioctl, no_ioctl, giant_ioctl); 675516ad423SPoul-Henning Kamp FIXUP(d_poll, no_poll, giant_poll); 676516ad423SPoul-Henning Kamp FIXUP(d_mmap, no_mmap, giant_mmap); 677516ad423SPoul-Henning Kamp FIXUP(d_strategy, no_strategy, giant_strategy); 678516ad423SPoul-Henning Kamp FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 679516ad423SPoul-Henning Kamp 680b2941431SPoul-Henning Kamp if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 681cd690b60SPoul-Henning Kamp 682cd690b60SPoul-Henning Kamp LIST_INIT(&devsw->d_devs); 683cd690b60SPoul-Henning Kamp 684cd690b60SPoul-Henning Kamp devsw->d_flags |= D_INIT; 685cd690b60SPoul-Henning Kamp 686aeeb4202SKonstantin Belousov if (dsw2 != NULL) 687aeeb4202SKonstantin Belousov cdevsw_free_devlocked(dsw2); 6882a3faf2fSPoul-Henning Kamp } 68911586717SBrian Somers 690de10ffa5SKonstantin Belousov struct cdev * 691de10ffa5SKonstantin Belousov make_dev_credv(int flags, struct cdevsw *devsw, int minornr, 692de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 693d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, va_list ap) 6942a3faf2fSPoul-Henning Kamp { 69589c9c53dSPoul-Henning Kamp struct cdev *dev; 6962a3faf2fSPoul-Henning Kamp int i; 6972a3faf2fSPoul-Henning Kamp 698d9aaa28fSPoul-Henning Kamp KASSERT((minornr & ~MAXMINOR) == 0, 699cd690b60SPoul-Henning Kamp ("Invalid minor (0x%x) in make_dev", minornr)); 700cd690b60SPoul-Henning Kamp 701e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 702027b1f71SPoul-Henning Kamp dev_lock(); 703aeeb4202SKonstantin Belousov prep_cdevsw(devsw); 704ff7284eeSPoul-Henning Kamp dev = newdev(devsw, minornr, dev); 705de10ffa5SKonstantin Belousov if (flags & MAKEDEV_REF) 706de10ffa5SKonstantin Belousov dev_refl(dev); 70798c469d4SPoul-Henning Kamp if (dev->si_flags & SI_CHEAPCLONE && 708e606a3c6SPoul-Henning Kamp dev->si_flags & SI_NAMED) { 70998c469d4SPoul-Henning Kamp /* 71098c469d4SPoul-Henning Kamp * This is allowed as it removes races and generally 71198c469d4SPoul-Henning Kamp * simplifies cloning devices. 712cd690b60SPoul-Henning Kamp * XXX: still ?? 71398c469d4SPoul-Henning Kamp */ 7149bc911d4SKonstantin Belousov dev_unlock_and_free(); 71598c469d4SPoul-Henning Kamp return (dev); 71698c469d4SPoul-Henning Kamp } 717cd690b60SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_NAMED), 718ff7284eeSPoul-Henning Kamp ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 719ff7284eeSPoul-Henning Kamp devsw->d_name, minor(dev), devtoname(dev))); 720cd690b60SPoul-Henning Kamp 7216334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 7226334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 7232e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 7246334a663SPoul-Henning Kamp dev->__si_namebuf); 7256334a663SPoul-Henning Kamp } 7261a1b2800SPoul-Henning Kamp 7275ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 72822cf3475SAndrew Thompson #ifdef MAC 729d26dd2d9SRobert Watson if (cr != NULL) 730d26dd2d9SRobert Watson dev->si_cred = crhold(cr); 731d26dd2d9SRobert Watson else 73222cf3475SAndrew Thompson #endif 733d26dd2d9SRobert Watson dev->si_cred = NULL; 7349477d73eSPoul-Henning Kamp dev->si_uid = uid; 7359477d73eSPoul-Henning Kamp dev->si_gid = gid; 7369477d73eSPoul-Henning Kamp dev->si_mode = mode; 7371744fcd0SJulian Elischer 7389285a87eSPoul-Henning Kamp devfs_create(dev); 73909828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 740aeeb4202SKonstantin Belousov dev_unlock_and_free(); 74148504cc2SKonstantin Belousov 74248504cc2SKonstantin Belousov notify_create(dev); 74348504cc2SKonstantin Belousov 7443f54a085SPoul-Henning Kamp return (dev); 7453f54a085SPoul-Henning Kamp } 7463f54a085SPoul-Henning Kamp 747d26dd2d9SRobert Watson struct cdev * 748d26dd2d9SRobert Watson make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, 749d26dd2d9SRobert Watson const char *fmt, ...) 750d26dd2d9SRobert Watson { 751d26dd2d9SRobert Watson struct cdev *dev; 752d26dd2d9SRobert Watson va_list ap; 753d26dd2d9SRobert Watson 754d26dd2d9SRobert Watson va_start(ap, fmt); 755de10ffa5SKonstantin Belousov dev = make_dev_credv(0, devsw, minornr, NULL, uid, gid, mode, fmt, ap); 756d26dd2d9SRobert Watson va_end(ap); 757d26dd2d9SRobert Watson return (dev); 758d26dd2d9SRobert Watson } 759d26dd2d9SRobert Watson 760d26dd2d9SRobert Watson struct cdev * 761d26dd2d9SRobert Watson make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 762d26dd2d9SRobert Watson gid_t gid, int mode, const char *fmt, ...) 763d26dd2d9SRobert Watson { 764d26dd2d9SRobert Watson struct cdev *dev; 765d26dd2d9SRobert Watson va_list ap; 766d26dd2d9SRobert Watson 767d26dd2d9SRobert Watson va_start(ap, fmt); 768de10ffa5SKonstantin Belousov dev = make_dev_credv(0, devsw, minornr, cr, uid, gid, mode, fmt, ap); 769de10ffa5SKonstantin Belousov va_end(ap); 770de10ffa5SKonstantin Belousov 771de10ffa5SKonstantin Belousov return (dev); 772de10ffa5SKonstantin Belousov } 773de10ffa5SKonstantin Belousov 774de10ffa5SKonstantin Belousov struct cdev * 775de10ffa5SKonstantin Belousov make_dev_credf(int flags, struct cdevsw *devsw, int minornr, 776de10ffa5SKonstantin Belousov struct ucred *cr, uid_t uid, 777de10ffa5SKonstantin Belousov gid_t gid, int mode, const char *fmt, ...) 778de10ffa5SKonstantin Belousov { 779de10ffa5SKonstantin Belousov struct cdev *dev; 780de10ffa5SKonstantin Belousov va_list ap; 781de10ffa5SKonstantin Belousov 782de10ffa5SKonstantin Belousov va_start(ap, fmt); 783de10ffa5SKonstantin Belousov dev = make_dev_credv(flags, devsw, minornr, cr, uid, gid, mode, 784de10ffa5SKonstantin Belousov fmt, ap); 785d26dd2d9SRobert Watson va_end(ap); 786d26dd2d9SRobert Watson 787d26dd2d9SRobert Watson return (dev); 788d26dd2d9SRobert Watson } 789d26dd2d9SRobert Watson 790e606a3c6SPoul-Henning Kamp static void 791e606a3c6SPoul-Henning Kamp dev_dependsl(struct cdev *pdev, struct cdev *cdev) 792e606a3c6SPoul-Henning Kamp { 793e606a3c6SPoul-Henning Kamp 794e606a3c6SPoul-Henning Kamp cdev->si_parent = pdev; 795e606a3c6SPoul-Henning Kamp cdev->si_flags |= SI_CHILD; 796e606a3c6SPoul-Henning Kamp LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 797e606a3c6SPoul-Henning Kamp } 798e606a3c6SPoul-Henning Kamp 799e606a3c6SPoul-Henning Kamp 8003344c5a1SPoul-Henning Kamp void 80189c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev) 8023344c5a1SPoul-Henning Kamp { 8033344c5a1SPoul-Henning Kamp 804a0e78d2eSPoul-Henning Kamp dev_lock(); 805e606a3c6SPoul-Henning Kamp dev_dependsl(pdev, cdev); 806a0e78d2eSPoul-Henning Kamp dev_unlock(); 8073344c5a1SPoul-Henning Kamp } 8083344c5a1SPoul-Henning Kamp 80989c9c53dSPoul-Henning Kamp struct cdev * 81089c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...) 8113f54a085SPoul-Henning Kamp { 81289c9c53dSPoul-Henning Kamp struct cdev *dev; 8133f54a085SPoul-Henning Kamp va_list ap; 8143f54a085SPoul-Henning Kamp int i; 8153f54a085SPoul-Henning Kamp 816e606a3c6SPoul-Henning Kamp dev = devfs_alloc(); 817a0e78d2eSPoul-Henning Kamp dev_lock(); 8183f54a085SPoul-Henning Kamp dev->si_flags |= SI_ALIAS; 8195ef2707eSPoul-Henning Kamp dev->si_flags |= SI_NAMED; 8203f54a085SPoul-Henning Kamp va_start(ap, fmt); 8216334a663SPoul-Henning Kamp i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 8226334a663SPoul-Henning Kamp if (i > (sizeof dev->__si_namebuf - 1)) { 8232e4db7cfSPawel Jakub Dawidek printf("WARNING: Device name truncated! (%s)\n", 8246334a663SPoul-Henning Kamp dev->__si_namebuf); 8256334a663SPoul-Henning Kamp } 8263f54a085SPoul-Henning Kamp va_end(ap); 8273f54a085SPoul-Henning Kamp 8289285a87eSPoul-Henning Kamp devfs_create(dev); 82909828ba9SKonstantin Belousov clean_unrhdrl(devfs_inos); 830a0e78d2eSPoul-Henning Kamp dev_unlock(); 831cd690b60SPoul-Henning Kamp dev_depends(pdev, dev); 83248504cc2SKonstantin Belousov 83348504cc2SKonstantin Belousov notify_create(dev); 83448504cc2SKonstantin Belousov 8350ef1c826SPoul-Henning Kamp return (dev); 8360ef1c826SPoul-Henning Kamp } 8370ef1c826SPoul-Henning Kamp 838cd690b60SPoul-Henning Kamp static void 839aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev) 840d137acccSPoul-Henning Kamp { 841743cd76aSPoul-Henning Kamp struct cdevsw *csw; 842743cd76aSPoul-Henning Kamp 843aa2f6ddcSPoul-Henning Kamp mtx_assert(&devmtx, MA_OWNED); 844743cd76aSPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 845ff7284eeSPoul-Henning Kamp ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 8465ef2707eSPoul-Henning Kamp 8479285a87eSPoul-Henning Kamp devfs_destroy(dev); 848cd690b60SPoul-Henning Kamp 849cd690b60SPoul-Henning Kamp /* Remove name marking */ 850b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_NAMED; 851b0b03348SPoul-Henning Kamp 852cd690b60SPoul-Henning Kamp /* If we are a child, remove us from the parents list */ 8533344c5a1SPoul-Henning Kamp if (dev->si_flags & SI_CHILD) { 8543344c5a1SPoul-Henning Kamp LIST_REMOVE(dev, si_siblings); 8553344c5a1SPoul-Henning Kamp dev->si_flags &= ~SI_CHILD; 8563344c5a1SPoul-Henning Kamp } 857cd690b60SPoul-Henning Kamp 858cd690b60SPoul-Henning Kamp /* Kill our children */ 8593344c5a1SPoul-Henning Kamp while (!LIST_EMPTY(&dev->si_children)) 860aa2f6ddcSPoul-Henning Kamp destroy_devl(LIST_FIRST(&dev->si_children)); 861cd690b60SPoul-Henning Kamp 862cd690b60SPoul-Henning Kamp /* Remove from clone list */ 863b0b03348SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 864b0b03348SPoul-Henning Kamp LIST_REMOVE(dev, si_clone); 865b0b03348SPoul-Henning Kamp dev->si_flags &= ~SI_CLONELIST; 866b0b03348SPoul-Henning Kamp } 867cd690b60SPoul-Henning Kamp 868e0c33ad5STor Egge dev->si_refcount++; /* Avoid race with dev_rel() */ 869743cd76aSPoul-Henning Kamp csw = dev->si_devsw; 8701abf2c36SBrian Feldman dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 8711abf2c36SBrian Feldman while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 872743cd76aSPoul-Henning Kamp csw->d_purge(dev); 873743cd76aSPoul-Henning Kamp msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 874d595182fSPoul-Henning Kamp if (dev->si_threadcount) 875d595182fSPoul-Henning Kamp printf("Still %lu threads in %s\n", 876d595182fSPoul-Henning Kamp dev->si_threadcount, devtoname(dev)); 877743cd76aSPoul-Henning Kamp } 878e0c33ad5STor Egge while (dev->si_threadcount != 0) { 879e0c33ad5STor Egge /* Use unique dummy wait ident */ 880e0c33ad5STor Egge msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 881e0c33ad5STor Egge } 882743cd76aSPoul-Henning Kamp 88348504cc2SKonstantin Belousov mtx_unlock(&devmtx); 88448504cc2SKonstantin Belousov notify_destroy(dev); 88548504cc2SKonstantin Belousov mtx_lock(&devmtx); 88648504cc2SKonstantin Belousov 887743cd76aSPoul-Henning Kamp dev->si_drv1 = 0; 888743cd76aSPoul-Henning Kamp dev->si_drv2 = 0; 889743cd76aSPoul-Henning Kamp bzero(&dev->__si_u, sizeof(dev->__si_u)); 890743cd76aSPoul-Henning Kamp 891cd690b60SPoul-Henning Kamp if (!(dev->si_flags & SI_ALIAS)) { 892cd690b60SPoul-Henning Kamp /* Remove from cdevsw list */ 893cd690b60SPoul-Henning Kamp LIST_REMOVE(dev, si_list); 894cd690b60SPoul-Henning Kamp 895e606a3c6SPoul-Henning Kamp /* If cdevsw has no more struct cdev *'s, clean it */ 896de10ffa5SKonstantin Belousov if (LIST_EMPTY(&csw->d_devs)) { 897a5993c33SPoul-Henning Kamp fini_cdevsw(csw); 898de10ffa5SKonstantin Belousov wakeup(&csw->d_devs); 899de10ffa5SKonstantin Belousov } 900cd690b60SPoul-Henning Kamp } 9015ef2707eSPoul-Henning Kamp dev->si_flags &= ~SI_ALIAS; 902e0c33ad5STor Egge dev->si_refcount--; /* Avoid race with dev_rel() */ 903743cd76aSPoul-Henning Kamp 904cd690b60SPoul-Henning Kamp if (dev->si_refcount > 0) { 905cd690b60SPoul-Henning Kamp LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 906cd690b60SPoul-Henning Kamp } else { 9079bc911d4SKonstantin Belousov dev_free_devlocked(dev); 908d137acccSPoul-Henning Kamp } 909cd690b60SPoul-Henning Kamp } 910cd690b60SPoul-Henning Kamp 911cd690b60SPoul-Henning Kamp void 91289c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev) 913cd690b60SPoul-Henning Kamp { 914cd690b60SPoul-Henning Kamp 915a0e78d2eSPoul-Henning Kamp dev_lock(); 916aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 9179bc911d4SKonstantin Belousov dev_unlock_and_free(); 918cd690b60SPoul-Henning Kamp } 919d137acccSPoul-Henning Kamp 920c32cc149SBruce Evans const char * 92189c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev) 922b8e49f68SBill Fumerola { 923d137acccSPoul-Henning Kamp char *p; 9248ff33adbSPoul-Henning Kamp struct cdevsw *csw; 925c32cc149SBruce Evans int mynor; 926b8e49f68SBill Fumerola 927d137acccSPoul-Henning Kamp if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 928d137acccSPoul-Henning Kamp p = dev->si_name; 9298ff33adbSPoul-Henning Kamp csw = dev_refthread(dev); 9308ff33adbSPoul-Henning Kamp if (csw != NULL) { 9318ff33adbSPoul-Henning Kamp sprintf(p, "(%s)", csw->d_name); 9328ff33adbSPoul-Henning Kamp dev_relthread(dev); 9338ff33adbSPoul-Henning Kamp } 934d137acccSPoul-Henning Kamp p += strlen(p); 935c32cc149SBruce Evans mynor = minor(dev); 936c32cc149SBruce Evans if (mynor < 0 || mynor > 255) 9378ff33adbSPoul-Henning Kamp sprintf(p, "/%#x", (u_int)mynor); 938c32cc149SBruce Evans else 9398ff33adbSPoul-Henning Kamp sprintf(p, "/%d", mynor); 940d137acccSPoul-Henning Kamp } 941b8e49f68SBill Fumerola return (dev->si_name); 942b8e49f68SBill Fumerola } 943db901281SPoul-Henning Kamp 944db901281SPoul-Henning Kamp int 94501de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit) 946db901281SPoul-Henning Kamp { 947db901281SPoul-Henning Kamp int u, i; 948db901281SPoul-Henning Kamp 949db901281SPoul-Henning Kamp i = strlen(stem); 95056700d46SBrian Somers if (bcmp(stem, name, i) != 0) 95156700d46SBrian Somers return (0); 952db901281SPoul-Henning Kamp if (!isdigit(name[i])) 953db901281SPoul-Henning Kamp return (0); 954db901281SPoul-Henning Kamp u = 0; 95510786074SPoul-Henning Kamp if (name[i] == '0' && isdigit(name[i+1])) 95610786074SPoul-Henning Kamp return (0); 957db901281SPoul-Henning Kamp while (isdigit(name[i])) { 958db901281SPoul-Henning Kamp u *= 10; 959db901281SPoul-Henning Kamp u += name[i++] - '0'; 960db901281SPoul-Henning Kamp } 961dab3d85fSBrian Feldman if (u > 0xffffff) 962dab3d85fSBrian Feldman return (0); 963db901281SPoul-Henning Kamp *unit = u; 964db901281SPoul-Henning Kamp if (namep) 965db901281SPoul-Henning Kamp *namep = &name[i]; 966db901281SPoul-Henning Kamp if (name[i]) 967db901281SPoul-Henning Kamp return (2); 968db901281SPoul-Henning Kamp return (1); 969db901281SPoul-Henning Kamp } 9708d25eb2cSPoul-Henning Kamp 9718d25eb2cSPoul-Henning Kamp /* 972b0b03348SPoul-Henning Kamp * Helper functions for cloning device drivers. 973b0b03348SPoul-Henning Kamp * 974b0b03348SPoul-Henning Kamp * The objective here is to make it unnecessary for the device drivers to 975b0b03348SPoul-Henning Kamp * use rman or similar to manage their unit number space. Due to the way 976b0b03348SPoul-Henning Kamp * we do "on-demand" devices, using rman or other "private" methods 977b0b03348SPoul-Henning Kamp * will be very tricky to lock down properly once we lock down this file. 978b0b03348SPoul-Henning Kamp * 9799a98ae94SLukas Ertl * Instead we give the drivers these routines which puts the struct cdev *'s 9809a98ae94SLukas Ertl * that are to be managed on their own list, and gives the driver the ability 981b0b03348SPoul-Henning Kamp * to ask for the first free unit number or a given specified unit number. 982b0b03348SPoul-Henning Kamp * 983b0b03348SPoul-Henning Kamp * In addition these routines support paired devices (pty, nmdm and similar) 984b0b03348SPoul-Henning Kamp * by respecting a number of "flag" bits in the minor number. 985b0b03348SPoul-Henning Kamp * 986b0b03348SPoul-Henning Kamp */ 987b0b03348SPoul-Henning Kamp 988b0b03348SPoul-Henning Kamp struct clonedevs { 989b0b03348SPoul-Henning Kamp LIST_HEAD(,cdev) head; 990b0b03348SPoul-Henning Kamp }; 991b0b03348SPoul-Henning Kamp 9929397290eSPoul-Henning Kamp void 9939397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp) 9949397290eSPoul-Henning Kamp { 9959397290eSPoul-Henning Kamp 9969397290eSPoul-Henning Kamp *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 9979397290eSPoul-Henning Kamp LIST_INIT(&(*cdp)->head); 9989397290eSPoul-Henning Kamp } 9999397290eSPoul-Henning Kamp 1000b0b03348SPoul-Henning Kamp int 1001217f71d8SBruce M Simpson clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra) 1002b0b03348SPoul-Henning Kamp { 1003b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1004027b1f71SPoul-Henning Kamp struct cdev *dev, *ndev, *dl, *de; 1005b0b03348SPoul-Henning Kamp int unit, low, u; 1006b0b03348SPoul-Henning Kamp 10079397290eSPoul-Henning Kamp KASSERT(*cdp != NULL, 10089397290eSPoul-Henning Kamp ("clone_setup() not called in driver \"%s\"", csw->d_name)); 1009b0b03348SPoul-Henning Kamp KASSERT(!(extra & CLONE_UNITMASK), 1010b0b03348SPoul-Henning Kamp ("Illegal extra bits (0x%x) in clone_create", extra)); 1011b0b03348SPoul-Henning Kamp KASSERT(*up <= CLONE_UNITMASK, 1012b0b03348SPoul-Henning Kamp ("Too high unit (0x%x) in clone_create", *up)); 1013b0b03348SPoul-Henning Kamp 1014b0b03348SPoul-Henning Kamp 1015b0b03348SPoul-Henning Kamp /* 1016b0b03348SPoul-Henning Kamp * Search the list for a lot of things in one go: 1017b0b03348SPoul-Henning Kamp * A preexisting match is returned immediately. 1018b0b03348SPoul-Henning Kamp * The lowest free unit number if we are passed -1, and the place 1019b0b03348SPoul-Henning Kamp * in the list where we should insert that new element. 1020b0b03348SPoul-Henning Kamp * The place to insert a specified unit number, if applicable 1021b0b03348SPoul-Henning Kamp * the end of the list. 1022b0b03348SPoul-Henning Kamp */ 1023b0b03348SPoul-Henning Kamp unit = *up; 1024e606a3c6SPoul-Henning Kamp ndev = devfs_alloc(); 1025027b1f71SPoul-Henning Kamp dev_lock(); 1026aeeb4202SKonstantin Belousov prep_cdevsw(csw); 10278666b655SPoul-Henning Kamp low = extra; 1028b0b03348SPoul-Henning Kamp de = dl = NULL; 10299397290eSPoul-Henning Kamp cd = *cdp; 1030b0b03348SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1031027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1032027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1033b0b03348SPoul-Henning Kamp u = dev2unit(dev); 1034b0b03348SPoul-Henning Kamp if (u == (unit | extra)) { 1035b0b03348SPoul-Henning Kamp *dp = dev; 1036027b1f71SPoul-Henning Kamp dev_unlock(); 10379bc911d4SKonstantin Belousov devfs_free(ndev); 1038b0b03348SPoul-Henning Kamp return (0); 1039b0b03348SPoul-Henning Kamp } 1040b0b03348SPoul-Henning Kamp if (unit == -1 && u == low) { 1041b0b03348SPoul-Henning Kamp low++; 1042b0b03348SPoul-Henning Kamp de = dev; 1043b0b03348SPoul-Henning Kamp continue; 10447bbb3a26SPoul-Henning Kamp } else if (u < (unit | extra)) { 10457bbb3a26SPoul-Henning Kamp de = dev; 10467bbb3a26SPoul-Henning Kamp continue; 10477bbb3a26SPoul-Henning Kamp } else if (u > (unit | extra)) { 1048b0b03348SPoul-Henning Kamp dl = dev; 1049b0b03348SPoul-Henning Kamp break; 1050b0b03348SPoul-Henning Kamp } 1051b0b03348SPoul-Henning Kamp } 1052b0b03348SPoul-Henning Kamp if (unit == -1) 10538666b655SPoul-Henning Kamp unit = low & CLONE_UNITMASK; 1054ff7284eeSPoul-Henning Kamp dev = newdev(csw, unit2minor(unit | extra), ndev); 1055027b1f71SPoul-Henning Kamp if (dev->si_flags & SI_CLONELIST) { 1056027b1f71SPoul-Henning Kamp printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 10577bbb3a26SPoul-Henning Kamp printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 1058027b1f71SPoul-Henning Kamp LIST_FOREACH(dev, &cd->head, si_clone) { 1059027b1f71SPoul-Henning Kamp printf("\t%p %s\n", dev, dev->si_name); 1060027b1f71SPoul-Henning Kamp } 1061027b1f71SPoul-Henning Kamp panic("foo"); 1062027b1f71SPoul-Henning Kamp } 1063b0b03348SPoul-Henning Kamp KASSERT(!(dev->si_flags & SI_CLONELIST), 1064027b1f71SPoul-Henning Kamp ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 1065b0b03348SPoul-Henning Kamp if (dl != NULL) 1066b0b03348SPoul-Henning Kamp LIST_INSERT_BEFORE(dl, dev, si_clone); 1067b0b03348SPoul-Henning Kamp else if (de != NULL) 1068b0b03348SPoul-Henning Kamp LIST_INSERT_AFTER(de, dev, si_clone); 1069b0b03348SPoul-Henning Kamp else 1070b0b03348SPoul-Henning Kamp LIST_INSERT_HEAD(&cd->head, dev, si_clone); 1071b0b03348SPoul-Henning Kamp dev->si_flags |= SI_CLONELIST; 1072b0b03348SPoul-Henning Kamp *up = unit; 10739bc911d4SKonstantin Belousov dev_unlock_and_free(); 1074b0b03348SPoul-Henning Kamp return (1); 1075b0b03348SPoul-Henning Kamp } 1076b0b03348SPoul-Henning Kamp 1077b0b03348SPoul-Henning Kamp /* 1078b0b03348SPoul-Henning Kamp * Kill everything still on the list. The driver should already have 107989c9c53dSPoul-Henning Kamp * disposed of any softc hung of the struct cdev *'s at this time. 1080b0b03348SPoul-Henning Kamp */ 1081b0b03348SPoul-Henning Kamp void 1082b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp) 1083b0b03348SPoul-Henning Kamp { 1084de10ffa5SKonstantin Belousov struct cdev *dev; 1085de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1086b0b03348SPoul-Henning Kamp struct clonedevs *cd; 1087b0b03348SPoul-Henning Kamp 1088b0b03348SPoul-Henning Kamp cd = *cdp; 1089b0b03348SPoul-Henning Kamp if (cd == NULL) 1090b0b03348SPoul-Henning Kamp return; 1091027b1f71SPoul-Henning Kamp dev_lock(); 1092de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&cd->head)) { 1093de10ffa5SKonstantin Belousov dev = LIST_FIRST(&cd->head); 1094de10ffa5SKonstantin Belousov LIST_REMOVE(dev, si_clone); 1095027b1f71SPoul-Henning Kamp KASSERT(dev->si_flags & SI_CLONELIST, 1096027b1f71SPoul-Henning Kamp ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 1097de10ffa5SKonstantin Belousov dev->si_flags &= ~SI_CLONELIST; 1098de10ffa5SKonstantin Belousov cp = dev->si_priv; 1099de10ffa5SKonstantin Belousov if (!(cp->cdp_flags & CDP_SCHED_DTR)) { 1100de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1101b0b03348SPoul-Henning Kamp KASSERT(dev->si_flags & SI_NAMED, 11020a2e49f1SPoul-Henning Kamp ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 1103aa2f6ddcSPoul-Henning Kamp destroy_devl(dev); 1104b0b03348SPoul-Henning Kamp } 1105de10ffa5SKonstantin Belousov } 1106aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1107b0b03348SPoul-Henning Kamp free(cd, M_DEVBUF); 1108b0b03348SPoul-Henning Kamp *cdp = NULL; 1109b0b03348SPoul-Henning Kamp } 1110de10ffa5SKonstantin Belousov 1111de10ffa5SKonstantin Belousov static TAILQ_HEAD(, cdev_priv) dev_ddtr = 1112de10ffa5SKonstantin Belousov TAILQ_HEAD_INITIALIZER(dev_ddtr); 1113de10ffa5SKonstantin Belousov static struct task dev_dtr_task; 1114de10ffa5SKonstantin Belousov 1115de10ffa5SKonstantin Belousov static void 1116de10ffa5SKonstantin Belousov destroy_dev_tq(void *ctx, int pending) 1117de10ffa5SKonstantin Belousov { 1118de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1119de10ffa5SKonstantin Belousov struct cdev *dev; 1120de10ffa5SKonstantin Belousov void (*cb)(void *); 1121de10ffa5SKonstantin Belousov void *cb_arg; 1122de10ffa5SKonstantin Belousov 1123de10ffa5SKonstantin Belousov dev_lock(); 1124de10ffa5SKonstantin Belousov while (!TAILQ_EMPTY(&dev_ddtr)) { 1125de10ffa5SKonstantin Belousov cp = TAILQ_FIRST(&dev_ddtr); 1126de10ffa5SKonstantin Belousov dev = &cp->cdp_c; 1127de10ffa5SKonstantin Belousov KASSERT(cp->cdp_flags & CDP_SCHED_DTR, 1128de10ffa5SKonstantin Belousov ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp)); 1129de10ffa5SKonstantin Belousov TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list); 1130de10ffa5SKonstantin Belousov cb = cp->cdp_dtr_cb; 1131de10ffa5SKonstantin Belousov cb_arg = cp->cdp_dtr_cb_arg; 1132de10ffa5SKonstantin Belousov destroy_devl(dev); 1133aeeb4202SKonstantin Belousov dev_unlock_and_free(); 1134de10ffa5SKonstantin Belousov dev_rel(dev); 1135de10ffa5SKonstantin Belousov if (cb != NULL) 1136de10ffa5SKonstantin Belousov cb(cb_arg); 1137de10ffa5SKonstantin Belousov dev_lock(); 1138de10ffa5SKonstantin Belousov } 1139de10ffa5SKonstantin Belousov dev_unlock(); 1140de10ffa5SKonstantin Belousov } 1141de10ffa5SKonstantin Belousov 11429d53363bSKonstantin Belousov /* 11439d53363bSKonstantin Belousov * devmtx shall be locked on entry. devmtx will be unlocked after 11449d53363bSKonstantin Belousov * function return. 11459d53363bSKonstantin Belousov */ 11469d53363bSKonstantin Belousov static int 11479d53363bSKonstantin Belousov destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg) 1148de10ffa5SKonstantin Belousov { 1149de10ffa5SKonstantin Belousov struct cdev_priv *cp; 1150de10ffa5SKonstantin Belousov 11519d53363bSKonstantin Belousov mtx_assert(&devmtx, MA_OWNED); 1152de10ffa5SKonstantin Belousov cp = dev->si_priv; 1153de10ffa5SKonstantin Belousov if (cp->cdp_flags & CDP_SCHED_DTR) { 1154de10ffa5SKonstantin Belousov dev_unlock(); 1155de10ffa5SKonstantin Belousov return (0); 1156de10ffa5SKonstantin Belousov } 1157de10ffa5SKonstantin Belousov dev_refl(dev); 1158de10ffa5SKonstantin Belousov cp->cdp_flags |= CDP_SCHED_DTR; 1159de10ffa5SKonstantin Belousov cp->cdp_dtr_cb = cb; 1160de10ffa5SKonstantin Belousov cp->cdp_dtr_cb_arg = arg; 1161de10ffa5SKonstantin Belousov TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list); 1162de10ffa5SKonstantin Belousov dev_unlock(); 1163de10ffa5SKonstantin Belousov taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task); 1164de10ffa5SKonstantin Belousov return (1); 1165de10ffa5SKonstantin Belousov } 1166de10ffa5SKonstantin Belousov 1167de10ffa5SKonstantin Belousov int 11689d53363bSKonstantin Belousov destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg) 11699d53363bSKonstantin Belousov { 11709d53363bSKonstantin Belousov dev_lock(); 11719d53363bSKonstantin Belousov return (destroy_dev_sched_cbl(dev, cb, arg)); 11729d53363bSKonstantin Belousov } 11739d53363bSKonstantin Belousov 11749d53363bSKonstantin Belousov int 1175de10ffa5SKonstantin Belousov destroy_dev_sched(struct cdev *dev) 1176de10ffa5SKonstantin Belousov { 1177de10ffa5SKonstantin Belousov return (destroy_dev_sched_cb(dev, NULL, NULL)); 1178de10ffa5SKonstantin Belousov } 1179de10ffa5SKonstantin Belousov 1180de10ffa5SKonstantin Belousov void 1181de10ffa5SKonstantin Belousov destroy_dev_drain(struct cdevsw *csw) 1182de10ffa5SKonstantin Belousov { 1183de10ffa5SKonstantin Belousov 1184de10ffa5SKonstantin Belousov dev_lock(); 1185de10ffa5SKonstantin Belousov while (!LIST_EMPTY(&csw->d_devs)) { 1186de10ffa5SKonstantin Belousov msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10); 1187de10ffa5SKonstantin Belousov } 1188de10ffa5SKonstantin Belousov dev_unlock(); 1189de10ffa5SKonstantin Belousov } 1190de10ffa5SKonstantin Belousov 1191de10ffa5SKonstantin Belousov void 1192de10ffa5SKonstantin Belousov drain_dev_clone_events(void) 1193de10ffa5SKonstantin Belousov { 1194de10ffa5SKonstantin Belousov 1195de10ffa5SKonstantin Belousov sx_xlock(&clone_drain_lock); 1196de10ffa5SKonstantin Belousov sx_xunlock(&clone_drain_lock); 1197de10ffa5SKonstantin Belousov } 1198de10ffa5SKonstantin Belousov 1199de10ffa5SKonstantin Belousov static void 1200de10ffa5SKonstantin Belousov devdtr_init(void *dummy __unused) 1201de10ffa5SKonstantin Belousov { 1202de10ffa5SKonstantin Belousov 1203de10ffa5SKonstantin Belousov TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL); 1204de10ffa5SKonstantin Belousov } 1205de10ffa5SKonstantin Belousov 1206de10ffa5SKonstantin Belousov SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL); 1207