xref: /freebsd/sys/kern/kern_conf.c (revision eb151cb9894524bd39e112c72a401463b1c37482)
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
71eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev)
72cd690b60SPoul-Henning Kamp {
732c15afd8SPoul-Henning Kamp 
741a1457d4SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
75cd690b60SPoul-Henning Kamp 	dev->si_refcount++;
76cd690b60SPoul-Henning Kamp }
77cd690b60SPoul-Henning Kamp 
78cd690b60SPoul-Henning Kamp void
79aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev)
80cd690b60SPoul-Henning Kamp {
81aa2f6ddcSPoul-Henning Kamp 	int flag = 0;
82a0e78d2eSPoul-Henning Kamp 
83ba285125SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
84ba285125SPoul-Henning Kamp 	dev_lock();
85cd690b60SPoul-Henning Kamp 	dev->si_refcount--;
86cd690b60SPoul-Henning Kamp 	KASSERT(dev->si_refcount >= 0,
87cd690b60SPoul-Henning Kamp 	    ("dev_rel(%s) gave negative count", devtoname(dev)));
88aa2f6ddcSPoul-Henning Kamp 	if (dev->si_usecount == 0 &&
89aa2f6ddcSPoul-Henning Kamp 	    (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
90cd690b60SPoul-Henning Kamp 	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
91cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
92ba285125SPoul-Henning Kamp 		flag = 1;
93ba285125SPoul-Henning Kamp 	}
94ba285125SPoul-Henning Kamp 	dev_unlock();
95ba285125SPoul-Henning Kamp 	if (flag)
96cd690b60SPoul-Henning Kamp 		freedev(dev);
97cd690b60SPoul-Henning Kamp }
98ba285125SPoul-Henning Kamp 
992c15afd8SPoul-Henning Kamp struct cdevsw *
1002c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev)
1012c15afd8SPoul-Henning Kamp {
1022c15afd8SPoul-Henning Kamp 	struct cdevsw *csw;
1032c15afd8SPoul-Henning Kamp 
1042c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1052c15afd8SPoul-Henning Kamp 	dev_lock();
1062c15afd8SPoul-Henning Kamp 	csw = dev->si_devsw;
1072c15afd8SPoul-Henning Kamp 	if (csw != NULL)
1082c15afd8SPoul-Henning Kamp 		dev->si_threadcount++;
1092c15afd8SPoul-Henning Kamp 	dev_unlock();
1102c15afd8SPoul-Henning Kamp 	return (csw);
1112c15afd8SPoul-Henning Kamp }
1122c15afd8SPoul-Henning Kamp 
1132c15afd8SPoul-Henning Kamp void
1142c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev)
1152c15afd8SPoul-Henning Kamp {
1162c15afd8SPoul-Henning Kamp 
1172c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1182c15afd8SPoul-Henning Kamp 	dev_lock();
1192c15afd8SPoul-Henning Kamp 	dev->si_threadcount--;
1202c15afd8SPoul-Henning Kamp 	dev_unlock();
1212c15afd8SPoul-Henning Kamp }
122cd690b60SPoul-Henning Kamp 
123b2941431SPoul-Henning Kamp int
124b2941431SPoul-Henning Kamp nullop(void)
125b2941431SPoul-Henning Kamp {
126b2941431SPoul-Henning Kamp 
127b2941431SPoul-Henning Kamp 	return (0);
128b2941431SPoul-Henning Kamp }
129b2941431SPoul-Henning Kamp 
130b2941431SPoul-Henning Kamp int
131b2941431SPoul-Henning Kamp eopnotsupp(void)
132b2941431SPoul-Henning Kamp {
133b2941431SPoul-Henning Kamp 
134b2941431SPoul-Henning Kamp 	return (EOPNOTSUPP);
135b2941431SPoul-Henning Kamp }
13602574b19SPoul-Henning Kamp 
13702574b19SPoul-Henning Kamp static int
13802574b19SPoul-Henning Kamp enxio(void)
13902574b19SPoul-Henning Kamp {
14002574b19SPoul-Henning Kamp 	return (ENXIO);
14102574b19SPoul-Henning Kamp }
14202574b19SPoul-Henning Kamp 
143b2941431SPoul-Henning Kamp static int
144b2941431SPoul-Henning Kamp enodev(void)
145b2941431SPoul-Henning Kamp {
146b2941431SPoul-Henning Kamp 	return (ENODEV);
147b2941431SPoul-Henning Kamp }
148b2941431SPoul-Henning Kamp 
149b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */
150b2941431SPoul-Henning Kamp 
15102574b19SPoul-Henning Kamp #define dead_open	(d_open_t *)enxio
15202574b19SPoul-Henning Kamp #define dead_close	(d_close_t *)enxio
15302574b19SPoul-Henning Kamp #define dead_read	(d_read_t *)enxio
15402574b19SPoul-Henning Kamp #define dead_write	(d_write_t *)enxio
15502574b19SPoul-Henning Kamp #define dead_ioctl	(d_ioctl_t *)enxio
156b2941431SPoul-Henning Kamp #define dead_poll	(d_poll_t *)enodev
157b2941431SPoul-Henning Kamp #define dead_mmap	(d_mmap_t *)enodev
15802574b19SPoul-Henning Kamp 
15902574b19SPoul-Henning Kamp static void
16002574b19SPoul-Henning Kamp dead_strategy(struct bio *bp)
16102574b19SPoul-Henning Kamp {
16202574b19SPoul-Henning Kamp 
16302574b19SPoul-Henning Kamp 	biofinish(bp, NULL, ENXIO);
16402574b19SPoul-Henning Kamp }
16502574b19SPoul-Henning Kamp 
1662c6b49f6SPoul-Henning Kamp #define dead_dump	(dumper_t *)enxio
16702574b19SPoul-Henning Kamp #define dead_kqfilter	(d_kqfilter_t *)enxio
16802574b19SPoul-Henning Kamp 
16902574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = {
170dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
171dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
1727ac40f5fSPoul-Henning Kamp 	.d_open =	dead_open,
1737ac40f5fSPoul-Henning Kamp 	.d_close =	dead_close,
1747ac40f5fSPoul-Henning Kamp 	.d_read =	dead_read,
1757ac40f5fSPoul-Henning Kamp 	.d_write =	dead_write,
1767ac40f5fSPoul-Henning Kamp 	.d_ioctl =	dead_ioctl,
1777ac40f5fSPoul-Henning Kamp 	.d_poll =	dead_poll,
1787ac40f5fSPoul-Henning Kamp 	.d_mmap =	dead_mmap,
1797ac40f5fSPoul-Henning Kamp 	.d_strategy =	dead_strategy,
1807ac40f5fSPoul-Henning Kamp 	.d_name =	"dead",
1817ac40f5fSPoul-Henning Kamp 	.d_dump =	dead_dump,
1827ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	dead_kqfilter
18302574b19SPoul-Henning Kamp };
18402574b19SPoul-Henning Kamp 
185b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */
186b2941431SPoul-Henning Kamp 
187b2941431SPoul-Henning Kamp #define null_open	(d_open_t *)nullop
188b2941431SPoul-Henning Kamp #define null_close	(d_close_t *)nullop
189b2941431SPoul-Henning Kamp #define no_read		(d_read_t *)enodev
190b2941431SPoul-Henning Kamp #define no_write	(d_write_t *)enodev
191b2941431SPoul-Henning Kamp #define no_ioctl	(d_ioctl_t *)enodev
192b2941431SPoul-Henning Kamp #define no_mmap		(d_mmap_t *)enodev
193ad3b9257SJohn-Mark Gurney #define no_kqfilter	(d_kqfilter_t *)enodev
194b2941431SPoul-Henning Kamp 
195b2941431SPoul-Henning Kamp static void
196b2941431SPoul-Henning Kamp no_strategy(struct bio *bp)
197b2941431SPoul-Henning Kamp {
198b2941431SPoul-Henning Kamp 
199b2941431SPoul-Henning Kamp 	biofinish(bp, NULL, ENODEV);
200b2941431SPoul-Henning Kamp }
201b2941431SPoul-Henning Kamp 
202b2941431SPoul-Henning Kamp static int
20389c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
204b2941431SPoul-Henning Kamp {
205b2941431SPoul-Henning Kamp 	/*
206b2941431SPoul-Henning Kamp 	 * Return true for read/write.  If the user asked for something
207b2941431SPoul-Henning Kamp 	 * special, return POLLNVAL, so that clients have a way of
208b2941431SPoul-Henning Kamp 	 * determining reliably whether or not the extended
209b2941431SPoul-Henning Kamp 	 * functionality is present without hard-coding knowledge
210b2941431SPoul-Henning Kamp 	 * of specific filesystem implementations.
211b2941431SPoul-Henning Kamp 	 * Stay in sync with vop_nopoll().
212b2941431SPoul-Henning Kamp 	 */
213b2941431SPoul-Henning Kamp 	if (events & ~POLLSTANDARD)
214b2941431SPoul-Henning Kamp 		return (POLLNVAL);
215b2941431SPoul-Henning Kamp 
216b2941431SPoul-Henning Kamp 	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
217b2941431SPoul-Henning Kamp }
218b2941431SPoul-Henning Kamp 
219b2941431SPoul-Henning Kamp #define no_dump		(dumper_t *)enodev
2204e4a7663SPoul-Henning Kamp 
2212447bec8SPoul-Henning Kamp /*
22289c9c53dSPoul-Henning Kamp  * struct cdev * and u_dev_t primitives
223bfbb9ce6SPoul-Henning Kamp  */
224bfbb9ce6SPoul-Henning Kamp 
225bfbb9ce6SPoul-Henning Kamp int
22689c9c53dSPoul-Henning Kamp minor(struct cdev *x)
227bfbb9ce6SPoul-Henning Kamp {
228f3732fd1SPoul-Henning Kamp 	if (x == NULL)
229f3732fd1SPoul-Henning Kamp 		return NODEV;
2300a2e49f1SPoul-Henning Kamp 	return(x->si_drv0 & MAXMINOR);
231bfbb9ce6SPoul-Henning Kamp }
232bfbb9ce6SPoul-Henning Kamp 
2339a27d579SPoul-Henning Kamp int
23489c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x)
2359a27d579SPoul-Henning Kamp {
2369a27d579SPoul-Henning Kamp 
237f3732fd1SPoul-Henning Kamp 	if (x == NULL)
238f3732fd1SPoul-Henning Kamp 		return NODEV;
23937085a39SPoul-Henning Kamp 	return (minor2unit(minor(x)));
2403a85fd26SPoul-Henning Kamp }
2413a85fd26SPoul-Henning Kamp 
2423238ec33SPoul-Henning Kamp u_int
2433238ec33SPoul-Henning Kamp minor2unit(u_int _minor)
2443a85fd26SPoul-Henning Kamp {
2453a85fd26SPoul-Henning Kamp 
246d9aaa28fSPoul-Henning Kamp 	KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
2473238ec33SPoul-Henning Kamp 	return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
2489a27d579SPoul-Henning Kamp }
2499a27d579SPoul-Henning Kamp 
250b0d17ba6SPoul-Henning Kamp int
251b0d17ba6SPoul-Henning Kamp unit2minor(int unit)
252b0d17ba6SPoul-Henning Kamp {
253b0d17ba6SPoul-Henning Kamp 
25415b6f00fSPoul-Henning Kamp 	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
255b0d17ba6SPoul-Henning Kamp 	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
256b0d17ba6SPoul-Henning Kamp }
257b0d17ba6SPoul-Henning Kamp 
25889c9c53dSPoul-Henning Kamp static struct cdev *
2593f54a085SPoul-Henning Kamp allocdev(void)
260bfbb9ce6SPoul-Henning Kamp {
261ca916247SPoul-Henning Kamp 	struct cdev *si;
262698bfad7SPoul-Henning Kamp 
2631a1b2800SPoul-Henning Kamp 	si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
264237d2765SPoul-Henning Kamp 	si->si_name = si->__si_namebuf;
2653344c5a1SPoul-Henning Kamp 	LIST_INIT(&si->si_children);
266aa2f6ddcSPoul-Henning Kamp 	LIST_INIT(&si->si_alist);
2673f54a085SPoul-Henning Kamp 	return (si);
2683f54a085SPoul-Henning Kamp }
2693f54a085SPoul-Henning Kamp 
27089c9c53dSPoul-Henning Kamp static struct cdev *
271ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si)
2723f54a085SPoul-Henning Kamp {
273027b1f71SPoul-Henning Kamp 	struct cdev *si2;
274f3732fd1SPoul-Henning Kamp 	dev_t	udev;
2753f54a085SPoul-Henning Kamp 
276027b1f71SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
277b3d82c03SPoul-Henning Kamp 	udev = y;
278ff7284eeSPoul-Henning Kamp 	LIST_FOREACH(si2, &csw->d_devs, si_list) {
2790a2e49f1SPoul-Henning Kamp 		if (si2->si_drv0 == udev) {
280027b1f71SPoul-Henning Kamp 			freedev(si);
281027b1f71SPoul-Henning Kamp 			return (si2);
2823f54a085SPoul-Henning Kamp 		}
283027b1f71SPoul-Henning Kamp 	}
2840a2e49f1SPoul-Henning Kamp 	si->si_drv0 = udev;
285ff7284eeSPoul-Henning Kamp 	LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
286698bfad7SPoul-Henning Kamp 	return (si);
287bfbb9ce6SPoul-Henning Kamp }
288bfbb9ce6SPoul-Henning Kamp 
289cd690b60SPoul-Henning Kamp static void
29089c9c53dSPoul-Henning Kamp freedev(struct cdev *dev)
291d137acccSPoul-Henning Kamp {
292d137acccSPoul-Henning Kamp 
2931a1b2800SPoul-Henning Kamp 	free(dev, M_DEVT);
294d137acccSPoul-Henning Kamp }
295d137acccSPoul-Henning Kamp 
296bfbb9ce6SPoul-Henning Kamp int
297f3732fd1SPoul-Henning Kamp uminor(dev_t dev)
298bfbb9ce6SPoul-Henning Kamp {
299d9aaa28fSPoul-Henning Kamp 	return (dev & MAXMINOR);
300bfbb9ce6SPoul-Henning Kamp }
301bfbb9ce6SPoul-Henning Kamp 
302bfbb9ce6SPoul-Henning Kamp int
303f3732fd1SPoul-Henning Kamp umajor(dev_t dev)
304bfbb9ce6SPoul-Henning Kamp {
305d9aaa28fSPoul-Henning Kamp 	return ((dev & ~MAXMINOR) >> 8);
306bfbb9ce6SPoul-Henning Kamp }
307bfbb9ce6SPoul-Henning Kamp 
3082a3faf2fSPoul-Henning Kamp static void
309cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw)
310cd690b60SPoul-Henning Kamp {
311b3d82c03SPoul-Henning Kamp 
312652d0472SPoul-Henning Kamp 	devsw->d_flags &= ~D_INIT;
313b0b03348SPoul-Henning Kamp }
314b0b03348SPoul-Henning Kamp 
315b0b03348SPoul-Henning Kamp static void
316b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw)
317b0b03348SPoul-Henning Kamp {
318b0b03348SPoul-Henning Kamp 
319a0e78d2eSPoul-Henning Kamp 	dev_lock();
320cd690b60SPoul-Henning Kamp 
321800b42bdSPoul-Henning Kamp 	if (devsw->d_version != D_VERSION_01) {
322cd690b60SPoul-Henning Kamp 		printf(
323cd690b60SPoul-Henning Kamp 		    "WARNING: Device driver \"%s\" has wrong version %s\n",
324cd690b60SPoul-Henning Kamp 		    devsw->d_name, "and is disabled.  Recompile KLD module.");
325cd690b60SPoul-Henning Kamp 		devsw->d_open = dead_open;
326cd690b60SPoul-Henning Kamp 		devsw->d_close = dead_close;
327cd690b60SPoul-Henning Kamp 		devsw->d_read = dead_read;
328cd690b60SPoul-Henning Kamp 		devsw->d_write = dead_write;
329cd690b60SPoul-Henning Kamp 		devsw->d_ioctl = dead_ioctl;
330cd690b60SPoul-Henning Kamp 		devsw->d_poll = dead_poll;
331cd690b60SPoul-Henning Kamp 		devsw->d_mmap = dead_mmap;
332cd690b60SPoul-Henning Kamp 		devsw->d_strategy = dead_strategy;
333cd690b60SPoul-Henning Kamp 		devsw->d_dump = dead_dump;
334cd690b60SPoul-Henning Kamp 		devsw->d_kqfilter = dead_kqfilter;
335cd690b60SPoul-Henning Kamp 	}
336cd690b60SPoul-Henning Kamp 
3378e1f1df0SPoul-Henning Kamp 	if (devsw->d_flags & D_TTY) {
3383a95025fSPoul-Henning Kamp 		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
3398e1f1df0SPoul-Henning Kamp 		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
3408e1f1df0SPoul-Henning Kamp 		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
3418e1f1df0SPoul-Henning Kamp 		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
3428e1f1df0SPoul-Henning Kamp 		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
3438e1f1df0SPoul-Henning Kamp 	}
3448e1f1df0SPoul-Henning Kamp 
345b2941431SPoul-Henning Kamp 	if (devsw->d_open == NULL)	devsw->d_open = null_open;
346b2941431SPoul-Henning Kamp 	if (devsw->d_close == NULL)	devsw->d_close = null_close;
347b2941431SPoul-Henning Kamp 	if (devsw->d_read == NULL)	devsw->d_read = no_read;
348b2941431SPoul-Henning Kamp 	if (devsw->d_write == NULL)	devsw->d_write = no_write;
349b2941431SPoul-Henning Kamp 	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
350b2941431SPoul-Henning Kamp 	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
351b2941431SPoul-Henning Kamp 	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
352b2941431SPoul-Henning Kamp 	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
353b2941431SPoul-Henning Kamp 	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
354b2941431SPoul-Henning Kamp 	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
355cd690b60SPoul-Henning Kamp 
356cd690b60SPoul-Henning Kamp 	LIST_INIT(&devsw->d_devs);
357cd690b60SPoul-Henning Kamp 
358cd690b60SPoul-Henning Kamp 	devsw->d_flags |= D_INIT;
359cd690b60SPoul-Henning Kamp 
360a0e78d2eSPoul-Henning Kamp 	dev_unlock();
3612a3faf2fSPoul-Henning Kamp }
36211586717SBrian Somers 
36389c9c53dSPoul-Henning Kamp struct cdev *
364cd690b60SPoul-Henning Kamp make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
3652a3faf2fSPoul-Henning Kamp {
36689c9c53dSPoul-Henning Kamp 	struct cdev *dev;
3672a3faf2fSPoul-Henning Kamp 	va_list ap;
3682a3faf2fSPoul-Henning Kamp 	int i;
3692a3faf2fSPoul-Henning Kamp 
370d9aaa28fSPoul-Henning Kamp 	KASSERT((minornr & ~MAXMINOR) == 0,
371cd690b60SPoul-Henning Kamp 	    ("Invalid minor (0x%x) in make_dev", minornr));
372cd690b60SPoul-Henning Kamp 
373800b42bdSPoul-Henning Kamp 	if (!(devsw->d_flags & D_INIT)) {
3742a3faf2fSPoul-Henning Kamp 		prep_cdevsw(devsw);
375800b42bdSPoul-Henning Kamp 		if (devsw->d_uid == 0)
376800b42bdSPoul-Henning Kamp 			devsw->d_uid = uid;
377800b42bdSPoul-Henning Kamp 		if (devsw->d_gid == 0)
378800b42bdSPoul-Henning Kamp 			devsw->d_gid = gid;
379800b42bdSPoul-Henning Kamp 		if (devsw->d_mode == 0)
380800b42bdSPoul-Henning Kamp 			devsw->d_mode = perms;
381800b42bdSPoul-Henning Kamp 	}
382027b1f71SPoul-Henning Kamp 	dev = allocdev();
383027b1f71SPoul-Henning Kamp 	dev_lock();
384ff7284eeSPoul-Henning Kamp 	dev = newdev(devsw, minornr, dev);
38598c469d4SPoul-Henning Kamp 	if (dev->si_flags & SI_CHEAPCLONE &&
38698c469d4SPoul-Henning Kamp 	    dev->si_flags & SI_NAMED &&
38798c469d4SPoul-Henning Kamp 	    dev->si_devsw == devsw) {
38898c469d4SPoul-Henning Kamp 		/*
38998c469d4SPoul-Henning Kamp 		 * This is allowed as it removes races and generally
39098c469d4SPoul-Henning Kamp 		 * simplifies cloning devices.
391cd690b60SPoul-Henning Kamp 		 * XXX: still ??
39298c469d4SPoul-Henning Kamp 		 */
393027b1f71SPoul-Henning Kamp 		dev_unlock();
39498c469d4SPoul-Henning Kamp 		return (dev);
39598c469d4SPoul-Henning Kamp 	}
396cd690b60SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_NAMED),
397ff7284eeSPoul-Henning Kamp 	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
398ff7284eeSPoul-Henning Kamp 	    devsw->d_name, minor(dev), devtoname(dev)));
399cd690b60SPoul-Henning Kamp 
4000ef1c826SPoul-Henning Kamp 	va_start(ap, fmt);
4016334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4026334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4032e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4046334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4056334a663SPoul-Henning Kamp 	}
4060ef1c826SPoul-Henning Kamp 	va_end(ap);
4071a1b2800SPoul-Henning Kamp 
4080ef1c826SPoul-Henning Kamp 	dev->si_devsw = devsw;
4095ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4101744fcd0SJulian Elischer 
4119285a87eSPoul-Henning Kamp 	devfs_create(dev);
412a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4133f54a085SPoul-Henning Kamp 	return (dev);
4143f54a085SPoul-Henning Kamp }
4153f54a085SPoul-Henning Kamp 
4167e7c3f3fSJonathan Lemon int
41789c9c53dSPoul-Henning Kamp dev_named(struct cdev *pdev, const char *name)
4187e7c3f3fSJonathan Lemon {
41989c9c53dSPoul-Henning Kamp 	struct cdev *cdev;
4207e7c3f3fSJonathan Lemon 
4217e7c3f3fSJonathan Lemon 	if (strcmp(devtoname(pdev), name) == 0)
4227e7c3f3fSJonathan Lemon 		return (1);
4237e7c3f3fSJonathan Lemon 	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
4247e7c3f3fSJonathan Lemon 		if (strcmp(devtoname(cdev), name) == 0)
4257e7c3f3fSJonathan Lemon 			return (1);
4267e7c3f3fSJonathan Lemon 	return (0);
4277e7c3f3fSJonathan Lemon }
4287e7c3f3fSJonathan Lemon 
4293344c5a1SPoul-Henning Kamp void
43089c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev)
4313344c5a1SPoul-Henning Kamp {
4323344c5a1SPoul-Henning Kamp 
433a0e78d2eSPoul-Henning Kamp 	dev_lock();
4343344c5a1SPoul-Henning Kamp 	cdev->si_parent = pdev;
4353344c5a1SPoul-Henning Kamp 	cdev->si_flags |= SI_CHILD;
4363344c5a1SPoul-Henning Kamp 	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
437a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4383344c5a1SPoul-Henning Kamp }
4393344c5a1SPoul-Henning Kamp 
44089c9c53dSPoul-Henning Kamp struct cdev *
44189c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...)
4423f54a085SPoul-Henning Kamp {
44389c9c53dSPoul-Henning Kamp 	struct cdev *dev;
4443f54a085SPoul-Henning Kamp 	va_list ap;
4453f54a085SPoul-Henning Kamp 	int i;
4463f54a085SPoul-Henning Kamp 
4473f54a085SPoul-Henning Kamp 	dev = allocdev();
448a0e78d2eSPoul-Henning Kamp 	dev_lock();
4493f54a085SPoul-Henning Kamp 	dev->si_flags |= SI_ALIAS;
4505ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4513f54a085SPoul-Henning Kamp 	va_start(ap, fmt);
4526334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4536334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4542e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4556334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4566334a663SPoul-Henning Kamp 	}
4573f54a085SPoul-Henning Kamp 	va_end(ap);
4583f54a085SPoul-Henning Kamp 
4599285a87eSPoul-Henning Kamp 	devfs_create(dev);
460a0e78d2eSPoul-Henning Kamp 	dev_unlock();
461cd690b60SPoul-Henning Kamp 	dev_depends(pdev, dev);
4620ef1c826SPoul-Henning Kamp 	return (dev);
4630ef1c826SPoul-Henning Kamp }
4640ef1c826SPoul-Henning Kamp 
465cd690b60SPoul-Henning Kamp static void
466aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev)
467d137acccSPoul-Henning Kamp {
468743cd76aSPoul-Henning Kamp 	struct cdevsw *csw;
469743cd76aSPoul-Henning Kamp 
470aa2f6ddcSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
471743cd76aSPoul-Henning Kamp 	KASSERT(dev->si_flags & SI_NAMED,
472ff7284eeSPoul-Henning Kamp 	    ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
4735ef2707eSPoul-Henning Kamp 
4749285a87eSPoul-Henning Kamp 	devfs_destroy(dev);
475cd690b60SPoul-Henning Kamp 
476cd690b60SPoul-Henning Kamp 	/* Remove name marking */
477b0b03348SPoul-Henning Kamp 	dev->si_flags &= ~SI_NAMED;
478b0b03348SPoul-Henning Kamp 
479cd690b60SPoul-Henning Kamp 	/* If we are a child, remove us from the parents list */
4803344c5a1SPoul-Henning Kamp 	if (dev->si_flags & SI_CHILD) {
4813344c5a1SPoul-Henning Kamp 		LIST_REMOVE(dev, si_siblings);
4823344c5a1SPoul-Henning Kamp 		dev->si_flags &= ~SI_CHILD;
4833344c5a1SPoul-Henning Kamp 	}
484cd690b60SPoul-Henning Kamp 
485cd690b60SPoul-Henning Kamp 	/* Kill our children */
4863344c5a1SPoul-Henning Kamp 	while (!LIST_EMPTY(&dev->si_children))
487aa2f6ddcSPoul-Henning Kamp 		destroy_devl(LIST_FIRST(&dev->si_children));
488cd690b60SPoul-Henning Kamp 
489cd690b60SPoul-Henning Kamp 	/* Remove from clone list */
490b0b03348SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
491b0b03348SPoul-Henning Kamp 		LIST_REMOVE(dev, si_clone);
492b0b03348SPoul-Henning Kamp 		dev->si_flags &= ~SI_CLONELIST;
493b0b03348SPoul-Henning Kamp 	}
494cd690b60SPoul-Henning Kamp 
495743cd76aSPoul-Henning Kamp 	csw = dev->si_devsw;
4961abf2c36SBrian Feldman 	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
4971abf2c36SBrian Feldman 	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
498743cd76aSPoul-Henning Kamp 		printf("Purging %lu threads from %s\n",
499743cd76aSPoul-Henning Kamp 		    dev->si_threadcount, devtoname(dev));
500743cd76aSPoul-Henning Kamp 		csw->d_purge(dev);
501743cd76aSPoul-Henning Kamp 		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
502743cd76aSPoul-Henning Kamp 	}
5031abf2c36SBrian Feldman 	if (csw != NULL && csw->d_purge != NULL)
504a5993c33SPoul-Henning Kamp 		printf("All threads purged from %s\n", devtoname(dev));
505743cd76aSPoul-Henning Kamp 
506743cd76aSPoul-Henning Kamp 	dev->si_drv1 = 0;
507743cd76aSPoul-Henning Kamp 	dev->si_drv2 = 0;
508743cd76aSPoul-Henning Kamp 	bzero(&dev->__si_u, sizeof(dev->__si_u));
509743cd76aSPoul-Henning Kamp 
510cd690b60SPoul-Henning Kamp 	if (!(dev->si_flags & SI_ALIAS)) {
511cd690b60SPoul-Henning Kamp 		/* Remove from cdevsw list */
512cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
513cd690b60SPoul-Henning Kamp 
51489c9c53dSPoul-Henning Kamp 		/* If cdevsw has no struct cdev *'s, clean it */
515a5993c33SPoul-Henning Kamp 		if (LIST_EMPTY(&csw->d_devs))
516a5993c33SPoul-Henning Kamp 			fini_cdevsw(csw);
517cd690b60SPoul-Henning Kamp 	}
5185ef2707eSPoul-Henning Kamp 	dev->si_flags &= ~SI_ALIAS;
519743cd76aSPoul-Henning Kamp 
520cd690b60SPoul-Henning Kamp 	if (dev->si_refcount > 0) {
521cd690b60SPoul-Henning Kamp 		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
522cd690b60SPoul-Henning Kamp 	} else {
523d137acccSPoul-Henning Kamp 		freedev(dev);
524d137acccSPoul-Henning Kamp 	}
525cd690b60SPoul-Henning Kamp }
526cd690b60SPoul-Henning Kamp 
527cd690b60SPoul-Henning Kamp void
52889c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev)
529cd690b60SPoul-Henning Kamp {
530cd690b60SPoul-Henning Kamp 
531a0e78d2eSPoul-Henning Kamp 	dev_lock();
532aa2f6ddcSPoul-Henning Kamp 	destroy_devl(dev);
533a0e78d2eSPoul-Henning Kamp 	dev_unlock();
534cd690b60SPoul-Henning Kamp }
535d137acccSPoul-Henning Kamp 
536c32cc149SBruce Evans const char *
53789c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev)
538b8e49f68SBill Fumerola {
539d137acccSPoul-Henning Kamp 	char *p;
5408ff33adbSPoul-Henning Kamp 	struct cdevsw *csw;
541c32cc149SBruce Evans 	int mynor;
542b8e49f68SBill Fumerola 
543d137acccSPoul-Henning Kamp 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
544d137acccSPoul-Henning Kamp 		p = dev->si_name;
5458ff33adbSPoul-Henning Kamp 		csw = dev_refthread(dev);
5468ff33adbSPoul-Henning Kamp 		if (csw != NULL) {
5478ff33adbSPoul-Henning Kamp 			sprintf(p, "(%s)", csw->d_name);
5488ff33adbSPoul-Henning Kamp 			dev_relthread(dev);
5498ff33adbSPoul-Henning Kamp 		}
550d137acccSPoul-Henning Kamp 		p += strlen(p);
551c32cc149SBruce Evans 		mynor = minor(dev);
552c32cc149SBruce Evans 		if (mynor < 0 || mynor > 255)
5538ff33adbSPoul-Henning Kamp 			sprintf(p, "/%#x", (u_int)mynor);
554c32cc149SBruce Evans 		else
5558ff33adbSPoul-Henning Kamp 			sprintf(p, "/%d", mynor);
556d137acccSPoul-Henning Kamp 	}
557b8e49f68SBill Fumerola 	return (dev->si_name);
558b8e49f68SBill Fumerola }
559db901281SPoul-Henning Kamp 
560db901281SPoul-Henning Kamp int
56101de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit)
562db901281SPoul-Henning Kamp {
563db901281SPoul-Henning Kamp 	int u, i;
564db901281SPoul-Henning Kamp 
565db901281SPoul-Henning Kamp 	i = strlen(stem);
56656700d46SBrian Somers 	if (bcmp(stem, name, i) != 0)
56756700d46SBrian Somers 		return (0);
568db901281SPoul-Henning Kamp 	if (!isdigit(name[i]))
569db901281SPoul-Henning Kamp 		return (0);
570db901281SPoul-Henning Kamp 	u = 0;
57110786074SPoul-Henning Kamp 	if (name[i] == '0' && isdigit(name[i+1]))
57210786074SPoul-Henning Kamp 		return (0);
573db901281SPoul-Henning Kamp 	while (isdigit(name[i])) {
574db901281SPoul-Henning Kamp 		u *= 10;
575db901281SPoul-Henning Kamp 		u += name[i++] - '0';
576db901281SPoul-Henning Kamp 	}
577dab3d85fSBrian Feldman 	if (u > 0xffffff)
578dab3d85fSBrian Feldman 		return (0);
579db901281SPoul-Henning Kamp 	*unit = u;
580db901281SPoul-Henning Kamp 	if (namep)
581db901281SPoul-Henning Kamp 		*namep = &name[i];
582db901281SPoul-Henning Kamp 	if (name[i])
583db901281SPoul-Henning Kamp 		return (2);
584db901281SPoul-Henning Kamp 	return (1);
585db901281SPoul-Henning Kamp }
5868d25eb2cSPoul-Henning Kamp 
5878d25eb2cSPoul-Henning Kamp /*
588b0b03348SPoul-Henning Kamp  * Helper functions for cloning device drivers.
589b0b03348SPoul-Henning Kamp  *
590b0b03348SPoul-Henning Kamp  * The objective here is to make it unnecessary for the device drivers to
591b0b03348SPoul-Henning Kamp  * use rman or similar to manage their unit number space.  Due to the way
592b0b03348SPoul-Henning Kamp  * we do "on-demand" devices, using rman or other "private" methods
593b0b03348SPoul-Henning Kamp  * will be very tricky to lock down properly once we lock down this file.
594b0b03348SPoul-Henning Kamp  *
5959a98ae94SLukas Ertl  * Instead we give the drivers these routines which puts the struct cdev *'s
5969a98ae94SLukas Ertl  * that are to be managed on their own list, and gives the driver the ability
597b0b03348SPoul-Henning Kamp  * to ask for the first free unit number or a given specified unit number.
598b0b03348SPoul-Henning Kamp  *
599b0b03348SPoul-Henning Kamp  * In addition these routines support paired devices (pty, nmdm and similar)
600b0b03348SPoul-Henning Kamp  * by respecting a number of "flag" bits in the minor number.
601b0b03348SPoul-Henning Kamp  *
602b0b03348SPoul-Henning Kamp  */
603b0b03348SPoul-Henning Kamp 
604b0b03348SPoul-Henning Kamp struct clonedevs {
605b0b03348SPoul-Henning Kamp 	LIST_HEAD(,cdev)	head;
606b0b03348SPoul-Henning Kamp };
607b0b03348SPoul-Henning Kamp 
6089397290eSPoul-Henning Kamp void
6099397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp)
6109397290eSPoul-Henning Kamp {
6119397290eSPoul-Henning Kamp 
6129397290eSPoul-Henning Kamp 	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
6139397290eSPoul-Henning Kamp 	LIST_INIT(&(*cdp)->head);
6149397290eSPoul-Henning Kamp }
6159397290eSPoul-Henning Kamp 
616b0b03348SPoul-Henning Kamp int
61789c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
618b0b03348SPoul-Henning Kamp {
619b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
620027b1f71SPoul-Henning Kamp 	struct cdev *dev, *ndev, *dl, *de;
621b0b03348SPoul-Henning Kamp 	int unit, low, u;
622b0b03348SPoul-Henning Kamp 
6239397290eSPoul-Henning Kamp 	KASSERT(*cdp != NULL,
6249397290eSPoul-Henning Kamp 	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
625b0b03348SPoul-Henning Kamp 	KASSERT(!(extra & CLONE_UNITMASK),
626b0b03348SPoul-Henning Kamp 	    ("Illegal extra bits (0x%x) in clone_create", extra));
627b0b03348SPoul-Henning Kamp 	KASSERT(*up <= CLONE_UNITMASK,
628b0b03348SPoul-Henning Kamp 	    ("Too high unit (0x%x) in clone_create", *up));
629b0b03348SPoul-Henning Kamp 
6308045ce21SPoul-Henning Kamp 	if (!(csw->d_flags & D_INIT))
6318045ce21SPoul-Henning Kamp 		prep_cdevsw(csw);
632b0b03348SPoul-Henning Kamp 
633b0b03348SPoul-Henning Kamp 	/*
634b0b03348SPoul-Henning Kamp 	 * Search the list for a lot of things in one go:
635b0b03348SPoul-Henning Kamp 	 *   A preexisting match is returned immediately.
636b0b03348SPoul-Henning Kamp 	 *   The lowest free unit number if we are passed -1, and the place
637b0b03348SPoul-Henning Kamp 	 *	 in the list where we should insert that new element.
638b0b03348SPoul-Henning Kamp 	 *   The place to insert a specified unit number, if applicable
639b0b03348SPoul-Henning Kamp 	 *       the end of the list.
640b0b03348SPoul-Henning Kamp 	 */
641b0b03348SPoul-Henning Kamp 	unit = *up;
642027b1f71SPoul-Henning Kamp 	ndev = allocdev();
643027b1f71SPoul-Henning Kamp 	dev_lock();
6448666b655SPoul-Henning Kamp 	low = extra;
645b0b03348SPoul-Henning Kamp 	de = dl = NULL;
6469397290eSPoul-Henning Kamp 	cd = *cdp;
647b0b03348SPoul-Henning Kamp 	LIST_FOREACH(dev, &cd->head, si_clone) {
648027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
649027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
650b0b03348SPoul-Henning Kamp 		u = dev2unit(dev);
651b0b03348SPoul-Henning Kamp 		if (u == (unit | extra)) {
652b0b03348SPoul-Henning Kamp 			*dp = dev;
653027b1f71SPoul-Henning Kamp 			freedev(ndev);
654027b1f71SPoul-Henning Kamp 			dev_unlock();
655b0b03348SPoul-Henning Kamp 			return (0);
656b0b03348SPoul-Henning Kamp 		}
657b0b03348SPoul-Henning Kamp 		if (unit == -1 && u == low) {
658b0b03348SPoul-Henning Kamp 			low++;
659b0b03348SPoul-Henning Kamp 			de = dev;
660b0b03348SPoul-Henning Kamp 			continue;
661b0b03348SPoul-Henning Kamp 		}
6628666b655SPoul-Henning Kamp 		if (u > (unit | extra)) {
663b0b03348SPoul-Henning Kamp 			dl = dev;
664b0b03348SPoul-Henning Kamp 			break;
665b0b03348SPoul-Henning Kamp 		}
666b0b03348SPoul-Henning Kamp 	}
667b0b03348SPoul-Henning Kamp 	if (unit == -1)
6688666b655SPoul-Henning Kamp 		unit = low & CLONE_UNITMASK;
669ff7284eeSPoul-Henning Kamp 	dev = newdev(csw, unit2minor(unit | extra), ndev);
670027b1f71SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
671027b1f71SPoul-Henning Kamp 		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
672027b1f71SPoul-Henning Kamp 		printf("unit=%d\n", unit);
673027b1f71SPoul-Henning Kamp 		LIST_FOREACH(dev, &cd->head, si_clone) {
674027b1f71SPoul-Henning Kamp 			printf("\t%p %s\n", dev, dev->si_name);
675027b1f71SPoul-Henning Kamp 		}
676027b1f71SPoul-Henning Kamp 		panic("foo");
677027b1f71SPoul-Henning Kamp 	}
678b0b03348SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_CLONELIST),
679027b1f71SPoul-Henning Kamp 	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
680b0b03348SPoul-Henning Kamp 	if (dl != NULL)
681b0b03348SPoul-Henning Kamp 		LIST_INSERT_BEFORE(dl, dev, si_clone);
682b0b03348SPoul-Henning Kamp 	else if (de != NULL)
683b0b03348SPoul-Henning Kamp 		LIST_INSERT_AFTER(de, dev, si_clone);
684b0b03348SPoul-Henning Kamp 	else
685b0b03348SPoul-Henning Kamp 		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
686b0b03348SPoul-Henning Kamp 	dev->si_flags |= SI_CLONELIST;
687b0b03348SPoul-Henning Kamp 	*up = unit;
688027b1f71SPoul-Henning Kamp 	dev_unlock();
689b0b03348SPoul-Henning Kamp 	return (1);
690b0b03348SPoul-Henning Kamp }
691b0b03348SPoul-Henning Kamp 
692b0b03348SPoul-Henning Kamp /*
693b0b03348SPoul-Henning Kamp  * Kill everything still on the list.  The driver should already have
69489c9c53dSPoul-Henning Kamp  * disposed of any softc hung of the struct cdev *'s at this time.
695b0b03348SPoul-Henning Kamp  */
696b0b03348SPoul-Henning Kamp void
697b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp)
698b0b03348SPoul-Henning Kamp {
69989c9c53dSPoul-Henning Kamp 	struct cdev *dev, *tdev;
700b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
701b0b03348SPoul-Henning Kamp 
702b0b03348SPoul-Henning Kamp 	cd = *cdp;
703b0b03348SPoul-Henning Kamp 	if (cd == NULL)
704b0b03348SPoul-Henning Kamp 		return;
705027b1f71SPoul-Henning Kamp 	dev_lock();
706b0b03348SPoul-Henning Kamp 	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
707027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
708027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
709b0b03348SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_NAMED,
7100a2e49f1SPoul-Henning Kamp 		    ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
711aa2f6ddcSPoul-Henning Kamp 		destroy_devl(dev);
712b0b03348SPoul-Henning Kamp 	}
713027b1f71SPoul-Henning Kamp 	dev_unlock();
714b0b03348SPoul-Henning Kamp 	free(cd, M_DEVBUF);
715b0b03348SPoul-Henning Kamp 	*cdp = NULL;
716b0b03348SPoul-Henning Kamp }
717