xref: /freebsd/sys/kern/kern_conf.c (revision d26dd2d99ea64b63792fcb889a8276ed850a91da)
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>
45d26dd2d9SRobert Watson #include <sys/ucred.h>
460ef1c826SPoul-Henning Kamp #include <machine/stdarg.h>
471dfcbb0cSJulian Elischer 
489ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
49698bfad7SPoul-Henning Kamp 
50beea48b2SPoul-Henning Kamp /* Built at compile time from sys/conf/majors */
51beea48b2SPoul-Henning Kamp 
52cd690b60SPoul-Henning Kamp static struct mtx devmtx;
5389c9c53dSPoul-Henning Kamp static void freedev(struct cdev *dev);
54aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev);
55d26dd2d9SRobert Watson static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr,
56d26dd2d9SRobert Watson 	    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
57d26dd2d9SRobert Watson 	    va_list ap);
58f3732fd1SPoul-Henning Kamp 
59a0e78d2eSPoul-Henning Kamp void
60a0e78d2eSPoul-Henning Kamp dev_lock(void)
61cd690b60SPoul-Henning Kamp {
62cd690b60SPoul-Henning Kamp 	if (!mtx_initialized(&devmtx))
639ef295b7SPoul-Henning Kamp 		mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
64cd690b60SPoul-Henning Kamp 	mtx_lock(&devmtx);
65cd690b60SPoul-Henning Kamp }
66cd690b60SPoul-Henning Kamp 
67a0e78d2eSPoul-Henning Kamp void
68a0e78d2eSPoul-Henning Kamp dev_unlock(void)
69cd690b60SPoul-Henning Kamp {
702c15afd8SPoul-Henning Kamp 
71cd690b60SPoul-Henning Kamp 	mtx_unlock(&devmtx);
72cd690b60SPoul-Henning Kamp }
73cd690b60SPoul-Henning Kamp 
74cd690b60SPoul-Henning Kamp void
759477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev)
769477d73eSPoul-Henning Kamp {
779477d73eSPoul-Henning Kamp 
789477d73eSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
799477d73eSPoul-Henning Kamp 	mtx_lock(&devmtx);
809477d73eSPoul-Henning Kamp 	dev->si_refcount++;
819477d73eSPoul-Henning Kamp 	mtx_unlock(&devmtx);
829477d73eSPoul-Henning Kamp }
839477d73eSPoul-Henning Kamp 
849477d73eSPoul-Henning Kamp void
85eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev)
86cd690b60SPoul-Henning Kamp {
872c15afd8SPoul-Henning Kamp 
881a1457d4SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
89cd690b60SPoul-Henning Kamp 	dev->si_refcount++;
90cd690b60SPoul-Henning Kamp }
91cd690b60SPoul-Henning Kamp 
92cd690b60SPoul-Henning Kamp void
93aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev)
94cd690b60SPoul-Henning Kamp {
95aa2f6ddcSPoul-Henning Kamp 	int flag = 0;
96a0e78d2eSPoul-Henning Kamp 
97ba285125SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
98ba285125SPoul-Henning Kamp 	dev_lock();
99cd690b60SPoul-Henning Kamp 	dev->si_refcount--;
100cd690b60SPoul-Henning Kamp 	KASSERT(dev->si_refcount >= 0,
101cd690b60SPoul-Henning Kamp 	    ("dev_rel(%s) gave negative count", devtoname(dev)));
102aa2f6ddcSPoul-Henning Kamp 	if (dev->si_usecount == 0 &&
103aa2f6ddcSPoul-Henning Kamp 	    (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
104cd690b60SPoul-Henning Kamp 	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
105cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
106ba285125SPoul-Henning Kamp 		flag = 1;
107ba285125SPoul-Henning Kamp 	}
108ba285125SPoul-Henning Kamp 	dev_unlock();
109ba285125SPoul-Henning Kamp 	if (flag)
110cd690b60SPoul-Henning Kamp 		freedev(dev);
111cd690b60SPoul-Henning Kamp }
112ba285125SPoul-Henning Kamp 
1132c15afd8SPoul-Henning Kamp struct cdevsw *
1142c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev)
1152c15afd8SPoul-Henning Kamp {
1162c15afd8SPoul-Henning Kamp 	struct cdevsw *csw;
1172c15afd8SPoul-Henning Kamp 
1182c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1192c15afd8SPoul-Henning Kamp 	dev_lock();
1202c15afd8SPoul-Henning Kamp 	csw = dev->si_devsw;
1212c15afd8SPoul-Henning Kamp 	if (csw != NULL)
1222c15afd8SPoul-Henning Kamp 		dev->si_threadcount++;
1232c15afd8SPoul-Henning Kamp 	dev_unlock();
1242c15afd8SPoul-Henning Kamp 	return (csw);
1252c15afd8SPoul-Henning Kamp }
1262c15afd8SPoul-Henning Kamp 
1272c15afd8SPoul-Henning Kamp void
1282c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev)
1292c15afd8SPoul-Henning Kamp {
1302c15afd8SPoul-Henning Kamp 
1312c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1322c15afd8SPoul-Henning Kamp 	dev_lock();
1332c15afd8SPoul-Henning Kamp 	dev->si_threadcount--;
1342c15afd8SPoul-Henning Kamp 	dev_unlock();
1352c15afd8SPoul-Henning Kamp }
136cd690b60SPoul-Henning Kamp 
137b2941431SPoul-Henning Kamp int
138b2941431SPoul-Henning Kamp nullop(void)
139b2941431SPoul-Henning Kamp {
140b2941431SPoul-Henning Kamp 
141b2941431SPoul-Henning Kamp 	return (0);
142b2941431SPoul-Henning Kamp }
143b2941431SPoul-Henning Kamp 
144b2941431SPoul-Henning Kamp int
145b2941431SPoul-Henning Kamp eopnotsupp(void)
146b2941431SPoul-Henning Kamp {
147b2941431SPoul-Henning Kamp 
148b2941431SPoul-Henning Kamp 	return (EOPNOTSUPP);
149b2941431SPoul-Henning Kamp }
15002574b19SPoul-Henning Kamp 
15102574b19SPoul-Henning Kamp static int
15202574b19SPoul-Henning Kamp enxio(void)
15302574b19SPoul-Henning Kamp {
15402574b19SPoul-Henning Kamp 	return (ENXIO);
15502574b19SPoul-Henning Kamp }
15602574b19SPoul-Henning Kamp 
157b2941431SPoul-Henning Kamp static int
158b2941431SPoul-Henning Kamp enodev(void)
159b2941431SPoul-Henning Kamp {
160b2941431SPoul-Henning Kamp 	return (ENODEV);
161b2941431SPoul-Henning Kamp }
162b2941431SPoul-Henning Kamp 
163b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */
164b2941431SPoul-Henning Kamp 
16502574b19SPoul-Henning Kamp #define dead_open	(d_open_t *)enxio
16602574b19SPoul-Henning Kamp #define dead_close	(d_close_t *)enxio
16702574b19SPoul-Henning Kamp #define dead_read	(d_read_t *)enxio
16802574b19SPoul-Henning Kamp #define dead_write	(d_write_t *)enxio
16902574b19SPoul-Henning Kamp #define dead_ioctl	(d_ioctl_t *)enxio
170b2941431SPoul-Henning Kamp #define dead_poll	(d_poll_t *)enodev
171b2941431SPoul-Henning Kamp #define dead_mmap	(d_mmap_t *)enodev
17202574b19SPoul-Henning Kamp 
17302574b19SPoul-Henning Kamp static void
17402574b19SPoul-Henning Kamp dead_strategy(struct bio *bp)
17502574b19SPoul-Henning Kamp {
17602574b19SPoul-Henning Kamp 
17702574b19SPoul-Henning Kamp 	biofinish(bp, NULL, ENXIO);
17802574b19SPoul-Henning Kamp }
17902574b19SPoul-Henning Kamp 
1802c6b49f6SPoul-Henning Kamp #define dead_dump	(dumper_t *)enxio
18102574b19SPoul-Henning Kamp #define dead_kqfilter	(d_kqfilter_t *)enxio
18202574b19SPoul-Henning Kamp 
18302574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = {
184dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
185dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
1867ac40f5fSPoul-Henning Kamp 	.d_open =	dead_open,
1877ac40f5fSPoul-Henning Kamp 	.d_close =	dead_close,
1887ac40f5fSPoul-Henning Kamp 	.d_read =	dead_read,
1897ac40f5fSPoul-Henning Kamp 	.d_write =	dead_write,
1907ac40f5fSPoul-Henning Kamp 	.d_ioctl =	dead_ioctl,
1917ac40f5fSPoul-Henning Kamp 	.d_poll =	dead_poll,
1927ac40f5fSPoul-Henning Kamp 	.d_mmap =	dead_mmap,
1937ac40f5fSPoul-Henning Kamp 	.d_strategy =	dead_strategy,
1947ac40f5fSPoul-Henning Kamp 	.d_name =	"dead",
1957ac40f5fSPoul-Henning Kamp 	.d_dump =	dead_dump,
1967ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	dead_kqfilter
19702574b19SPoul-Henning Kamp };
19802574b19SPoul-Henning Kamp 
199b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */
200b2941431SPoul-Henning Kamp 
201b2941431SPoul-Henning Kamp #define null_open	(d_open_t *)nullop
202b2941431SPoul-Henning Kamp #define null_close	(d_close_t *)nullop
203b2941431SPoul-Henning Kamp #define no_read		(d_read_t *)enodev
204b2941431SPoul-Henning Kamp #define no_write	(d_write_t *)enodev
205b2941431SPoul-Henning Kamp #define no_ioctl	(d_ioctl_t *)enodev
206b2941431SPoul-Henning Kamp #define no_mmap		(d_mmap_t *)enodev
207ad3b9257SJohn-Mark Gurney #define no_kqfilter	(d_kqfilter_t *)enodev
208b2941431SPoul-Henning Kamp 
209b2941431SPoul-Henning Kamp static void
210b2941431SPoul-Henning Kamp no_strategy(struct bio *bp)
211b2941431SPoul-Henning Kamp {
212b2941431SPoul-Henning Kamp 
213b2941431SPoul-Henning Kamp 	biofinish(bp, NULL, ENODEV);
214b2941431SPoul-Henning Kamp }
215b2941431SPoul-Henning Kamp 
216b2941431SPoul-Henning Kamp static int
21789c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
218b2941431SPoul-Henning Kamp {
219b2941431SPoul-Henning Kamp 	/*
220b2941431SPoul-Henning Kamp 	 * Return true for read/write.  If the user asked for something
221b2941431SPoul-Henning Kamp 	 * special, return POLLNVAL, so that clients have a way of
222b2941431SPoul-Henning Kamp 	 * determining reliably whether or not the extended
223b2941431SPoul-Henning Kamp 	 * functionality is present without hard-coding knowledge
224b2941431SPoul-Henning Kamp 	 * of specific filesystem implementations.
225b2941431SPoul-Henning Kamp 	 * Stay in sync with vop_nopoll().
226b2941431SPoul-Henning Kamp 	 */
227b2941431SPoul-Henning Kamp 	if (events & ~POLLSTANDARD)
228b2941431SPoul-Henning Kamp 		return (POLLNVAL);
229b2941431SPoul-Henning Kamp 
230b2941431SPoul-Henning Kamp 	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
231b2941431SPoul-Henning Kamp }
232b2941431SPoul-Henning Kamp 
233b2941431SPoul-Henning Kamp #define no_dump		(dumper_t *)enodev
2344e4a7663SPoul-Henning Kamp 
2352447bec8SPoul-Henning Kamp /*
23689c9c53dSPoul-Henning Kamp  * struct cdev * and u_dev_t primitives
237bfbb9ce6SPoul-Henning Kamp  */
238bfbb9ce6SPoul-Henning Kamp 
239bfbb9ce6SPoul-Henning Kamp int
24089c9c53dSPoul-Henning Kamp minor(struct cdev *x)
241bfbb9ce6SPoul-Henning Kamp {
242f3732fd1SPoul-Henning Kamp 	if (x == NULL)
243f3732fd1SPoul-Henning Kamp 		return NODEV;
2440a2e49f1SPoul-Henning Kamp 	return(x->si_drv0 & MAXMINOR);
245bfbb9ce6SPoul-Henning Kamp }
246bfbb9ce6SPoul-Henning Kamp 
2479a27d579SPoul-Henning Kamp int
24889c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x)
2499a27d579SPoul-Henning Kamp {
2509a27d579SPoul-Henning Kamp 
251f3732fd1SPoul-Henning Kamp 	if (x == NULL)
252f3732fd1SPoul-Henning Kamp 		return NODEV;
25337085a39SPoul-Henning Kamp 	return (minor2unit(minor(x)));
2543a85fd26SPoul-Henning Kamp }
2553a85fd26SPoul-Henning Kamp 
2563238ec33SPoul-Henning Kamp u_int
2573238ec33SPoul-Henning Kamp minor2unit(u_int _minor)
2583a85fd26SPoul-Henning Kamp {
2593a85fd26SPoul-Henning Kamp 
260d9aaa28fSPoul-Henning Kamp 	KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
2613238ec33SPoul-Henning Kamp 	return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
2629a27d579SPoul-Henning Kamp }
2639a27d579SPoul-Henning Kamp 
264b0d17ba6SPoul-Henning Kamp int
265b0d17ba6SPoul-Henning Kamp unit2minor(int unit)
266b0d17ba6SPoul-Henning Kamp {
267b0d17ba6SPoul-Henning Kamp 
26815b6f00fSPoul-Henning Kamp 	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
269b0d17ba6SPoul-Henning Kamp 	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
270b0d17ba6SPoul-Henning Kamp }
271b0d17ba6SPoul-Henning Kamp 
27289c9c53dSPoul-Henning Kamp static struct cdev *
2733f54a085SPoul-Henning Kamp allocdev(void)
274bfbb9ce6SPoul-Henning Kamp {
275ca916247SPoul-Henning Kamp 	struct cdev *si;
276698bfad7SPoul-Henning Kamp 
2771a1b2800SPoul-Henning Kamp 	si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
278237d2765SPoul-Henning Kamp 	si->si_name = si->__si_namebuf;
2793344c5a1SPoul-Henning Kamp 	LIST_INIT(&si->si_children);
280aa2f6ddcSPoul-Henning Kamp 	LIST_INIT(&si->si_alist);
2813f54a085SPoul-Henning Kamp 	return (si);
2823f54a085SPoul-Henning Kamp }
2833f54a085SPoul-Henning Kamp 
28489c9c53dSPoul-Henning Kamp static struct cdev *
285ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si)
2863f54a085SPoul-Henning Kamp {
287027b1f71SPoul-Henning Kamp 	struct cdev *si2;
288f3732fd1SPoul-Henning Kamp 	dev_t	udev;
2893f54a085SPoul-Henning Kamp 
290027b1f71SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
291b3d82c03SPoul-Henning Kamp 	udev = y;
292ff7284eeSPoul-Henning Kamp 	LIST_FOREACH(si2, &csw->d_devs, si_list) {
2930a2e49f1SPoul-Henning Kamp 		if (si2->si_drv0 == udev) {
294027b1f71SPoul-Henning Kamp 			freedev(si);
295027b1f71SPoul-Henning Kamp 			return (si2);
2963f54a085SPoul-Henning Kamp 		}
297027b1f71SPoul-Henning Kamp 	}
2980a2e49f1SPoul-Henning Kamp 	si->si_drv0 = udev;
299ff7284eeSPoul-Henning Kamp 	LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
300698bfad7SPoul-Henning Kamp 	return (si);
301bfbb9ce6SPoul-Henning Kamp }
302bfbb9ce6SPoul-Henning Kamp 
303cd690b60SPoul-Henning Kamp static void
30489c9c53dSPoul-Henning Kamp freedev(struct cdev *dev)
305d137acccSPoul-Henning Kamp {
306d137acccSPoul-Henning Kamp 
307d26dd2d9SRobert Watson 	if (dev->si_cred != NULL)
308d26dd2d9SRobert Watson 		crfree(dev->si_cred);
3091a1b2800SPoul-Henning Kamp 	free(dev, M_DEVT);
310d137acccSPoul-Henning Kamp }
311d137acccSPoul-Henning Kamp 
312bfbb9ce6SPoul-Henning Kamp int
313f3732fd1SPoul-Henning Kamp uminor(dev_t dev)
314bfbb9ce6SPoul-Henning Kamp {
315d9aaa28fSPoul-Henning Kamp 	return (dev & MAXMINOR);
316bfbb9ce6SPoul-Henning Kamp }
317bfbb9ce6SPoul-Henning Kamp 
318bfbb9ce6SPoul-Henning Kamp int
319f3732fd1SPoul-Henning Kamp umajor(dev_t dev)
320bfbb9ce6SPoul-Henning Kamp {
321d9aaa28fSPoul-Henning Kamp 	return ((dev & ~MAXMINOR) >> 8);
322bfbb9ce6SPoul-Henning Kamp }
323bfbb9ce6SPoul-Henning Kamp 
3242a3faf2fSPoul-Henning Kamp static void
325cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw)
326cd690b60SPoul-Henning Kamp {
327b3d82c03SPoul-Henning Kamp 
328652d0472SPoul-Henning Kamp 	devsw->d_flags &= ~D_INIT;
329b0b03348SPoul-Henning Kamp }
330b0b03348SPoul-Henning Kamp 
331b0b03348SPoul-Henning Kamp static void
332b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw)
333b0b03348SPoul-Henning Kamp {
334b0b03348SPoul-Henning Kamp 
335a0e78d2eSPoul-Henning Kamp 	dev_lock();
336cd690b60SPoul-Henning Kamp 
337800b42bdSPoul-Henning Kamp 	if (devsw->d_version != D_VERSION_01) {
338cd690b60SPoul-Henning Kamp 		printf(
339cd690b60SPoul-Henning Kamp 		    "WARNING: Device driver \"%s\" has wrong version %s\n",
340cd690b60SPoul-Henning Kamp 		    devsw->d_name, "and is disabled.  Recompile KLD module.");
341cd690b60SPoul-Henning Kamp 		devsw->d_open = dead_open;
342cd690b60SPoul-Henning Kamp 		devsw->d_close = dead_close;
343cd690b60SPoul-Henning Kamp 		devsw->d_read = dead_read;
344cd690b60SPoul-Henning Kamp 		devsw->d_write = dead_write;
345cd690b60SPoul-Henning Kamp 		devsw->d_ioctl = dead_ioctl;
346cd690b60SPoul-Henning Kamp 		devsw->d_poll = dead_poll;
347cd690b60SPoul-Henning Kamp 		devsw->d_mmap = dead_mmap;
348cd690b60SPoul-Henning Kamp 		devsw->d_strategy = dead_strategy;
349cd690b60SPoul-Henning Kamp 		devsw->d_dump = dead_dump;
350cd690b60SPoul-Henning Kamp 		devsw->d_kqfilter = dead_kqfilter;
351cd690b60SPoul-Henning Kamp 	}
352cd690b60SPoul-Henning Kamp 
3538e1f1df0SPoul-Henning Kamp 	if (devsw->d_flags & D_TTY) {
3543a95025fSPoul-Henning Kamp 		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
3558e1f1df0SPoul-Henning Kamp 		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
3568e1f1df0SPoul-Henning Kamp 		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
3578e1f1df0SPoul-Henning Kamp 		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
3588e1f1df0SPoul-Henning Kamp 		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
3598e1f1df0SPoul-Henning Kamp 	}
3608e1f1df0SPoul-Henning Kamp 
361b2941431SPoul-Henning Kamp 	if (devsw->d_open == NULL)	devsw->d_open = null_open;
362b2941431SPoul-Henning Kamp 	if (devsw->d_close == NULL)	devsw->d_close = null_close;
363b2941431SPoul-Henning Kamp 	if (devsw->d_read == NULL)	devsw->d_read = no_read;
364b2941431SPoul-Henning Kamp 	if (devsw->d_write == NULL)	devsw->d_write = no_write;
365b2941431SPoul-Henning Kamp 	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
366b2941431SPoul-Henning Kamp 	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
367b2941431SPoul-Henning Kamp 	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
368b2941431SPoul-Henning Kamp 	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
369b2941431SPoul-Henning Kamp 	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
370b2941431SPoul-Henning Kamp 	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
371cd690b60SPoul-Henning Kamp 
372cd690b60SPoul-Henning Kamp 	LIST_INIT(&devsw->d_devs);
373cd690b60SPoul-Henning Kamp 
374cd690b60SPoul-Henning Kamp 	devsw->d_flags |= D_INIT;
375cd690b60SPoul-Henning Kamp 
376a0e78d2eSPoul-Henning Kamp 	dev_unlock();
3772a3faf2fSPoul-Henning Kamp }
37811586717SBrian Somers 
379d26dd2d9SRobert Watson static struct cdev *
380d26dd2d9SRobert Watson make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
381d26dd2d9SRobert Watson     gid_t gid, int mode, const char *fmt, va_list ap)
3822a3faf2fSPoul-Henning Kamp {
38389c9c53dSPoul-Henning Kamp 	struct cdev *dev;
3842a3faf2fSPoul-Henning Kamp 	int i;
3852a3faf2fSPoul-Henning Kamp 
386d9aaa28fSPoul-Henning Kamp 	KASSERT((minornr & ~MAXMINOR) == 0,
387cd690b60SPoul-Henning Kamp 	    ("Invalid minor (0x%x) in make_dev", minornr));
388cd690b60SPoul-Henning Kamp 
3899477d73eSPoul-Henning Kamp 	if (!(devsw->d_flags & D_INIT))
3902a3faf2fSPoul-Henning Kamp 		prep_cdevsw(devsw);
391027b1f71SPoul-Henning Kamp 	dev = allocdev();
392027b1f71SPoul-Henning Kamp 	dev_lock();
393ff7284eeSPoul-Henning Kamp 	dev = newdev(devsw, minornr, dev);
39498c469d4SPoul-Henning Kamp 	if (dev->si_flags & SI_CHEAPCLONE &&
39598c469d4SPoul-Henning Kamp 	    dev->si_flags & SI_NAMED &&
39698c469d4SPoul-Henning Kamp 	    dev->si_devsw == devsw) {
39798c469d4SPoul-Henning Kamp 		/*
39898c469d4SPoul-Henning Kamp 		 * This is allowed as it removes races and generally
39998c469d4SPoul-Henning Kamp 		 * simplifies cloning devices.
400cd690b60SPoul-Henning Kamp 		 * XXX: still ??
40198c469d4SPoul-Henning Kamp 		 */
402027b1f71SPoul-Henning Kamp 		dev_unlock();
40398c469d4SPoul-Henning Kamp 		return (dev);
40498c469d4SPoul-Henning Kamp 	}
405cd690b60SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_NAMED),
406ff7284eeSPoul-Henning Kamp 	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
407ff7284eeSPoul-Henning Kamp 	    devsw->d_name, minor(dev), devtoname(dev)));
408cd690b60SPoul-Henning Kamp 
4096334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4106334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4112e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4126334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4136334a663SPoul-Henning Kamp 	}
4141a1b2800SPoul-Henning Kamp 
4150ef1c826SPoul-Henning Kamp 	dev->si_devsw = devsw;
4165ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
417d26dd2d9SRobert Watson 	if (cr != NULL)
418d26dd2d9SRobert Watson 		dev->si_cred = crhold(cr);
419d26dd2d9SRobert Watson 	else
420d26dd2d9SRobert Watson 		dev->si_cred = NULL;
4219477d73eSPoul-Henning Kamp 	dev->si_uid = uid;
4229477d73eSPoul-Henning Kamp 	dev->si_gid = gid;
4239477d73eSPoul-Henning Kamp 	dev->si_mode = mode;
4241744fcd0SJulian Elischer 
4259285a87eSPoul-Henning Kamp 	devfs_create(dev);
426a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4273f54a085SPoul-Henning Kamp 	return (dev);
4283f54a085SPoul-Henning Kamp }
4293f54a085SPoul-Henning Kamp 
430d26dd2d9SRobert Watson struct cdev *
431d26dd2d9SRobert Watson make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode,
432d26dd2d9SRobert Watson     const char *fmt, ...)
433d26dd2d9SRobert Watson {
434d26dd2d9SRobert Watson 	struct cdev *dev;
435d26dd2d9SRobert Watson 	va_list ap;
436d26dd2d9SRobert Watson 
437d26dd2d9SRobert Watson 	va_start(ap, fmt);
438d26dd2d9SRobert Watson 	dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap);
439d26dd2d9SRobert Watson 	va_end(ap);
440d26dd2d9SRobert Watson 	return (dev);
441d26dd2d9SRobert Watson }
442d26dd2d9SRobert Watson 
443d26dd2d9SRobert Watson struct cdev *
444d26dd2d9SRobert Watson make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
445d26dd2d9SRobert Watson     gid_t gid, int mode, const char *fmt, ...)
446d26dd2d9SRobert Watson {
447d26dd2d9SRobert Watson 	struct cdev *dev;
448d26dd2d9SRobert Watson 	va_list ap;
449d26dd2d9SRobert Watson 
450d26dd2d9SRobert Watson 	va_start(ap, fmt);
451d26dd2d9SRobert Watson 	dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap);
452d26dd2d9SRobert Watson 	va_end(ap);
453d26dd2d9SRobert Watson 
454d26dd2d9SRobert Watson 	return (dev);
455d26dd2d9SRobert Watson }
456d26dd2d9SRobert Watson 
4577e7c3f3fSJonathan Lemon int
45889c9c53dSPoul-Henning Kamp dev_named(struct cdev *pdev, const char *name)
4597e7c3f3fSJonathan Lemon {
46089c9c53dSPoul-Henning Kamp 	struct cdev *cdev;
4617e7c3f3fSJonathan Lemon 
4627e7c3f3fSJonathan Lemon 	if (strcmp(devtoname(pdev), name) == 0)
4637e7c3f3fSJonathan Lemon 		return (1);
4647e7c3f3fSJonathan Lemon 	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
4657e7c3f3fSJonathan Lemon 		if (strcmp(devtoname(cdev), name) == 0)
4667e7c3f3fSJonathan Lemon 			return (1);
4677e7c3f3fSJonathan Lemon 	return (0);
4687e7c3f3fSJonathan Lemon }
4697e7c3f3fSJonathan Lemon 
4703344c5a1SPoul-Henning Kamp void
47189c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev)
4723344c5a1SPoul-Henning Kamp {
4733344c5a1SPoul-Henning Kamp 
474a0e78d2eSPoul-Henning Kamp 	dev_lock();
4753344c5a1SPoul-Henning Kamp 	cdev->si_parent = pdev;
4763344c5a1SPoul-Henning Kamp 	cdev->si_flags |= SI_CHILD;
4773344c5a1SPoul-Henning Kamp 	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
478a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4793344c5a1SPoul-Henning Kamp }
4803344c5a1SPoul-Henning Kamp 
48189c9c53dSPoul-Henning Kamp struct cdev *
48289c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...)
4833f54a085SPoul-Henning Kamp {
48489c9c53dSPoul-Henning Kamp 	struct cdev *dev;
4853f54a085SPoul-Henning Kamp 	va_list ap;
4863f54a085SPoul-Henning Kamp 	int i;
4873f54a085SPoul-Henning Kamp 
4883f54a085SPoul-Henning Kamp 	dev = allocdev();
489a0e78d2eSPoul-Henning Kamp 	dev_lock();
4903f54a085SPoul-Henning Kamp 	dev->si_flags |= SI_ALIAS;
4915ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4923f54a085SPoul-Henning Kamp 	va_start(ap, fmt);
4936334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4946334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4952e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4966334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4976334a663SPoul-Henning Kamp 	}
4983f54a085SPoul-Henning Kamp 	va_end(ap);
4993f54a085SPoul-Henning Kamp 
5009285a87eSPoul-Henning Kamp 	devfs_create(dev);
501a0e78d2eSPoul-Henning Kamp 	dev_unlock();
502cd690b60SPoul-Henning Kamp 	dev_depends(pdev, dev);
5030ef1c826SPoul-Henning Kamp 	return (dev);
5040ef1c826SPoul-Henning Kamp }
5050ef1c826SPoul-Henning Kamp 
506cd690b60SPoul-Henning Kamp static void
507aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev)
508d137acccSPoul-Henning Kamp {
509743cd76aSPoul-Henning Kamp 	struct cdevsw *csw;
510743cd76aSPoul-Henning Kamp 
511aa2f6ddcSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
512743cd76aSPoul-Henning Kamp 	KASSERT(dev->si_flags & SI_NAMED,
513ff7284eeSPoul-Henning Kamp 	    ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
5145ef2707eSPoul-Henning Kamp 
5159285a87eSPoul-Henning Kamp 	devfs_destroy(dev);
516cd690b60SPoul-Henning Kamp 
517cd690b60SPoul-Henning Kamp 	/* Remove name marking */
518b0b03348SPoul-Henning Kamp 	dev->si_flags &= ~SI_NAMED;
519b0b03348SPoul-Henning Kamp 
520cd690b60SPoul-Henning Kamp 	/* If we are a child, remove us from the parents list */
5213344c5a1SPoul-Henning Kamp 	if (dev->si_flags & SI_CHILD) {
5223344c5a1SPoul-Henning Kamp 		LIST_REMOVE(dev, si_siblings);
5233344c5a1SPoul-Henning Kamp 		dev->si_flags &= ~SI_CHILD;
5243344c5a1SPoul-Henning Kamp 	}
525cd690b60SPoul-Henning Kamp 
526cd690b60SPoul-Henning Kamp 	/* Kill our children */
5273344c5a1SPoul-Henning Kamp 	while (!LIST_EMPTY(&dev->si_children))
528aa2f6ddcSPoul-Henning Kamp 		destroy_devl(LIST_FIRST(&dev->si_children));
529cd690b60SPoul-Henning Kamp 
530cd690b60SPoul-Henning Kamp 	/* Remove from clone list */
531b0b03348SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
532b0b03348SPoul-Henning Kamp 		LIST_REMOVE(dev, si_clone);
533b0b03348SPoul-Henning Kamp 		dev->si_flags &= ~SI_CLONELIST;
534b0b03348SPoul-Henning Kamp 	}
535cd690b60SPoul-Henning Kamp 
536743cd76aSPoul-Henning Kamp 	csw = dev->si_devsw;
5371abf2c36SBrian Feldman 	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
5381abf2c36SBrian Feldman 	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
539743cd76aSPoul-Henning Kamp 		printf("Purging %lu threads from %s\n",
540743cd76aSPoul-Henning Kamp 		    dev->si_threadcount, devtoname(dev));
541743cd76aSPoul-Henning Kamp 		csw->d_purge(dev);
542743cd76aSPoul-Henning Kamp 		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
543743cd76aSPoul-Henning Kamp 	}
5441abf2c36SBrian Feldman 	if (csw != NULL && csw->d_purge != NULL)
545a5993c33SPoul-Henning Kamp 		printf("All threads purged from %s\n", devtoname(dev));
546743cd76aSPoul-Henning Kamp 
547743cd76aSPoul-Henning Kamp 	dev->si_drv1 = 0;
548743cd76aSPoul-Henning Kamp 	dev->si_drv2 = 0;
549743cd76aSPoul-Henning Kamp 	bzero(&dev->__si_u, sizeof(dev->__si_u));
550743cd76aSPoul-Henning Kamp 
551cd690b60SPoul-Henning Kamp 	if (!(dev->si_flags & SI_ALIAS)) {
552cd690b60SPoul-Henning Kamp 		/* Remove from cdevsw list */
553cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
554cd690b60SPoul-Henning Kamp 
55589c9c53dSPoul-Henning Kamp 		/* If cdevsw has no struct cdev *'s, clean it */
556a5993c33SPoul-Henning Kamp 		if (LIST_EMPTY(&csw->d_devs))
557a5993c33SPoul-Henning Kamp 			fini_cdevsw(csw);
558cd690b60SPoul-Henning Kamp 	}
5595ef2707eSPoul-Henning Kamp 	dev->si_flags &= ~SI_ALIAS;
560743cd76aSPoul-Henning Kamp 
561cd690b60SPoul-Henning Kamp 	if (dev->si_refcount > 0) {
562cd690b60SPoul-Henning Kamp 		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
563cd690b60SPoul-Henning Kamp 	} else {
564d137acccSPoul-Henning Kamp 		freedev(dev);
565d137acccSPoul-Henning Kamp 	}
566cd690b60SPoul-Henning Kamp }
567cd690b60SPoul-Henning Kamp 
568cd690b60SPoul-Henning Kamp void
56989c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev)
570cd690b60SPoul-Henning Kamp {
571cd690b60SPoul-Henning Kamp 
572a0e78d2eSPoul-Henning Kamp 	dev_lock();
573aa2f6ddcSPoul-Henning Kamp 	destroy_devl(dev);
574a0e78d2eSPoul-Henning Kamp 	dev_unlock();
575cd690b60SPoul-Henning Kamp }
576d137acccSPoul-Henning Kamp 
577c32cc149SBruce Evans const char *
57889c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev)
579b8e49f68SBill Fumerola {
580d137acccSPoul-Henning Kamp 	char *p;
5818ff33adbSPoul-Henning Kamp 	struct cdevsw *csw;
582c32cc149SBruce Evans 	int mynor;
583b8e49f68SBill Fumerola 
584d137acccSPoul-Henning Kamp 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
585d137acccSPoul-Henning Kamp 		p = dev->si_name;
5868ff33adbSPoul-Henning Kamp 		csw = dev_refthread(dev);
5878ff33adbSPoul-Henning Kamp 		if (csw != NULL) {
5888ff33adbSPoul-Henning Kamp 			sprintf(p, "(%s)", csw->d_name);
5898ff33adbSPoul-Henning Kamp 			dev_relthread(dev);
5908ff33adbSPoul-Henning Kamp 		}
591d137acccSPoul-Henning Kamp 		p += strlen(p);
592c32cc149SBruce Evans 		mynor = minor(dev);
593c32cc149SBruce Evans 		if (mynor < 0 || mynor > 255)
5948ff33adbSPoul-Henning Kamp 			sprintf(p, "/%#x", (u_int)mynor);
595c32cc149SBruce Evans 		else
5968ff33adbSPoul-Henning Kamp 			sprintf(p, "/%d", mynor);
597d137acccSPoul-Henning Kamp 	}
598b8e49f68SBill Fumerola 	return (dev->si_name);
599b8e49f68SBill Fumerola }
600db901281SPoul-Henning Kamp 
601db901281SPoul-Henning Kamp int
60201de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit)
603db901281SPoul-Henning Kamp {
604db901281SPoul-Henning Kamp 	int u, i;
605db901281SPoul-Henning Kamp 
606db901281SPoul-Henning Kamp 	i = strlen(stem);
60756700d46SBrian Somers 	if (bcmp(stem, name, i) != 0)
60856700d46SBrian Somers 		return (0);
609db901281SPoul-Henning Kamp 	if (!isdigit(name[i]))
610db901281SPoul-Henning Kamp 		return (0);
611db901281SPoul-Henning Kamp 	u = 0;
61210786074SPoul-Henning Kamp 	if (name[i] == '0' && isdigit(name[i+1]))
61310786074SPoul-Henning Kamp 		return (0);
614db901281SPoul-Henning Kamp 	while (isdigit(name[i])) {
615db901281SPoul-Henning Kamp 		u *= 10;
616db901281SPoul-Henning Kamp 		u += name[i++] - '0';
617db901281SPoul-Henning Kamp 	}
618dab3d85fSBrian Feldman 	if (u > 0xffffff)
619dab3d85fSBrian Feldman 		return (0);
620db901281SPoul-Henning Kamp 	*unit = u;
621db901281SPoul-Henning Kamp 	if (namep)
622db901281SPoul-Henning Kamp 		*namep = &name[i];
623db901281SPoul-Henning Kamp 	if (name[i])
624db901281SPoul-Henning Kamp 		return (2);
625db901281SPoul-Henning Kamp 	return (1);
626db901281SPoul-Henning Kamp }
6278d25eb2cSPoul-Henning Kamp 
6288d25eb2cSPoul-Henning Kamp /*
629b0b03348SPoul-Henning Kamp  * Helper functions for cloning device drivers.
630b0b03348SPoul-Henning Kamp  *
631b0b03348SPoul-Henning Kamp  * The objective here is to make it unnecessary for the device drivers to
632b0b03348SPoul-Henning Kamp  * use rman or similar to manage their unit number space.  Due to the way
633b0b03348SPoul-Henning Kamp  * we do "on-demand" devices, using rman or other "private" methods
634b0b03348SPoul-Henning Kamp  * will be very tricky to lock down properly once we lock down this file.
635b0b03348SPoul-Henning Kamp  *
6369a98ae94SLukas Ertl  * Instead we give the drivers these routines which puts the struct cdev *'s
6379a98ae94SLukas Ertl  * that are to be managed on their own list, and gives the driver the ability
638b0b03348SPoul-Henning Kamp  * to ask for the first free unit number or a given specified unit number.
639b0b03348SPoul-Henning Kamp  *
640b0b03348SPoul-Henning Kamp  * In addition these routines support paired devices (pty, nmdm and similar)
641b0b03348SPoul-Henning Kamp  * by respecting a number of "flag" bits in the minor number.
642b0b03348SPoul-Henning Kamp  *
643b0b03348SPoul-Henning Kamp  */
644b0b03348SPoul-Henning Kamp 
645b0b03348SPoul-Henning Kamp struct clonedevs {
646b0b03348SPoul-Henning Kamp 	LIST_HEAD(,cdev)	head;
647b0b03348SPoul-Henning Kamp };
648b0b03348SPoul-Henning Kamp 
6499397290eSPoul-Henning Kamp void
6509397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp)
6519397290eSPoul-Henning Kamp {
6529397290eSPoul-Henning Kamp 
6539397290eSPoul-Henning Kamp 	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
6549397290eSPoul-Henning Kamp 	LIST_INIT(&(*cdp)->head);
6559397290eSPoul-Henning Kamp }
6569397290eSPoul-Henning Kamp 
657b0b03348SPoul-Henning Kamp int
65889c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
659b0b03348SPoul-Henning Kamp {
660b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
661027b1f71SPoul-Henning Kamp 	struct cdev *dev, *ndev, *dl, *de;
662b0b03348SPoul-Henning Kamp 	int unit, low, u;
663b0b03348SPoul-Henning Kamp 
6649397290eSPoul-Henning Kamp 	KASSERT(*cdp != NULL,
6659397290eSPoul-Henning Kamp 	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
666b0b03348SPoul-Henning Kamp 	KASSERT(!(extra & CLONE_UNITMASK),
667b0b03348SPoul-Henning Kamp 	    ("Illegal extra bits (0x%x) in clone_create", extra));
668b0b03348SPoul-Henning Kamp 	KASSERT(*up <= CLONE_UNITMASK,
669b0b03348SPoul-Henning Kamp 	    ("Too high unit (0x%x) in clone_create", *up));
670b0b03348SPoul-Henning Kamp 
6718045ce21SPoul-Henning Kamp 	if (!(csw->d_flags & D_INIT))
6728045ce21SPoul-Henning Kamp 		prep_cdevsw(csw);
673b0b03348SPoul-Henning Kamp 
674b0b03348SPoul-Henning Kamp 	/*
675b0b03348SPoul-Henning Kamp 	 * Search the list for a lot of things in one go:
676b0b03348SPoul-Henning Kamp 	 *   A preexisting match is returned immediately.
677b0b03348SPoul-Henning Kamp 	 *   The lowest free unit number if we are passed -1, and the place
678b0b03348SPoul-Henning Kamp 	 *	 in the list where we should insert that new element.
679b0b03348SPoul-Henning Kamp 	 *   The place to insert a specified unit number, if applicable
680b0b03348SPoul-Henning Kamp 	 *       the end of the list.
681b0b03348SPoul-Henning Kamp 	 */
682b0b03348SPoul-Henning Kamp 	unit = *up;
683027b1f71SPoul-Henning Kamp 	ndev = allocdev();
684027b1f71SPoul-Henning Kamp 	dev_lock();
6858666b655SPoul-Henning Kamp 	low = extra;
686b0b03348SPoul-Henning Kamp 	de = dl = NULL;
6879397290eSPoul-Henning Kamp 	cd = *cdp;
688b0b03348SPoul-Henning Kamp 	LIST_FOREACH(dev, &cd->head, si_clone) {
689027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
690027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
691b0b03348SPoul-Henning Kamp 		u = dev2unit(dev);
692b0b03348SPoul-Henning Kamp 		if (u == (unit | extra)) {
693b0b03348SPoul-Henning Kamp 			*dp = dev;
694027b1f71SPoul-Henning Kamp 			freedev(ndev);
695027b1f71SPoul-Henning Kamp 			dev_unlock();
696b0b03348SPoul-Henning Kamp 			return (0);
697b0b03348SPoul-Henning Kamp 		}
698b0b03348SPoul-Henning Kamp 		if (unit == -1 && u == low) {
699b0b03348SPoul-Henning Kamp 			low++;
700b0b03348SPoul-Henning Kamp 			de = dev;
701b0b03348SPoul-Henning Kamp 			continue;
702b0b03348SPoul-Henning Kamp 		}
7038666b655SPoul-Henning Kamp 		if (u > (unit | extra)) {
704b0b03348SPoul-Henning Kamp 			dl = dev;
705b0b03348SPoul-Henning Kamp 			break;
706b0b03348SPoul-Henning Kamp 		}
707b0b03348SPoul-Henning Kamp 	}
708b0b03348SPoul-Henning Kamp 	if (unit == -1)
7098666b655SPoul-Henning Kamp 		unit = low & CLONE_UNITMASK;
710ff7284eeSPoul-Henning Kamp 	dev = newdev(csw, unit2minor(unit | extra), ndev);
711027b1f71SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
712027b1f71SPoul-Henning Kamp 		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
713027b1f71SPoul-Henning Kamp 		printf("unit=%d\n", unit);
714027b1f71SPoul-Henning Kamp 		LIST_FOREACH(dev, &cd->head, si_clone) {
715027b1f71SPoul-Henning Kamp 			printf("\t%p %s\n", dev, dev->si_name);
716027b1f71SPoul-Henning Kamp 		}
717027b1f71SPoul-Henning Kamp 		panic("foo");
718027b1f71SPoul-Henning Kamp 	}
719b0b03348SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_CLONELIST),
720027b1f71SPoul-Henning Kamp 	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
721b0b03348SPoul-Henning Kamp 	if (dl != NULL)
722b0b03348SPoul-Henning Kamp 		LIST_INSERT_BEFORE(dl, dev, si_clone);
723b0b03348SPoul-Henning Kamp 	else if (de != NULL)
724b0b03348SPoul-Henning Kamp 		LIST_INSERT_AFTER(de, dev, si_clone);
725b0b03348SPoul-Henning Kamp 	else
726b0b03348SPoul-Henning Kamp 		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
727b0b03348SPoul-Henning Kamp 	dev->si_flags |= SI_CLONELIST;
728b0b03348SPoul-Henning Kamp 	*up = unit;
729027b1f71SPoul-Henning Kamp 	dev_unlock();
730b0b03348SPoul-Henning Kamp 	return (1);
731b0b03348SPoul-Henning Kamp }
732b0b03348SPoul-Henning Kamp 
733b0b03348SPoul-Henning Kamp /*
734b0b03348SPoul-Henning Kamp  * Kill everything still on the list.  The driver should already have
73589c9c53dSPoul-Henning Kamp  * disposed of any softc hung of the struct cdev *'s at this time.
736b0b03348SPoul-Henning Kamp  */
737b0b03348SPoul-Henning Kamp void
738b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp)
739b0b03348SPoul-Henning Kamp {
74089c9c53dSPoul-Henning Kamp 	struct cdev *dev, *tdev;
741b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
742b0b03348SPoul-Henning Kamp 
743b0b03348SPoul-Henning Kamp 	cd = *cdp;
744b0b03348SPoul-Henning Kamp 	if (cd == NULL)
745b0b03348SPoul-Henning Kamp 		return;
746027b1f71SPoul-Henning Kamp 	dev_lock();
747b0b03348SPoul-Henning Kamp 	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
748027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
749027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
750b0b03348SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_NAMED,
7510a2e49f1SPoul-Henning Kamp 		    ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
752aa2f6ddcSPoul-Henning Kamp 		destroy_devl(dev);
753b0b03348SPoul-Henning Kamp 	}
754027b1f71SPoul-Henning Kamp 	dev_unlock();
755b0b03348SPoul-Henning Kamp 	free(cd, M_DEVBUF);
756b0b03348SPoul-Henning Kamp 	*cdp = NULL;
757b0b03348SPoul-Henning Kamp }
758