xref: /freebsd/sys/kern/kern_conf.c (revision 9477d73e32ad9e33f3102d8c545489d7f3f2af7a)
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>
36b40ce416SJulian Elischer #include <sys/sysctl.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>
43db901281SPoul-Henning Kamp #include <sys/ctype.h>
448e1f1df0SPoul-Henning Kamp #include <sys/tty.h>
450ef1c826SPoul-Henning Kamp #include <machine/stdarg.h>
461dfcbb0cSJulian Elischer 
479ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
48698bfad7SPoul-Henning Kamp 
49beea48b2SPoul-Henning Kamp /* Built at compile time from sys/conf/majors */
50beea48b2SPoul-Henning Kamp 
51cd690b60SPoul-Henning Kamp static struct mtx devmtx;
5289c9c53dSPoul-Henning Kamp static void freedev(struct cdev *dev);
53aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev);
54f3732fd1SPoul-Henning Kamp 
55a0e78d2eSPoul-Henning Kamp void
56a0e78d2eSPoul-Henning Kamp dev_lock(void)
57cd690b60SPoul-Henning Kamp {
58cd690b60SPoul-Henning Kamp 	if (!mtx_initialized(&devmtx))
599ef295b7SPoul-Henning Kamp 		mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
60cd690b60SPoul-Henning Kamp 	mtx_lock(&devmtx);
61cd690b60SPoul-Henning Kamp }
62cd690b60SPoul-Henning Kamp 
63a0e78d2eSPoul-Henning Kamp void
64a0e78d2eSPoul-Henning Kamp dev_unlock(void)
65cd690b60SPoul-Henning Kamp {
662c15afd8SPoul-Henning Kamp 
67cd690b60SPoul-Henning Kamp 	mtx_unlock(&devmtx);
68cd690b60SPoul-Henning Kamp }
69cd690b60SPoul-Henning Kamp 
70cd690b60SPoul-Henning Kamp void
719477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev)
729477d73eSPoul-Henning Kamp {
739477d73eSPoul-Henning Kamp 
749477d73eSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
759477d73eSPoul-Henning Kamp 	mtx_lock(&devmtx);
769477d73eSPoul-Henning Kamp 	dev->si_refcount++;
779477d73eSPoul-Henning Kamp 	mtx_unlock(&devmtx);
789477d73eSPoul-Henning Kamp }
799477d73eSPoul-Henning Kamp 
809477d73eSPoul-Henning Kamp void
81eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev)
82cd690b60SPoul-Henning Kamp {
832c15afd8SPoul-Henning Kamp 
841a1457d4SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
85cd690b60SPoul-Henning Kamp 	dev->si_refcount++;
86cd690b60SPoul-Henning Kamp }
87cd690b60SPoul-Henning Kamp 
88cd690b60SPoul-Henning Kamp void
89aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev)
90cd690b60SPoul-Henning Kamp {
91aa2f6ddcSPoul-Henning Kamp 	int flag = 0;
92a0e78d2eSPoul-Henning Kamp 
93ba285125SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
94ba285125SPoul-Henning Kamp 	dev_lock();
95cd690b60SPoul-Henning Kamp 	dev->si_refcount--;
96cd690b60SPoul-Henning Kamp 	KASSERT(dev->si_refcount >= 0,
97cd690b60SPoul-Henning Kamp 	    ("dev_rel(%s) gave negative count", devtoname(dev)));
98aa2f6ddcSPoul-Henning Kamp 	if (dev->si_usecount == 0 &&
99aa2f6ddcSPoul-Henning Kamp 	    (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
100cd690b60SPoul-Henning Kamp 	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
101cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
102ba285125SPoul-Henning Kamp 		flag = 1;
103ba285125SPoul-Henning Kamp 	}
104ba285125SPoul-Henning Kamp 	dev_unlock();
105ba285125SPoul-Henning Kamp 	if (flag)
106cd690b60SPoul-Henning Kamp 		freedev(dev);
107cd690b60SPoul-Henning Kamp }
108ba285125SPoul-Henning Kamp 
1092c15afd8SPoul-Henning Kamp struct cdevsw *
1102c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev)
1112c15afd8SPoul-Henning Kamp {
1122c15afd8SPoul-Henning Kamp 	struct cdevsw *csw;
1132c15afd8SPoul-Henning Kamp 
1142c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1152c15afd8SPoul-Henning Kamp 	dev_lock();
1162c15afd8SPoul-Henning Kamp 	csw = dev->si_devsw;
1172c15afd8SPoul-Henning Kamp 	if (csw != NULL)
1182c15afd8SPoul-Henning Kamp 		dev->si_threadcount++;
1192c15afd8SPoul-Henning Kamp 	dev_unlock();
1202c15afd8SPoul-Henning Kamp 	return (csw);
1212c15afd8SPoul-Henning Kamp }
1222c15afd8SPoul-Henning Kamp 
1232c15afd8SPoul-Henning Kamp void
1242c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev)
1252c15afd8SPoul-Henning Kamp {
1262c15afd8SPoul-Henning Kamp 
1272c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1282c15afd8SPoul-Henning Kamp 	dev_lock();
1292c15afd8SPoul-Henning Kamp 	dev->si_threadcount--;
1302c15afd8SPoul-Henning Kamp 	dev_unlock();
1312c15afd8SPoul-Henning Kamp }
132cd690b60SPoul-Henning Kamp 
133b2941431SPoul-Henning Kamp int
134b2941431SPoul-Henning Kamp nullop(void)
135b2941431SPoul-Henning Kamp {
136b2941431SPoul-Henning Kamp 
137b2941431SPoul-Henning Kamp 	return (0);
138b2941431SPoul-Henning Kamp }
139b2941431SPoul-Henning Kamp 
140b2941431SPoul-Henning Kamp int
141b2941431SPoul-Henning Kamp eopnotsupp(void)
142b2941431SPoul-Henning Kamp {
143b2941431SPoul-Henning Kamp 
144b2941431SPoul-Henning Kamp 	return (EOPNOTSUPP);
145b2941431SPoul-Henning Kamp }
14602574b19SPoul-Henning Kamp 
14702574b19SPoul-Henning Kamp static int
14802574b19SPoul-Henning Kamp enxio(void)
14902574b19SPoul-Henning Kamp {
15002574b19SPoul-Henning Kamp 	return (ENXIO);
15102574b19SPoul-Henning Kamp }
15202574b19SPoul-Henning Kamp 
153b2941431SPoul-Henning Kamp static int
154b2941431SPoul-Henning Kamp enodev(void)
155b2941431SPoul-Henning Kamp {
156b2941431SPoul-Henning Kamp 	return (ENODEV);
157b2941431SPoul-Henning Kamp }
158b2941431SPoul-Henning Kamp 
159b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */
160b2941431SPoul-Henning Kamp 
16102574b19SPoul-Henning Kamp #define dead_open	(d_open_t *)enxio
16202574b19SPoul-Henning Kamp #define dead_close	(d_close_t *)enxio
16302574b19SPoul-Henning Kamp #define dead_read	(d_read_t *)enxio
16402574b19SPoul-Henning Kamp #define dead_write	(d_write_t *)enxio
16502574b19SPoul-Henning Kamp #define dead_ioctl	(d_ioctl_t *)enxio
166b2941431SPoul-Henning Kamp #define dead_poll	(d_poll_t *)enodev
167b2941431SPoul-Henning Kamp #define dead_mmap	(d_mmap_t *)enodev
16802574b19SPoul-Henning Kamp 
16902574b19SPoul-Henning Kamp static void
17002574b19SPoul-Henning Kamp dead_strategy(struct bio *bp)
17102574b19SPoul-Henning Kamp {
17202574b19SPoul-Henning Kamp 
17302574b19SPoul-Henning Kamp 	biofinish(bp, NULL, ENXIO);
17402574b19SPoul-Henning Kamp }
17502574b19SPoul-Henning Kamp 
1762c6b49f6SPoul-Henning Kamp #define dead_dump	(dumper_t *)enxio
17702574b19SPoul-Henning Kamp #define dead_kqfilter	(d_kqfilter_t *)enxio
17802574b19SPoul-Henning Kamp 
17902574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = {
180dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
181dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
1827ac40f5fSPoul-Henning Kamp 	.d_open =	dead_open,
1837ac40f5fSPoul-Henning Kamp 	.d_close =	dead_close,
1847ac40f5fSPoul-Henning Kamp 	.d_read =	dead_read,
1857ac40f5fSPoul-Henning Kamp 	.d_write =	dead_write,
1867ac40f5fSPoul-Henning Kamp 	.d_ioctl =	dead_ioctl,
1877ac40f5fSPoul-Henning Kamp 	.d_poll =	dead_poll,
1887ac40f5fSPoul-Henning Kamp 	.d_mmap =	dead_mmap,
1897ac40f5fSPoul-Henning Kamp 	.d_strategy =	dead_strategy,
1907ac40f5fSPoul-Henning Kamp 	.d_name =	"dead",
1917ac40f5fSPoul-Henning Kamp 	.d_dump =	dead_dump,
1927ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	dead_kqfilter
19302574b19SPoul-Henning Kamp };
19402574b19SPoul-Henning Kamp 
195b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */
196b2941431SPoul-Henning Kamp 
197b2941431SPoul-Henning Kamp #define null_open	(d_open_t *)nullop
198b2941431SPoul-Henning Kamp #define null_close	(d_close_t *)nullop
199b2941431SPoul-Henning Kamp #define no_read		(d_read_t *)enodev
200b2941431SPoul-Henning Kamp #define no_write	(d_write_t *)enodev
201b2941431SPoul-Henning Kamp #define no_ioctl	(d_ioctl_t *)enodev
202b2941431SPoul-Henning Kamp #define no_mmap		(d_mmap_t *)enodev
203ad3b9257SJohn-Mark Gurney #define no_kqfilter	(d_kqfilter_t *)enodev
204b2941431SPoul-Henning Kamp 
205b2941431SPoul-Henning Kamp static void
206b2941431SPoul-Henning Kamp no_strategy(struct bio *bp)
207b2941431SPoul-Henning Kamp {
208b2941431SPoul-Henning Kamp 
209b2941431SPoul-Henning Kamp 	biofinish(bp, NULL, ENODEV);
210b2941431SPoul-Henning Kamp }
211b2941431SPoul-Henning Kamp 
212b2941431SPoul-Henning Kamp static int
21389c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
214b2941431SPoul-Henning Kamp {
215b2941431SPoul-Henning Kamp 	/*
216b2941431SPoul-Henning Kamp 	 * Return true for read/write.  If the user asked for something
217b2941431SPoul-Henning Kamp 	 * special, return POLLNVAL, so that clients have a way of
218b2941431SPoul-Henning Kamp 	 * determining reliably whether or not the extended
219b2941431SPoul-Henning Kamp 	 * functionality is present without hard-coding knowledge
220b2941431SPoul-Henning Kamp 	 * of specific filesystem implementations.
221b2941431SPoul-Henning Kamp 	 * Stay in sync with vop_nopoll().
222b2941431SPoul-Henning Kamp 	 */
223b2941431SPoul-Henning Kamp 	if (events & ~POLLSTANDARD)
224b2941431SPoul-Henning Kamp 		return (POLLNVAL);
225b2941431SPoul-Henning Kamp 
226b2941431SPoul-Henning Kamp 	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
227b2941431SPoul-Henning Kamp }
228b2941431SPoul-Henning Kamp 
229b2941431SPoul-Henning Kamp #define no_dump		(dumper_t *)enodev
2304e4a7663SPoul-Henning Kamp 
2312447bec8SPoul-Henning Kamp /*
23289c9c53dSPoul-Henning Kamp  * struct cdev * and u_dev_t primitives
233bfbb9ce6SPoul-Henning Kamp  */
234bfbb9ce6SPoul-Henning Kamp 
235bfbb9ce6SPoul-Henning Kamp int
23689c9c53dSPoul-Henning Kamp minor(struct cdev *x)
237bfbb9ce6SPoul-Henning Kamp {
238f3732fd1SPoul-Henning Kamp 	if (x == NULL)
239f3732fd1SPoul-Henning Kamp 		return NODEV;
2400a2e49f1SPoul-Henning Kamp 	return(x->si_drv0 & MAXMINOR);
241bfbb9ce6SPoul-Henning Kamp }
242bfbb9ce6SPoul-Henning Kamp 
2439a27d579SPoul-Henning Kamp int
24489c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x)
2459a27d579SPoul-Henning Kamp {
2469a27d579SPoul-Henning Kamp 
247f3732fd1SPoul-Henning Kamp 	if (x == NULL)
248f3732fd1SPoul-Henning Kamp 		return NODEV;
24937085a39SPoul-Henning Kamp 	return (minor2unit(minor(x)));
2503a85fd26SPoul-Henning Kamp }
2513a85fd26SPoul-Henning Kamp 
2523238ec33SPoul-Henning Kamp u_int
2533238ec33SPoul-Henning Kamp minor2unit(u_int _minor)
2543a85fd26SPoul-Henning Kamp {
2553a85fd26SPoul-Henning Kamp 
256d9aaa28fSPoul-Henning Kamp 	KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
2573238ec33SPoul-Henning Kamp 	return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
2589a27d579SPoul-Henning Kamp }
2599a27d579SPoul-Henning Kamp 
260b0d17ba6SPoul-Henning Kamp int
261b0d17ba6SPoul-Henning Kamp unit2minor(int unit)
262b0d17ba6SPoul-Henning Kamp {
263b0d17ba6SPoul-Henning Kamp 
26415b6f00fSPoul-Henning Kamp 	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
265b0d17ba6SPoul-Henning Kamp 	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
266b0d17ba6SPoul-Henning Kamp }
267b0d17ba6SPoul-Henning Kamp 
26889c9c53dSPoul-Henning Kamp static struct cdev *
2693f54a085SPoul-Henning Kamp allocdev(void)
270bfbb9ce6SPoul-Henning Kamp {
271ca916247SPoul-Henning Kamp 	struct cdev *si;
272698bfad7SPoul-Henning Kamp 
2731a1b2800SPoul-Henning Kamp 	si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
274237d2765SPoul-Henning Kamp 	si->si_name = si->__si_namebuf;
2753344c5a1SPoul-Henning Kamp 	LIST_INIT(&si->si_children);
276aa2f6ddcSPoul-Henning Kamp 	LIST_INIT(&si->si_alist);
2773f54a085SPoul-Henning Kamp 	return (si);
2783f54a085SPoul-Henning Kamp }
2793f54a085SPoul-Henning Kamp 
28089c9c53dSPoul-Henning Kamp static struct cdev *
281ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si)
2823f54a085SPoul-Henning Kamp {
283027b1f71SPoul-Henning Kamp 	struct cdev *si2;
284f3732fd1SPoul-Henning Kamp 	dev_t	udev;
2853f54a085SPoul-Henning Kamp 
286027b1f71SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
287b3d82c03SPoul-Henning Kamp 	udev = y;
288ff7284eeSPoul-Henning Kamp 	LIST_FOREACH(si2, &csw->d_devs, si_list) {
2890a2e49f1SPoul-Henning Kamp 		if (si2->si_drv0 == udev) {
290027b1f71SPoul-Henning Kamp 			freedev(si);
291027b1f71SPoul-Henning Kamp 			return (si2);
2923f54a085SPoul-Henning Kamp 		}
293027b1f71SPoul-Henning Kamp 	}
2940a2e49f1SPoul-Henning Kamp 	si->si_drv0 = udev;
295ff7284eeSPoul-Henning Kamp 	LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
296698bfad7SPoul-Henning Kamp 	return (si);
297bfbb9ce6SPoul-Henning Kamp }
298bfbb9ce6SPoul-Henning Kamp 
299cd690b60SPoul-Henning Kamp static void
30089c9c53dSPoul-Henning Kamp freedev(struct cdev *dev)
301d137acccSPoul-Henning Kamp {
302d137acccSPoul-Henning Kamp 
3031a1b2800SPoul-Henning Kamp 	free(dev, M_DEVT);
304d137acccSPoul-Henning Kamp }
305d137acccSPoul-Henning Kamp 
306bfbb9ce6SPoul-Henning Kamp int
307f3732fd1SPoul-Henning Kamp uminor(dev_t dev)
308bfbb9ce6SPoul-Henning Kamp {
309d9aaa28fSPoul-Henning Kamp 	return (dev & MAXMINOR);
310bfbb9ce6SPoul-Henning Kamp }
311bfbb9ce6SPoul-Henning Kamp 
312bfbb9ce6SPoul-Henning Kamp int
313f3732fd1SPoul-Henning Kamp umajor(dev_t dev)
314bfbb9ce6SPoul-Henning Kamp {
315d9aaa28fSPoul-Henning Kamp 	return ((dev & ~MAXMINOR) >> 8);
316bfbb9ce6SPoul-Henning Kamp }
317bfbb9ce6SPoul-Henning Kamp 
3182a3faf2fSPoul-Henning Kamp static void
319cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw)
320cd690b60SPoul-Henning Kamp {
321b3d82c03SPoul-Henning Kamp 
322652d0472SPoul-Henning Kamp 	devsw->d_flags &= ~D_INIT;
323b0b03348SPoul-Henning Kamp }
324b0b03348SPoul-Henning Kamp 
325b0b03348SPoul-Henning Kamp static void
326b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw)
327b0b03348SPoul-Henning Kamp {
328b0b03348SPoul-Henning Kamp 
329a0e78d2eSPoul-Henning Kamp 	dev_lock();
330cd690b60SPoul-Henning Kamp 
331800b42bdSPoul-Henning Kamp 	if (devsw->d_version != D_VERSION_01) {
332cd690b60SPoul-Henning Kamp 		printf(
333cd690b60SPoul-Henning Kamp 		    "WARNING: Device driver \"%s\" has wrong version %s\n",
334cd690b60SPoul-Henning Kamp 		    devsw->d_name, "and is disabled.  Recompile KLD module.");
335cd690b60SPoul-Henning Kamp 		devsw->d_open = dead_open;
336cd690b60SPoul-Henning Kamp 		devsw->d_close = dead_close;
337cd690b60SPoul-Henning Kamp 		devsw->d_read = dead_read;
338cd690b60SPoul-Henning Kamp 		devsw->d_write = dead_write;
339cd690b60SPoul-Henning Kamp 		devsw->d_ioctl = dead_ioctl;
340cd690b60SPoul-Henning Kamp 		devsw->d_poll = dead_poll;
341cd690b60SPoul-Henning Kamp 		devsw->d_mmap = dead_mmap;
342cd690b60SPoul-Henning Kamp 		devsw->d_strategy = dead_strategy;
343cd690b60SPoul-Henning Kamp 		devsw->d_dump = dead_dump;
344cd690b60SPoul-Henning Kamp 		devsw->d_kqfilter = dead_kqfilter;
345cd690b60SPoul-Henning Kamp 	}
346cd690b60SPoul-Henning Kamp 
3478e1f1df0SPoul-Henning Kamp 	if (devsw->d_flags & D_TTY) {
3483a95025fSPoul-Henning Kamp 		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
3498e1f1df0SPoul-Henning Kamp 		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
3508e1f1df0SPoul-Henning Kamp 		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
3518e1f1df0SPoul-Henning Kamp 		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
3528e1f1df0SPoul-Henning Kamp 		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
3538e1f1df0SPoul-Henning Kamp 	}
3548e1f1df0SPoul-Henning Kamp 
355b2941431SPoul-Henning Kamp 	if (devsw->d_open == NULL)	devsw->d_open = null_open;
356b2941431SPoul-Henning Kamp 	if (devsw->d_close == NULL)	devsw->d_close = null_close;
357b2941431SPoul-Henning Kamp 	if (devsw->d_read == NULL)	devsw->d_read = no_read;
358b2941431SPoul-Henning Kamp 	if (devsw->d_write == NULL)	devsw->d_write = no_write;
359b2941431SPoul-Henning Kamp 	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
360b2941431SPoul-Henning Kamp 	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
361b2941431SPoul-Henning Kamp 	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
362b2941431SPoul-Henning Kamp 	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
363b2941431SPoul-Henning Kamp 	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
364b2941431SPoul-Henning Kamp 	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
365cd690b60SPoul-Henning Kamp 
366cd690b60SPoul-Henning Kamp 	LIST_INIT(&devsw->d_devs);
367cd690b60SPoul-Henning Kamp 
368cd690b60SPoul-Henning Kamp 	devsw->d_flags |= D_INIT;
369cd690b60SPoul-Henning Kamp 
370a0e78d2eSPoul-Henning Kamp 	dev_unlock();
3712a3faf2fSPoul-Henning Kamp }
37211586717SBrian Somers 
37389c9c53dSPoul-Henning Kamp struct cdev *
3749477d73eSPoul-Henning Kamp make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, const char *fmt, ...)
3752a3faf2fSPoul-Henning Kamp {
37689c9c53dSPoul-Henning Kamp 	struct cdev *dev;
3772a3faf2fSPoul-Henning Kamp 	va_list ap;
3782a3faf2fSPoul-Henning Kamp 	int i;
3792a3faf2fSPoul-Henning Kamp 
380d9aaa28fSPoul-Henning Kamp 	KASSERT((minornr & ~MAXMINOR) == 0,
381cd690b60SPoul-Henning Kamp 	    ("Invalid minor (0x%x) in make_dev", minornr));
382cd690b60SPoul-Henning Kamp 
3839477d73eSPoul-Henning Kamp 	if (!(devsw->d_flags & D_INIT))
3842a3faf2fSPoul-Henning Kamp 		prep_cdevsw(devsw);
385027b1f71SPoul-Henning Kamp 	dev = allocdev();
386027b1f71SPoul-Henning Kamp 	dev_lock();
387ff7284eeSPoul-Henning Kamp 	dev = newdev(devsw, minornr, dev);
38898c469d4SPoul-Henning Kamp 	if (dev->si_flags & SI_CHEAPCLONE &&
38998c469d4SPoul-Henning Kamp 	    dev->si_flags & SI_NAMED &&
39098c469d4SPoul-Henning Kamp 	    dev->si_devsw == devsw) {
39198c469d4SPoul-Henning Kamp 		/*
39298c469d4SPoul-Henning Kamp 		 * This is allowed as it removes races and generally
39398c469d4SPoul-Henning Kamp 		 * simplifies cloning devices.
394cd690b60SPoul-Henning Kamp 		 * XXX: still ??
39598c469d4SPoul-Henning Kamp 		 */
396027b1f71SPoul-Henning Kamp 		dev_unlock();
39798c469d4SPoul-Henning Kamp 		return (dev);
39898c469d4SPoul-Henning Kamp 	}
399cd690b60SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_NAMED),
400ff7284eeSPoul-Henning Kamp 	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
401ff7284eeSPoul-Henning Kamp 	    devsw->d_name, minor(dev), devtoname(dev)));
402cd690b60SPoul-Henning Kamp 
4030ef1c826SPoul-Henning Kamp 	va_start(ap, fmt);
4046334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4056334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4062e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4076334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4086334a663SPoul-Henning Kamp 	}
4090ef1c826SPoul-Henning Kamp 	va_end(ap);
4101a1b2800SPoul-Henning Kamp 
4110ef1c826SPoul-Henning Kamp 	dev->si_devsw = devsw;
4125ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4139477d73eSPoul-Henning Kamp 	dev->si_uid = uid;
4149477d73eSPoul-Henning Kamp 	dev->si_gid = gid;
4159477d73eSPoul-Henning Kamp 	dev->si_mode = mode;
4161744fcd0SJulian Elischer 
4179285a87eSPoul-Henning Kamp 	devfs_create(dev);
418a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4193f54a085SPoul-Henning Kamp 	return (dev);
4203f54a085SPoul-Henning Kamp }
4213f54a085SPoul-Henning Kamp 
4227e7c3f3fSJonathan Lemon int
42389c9c53dSPoul-Henning Kamp dev_named(struct cdev *pdev, const char *name)
4247e7c3f3fSJonathan Lemon {
42589c9c53dSPoul-Henning Kamp 	struct cdev *cdev;
4267e7c3f3fSJonathan Lemon 
4277e7c3f3fSJonathan Lemon 	if (strcmp(devtoname(pdev), name) == 0)
4287e7c3f3fSJonathan Lemon 		return (1);
4297e7c3f3fSJonathan Lemon 	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
4307e7c3f3fSJonathan Lemon 		if (strcmp(devtoname(cdev), name) == 0)
4317e7c3f3fSJonathan Lemon 			return (1);
4327e7c3f3fSJonathan Lemon 	return (0);
4337e7c3f3fSJonathan Lemon }
4347e7c3f3fSJonathan Lemon 
4353344c5a1SPoul-Henning Kamp void
43689c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev)
4373344c5a1SPoul-Henning Kamp {
4383344c5a1SPoul-Henning Kamp 
439a0e78d2eSPoul-Henning Kamp 	dev_lock();
4403344c5a1SPoul-Henning Kamp 	cdev->si_parent = pdev;
4413344c5a1SPoul-Henning Kamp 	cdev->si_flags |= SI_CHILD;
4423344c5a1SPoul-Henning Kamp 	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
443a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4443344c5a1SPoul-Henning Kamp }
4453344c5a1SPoul-Henning Kamp 
44689c9c53dSPoul-Henning Kamp struct cdev *
44789c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...)
4483f54a085SPoul-Henning Kamp {
44989c9c53dSPoul-Henning Kamp 	struct cdev *dev;
4503f54a085SPoul-Henning Kamp 	va_list ap;
4513f54a085SPoul-Henning Kamp 	int i;
4523f54a085SPoul-Henning Kamp 
4533f54a085SPoul-Henning Kamp 	dev = allocdev();
454a0e78d2eSPoul-Henning Kamp 	dev_lock();
4553f54a085SPoul-Henning Kamp 	dev->si_flags |= SI_ALIAS;
4565ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4573f54a085SPoul-Henning Kamp 	va_start(ap, fmt);
4586334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4596334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4602e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4616334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4626334a663SPoul-Henning Kamp 	}
4633f54a085SPoul-Henning Kamp 	va_end(ap);
4643f54a085SPoul-Henning Kamp 
4659285a87eSPoul-Henning Kamp 	devfs_create(dev);
466a0e78d2eSPoul-Henning Kamp 	dev_unlock();
467cd690b60SPoul-Henning Kamp 	dev_depends(pdev, dev);
4680ef1c826SPoul-Henning Kamp 	return (dev);
4690ef1c826SPoul-Henning Kamp }
4700ef1c826SPoul-Henning Kamp 
471cd690b60SPoul-Henning Kamp static void
472aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev)
473d137acccSPoul-Henning Kamp {
474743cd76aSPoul-Henning Kamp 	struct cdevsw *csw;
475743cd76aSPoul-Henning Kamp 
476aa2f6ddcSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
477743cd76aSPoul-Henning Kamp 	KASSERT(dev->si_flags & SI_NAMED,
478ff7284eeSPoul-Henning Kamp 	    ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
4795ef2707eSPoul-Henning Kamp 
4809285a87eSPoul-Henning Kamp 	devfs_destroy(dev);
481cd690b60SPoul-Henning Kamp 
482cd690b60SPoul-Henning Kamp 	/* Remove name marking */
483b0b03348SPoul-Henning Kamp 	dev->si_flags &= ~SI_NAMED;
484b0b03348SPoul-Henning Kamp 
485cd690b60SPoul-Henning Kamp 	/* If we are a child, remove us from the parents list */
4863344c5a1SPoul-Henning Kamp 	if (dev->si_flags & SI_CHILD) {
4873344c5a1SPoul-Henning Kamp 		LIST_REMOVE(dev, si_siblings);
4883344c5a1SPoul-Henning Kamp 		dev->si_flags &= ~SI_CHILD;
4893344c5a1SPoul-Henning Kamp 	}
490cd690b60SPoul-Henning Kamp 
491cd690b60SPoul-Henning Kamp 	/* Kill our children */
4923344c5a1SPoul-Henning Kamp 	while (!LIST_EMPTY(&dev->si_children))
493aa2f6ddcSPoul-Henning Kamp 		destroy_devl(LIST_FIRST(&dev->si_children));
494cd690b60SPoul-Henning Kamp 
495cd690b60SPoul-Henning Kamp 	/* Remove from clone list */
496b0b03348SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
497b0b03348SPoul-Henning Kamp 		LIST_REMOVE(dev, si_clone);
498b0b03348SPoul-Henning Kamp 		dev->si_flags &= ~SI_CLONELIST;
499b0b03348SPoul-Henning Kamp 	}
500cd690b60SPoul-Henning Kamp 
501743cd76aSPoul-Henning Kamp 	csw = dev->si_devsw;
5021abf2c36SBrian Feldman 	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
5031abf2c36SBrian Feldman 	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
504743cd76aSPoul-Henning Kamp 		printf("Purging %lu threads from %s\n",
505743cd76aSPoul-Henning Kamp 		    dev->si_threadcount, devtoname(dev));
506743cd76aSPoul-Henning Kamp 		csw->d_purge(dev);
507743cd76aSPoul-Henning Kamp 		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
508743cd76aSPoul-Henning Kamp 	}
5091abf2c36SBrian Feldman 	if (csw != NULL && csw->d_purge != NULL)
510a5993c33SPoul-Henning Kamp 		printf("All threads purged from %s\n", devtoname(dev));
511743cd76aSPoul-Henning Kamp 
512743cd76aSPoul-Henning Kamp 	dev->si_drv1 = 0;
513743cd76aSPoul-Henning Kamp 	dev->si_drv2 = 0;
514743cd76aSPoul-Henning Kamp 	bzero(&dev->__si_u, sizeof(dev->__si_u));
515743cd76aSPoul-Henning Kamp 
516cd690b60SPoul-Henning Kamp 	if (!(dev->si_flags & SI_ALIAS)) {
517cd690b60SPoul-Henning Kamp 		/* Remove from cdevsw list */
518cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
519cd690b60SPoul-Henning Kamp 
52089c9c53dSPoul-Henning Kamp 		/* If cdevsw has no struct cdev *'s, clean it */
521a5993c33SPoul-Henning Kamp 		if (LIST_EMPTY(&csw->d_devs))
522a5993c33SPoul-Henning Kamp 			fini_cdevsw(csw);
523cd690b60SPoul-Henning Kamp 	}
5245ef2707eSPoul-Henning Kamp 	dev->si_flags &= ~SI_ALIAS;
525743cd76aSPoul-Henning Kamp 
526cd690b60SPoul-Henning Kamp 	if (dev->si_refcount > 0) {
527cd690b60SPoul-Henning Kamp 		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
528cd690b60SPoul-Henning Kamp 	} else {
529d137acccSPoul-Henning Kamp 		freedev(dev);
530d137acccSPoul-Henning Kamp 	}
531cd690b60SPoul-Henning Kamp }
532cd690b60SPoul-Henning Kamp 
533cd690b60SPoul-Henning Kamp void
53489c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev)
535cd690b60SPoul-Henning Kamp {
536cd690b60SPoul-Henning Kamp 
537a0e78d2eSPoul-Henning Kamp 	dev_lock();
538aa2f6ddcSPoul-Henning Kamp 	destroy_devl(dev);
539a0e78d2eSPoul-Henning Kamp 	dev_unlock();
540cd690b60SPoul-Henning Kamp }
541d137acccSPoul-Henning Kamp 
542c32cc149SBruce Evans const char *
54389c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev)
544b8e49f68SBill Fumerola {
545d137acccSPoul-Henning Kamp 	char *p;
5468ff33adbSPoul-Henning Kamp 	struct cdevsw *csw;
547c32cc149SBruce Evans 	int mynor;
548b8e49f68SBill Fumerola 
549d137acccSPoul-Henning Kamp 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
550d137acccSPoul-Henning Kamp 		p = dev->si_name;
5518ff33adbSPoul-Henning Kamp 		csw = dev_refthread(dev);
5528ff33adbSPoul-Henning Kamp 		if (csw != NULL) {
5538ff33adbSPoul-Henning Kamp 			sprintf(p, "(%s)", csw->d_name);
5548ff33adbSPoul-Henning Kamp 			dev_relthread(dev);
5558ff33adbSPoul-Henning Kamp 		}
556d137acccSPoul-Henning Kamp 		p += strlen(p);
557c32cc149SBruce Evans 		mynor = minor(dev);
558c32cc149SBruce Evans 		if (mynor < 0 || mynor > 255)
5598ff33adbSPoul-Henning Kamp 			sprintf(p, "/%#x", (u_int)mynor);
560c32cc149SBruce Evans 		else
5618ff33adbSPoul-Henning Kamp 			sprintf(p, "/%d", mynor);
562d137acccSPoul-Henning Kamp 	}
563b8e49f68SBill Fumerola 	return (dev->si_name);
564b8e49f68SBill Fumerola }
565db901281SPoul-Henning Kamp 
566db901281SPoul-Henning Kamp int
56701de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit)
568db901281SPoul-Henning Kamp {
569db901281SPoul-Henning Kamp 	int u, i;
570db901281SPoul-Henning Kamp 
571db901281SPoul-Henning Kamp 	i = strlen(stem);
57256700d46SBrian Somers 	if (bcmp(stem, name, i) != 0)
57356700d46SBrian Somers 		return (0);
574db901281SPoul-Henning Kamp 	if (!isdigit(name[i]))
575db901281SPoul-Henning Kamp 		return (0);
576db901281SPoul-Henning Kamp 	u = 0;
57710786074SPoul-Henning Kamp 	if (name[i] == '0' && isdigit(name[i+1]))
57810786074SPoul-Henning Kamp 		return (0);
579db901281SPoul-Henning Kamp 	while (isdigit(name[i])) {
580db901281SPoul-Henning Kamp 		u *= 10;
581db901281SPoul-Henning Kamp 		u += name[i++] - '0';
582db901281SPoul-Henning Kamp 	}
583dab3d85fSBrian Feldman 	if (u > 0xffffff)
584dab3d85fSBrian Feldman 		return (0);
585db901281SPoul-Henning Kamp 	*unit = u;
586db901281SPoul-Henning Kamp 	if (namep)
587db901281SPoul-Henning Kamp 		*namep = &name[i];
588db901281SPoul-Henning Kamp 	if (name[i])
589db901281SPoul-Henning Kamp 		return (2);
590db901281SPoul-Henning Kamp 	return (1);
591db901281SPoul-Henning Kamp }
5928d25eb2cSPoul-Henning Kamp 
5938d25eb2cSPoul-Henning Kamp /*
594b0b03348SPoul-Henning Kamp  * Helper functions for cloning device drivers.
595b0b03348SPoul-Henning Kamp  *
596b0b03348SPoul-Henning Kamp  * The objective here is to make it unnecessary for the device drivers to
597b0b03348SPoul-Henning Kamp  * use rman or similar to manage their unit number space.  Due to the way
598b0b03348SPoul-Henning Kamp  * we do "on-demand" devices, using rman or other "private" methods
599b0b03348SPoul-Henning Kamp  * will be very tricky to lock down properly once we lock down this file.
600b0b03348SPoul-Henning Kamp  *
6019a98ae94SLukas Ertl  * Instead we give the drivers these routines which puts the struct cdev *'s
6029a98ae94SLukas Ertl  * that are to be managed on their own list, and gives the driver the ability
603b0b03348SPoul-Henning Kamp  * to ask for the first free unit number or a given specified unit number.
604b0b03348SPoul-Henning Kamp  *
605b0b03348SPoul-Henning Kamp  * In addition these routines support paired devices (pty, nmdm and similar)
606b0b03348SPoul-Henning Kamp  * by respecting a number of "flag" bits in the minor number.
607b0b03348SPoul-Henning Kamp  *
608b0b03348SPoul-Henning Kamp  */
609b0b03348SPoul-Henning Kamp 
610b0b03348SPoul-Henning Kamp struct clonedevs {
611b0b03348SPoul-Henning Kamp 	LIST_HEAD(,cdev)	head;
612b0b03348SPoul-Henning Kamp };
613b0b03348SPoul-Henning Kamp 
6149397290eSPoul-Henning Kamp void
6159397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp)
6169397290eSPoul-Henning Kamp {
6179397290eSPoul-Henning Kamp 
6189397290eSPoul-Henning Kamp 	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
6199397290eSPoul-Henning Kamp 	LIST_INIT(&(*cdp)->head);
6209397290eSPoul-Henning Kamp }
6219397290eSPoul-Henning Kamp 
622b0b03348SPoul-Henning Kamp int
62389c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
624b0b03348SPoul-Henning Kamp {
625b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
626027b1f71SPoul-Henning Kamp 	struct cdev *dev, *ndev, *dl, *de;
627b0b03348SPoul-Henning Kamp 	int unit, low, u;
628b0b03348SPoul-Henning Kamp 
6299397290eSPoul-Henning Kamp 	KASSERT(*cdp != NULL,
6309397290eSPoul-Henning Kamp 	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
631b0b03348SPoul-Henning Kamp 	KASSERT(!(extra & CLONE_UNITMASK),
632b0b03348SPoul-Henning Kamp 	    ("Illegal extra bits (0x%x) in clone_create", extra));
633b0b03348SPoul-Henning Kamp 	KASSERT(*up <= CLONE_UNITMASK,
634b0b03348SPoul-Henning Kamp 	    ("Too high unit (0x%x) in clone_create", *up));
635b0b03348SPoul-Henning Kamp 
6368045ce21SPoul-Henning Kamp 	if (!(csw->d_flags & D_INIT))
6378045ce21SPoul-Henning Kamp 		prep_cdevsw(csw);
638b0b03348SPoul-Henning Kamp 
639b0b03348SPoul-Henning Kamp 	/*
640b0b03348SPoul-Henning Kamp 	 * Search the list for a lot of things in one go:
641b0b03348SPoul-Henning Kamp 	 *   A preexisting match is returned immediately.
642b0b03348SPoul-Henning Kamp 	 *   The lowest free unit number if we are passed -1, and the place
643b0b03348SPoul-Henning Kamp 	 *	 in the list where we should insert that new element.
644b0b03348SPoul-Henning Kamp 	 *   The place to insert a specified unit number, if applicable
645b0b03348SPoul-Henning Kamp 	 *       the end of the list.
646b0b03348SPoul-Henning Kamp 	 */
647b0b03348SPoul-Henning Kamp 	unit = *up;
648027b1f71SPoul-Henning Kamp 	ndev = allocdev();
649027b1f71SPoul-Henning Kamp 	dev_lock();
6508666b655SPoul-Henning Kamp 	low = extra;
651b0b03348SPoul-Henning Kamp 	de = dl = NULL;
6529397290eSPoul-Henning Kamp 	cd = *cdp;
653b0b03348SPoul-Henning Kamp 	LIST_FOREACH(dev, &cd->head, si_clone) {
654027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
655027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
656b0b03348SPoul-Henning Kamp 		u = dev2unit(dev);
657b0b03348SPoul-Henning Kamp 		if (u == (unit | extra)) {
658b0b03348SPoul-Henning Kamp 			*dp = dev;
659027b1f71SPoul-Henning Kamp 			freedev(ndev);
660027b1f71SPoul-Henning Kamp 			dev_unlock();
661b0b03348SPoul-Henning Kamp 			return (0);
662b0b03348SPoul-Henning Kamp 		}
663b0b03348SPoul-Henning Kamp 		if (unit == -1 && u == low) {
664b0b03348SPoul-Henning Kamp 			low++;
665b0b03348SPoul-Henning Kamp 			de = dev;
666b0b03348SPoul-Henning Kamp 			continue;
667b0b03348SPoul-Henning Kamp 		}
6688666b655SPoul-Henning Kamp 		if (u > (unit | extra)) {
669b0b03348SPoul-Henning Kamp 			dl = dev;
670b0b03348SPoul-Henning Kamp 			break;
671b0b03348SPoul-Henning Kamp 		}
672b0b03348SPoul-Henning Kamp 	}
673b0b03348SPoul-Henning Kamp 	if (unit == -1)
6748666b655SPoul-Henning Kamp 		unit = low & CLONE_UNITMASK;
675ff7284eeSPoul-Henning Kamp 	dev = newdev(csw, unit2minor(unit | extra), ndev);
676027b1f71SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
677027b1f71SPoul-Henning Kamp 		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
678027b1f71SPoul-Henning Kamp 		printf("unit=%d\n", unit);
679027b1f71SPoul-Henning Kamp 		LIST_FOREACH(dev, &cd->head, si_clone) {
680027b1f71SPoul-Henning Kamp 			printf("\t%p %s\n", dev, dev->si_name);
681027b1f71SPoul-Henning Kamp 		}
682027b1f71SPoul-Henning Kamp 		panic("foo");
683027b1f71SPoul-Henning Kamp 	}
684b0b03348SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_CLONELIST),
685027b1f71SPoul-Henning Kamp 	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
686b0b03348SPoul-Henning Kamp 	if (dl != NULL)
687b0b03348SPoul-Henning Kamp 		LIST_INSERT_BEFORE(dl, dev, si_clone);
688b0b03348SPoul-Henning Kamp 	else if (de != NULL)
689b0b03348SPoul-Henning Kamp 		LIST_INSERT_AFTER(de, dev, si_clone);
690b0b03348SPoul-Henning Kamp 	else
691b0b03348SPoul-Henning Kamp 		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
692b0b03348SPoul-Henning Kamp 	dev->si_flags |= SI_CLONELIST;
693b0b03348SPoul-Henning Kamp 	*up = unit;
694027b1f71SPoul-Henning Kamp 	dev_unlock();
695b0b03348SPoul-Henning Kamp 	return (1);
696b0b03348SPoul-Henning Kamp }
697b0b03348SPoul-Henning Kamp 
698b0b03348SPoul-Henning Kamp /*
699b0b03348SPoul-Henning Kamp  * Kill everything still on the list.  The driver should already have
70089c9c53dSPoul-Henning Kamp  * disposed of any softc hung of the struct cdev *'s at this time.
701b0b03348SPoul-Henning Kamp  */
702b0b03348SPoul-Henning Kamp void
703b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp)
704b0b03348SPoul-Henning Kamp {
70589c9c53dSPoul-Henning Kamp 	struct cdev *dev, *tdev;
706b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
707b0b03348SPoul-Henning Kamp 
708b0b03348SPoul-Henning Kamp 	cd = *cdp;
709b0b03348SPoul-Henning Kamp 	if (cd == NULL)
710b0b03348SPoul-Henning Kamp 		return;
711027b1f71SPoul-Henning Kamp 	dev_lock();
712b0b03348SPoul-Henning Kamp 	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
713027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
714027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
715b0b03348SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_NAMED,
7160a2e49f1SPoul-Henning Kamp 		    ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
717aa2f6ddcSPoul-Henning Kamp 		destroy_devl(dev);
718b0b03348SPoul-Henning Kamp 	}
719027b1f71SPoul-Henning Kamp 	dev_unlock();
720b0b03348SPoul-Henning Kamp 	free(cd, M_DEVBUF);
721b0b03348SPoul-Henning Kamp 	*cdp = NULL;
722b0b03348SPoul-Henning Kamp }
723