xref: /freebsd/sys/kern/kern_conf.c (revision 9c0af1310c99b66db08a88d84d13dd78d3d821ee)
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 
489c0af131SPoul-Henning Kamp #include <fs/devfs/devfs_int.h>
499c0af131SPoul-Henning Kamp 
509ef295b7SPoul-Henning Kamp static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
51698bfad7SPoul-Henning Kamp 
52beea48b2SPoul-Henning Kamp /* Built at compile time from sys/conf/majors */
53beea48b2SPoul-Henning Kamp 
54cd690b60SPoul-Henning Kamp static struct mtx devmtx;
5589c9c53dSPoul-Henning Kamp static void freedev(struct cdev *dev);
56aa2f6ddcSPoul-Henning Kamp static void destroy_devl(struct cdev *dev);
57d26dd2d9SRobert Watson static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr,
58d26dd2d9SRobert Watson 	    struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
59d26dd2d9SRobert Watson 	    va_list ap);
60f3732fd1SPoul-Henning Kamp 
61a0e78d2eSPoul-Henning Kamp void
62a0e78d2eSPoul-Henning Kamp dev_lock(void)
63cd690b60SPoul-Henning Kamp {
64cd690b60SPoul-Henning Kamp 	if (!mtx_initialized(&devmtx))
659ef295b7SPoul-Henning Kamp 		mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
66cd690b60SPoul-Henning Kamp 	mtx_lock(&devmtx);
67cd690b60SPoul-Henning Kamp }
68cd690b60SPoul-Henning Kamp 
69a0e78d2eSPoul-Henning Kamp void
70a0e78d2eSPoul-Henning Kamp dev_unlock(void)
71cd690b60SPoul-Henning Kamp {
722c15afd8SPoul-Henning Kamp 
73cd690b60SPoul-Henning Kamp 	mtx_unlock(&devmtx);
74cd690b60SPoul-Henning Kamp }
75cd690b60SPoul-Henning Kamp 
76cd690b60SPoul-Henning Kamp void
779477d73eSPoul-Henning Kamp dev_ref(struct cdev *dev)
789477d73eSPoul-Henning Kamp {
799477d73eSPoul-Henning Kamp 
809477d73eSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
819477d73eSPoul-Henning Kamp 	mtx_lock(&devmtx);
829477d73eSPoul-Henning Kamp 	dev->si_refcount++;
839477d73eSPoul-Henning Kamp 	mtx_unlock(&devmtx);
849477d73eSPoul-Henning Kamp }
859477d73eSPoul-Henning Kamp 
869477d73eSPoul-Henning Kamp void
87eb151cb9SPoul-Henning Kamp dev_refl(struct cdev *dev)
88cd690b60SPoul-Henning Kamp {
892c15afd8SPoul-Henning Kamp 
901a1457d4SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
91cd690b60SPoul-Henning Kamp 	dev->si_refcount++;
92cd690b60SPoul-Henning Kamp }
93cd690b60SPoul-Henning Kamp 
94cd690b60SPoul-Henning Kamp void
95aa2f6ddcSPoul-Henning Kamp dev_rel(struct cdev *dev)
96cd690b60SPoul-Henning Kamp {
97aa2f6ddcSPoul-Henning Kamp 	int flag = 0;
98a0e78d2eSPoul-Henning Kamp 
99ba285125SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
100ba285125SPoul-Henning Kamp 	dev_lock();
101cd690b60SPoul-Henning Kamp 	dev->si_refcount--;
102cd690b60SPoul-Henning Kamp 	KASSERT(dev->si_refcount >= 0,
103cd690b60SPoul-Henning Kamp 	    ("dev_rel(%s) gave negative count", devtoname(dev)));
104aa2f6ddcSPoul-Henning Kamp 	if (dev->si_usecount == 0 &&
105aa2f6ddcSPoul-Henning Kamp 	    (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
106cd690b60SPoul-Henning Kamp 	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
107cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
108ba285125SPoul-Henning Kamp 		flag = 1;
109ba285125SPoul-Henning Kamp 	}
110ba285125SPoul-Henning Kamp 	dev_unlock();
111ba285125SPoul-Henning Kamp 	if (flag)
112cd690b60SPoul-Henning Kamp 		freedev(dev);
113cd690b60SPoul-Henning Kamp }
114ba285125SPoul-Henning Kamp 
1152c15afd8SPoul-Henning Kamp struct cdevsw *
1162c15afd8SPoul-Henning Kamp dev_refthread(struct cdev *dev)
1172c15afd8SPoul-Henning Kamp {
1182c15afd8SPoul-Henning Kamp 	struct cdevsw *csw;
1192c15afd8SPoul-Henning Kamp 
1202c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1212c15afd8SPoul-Henning Kamp 	dev_lock();
1222c15afd8SPoul-Henning Kamp 	csw = dev->si_devsw;
1232c15afd8SPoul-Henning Kamp 	if (csw != NULL)
1242c15afd8SPoul-Henning Kamp 		dev->si_threadcount++;
1252c15afd8SPoul-Henning Kamp 	dev_unlock();
1262c15afd8SPoul-Henning Kamp 	return (csw);
1272c15afd8SPoul-Henning Kamp }
1282c15afd8SPoul-Henning Kamp 
1292c15afd8SPoul-Henning Kamp void
1302c15afd8SPoul-Henning Kamp dev_relthread(struct cdev *dev)
1312c15afd8SPoul-Henning Kamp {
1322c15afd8SPoul-Henning Kamp 
1332c15afd8SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_NOTOWNED);
1342c15afd8SPoul-Henning Kamp 	dev_lock();
1352c15afd8SPoul-Henning Kamp 	dev->si_threadcount--;
1362c15afd8SPoul-Henning Kamp 	dev_unlock();
1372c15afd8SPoul-Henning Kamp }
138cd690b60SPoul-Henning Kamp 
139b2941431SPoul-Henning Kamp int
140b2941431SPoul-Henning Kamp nullop(void)
141b2941431SPoul-Henning Kamp {
142b2941431SPoul-Henning Kamp 
143b2941431SPoul-Henning Kamp 	return (0);
144b2941431SPoul-Henning Kamp }
145b2941431SPoul-Henning Kamp 
146b2941431SPoul-Henning Kamp int
147b2941431SPoul-Henning Kamp eopnotsupp(void)
148b2941431SPoul-Henning Kamp {
149b2941431SPoul-Henning Kamp 
150b2941431SPoul-Henning Kamp 	return (EOPNOTSUPP);
151b2941431SPoul-Henning Kamp }
15202574b19SPoul-Henning Kamp 
15302574b19SPoul-Henning Kamp static int
15402574b19SPoul-Henning Kamp enxio(void)
15502574b19SPoul-Henning Kamp {
15602574b19SPoul-Henning Kamp 	return (ENXIO);
15702574b19SPoul-Henning Kamp }
15802574b19SPoul-Henning Kamp 
159b2941431SPoul-Henning Kamp static int
160b2941431SPoul-Henning Kamp enodev(void)
161b2941431SPoul-Henning Kamp {
162b2941431SPoul-Henning Kamp 	return (ENODEV);
163b2941431SPoul-Henning Kamp }
164b2941431SPoul-Henning Kamp 
165b2941431SPoul-Henning Kamp /* Define a dead_cdevsw for use when devices leave unexpectedly. */
166b2941431SPoul-Henning Kamp 
16702574b19SPoul-Henning Kamp #define dead_open	(d_open_t *)enxio
16802574b19SPoul-Henning Kamp #define dead_close	(d_close_t *)enxio
16902574b19SPoul-Henning Kamp #define dead_read	(d_read_t *)enxio
17002574b19SPoul-Henning Kamp #define dead_write	(d_write_t *)enxio
17102574b19SPoul-Henning Kamp #define dead_ioctl	(d_ioctl_t *)enxio
172b2941431SPoul-Henning Kamp #define dead_poll	(d_poll_t *)enodev
173b2941431SPoul-Henning Kamp #define dead_mmap	(d_mmap_t *)enodev
17402574b19SPoul-Henning Kamp 
17502574b19SPoul-Henning Kamp static void
17602574b19SPoul-Henning Kamp dead_strategy(struct bio *bp)
17702574b19SPoul-Henning Kamp {
17802574b19SPoul-Henning Kamp 
17902574b19SPoul-Henning Kamp 	biofinish(bp, NULL, ENXIO);
18002574b19SPoul-Henning Kamp }
18102574b19SPoul-Henning Kamp 
1822c6b49f6SPoul-Henning Kamp #define dead_dump	(dumper_t *)enxio
18302574b19SPoul-Henning Kamp #define dead_kqfilter	(d_kqfilter_t *)enxio
18402574b19SPoul-Henning Kamp 
18502574b19SPoul-Henning Kamp static struct cdevsw dead_cdevsw = {
186dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
187dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
1887ac40f5fSPoul-Henning Kamp 	.d_open =	dead_open,
1897ac40f5fSPoul-Henning Kamp 	.d_close =	dead_close,
1907ac40f5fSPoul-Henning Kamp 	.d_read =	dead_read,
1917ac40f5fSPoul-Henning Kamp 	.d_write =	dead_write,
1927ac40f5fSPoul-Henning Kamp 	.d_ioctl =	dead_ioctl,
1937ac40f5fSPoul-Henning Kamp 	.d_poll =	dead_poll,
1947ac40f5fSPoul-Henning Kamp 	.d_mmap =	dead_mmap,
1957ac40f5fSPoul-Henning Kamp 	.d_strategy =	dead_strategy,
1967ac40f5fSPoul-Henning Kamp 	.d_name =	"dead",
1977ac40f5fSPoul-Henning Kamp 	.d_dump =	dead_dump,
1987ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	dead_kqfilter
19902574b19SPoul-Henning Kamp };
20002574b19SPoul-Henning Kamp 
201b2941431SPoul-Henning Kamp /* Default methods if driver does not specify method */
202b2941431SPoul-Henning Kamp 
203b2941431SPoul-Henning Kamp #define null_open	(d_open_t *)nullop
204b2941431SPoul-Henning Kamp #define null_close	(d_close_t *)nullop
205b2941431SPoul-Henning Kamp #define no_read		(d_read_t *)enodev
206b2941431SPoul-Henning Kamp #define no_write	(d_write_t *)enodev
207b2941431SPoul-Henning Kamp #define no_ioctl	(d_ioctl_t *)enodev
208b2941431SPoul-Henning Kamp #define no_mmap		(d_mmap_t *)enodev
209ad3b9257SJohn-Mark Gurney #define no_kqfilter	(d_kqfilter_t *)enodev
210b2941431SPoul-Henning Kamp 
211b2941431SPoul-Henning Kamp static void
212b2941431SPoul-Henning Kamp no_strategy(struct bio *bp)
213b2941431SPoul-Henning Kamp {
214b2941431SPoul-Henning Kamp 
215b2941431SPoul-Henning Kamp 	biofinish(bp, NULL, ENODEV);
216b2941431SPoul-Henning Kamp }
217b2941431SPoul-Henning Kamp 
218b2941431SPoul-Henning Kamp static int
21989c9c53dSPoul-Henning Kamp no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
220b2941431SPoul-Henning Kamp {
221b2941431SPoul-Henning Kamp 	/*
222b2941431SPoul-Henning Kamp 	 * Return true for read/write.  If the user asked for something
223b2941431SPoul-Henning Kamp 	 * special, return POLLNVAL, so that clients have a way of
224b2941431SPoul-Henning Kamp 	 * determining reliably whether or not the extended
225b2941431SPoul-Henning Kamp 	 * functionality is present without hard-coding knowledge
226b2941431SPoul-Henning Kamp 	 * of specific filesystem implementations.
227b2941431SPoul-Henning Kamp 	 * Stay in sync with vop_nopoll().
228b2941431SPoul-Henning Kamp 	 */
229b2941431SPoul-Henning Kamp 	if (events & ~POLLSTANDARD)
230b2941431SPoul-Henning Kamp 		return (POLLNVAL);
231b2941431SPoul-Henning Kamp 
232b2941431SPoul-Henning Kamp 	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
233b2941431SPoul-Henning Kamp }
234b2941431SPoul-Henning Kamp 
235b2941431SPoul-Henning Kamp #define no_dump		(dumper_t *)enodev
2364e4a7663SPoul-Henning Kamp 
2372447bec8SPoul-Henning Kamp /*
23889c9c53dSPoul-Henning Kamp  * struct cdev * and u_dev_t primitives
239bfbb9ce6SPoul-Henning Kamp  */
240bfbb9ce6SPoul-Henning Kamp 
241bfbb9ce6SPoul-Henning Kamp int
24289c9c53dSPoul-Henning Kamp minor(struct cdev *x)
243bfbb9ce6SPoul-Henning Kamp {
244f3732fd1SPoul-Henning Kamp 	if (x == NULL)
245f3732fd1SPoul-Henning Kamp 		return NODEV;
2460a2e49f1SPoul-Henning Kamp 	return(x->si_drv0 & MAXMINOR);
247bfbb9ce6SPoul-Henning Kamp }
248bfbb9ce6SPoul-Henning Kamp 
2499a27d579SPoul-Henning Kamp int
25089c9c53dSPoul-Henning Kamp dev2unit(struct cdev *x)
2519a27d579SPoul-Henning Kamp {
2529a27d579SPoul-Henning Kamp 
253f3732fd1SPoul-Henning Kamp 	if (x == NULL)
254f3732fd1SPoul-Henning Kamp 		return NODEV;
25537085a39SPoul-Henning Kamp 	return (minor2unit(minor(x)));
2563a85fd26SPoul-Henning Kamp }
2573a85fd26SPoul-Henning Kamp 
2583238ec33SPoul-Henning Kamp u_int
2593238ec33SPoul-Henning Kamp minor2unit(u_int _minor)
2603a85fd26SPoul-Henning Kamp {
2613a85fd26SPoul-Henning Kamp 
262d9aaa28fSPoul-Henning Kamp 	KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
2633238ec33SPoul-Henning Kamp 	return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
2649a27d579SPoul-Henning Kamp }
2659a27d579SPoul-Henning Kamp 
266b0d17ba6SPoul-Henning Kamp int
267b0d17ba6SPoul-Henning Kamp unit2minor(int unit)
268b0d17ba6SPoul-Henning Kamp {
269b0d17ba6SPoul-Henning Kamp 
27015b6f00fSPoul-Henning Kamp 	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
271b0d17ba6SPoul-Henning Kamp 	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
272b0d17ba6SPoul-Henning Kamp }
273b0d17ba6SPoul-Henning Kamp 
27489c9c53dSPoul-Henning Kamp static struct cdev *
2753f54a085SPoul-Henning Kamp allocdev(void)
276bfbb9ce6SPoul-Henning Kamp {
277ca916247SPoul-Henning Kamp 	struct cdev *si;
278698bfad7SPoul-Henning Kamp 
2791a1b2800SPoul-Henning Kamp 	si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
280237d2765SPoul-Henning Kamp 	si->si_name = si->__si_namebuf;
2813344c5a1SPoul-Henning Kamp 	LIST_INIT(&si->si_children);
282aa2f6ddcSPoul-Henning Kamp 	LIST_INIT(&si->si_alist);
2833f54a085SPoul-Henning Kamp 	return (si);
2843f54a085SPoul-Henning Kamp }
2853f54a085SPoul-Henning Kamp 
28689c9c53dSPoul-Henning Kamp static struct cdev *
287ff7284eeSPoul-Henning Kamp newdev(struct cdevsw *csw, int y, struct cdev *si)
2883f54a085SPoul-Henning Kamp {
289027b1f71SPoul-Henning Kamp 	struct cdev *si2;
290f3732fd1SPoul-Henning Kamp 	dev_t	udev;
2913f54a085SPoul-Henning Kamp 
292027b1f71SPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
293b3d82c03SPoul-Henning Kamp 	udev = y;
294ff7284eeSPoul-Henning Kamp 	LIST_FOREACH(si2, &csw->d_devs, si_list) {
2950a2e49f1SPoul-Henning Kamp 		if (si2->si_drv0 == udev) {
296027b1f71SPoul-Henning Kamp 			freedev(si);
297027b1f71SPoul-Henning Kamp 			return (si2);
2983f54a085SPoul-Henning Kamp 		}
299027b1f71SPoul-Henning Kamp 	}
3000a2e49f1SPoul-Henning Kamp 	si->si_drv0 = udev;
301ff7284eeSPoul-Henning Kamp 	LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
302698bfad7SPoul-Henning Kamp 	return (si);
303bfbb9ce6SPoul-Henning Kamp }
304bfbb9ce6SPoul-Henning Kamp 
305cd690b60SPoul-Henning Kamp static void
30689c9c53dSPoul-Henning Kamp freedev(struct cdev *dev)
307d137acccSPoul-Henning Kamp {
308d137acccSPoul-Henning Kamp 
309d26dd2d9SRobert Watson 	if (dev->si_cred != NULL)
310d26dd2d9SRobert Watson 		crfree(dev->si_cred);
3111a1b2800SPoul-Henning Kamp 	free(dev, M_DEVT);
312d137acccSPoul-Henning Kamp }
313d137acccSPoul-Henning Kamp 
314bfbb9ce6SPoul-Henning Kamp int
315f3732fd1SPoul-Henning Kamp uminor(dev_t dev)
316bfbb9ce6SPoul-Henning Kamp {
317d9aaa28fSPoul-Henning Kamp 	return (dev & MAXMINOR);
318bfbb9ce6SPoul-Henning Kamp }
319bfbb9ce6SPoul-Henning Kamp 
320bfbb9ce6SPoul-Henning Kamp int
321f3732fd1SPoul-Henning Kamp umajor(dev_t dev)
322bfbb9ce6SPoul-Henning Kamp {
323d9aaa28fSPoul-Henning Kamp 	return ((dev & ~MAXMINOR) >> 8);
324bfbb9ce6SPoul-Henning Kamp }
325bfbb9ce6SPoul-Henning Kamp 
3262a3faf2fSPoul-Henning Kamp static void
327cd690b60SPoul-Henning Kamp fini_cdevsw(struct cdevsw *devsw)
328cd690b60SPoul-Henning Kamp {
329b3d82c03SPoul-Henning Kamp 
330652d0472SPoul-Henning Kamp 	devsw->d_flags &= ~D_INIT;
331b0b03348SPoul-Henning Kamp }
332b0b03348SPoul-Henning Kamp 
333b0b03348SPoul-Henning Kamp static void
334b0b03348SPoul-Henning Kamp prep_cdevsw(struct cdevsw *devsw)
335b0b03348SPoul-Henning Kamp {
336b0b03348SPoul-Henning Kamp 
337a0e78d2eSPoul-Henning Kamp 	dev_lock();
338cd690b60SPoul-Henning Kamp 
339800b42bdSPoul-Henning Kamp 	if (devsw->d_version != D_VERSION_01) {
340cd690b60SPoul-Henning Kamp 		printf(
341cd690b60SPoul-Henning Kamp 		    "WARNING: Device driver \"%s\" has wrong version %s\n",
342cd690b60SPoul-Henning Kamp 		    devsw->d_name, "and is disabled.  Recompile KLD module.");
343cd690b60SPoul-Henning Kamp 		devsw->d_open = dead_open;
344cd690b60SPoul-Henning Kamp 		devsw->d_close = dead_close;
345cd690b60SPoul-Henning Kamp 		devsw->d_read = dead_read;
346cd690b60SPoul-Henning Kamp 		devsw->d_write = dead_write;
347cd690b60SPoul-Henning Kamp 		devsw->d_ioctl = dead_ioctl;
348cd690b60SPoul-Henning Kamp 		devsw->d_poll = dead_poll;
349cd690b60SPoul-Henning Kamp 		devsw->d_mmap = dead_mmap;
350cd690b60SPoul-Henning Kamp 		devsw->d_strategy = dead_strategy;
351cd690b60SPoul-Henning Kamp 		devsw->d_dump = dead_dump;
352cd690b60SPoul-Henning Kamp 		devsw->d_kqfilter = dead_kqfilter;
353cd690b60SPoul-Henning Kamp 	}
354cd690b60SPoul-Henning Kamp 
3558e1f1df0SPoul-Henning Kamp 	if (devsw->d_flags & D_TTY) {
3563a95025fSPoul-Henning Kamp 		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
3578e1f1df0SPoul-Henning Kamp 		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
3588e1f1df0SPoul-Henning Kamp 		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
3598e1f1df0SPoul-Henning Kamp 		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
3608e1f1df0SPoul-Henning Kamp 		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
3618e1f1df0SPoul-Henning Kamp 	}
3628e1f1df0SPoul-Henning Kamp 
363b2941431SPoul-Henning Kamp 	if (devsw->d_open == NULL)	devsw->d_open = null_open;
364b2941431SPoul-Henning Kamp 	if (devsw->d_close == NULL)	devsw->d_close = null_close;
365b2941431SPoul-Henning Kamp 	if (devsw->d_read == NULL)	devsw->d_read = no_read;
366b2941431SPoul-Henning Kamp 	if (devsw->d_write == NULL)	devsw->d_write = no_write;
367b2941431SPoul-Henning Kamp 	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
368b2941431SPoul-Henning Kamp 	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
369b2941431SPoul-Henning Kamp 	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
370b2941431SPoul-Henning Kamp 	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
371b2941431SPoul-Henning Kamp 	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
372b2941431SPoul-Henning Kamp 	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
373cd690b60SPoul-Henning Kamp 
374cd690b60SPoul-Henning Kamp 	LIST_INIT(&devsw->d_devs);
375cd690b60SPoul-Henning Kamp 
376cd690b60SPoul-Henning Kamp 	devsw->d_flags |= D_INIT;
377cd690b60SPoul-Henning Kamp 
378a0e78d2eSPoul-Henning Kamp 	dev_unlock();
3792a3faf2fSPoul-Henning Kamp }
38011586717SBrian Somers 
381d26dd2d9SRobert Watson static struct cdev *
382d26dd2d9SRobert Watson make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
383d26dd2d9SRobert Watson     gid_t gid, int mode, const char *fmt, va_list ap)
3842a3faf2fSPoul-Henning Kamp {
38589c9c53dSPoul-Henning Kamp 	struct cdev *dev;
3862a3faf2fSPoul-Henning Kamp 	int i;
3872a3faf2fSPoul-Henning Kamp 
388d9aaa28fSPoul-Henning Kamp 	KASSERT((minornr & ~MAXMINOR) == 0,
389cd690b60SPoul-Henning Kamp 	    ("Invalid minor (0x%x) in make_dev", minornr));
390cd690b60SPoul-Henning Kamp 
3919477d73eSPoul-Henning Kamp 	if (!(devsw->d_flags & D_INIT))
3922a3faf2fSPoul-Henning Kamp 		prep_cdevsw(devsw);
393027b1f71SPoul-Henning Kamp 	dev = allocdev();
394027b1f71SPoul-Henning Kamp 	dev_lock();
395ff7284eeSPoul-Henning Kamp 	dev = newdev(devsw, minornr, dev);
39698c469d4SPoul-Henning Kamp 	if (dev->si_flags & SI_CHEAPCLONE &&
39798c469d4SPoul-Henning Kamp 	    dev->si_flags & SI_NAMED &&
39898c469d4SPoul-Henning Kamp 	    dev->si_devsw == devsw) {
39998c469d4SPoul-Henning Kamp 		/*
40098c469d4SPoul-Henning Kamp 		 * This is allowed as it removes races and generally
40198c469d4SPoul-Henning Kamp 		 * simplifies cloning devices.
402cd690b60SPoul-Henning Kamp 		 * XXX: still ??
40398c469d4SPoul-Henning Kamp 		 */
404027b1f71SPoul-Henning Kamp 		dev_unlock();
40598c469d4SPoul-Henning Kamp 		return (dev);
40698c469d4SPoul-Henning Kamp 	}
407cd690b60SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_NAMED),
408ff7284eeSPoul-Henning Kamp 	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
409ff7284eeSPoul-Henning Kamp 	    devsw->d_name, minor(dev), devtoname(dev)));
410cd690b60SPoul-Henning Kamp 
4116334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4126334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4132e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4146334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4156334a663SPoul-Henning Kamp 	}
4161a1b2800SPoul-Henning Kamp 
4170ef1c826SPoul-Henning Kamp 	dev->si_devsw = devsw;
4185ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
419d26dd2d9SRobert Watson 	if (cr != NULL)
420d26dd2d9SRobert Watson 		dev->si_cred = crhold(cr);
421d26dd2d9SRobert Watson 	else
422d26dd2d9SRobert Watson 		dev->si_cred = NULL;
4239477d73eSPoul-Henning Kamp 	dev->si_uid = uid;
4249477d73eSPoul-Henning Kamp 	dev->si_gid = gid;
4259477d73eSPoul-Henning Kamp 	dev->si_mode = mode;
4261744fcd0SJulian Elischer 
4279285a87eSPoul-Henning Kamp 	devfs_create(dev);
428a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4293f54a085SPoul-Henning Kamp 	return (dev);
4303f54a085SPoul-Henning Kamp }
4313f54a085SPoul-Henning Kamp 
432d26dd2d9SRobert Watson struct cdev *
433d26dd2d9SRobert Watson make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode,
434d26dd2d9SRobert Watson     const char *fmt, ...)
435d26dd2d9SRobert Watson {
436d26dd2d9SRobert Watson 	struct cdev *dev;
437d26dd2d9SRobert Watson 	va_list ap;
438d26dd2d9SRobert Watson 
439d26dd2d9SRobert Watson 	va_start(ap, fmt);
440d26dd2d9SRobert Watson 	dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap);
441d26dd2d9SRobert Watson 	va_end(ap);
442d26dd2d9SRobert Watson 	return (dev);
443d26dd2d9SRobert Watson }
444d26dd2d9SRobert Watson 
445d26dd2d9SRobert Watson struct cdev *
446d26dd2d9SRobert Watson make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
447d26dd2d9SRobert Watson     gid_t gid, int mode, const char *fmt, ...)
448d26dd2d9SRobert Watson {
449d26dd2d9SRobert Watson 	struct cdev *dev;
450d26dd2d9SRobert Watson 	va_list ap;
451d26dd2d9SRobert Watson 
452d26dd2d9SRobert Watson 	va_start(ap, fmt);
453d26dd2d9SRobert Watson 	dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap);
454d26dd2d9SRobert Watson 	va_end(ap);
455d26dd2d9SRobert Watson 
456d26dd2d9SRobert Watson 	return (dev);
457d26dd2d9SRobert Watson }
458d26dd2d9SRobert Watson 
4597e7c3f3fSJonathan Lemon int
46089c9c53dSPoul-Henning Kamp dev_named(struct cdev *pdev, const char *name)
4617e7c3f3fSJonathan Lemon {
46289c9c53dSPoul-Henning Kamp 	struct cdev *cdev;
4637e7c3f3fSJonathan Lemon 
4647e7c3f3fSJonathan Lemon 	if (strcmp(devtoname(pdev), name) == 0)
4657e7c3f3fSJonathan Lemon 		return (1);
4667e7c3f3fSJonathan Lemon 	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
4677e7c3f3fSJonathan Lemon 		if (strcmp(devtoname(cdev), name) == 0)
4687e7c3f3fSJonathan Lemon 			return (1);
4697e7c3f3fSJonathan Lemon 	return (0);
4707e7c3f3fSJonathan Lemon }
4717e7c3f3fSJonathan Lemon 
4723344c5a1SPoul-Henning Kamp void
47389c9c53dSPoul-Henning Kamp dev_depends(struct cdev *pdev, struct cdev *cdev)
4743344c5a1SPoul-Henning Kamp {
4753344c5a1SPoul-Henning Kamp 
476a0e78d2eSPoul-Henning Kamp 	dev_lock();
4773344c5a1SPoul-Henning Kamp 	cdev->si_parent = pdev;
4783344c5a1SPoul-Henning Kamp 	cdev->si_flags |= SI_CHILD;
4793344c5a1SPoul-Henning Kamp 	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
480a0e78d2eSPoul-Henning Kamp 	dev_unlock();
4813344c5a1SPoul-Henning Kamp }
4823344c5a1SPoul-Henning Kamp 
48389c9c53dSPoul-Henning Kamp struct cdev *
48489c9c53dSPoul-Henning Kamp make_dev_alias(struct cdev *pdev, const char *fmt, ...)
4853f54a085SPoul-Henning Kamp {
48689c9c53dSPoul-Henning Kamp 	struct cdev *dev;
4873f54a085SPoul-Henning Kamp 	va_list ap;
4883f54a085SPoul-Henning Kamp 	int i;
4893f54a085SPoul-Henning Kamp 
4903f54a085SPoul-Henning Kamp 	dev = allocdev();
491a0e78d2eSPoul-Henning Kamp 	dev_lock();
4923f54a085SPoul-Henning Kamp 	dev->si_flags |= SI_ALIAS;
4935ef2707eSPoul-Henning Kamp 	dev->si_flags |= SI_NAMED;
4943f54a085SPoul-Henning Kamp 	va_start(ap, fmt);
4956334a663SPoul-Henning Kamp 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
4966334a663SPoul-Henning Kamp 	if (i > (sizeof dev->__si_namebuf - 1)) {
4972e4db7cfSPawel Jakub Dawidek 		printf("WARNING: Device name truncated! (%s)\n",
4986334a663SPoul-Henning Kamp 		    dev->__si_namebuf);
4996334a663SPoul-Henning Kamp 	}
5003f54a085SPoul-Henning Kamp 	va_end(ap);
5013f54a085SPoul-Henning Kamp 
5029285a87eSPoul-Henning Kamp 	devfs_create(dev);
503a0e78d2eSPoul-Henning Kamp 	dev_unlock();
504cd690b60SPoul-Henning Kamp 	dev_depends(pdev, dev);
5050ef1c826SPoul-Henning Kamp 	return (dev);
5060ef1c826SPoul-Henning Kamp }
5070ef1c826SPoul-Henning Kamp 
508cd690b60SPoul-Henning Kamp static void
509aa2f6ddcSPoul-Henning Kamp destroy_devl(struct cdev *dev)
510d137acccSPoul-Henning Kamp {
511743cd76aSPoul-Henning Kamp 	struct cdevsw *csw;
512743cd76aSPoul-Henning Kamp 
513aa2f6ddcSPoul-Henning Kamp 	mtx_assert(&devmtx, MA_OWNED);
514743cd76aSPoul-Henning Kamp 	KASSERT(dev->si_flags & SI_NAMED,
515ff7284eeSPoul-Henning Kamp 	    ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
5165ef2707eSPoul-Henning Kamp 
5179285a87eSPoul-Henning Kamp 	devfs_destroy(dev);
518cd690b60SPoul-Henning Kamp 
519cd690b60SPoul-Henning Kamp 	/* Remove name marking */
520b0b03348SPoul-Henning Kamp 	dev->si_flags &= ~SI_NAMED;
521b0b03348SPoul-Henning Kamp 
522cd690b60SPoul-Henning Kamp 	/* If we are a child, remove us from the parents list */
5233344c5a1SPoul-Henning Kamp 	if (dev->si_flags & SI_CHILD) {
5243344c5a1SPoul-Henning Kamp 		LIST_REMOVE(dev, si_siblings);
5253344c5a1SPoul-Henning Kamp 		dev->si_flags &= ~SI_CHILD;
5263344c5a1SPoul-Henning Kamp 	}
527cd690b60SPoul-Henning Kamp 
528cd690b60SPoul-Henning Kamp 	/* Kill our children */
5293344c5a1SPoul-Henning Kamp 	while (!LIST_EMPTY(&dev->si_children))
530aa2f6ddcSPoul-Henning Kamp 		destroy_devl(LIST_FIRST(&dev->si_children));
531cd690b60SPoul-Henning Kamp 
532cd690b60SPoul-Henning Kamp 	/* Remove from clone list */
533b0b03348SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
534b0b03348SPoul-Henning Kamp 		LIST_REMOVE(dev, si_clone);
535b0b03348SPoul-Henning Kamp 		dev->si_flags &= ~SI_CLONELIST;
536b0b03348SPoul-Henning Kamp 	}
537cd690b60SPoul-Henning Kamp 
538743cd76aSPoul-Henning Kamp 	csw = dev->si_devsw;
5391abf2c36SBrian Feldman 	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
5401abf2c36SBrian Feldman 	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
541743cd76aSPoul-Henning Kamp 		printf("Purging %lu threads from %s\n",
542743cd76aSPoul-Henning Kamp 		    dev->si_threadcount, devtoname(dev));
543743cd76aSPoul-Henning Kamp 		csw->d_purge(dev);
544743cd76aSPoul-Henning Kamp 		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
545743cd76aSPoul-Henning Kamp 	}
5461abf2c36SBrian Feldman 	if (csw != NULL && csw->d_purge != NULL)
547a5993c33SPoul-Henning Kamp 		printf("All threads purged from %s\n", devtoname(dev));
548743cd76aSPoul-Henning Kamp 
549743cd76aSPoul-Henning Kamp 	dev->si_drv1 = 0;
550743cd76aSPoul-Henning Kamp 	dev->si_drv2 = 0;
551743cd76aSPoul-Henning Kamp 	bzero(&dev->__si_u, sizeof(dev->__si_u));
552743cd76aSPoul-Henning Kamp 
553cd690b60SPoul-Henning Kamp 	if (!(dev->si_flags & SI_ALIAS)) {
554cd690b60SPoul-Henning Kamp 		/* Remove from cdevsw list */
555cd690b60SPoul-Henning Kamp 		LIST_REMOVE(dev, si_list);
556cd690b60SPoul-Henning Kamp 
55789c9c53dSPoul-Henning Kamp 		/* If cdevsw has no struct cdev *'s, clean it */
558a5993c33SPoul-Henning Kamp 		if (LIST_EMPTY(&csw->d_devs))
559a5993c33SPoul-Henning Kamp 			fini_cdevsw(csw);
560cd690b60SPoul-Henning Kamp 	}
5615ef2707eSPoul-Henning Kamp 	dev->si_flags &= ~SI_ALIAS;
562743cd76aSPoul-Henning Kamp 
563cd690b60SPoul-Henning Kamp 	if (dev->si_refcount > 0) {
564cd690b60SPoul-Henning Kamp 		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
565cd690b60SPoul-Henning Kamp 	} else {
566d137acccSPoul-Henning Kamp 		freedev(dev);
567d137acccSPoul-Henning Kamp 	}
568cd690b60SPoul-Henning Kamp }
569cd690b60SPoul-Henning Kamp 
570cd690b60SPoul-Henning Kamp void
57189c9c53dSPoul-Henning Kamp destroy_dev(struct cdev *dev)
572cd690b60SPoul-Henning Kamp {
573cd690b60SPoul-Henning Kamp 
574a0e78d2eSPoul-Henning Kamp 	dev_lock();
575aa2f6ddcSPoul-Henning Kamp 	destroy_devl(dev);
576a0e78d2eSPoul-Henning Kamp 	dev_unlock();
577cd690b60SPoul-Henning Kamp }
578d137acccSPoul-Henning Kamp 
579c32cc149SBruce Evans const char *
58089c9c53dSPoul-Henning Kamp devtoname(struct cdev *dev)
581b8e49f68SBill Fumerola {
582d137acccSPoul-Henning Kamp 	char *p;
5838ff33adbSPoul-Henning Kamp 	struct cdevsw *csw;
584c32cc149SBruce Evans 	int mynor;
585b8e49f68SBill Fumerola 
586d137acccSPoul-Henning Kamp 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
587d137acccSPoul-Henning Kamp 		p = dev->si_name;
5888ff33adbSPoul-Henning Kamp 		csw = dev_refthread(dev);
5898ff33adbSPoul-Henning Kamp 		if (csw != NULL) {
5908ff33adbSPoul-Henning Kamp 			sprintf(p, "(%s)", csw->d_name);
5918ff33adbSPoul-Henning Kamp 			dev_relthread(dev);
5928ff33adbSPoul-Henning Kamp 		}
593d137acccSPoul-Henning Kamp 		p += strlen(p);
594c32cc149SBruce Evans 		mynor = minor(dev);
595c32cc149SBruce Evans 		if (mynor < 0 || mynor > 255)
5968ff33adbSPoul-Henning Kamp 			sprintf(p, "/%#x", (u_int)mynor);
597c32cc149SBruce Evans 		else
5988ff33adbSPoul-Henning Kamp 			sprintf(p, "/%d", mynor);
599d137acccSPoul-Henning Kamp 	}
600b8e49f68SBill Fumerola 	return (dev->si_name);
601b8e49f68SBill Fumerola }
602db901281SPoul-Henning Kamp 
603db901281SPoul-Henning Kamp int
60401de1b13SPoul-Henning Kamp dev_stdclone(char *name, char **namep, const char *stem, int *unit)
605db901281SPoul-Henning Kamp {
606db901281SPoul-Henning Kamp 	int u, i;
607db901281SPoul-Henning Kamp 
608db901281SPoul-Henning Kamp 	i = strlen(stem);
60956700d46SBrian Somers 	if (bcmp(stem, name, i) != 0)
61056700d46SBrian Somers 		return (0);
611db901281SPoul-Henning Kamp 	if (!isdigit(name[i]))
612db901281SPoul-Henning Kamp 		return (0);
613db901281SPoul-Henning Kamp 	u = 0;
61410786074SPoul-Henning Kamp 	if (name[i] == '0' && isdigit(name[i+1]))
61510786074SPoul-Henning Kamp 		return (0);
616db901281SPoul-Henning Kamp 	while (isdigit(name[i])) {
617db901281SPoul-Henning Kamp 		u *= 10;
618db901281SPoul-Henning Kamp 		u += name[i++] - '0';
619db901281SPoul-Henning Kamp 	}
620dab3d85fSBrian Feldman 	if (u > 0xffffff)
621dab3d85fSBrian Feldman 		return (0);
622db901281SPoul-Henning Kamp 	*unit = u;
623db901281SPoul-Henning Kamp 	if (namep)
624db901281SPoul-Henning Kamp 		*namep = &name[i];
625db901281SPoul-Henning Kamp 	if (name[i])
626db901281SPoul-Henning Kamp 		return (2);
627db901281SPoul-Henning Kamp 	return (1);
628db901281SPoul-Henning Kamp }
6298d25eb2cSPoul-Henning Kamp 
6308d25eb2cSPoul-Henning Kamp /*
631b0b03348SPoul-Henning Kamp  * Helper functions for cloning device drivers.
632b0b03348SPoul-Henning Kamp  *
633b0b03348SPoul-Henning Kamp  * The objective here is to make it unnecessary for the device drivers to
634b0b03348SPoul-Henning Kamp  * use rman or similar to manage their unit number space.  Due to the way
635b0b03348SPoul-Henning Kamp  * we do "on-demand" devices, using rman or other "private" methods
636b0b03348SPoul-Henning Kamp  * will be very tricky to lock down properly once we lock down this file.
637b0b03348SPoul-Henning Kamp  *
6389a98ae94SLukas Ertl  * Instead we give the drivers these routines which puts the struct cdev *'s
6399a98ae94SLukas Ertl  * that are to be managed on their own list, and gives the driver the ability
640b0b03348SPoul-Henning Kamp  * to ask for the first free unit number or a given specified unit number.
641b0b03348SPoul-Henning Kamp  *
642b0b03348SPoul-Henning Kamp  * In addition these routines support paired devices (pty, nmdm and similar)
643b0b03348SPoul-Henning Kamp  * by respecting a number of "flag" bits in the minor number.
644b0b03348SPoul-Henning Kamp  *
645b0b03348SPoul-Henning Kamp  */
646b0b03348SPoul-Henning Kamp 
647b0b03348SPoul-Henning Kamp struct clonedevs {
648b0b03348SPoul-Henning Kamp 	LIST_HEAD(,cdev)	head;
649b0b03348SPoul-Henning Kamp };
650b0b03348SPoul-Henning Kamp 
6519397290eSPoul-Henning Kamp void
6529397290eSPoul-Henning Kamp clone_setup(struct clonedevs **cdp)
6539397290eSPoul-Henning Kamp {
6549397290eSPoul-Henning Kamp 
6559397290eSPoul-Henning Kamp 	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
6569397290eSPoul-Henning Kamp 	LIST_INIT(&(*cdp)->head);
6579397290eSPoul-Henning Kamp }
6589397290eSPoul-Henning Kamp 
659b0b03348SPoul-Henning Kamp int
66089c9c53dSPoul-Henning Kamp clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
661b0b03348SPoul-Henning Kamp {
662b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
663027b1f71SPoul-Henning Kamp 	struct cdev *dev, *ndev, *dl, *de;
664b0b03348SPoul-Henning Kamp 	int unit, low, u;
665b0b03348SPoul-Henning Kamp 
6669397290eSPoul-Henning Kamp 	KASSERT(*cdp != NULL,
6679397290eSPoul-Henning Kamp 	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
668b0b03348SPoul-Henning Kamp 	KASSERT(!(extra & CLONE_UNITMASK),
669b0b03348SPoul-Henning Kamp 	    ("Illegal extra bits (0x%x) in clone_create", extra));
670b0b03348SPoul-Henning Kamp 	KASSERT(*up <= CLONE_UNITMASK,
671b0b03348SPoul-Henning Kamp 	    ("Too high unit (0x%x) in clone_create", *up));
672b0b03348SPoul-Henning Kamp 
6738045ce21SPoul-Henning Kamp 	if (!(csw->d_flags & D_INIT))
6748045ce21SPoul-Henning Kamp 		prep_cdevsw(csw);
675b0b03348SPoul-Henning Kamp 
676b0b03348SPoul-Henning Kamp 	/*
677b0b03348SPoul-Henning Kamp 	 * Search the list for a lot of things in one go:
678b0b03348SPoul-Henning Kamp 	 *   A preexisting match is returned immediately.
679b0b03348SPoul-Henning Kamp 	 *   The lowest free unit number if we are passed -1, and the place
680b0b03348SPoul-Henning Kamp 	 *	 in the list where we should insert that new element.
681b0b03348SPoul-Henning Kamp 	 *   The place to insert a specified unit number, if applicable
682b0b03348SPoul-Henning Kamp 	 *       the end of the list.
683b0b03348SPoul-Henning Kamp 	 */
684b0b03348SPoul-Henning Kamp 	unit = *up;
685027b1f71SPoul-Henning Kamp 	ndev = allocdev();
686027b1f71SPoul-Henning Kamp 	dev_lock();
6878666b655SPoul-Henning Kamp 	low = extra;
688b0b03348SPoul-Henning Kamp 	de = dl = NULL;
6899397290eSPoul-Henning Kamp 	cd = *cdp;
690b0b03348SPoul-Henning Kamp 	LIST_FOREACH(dev, &cd->head, si_clone) {
691027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
692027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
693b0b03348SPoul-Henning Kamp 		u = dev2unit(dev);
694b0b03348SPoul-Henning Kamp 		if (u == (unit | extra)) {
695b0b03348SPoul-Henning Kamp 			*dp = dev;
696027b1f71SPoul-Henning Kamp 			freedev(ndev);
697027b1f71SPoul-Henning Kamp 			dev_unlock();
698b0b03348SPoul-Henning Kamp 			return (0);
699b0b03348SPoul-Henning Kamp 		}
700b0b03348SPoul-Henning Kamp 		if (unit == -1 && u == low) {
701b0b03348SPoul-Henning Kamp 			low++;
702b0b03348SPoul-Henning Kamp 			de = dev;
703b0b03348SPoul-Henning Kamp 			continue;
704b0b03348SPoul-Henning Kamp 		}
7058666b655SPoul-Henning Kamp 		if (u > (unit | extra)) {
706b0b03348SPoul-Henning Kamp 			dl = dev;
707b0b03348SPoul-Henning Kamp 			break;
708b0b03348SPoul-Henning Kamp 		}
709b0b03348SPoul-Henning Kamp 	}
710b0b03348SPoul-Henning Kamp 	if (unit == -1)
7118666b655SPoul-Henning Kamp 		unit = low & CLONE_UNITMASK;
712ff7284eeSPoul-Henning Kamp 	dev = newdev(csw, unit2minor(unit | extra), ndev);
713027b1f71SPoul-Henning Kamp 	if (dev->si_flags & SI_CLONELIST) {
714027b1f71SPoul-Henning Kamp 		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
715027b1f71SPoul-Henning Kamp 		printf("unit=%d\n", unit);
716027b1f71SPoul-Henning Kamp 		LIST_FOREACH(dev, &cd->head, si_clone) {
717027b1f71SPoul-Henning Kamp 			printf("\t%p %s\n", dev, dev->si_name);
718027b1f71SPoul-Henning Kamp 		}
719027b1f71SPoul-Henning Kamp 		panic("foo");
720027b1f71SPoul-Henning Kamp 	}
721b0b03348SPoul-Henning Kamp 	KASSERT(!(dev->si_flags & SI_CLONELIST),
722027b1f71SPoul-Henning Kamp 	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
723b0b03348SPoul-Henning Kamp 	if (dl != NULL)
724b0b03348SPoul-Henning Kamp 		LIST_INSERT_BEFORE(dl, dev, si_clone);
725b0b03348SPoul-Henning Kamp 	else if (de != NULL)
726b0b03348SPoul-Henning Kamp 		LIST_INSERT_AFTER(de, dev, si_clone);
727b0b03348SPoul-Henning Kamp 	else
728b0b03348SPoul-Henning Kamp 		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
729b0b03348SPoul-Henning Kamp 	dev->si_flags |= SI_CLONELIST;
730b0b03348SPoul-Henning Kamp 	*up = unit;
731027b1f71SPoul-Henning Kamp 	dev_unlock();
732b0b03348SPoul-Henning Kamp 	return (1);
733b0b03348SPoul-Henning Kamp }
734b0b03348SPoul-Henning Kamp 
735b0b03348SPoul-Henning Kamp /*
736b0b03348SPoul-Henning Kamp  * Kill everything still on the list.  The driver should already have
73789c9c53dSPoul-Henning Kamp  * disposed of any softc hung of the struct cdev *'s at this time.
738b0b03348SPoul-Henning Kamp  */
739b0b03348SPoul-Henning Kamp void
740b0b03348SPoul-Henning Kamp clone_cleanup(struct clonedevs **cdp)
741b0b03348SPoul-Henning Kamp {
74289c9c53dSPoul-Henning Kamp 	struct cdev *dev, *tdev;
743b0b03348SPoul-Henning Kamp 	struct clonedevs *cd;
744b0b03348SPoul-Henning Kamp 
745b0b03348SPoul-Henning Kamp 	cd = *cdp;
746b0b03348SPoul-Henning Kamp 	if (cd == NULL)
747b0b03348SPoul-Henning Kamp 		return;
748027b1f71SPoul-Henning Kamp 	dev_lock();
749b0b03348SPoul-Henning Kamp 	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
750027b1f71SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_CLONELIST,
751027b1f71SPoul-Henning Kamp 		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
752b0b03348SPoul-Henning Kamp 		KASSERT(dev->si_flags & SI_NAMED,
7530a2e49f1SPoul-Henning Kamp 		    ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
754aa2f6ddcSPoul-Henning Kamp 		destroy_devl(dev);
755b0b03348SPoul-Henning Kamp 	}
756027b1f71SPoul-Henning Kamp 	dev_unlock();
757b0b03348SPoul-Henning Kamp 	free(cd, M_DEVBUF);
758b0b03348SPoul-Henning Kamp 	*cdp = NULL;
759b0b03348SPoul-Henning Kamp }
760