kern_conf.c revision 129943
190075Sobrien/*-
2169689Skan * Copyright (c) 1999-2002 Poul-Henning Kamp
3169689Skan * All rights reserved.
490075Sobrien *
590075Sobrien * Redistribution and use in source and binary forms, with or without
690075Sobrien * modification, are permitted provided that the following conditions
790075Sobrien * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1190075Sobrien *    notice, this list of conditions and the following disclaimer in the
1290075Sobrien *    documentation and/or other materials provided with the distribution.
1390075Sobrien *
1490075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1990075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2490075Sobrien * SUCH DAMAGE.
2590075Sobrien */
2690075Sobrien
2790075Sobrien#include <sys/cdefs.h>
2890075Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 129943 2004-06-01 13:39:02Z phk $");
2990075Sobrien
3090075Sobrien#include <sys/param.h>
3190075Sobrien#include <sys/kernel.h>
3290075Sobrien#include <sys/systm.h>
3390075Sobrien#include <sys/bio.h>
3490075Sobrien#include <sys/lock.h>
3590075Sobrien#include <sys/mutex.h>
3690075Sobrien#include <sys/sysctl.h>
3790075Sobrien#include <sys/module.h>
3890075Sobrien#include <sys/malloc.h>
3990075Sobrien#include <sys/conf.h>
4090075Sobrien#include <sys/vnode.h>
4190075Sobrien#include <sys/queue.h>
4290075Sobrien#include <sys/poll.h>
4390075Sobrien#include <sys/ctype.h>
4490075Sobrien#include <sys/tty.h>
4590075Sobrien#include <machine/stdarg.h>
4690075Sobrien
4790075Sobrienstatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
48169689Skan
49169689Skan/* Built at compile time from sys/conf/majors */
50169689Skanextern unsigned char reserved_majors[256];
51132718Skan
52169689Skan/*
53132718Skan * This is the number of hash-buckets.  Experiements with 'real-life'
54169689Skan * udev_t's show that a prime halfway between two powers of two works
55169689Skan * best.
56169689Skan */
57169689Skan#define DEVT_HASH 83
58169689Skan
59169689Skan/* The number of dev_t's we can create before malloc(9) kick in.  */
60169689Skan#define DEVT_STASH 50
61169689Skan
62169689Skanstatic struct cdev devt_stash[DEVT_STASH];
63169689Skan
64169689Skanstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
65169689Skan
66169689Skanstatic LIST_HEAD(, cdev) dev_free;
67169689Skan
68169689Skanstatic int free_devt;
69169689SkanSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
70169689Skan
71169689Skanstatic struct mtx devmtx;
7290075Sobrienstatic void freedev(dev_t dev);
7390075Sobrien
7490075Sobrienstatic void
7590075Sobriendevlock(void)
7690075Sobrien{
7790075Sobrien	if (!mtx_initialized(&devmtx))
7890075Sobrien		mtx_init(&devmtx, "dev_t", NULL, MTX_DEF);
7990075Sobrien	mtx_lock(&devmtx);
8090075Sobrien}
8190075Sobrien
8290075Sobrienstatic void
8390075Sobriendevunlock(void)
8490075Sobrien{
8590075Sobrien	mtx_unlock(&devmtx);
8690075Sobrien}
8790075Sobrien
8890075Sobrienvoid
8990075Sobriendev_ref(dev_t dev)
9090075Sobrien{
9190075Sobrien	devlock();
9290075Sobrien	dev->si_refcount++;
9390075Sobrien	devunlock();
9490075Sobrien}
95132718Skan
9690075Sobrienvoid
97117395Skandev_rel(dev_t dev)
98132718Skan{
99117395Skan	devlock();
100169689Skan	dev->si_refcount--;
101169689Skan	KASSERT(dev->si_refcount >= 0,
102169689Skan	    ("dev_rel(%s) gave negative count", devtoname(dev)));
103169689Skan	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
104169689Skan		LIST_REMOVE(dev, si_list);
105169689Skan		freedev(dev);
106169689Skan	}
107169689Skan	devunlock();
108169689Skan}
109169689Skan
110169689Skanvoid
111169689Skancdevsw_ref(struct cdevsw *csw)
112169689Skan{
113169689Skan	devlock();
114132718Skan	csw->d_refcount++;
115132718Skan	devunlock();
116132718Skan}
117169689Skan
118169689Skanvoid
119169689Skancdevsw_rel(struct cdevsw *csw)
120117395Skan{
121117395Skan	devlock();
122132718Skan	csw->d_refcount--;
123117395Skan	KASSERT(csw->d_refcount >= 0,
12490075Sobrien	    ("cdevsw_vrel(%s) gave negative count", csw->d_name));
125132718Skan	devunlock();
12690075Sobrien}
12790075Sobrien
128132718Skanstatic dev_t makedev(int x, int y);
12990075Sobrien
13090075Sobrienint
131132718Skannullop(void)
13290075Sobrien{
13390075Sobrien
134132718Skan	return (0);
13590075Sobrien}
136169689Skan
137169689Skanint
13890075Sobrieneopnotsupp(void)
139169689Skan{
140169689Skan
141169689Skan	return (EOPNOTSUPP);
142169689Skan}
14390075Sobrien
144169689Skanstatic int
145169689Skanenxio(void)
146169689Skan{
147169689Skan	return (ENXIO);
148169689Skan}
14990075Sobrien
150169689Skanstatic int
151169689Skanenodev(void)
152169689Skan{
153169689Skan	return (ENODEV);
154169689Skan}
155117395Skan
156169689Skan/* Define a dead_cdevsw for use when devices leave unexpectedly. */
157169689Skan
158169689Skan#define dead_open	(d_open_t *)enxio
159169689Skan#define dead_close	(d_close_t *)enxio
160117395Skan#define dead_read	(d_read_t *)enxio
161117395Skan#define dead_write	(d_write_t *)enxio
162117395Skan#define dead_ioctl	(d_ioctl_t *)enxio
163132718Skan#define dead_poll	(d_poll_t *)enodev
164117395Skan#define dead_mmap	(d_mmap_t *)enodev
165169689Skan
166169689Skanstatic void
167169689Skandead_strategy(struct bio *bp)
16890075Sobrien{
169132718Skan
17090075Sobrien	biofinish(bp, NULL, ENXIO);
17190075Sobrien}
172132718Skan
173117395Skan#define dead_dump	(dumper_t *)enxio
174117395Skan#define dead_kqfilter	(d_kqfilter_t *)enxio
175117395Skan
176117395Skanstatic struct cdevsw dead_cdevsw = {
177117395Skan	.d_version =	D_VERSION,
178117395Skan	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
179132718Skan	.d_open =	dead_open,
180132718Skan	.d_close =	dead_close,
181132718Skan	.d_read =	dead_read,
182117395Skan	.d_write =	dead_write,
183117395Skan	.d_ioctl =	dead_ioctl,
184117395Skan	.d_poll =	dead_poll,
185117395Skan	.d_mmap =	dead_mmap,
186117395Skan	.d_strategy =	dead_strategy,
187117395Skan	.d_name =	"dead",
188117395Skan	.d_maj =	255,
189132718Skan	.d_dump =	dead_dump,
190132718Skan	.d_kqfilter =	dead_kqfilter
191132718Skan};
192132718Skan
193132718Skan/* Default methods if driver does not specify method */
194132718Skan
195132718Skan#define null_open	(d_open_t *)nullop
196132718Skan#define null_close	(d_close_t *)nullop
197132718Skan#define no_read		(d_read_t *)enodev
198132718Skan#define no_write	(d_write_t *)enodev
199132718Skan#define no_ioctl	(d_ioctl_t *)enodev
200132718Skan#define no_mmap		(d_mmap_t *)enodev
201132718Skan
202132718Skanstatic int
203132718Skanno_kqfilter(dev_t dev __unused, struct knote *kn __unused)
204169689Skan{
205169689Skan
206169689Skan	return (1);
207169689Skan}
208169689Skan
209169689Skanstatic void
210169689Skanno_strategy(struct bio *bp)
211169689Skan{
212169689Skan
213169689Skan	biofinish(bp, NULL, ENODEV);
214169689Skan}
21590075Sobrien
21690075Sobrienstatic int
21790075Sobrienno_poll(dev_t dev __unused, int events, struct thread *td __unused)
21890075Sobrien{
21990075Sobrien	/*
22090075Sobrien	 * Return true for read/write.  If the user asked for something
22190075Sobrien	 * special, return POLLNVAL, so that clients have a way of
22290075Sobrien	 * determining reliably whether or not the extended
223132718Skan	 * functionality is present without hard-coding knowledge
22490075Sobrien	 * of specific filesystem implementations.
22590075Sobrien	 * Stay in sync with vop_nopoll().
22690075Sobrien	 */
227132718Skan	if (events & ~POLLSTANDARD)
22890075Sobrien		return (POLLNVAL);
22990075Sobrien
23090075Sobrien	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
23190075Sobrien}
232132718Skan
23390075Sobrien#define no_dump		(dumper_t *)enodev
23490075Sobrien
23590075Sobrienstruct cdevsw *
236132718Skandevsw(dev_t dev)
237117395Skan{
23890075Sobrien	if (dev->si_devsw != NULL)
239132718Skan		return (dev->si_devsw);
24090075Sobrien	return (&dead_cdevsw);
24190075Sobrien}
242132718Skan
24390075Sobrien/*
244169689Skan * dev_t and u_dev_t primitives
245169689Skan */
246169689Skan
247169689Skanint
248169689Skanmajor(dev_t x)
249169689Skan{
25090075Sobrien	if (x == NODEV)
25190075Sobrien		return NOUDEV;
252132718Skan	return((x->si_udev >> 8) & 0xff);
253132718Skan}
25490075Sobrien
255132718Skanint
256132718Skanminor(dev_t x)
257132718Skan{
258132718Skan	if (x == NODEV)
259132718Skan		return NOUDEV;
260117395Skan	return(x->si_udev & 0xffff00ff);
261117395Skan}
262117395Skan
263117395Skanint
264117395Skandev2unit(dev_t x)
265117395Skan{
266117395Skan	int i;
267117395Skan
268132718Skan	if (x == NODEV)
269117395Skan		return NOUDEV;
270117395Skan	i = minor(x);
271132718Skan	return ((i & 0xff) | (i >> 8));
272132718Skan}
273132718Skan
274132718Skanint
275169689Skanunit2minor(int unit)
276117395Skan{
277117395Skan
278169689Skan	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
279117395Skan	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
280117395Skan}
281117395Skan
282117395Skanstatic dev_t
283132718Skanallocdev(void)
284169689Skan{
285132718Skan	static int stashed;
286132718Skan	struct cdev *si;
287132718Skan
288132718Skan	if (LIST_FIRST(&dev_free)) {
289132718Skan		si = LIST_FIRST(&dev_free);
290132718Skan		LIST_REMOVE(si, si_hash);
291169689Skan	} else if (stashed >= DEVT_STASH) {
292132718Skan		MALLOC(si, struct cdev *, sizeof(*si), M_DEVT,
293132718Skan		    M_USE_RESERVE | M_ZERO | M_WAITOK);
294132718Skan	} else {
295132718Skan		si = devt_stash + stashed++;
296132718Skan		bzero(si, sizeof *si);
297132718Skan		si->si_flags |= SI_STASHED;
298132718Skan	}
299132718Skan	si->__si_namebuf[0] = '\0';
300132718Skan	si->si_name = si->__si_namebuf;
301132718Skan	LIST_INIT(&si->si_children);
302132718Skan	TAILQ_INIT(&si->si_snapshots);
303132718Skan	return (si);
304132718Skan}
305169689Skan
306132718Skanstatic dev_t
307132718Skanmakedev(int x, int y)
308169689Skan{
309169689Skan	struct cdev *si;
310169689Skan	udev_t	udev;
311132718Skan	int hash;
312132718Skan
313169689Skan	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
314132718Skan		panic("makedev of NOUDEV");
315132718Skan	udev = (x << 8) | y;
316132718Skan	hash = udev % DEVT_HASH;
317169689Skan	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
318169689Skan		if (si->si_udev == udev)
319169689Skan			return (si);
320169689Skan	}
321169689Skan	si = allocdev();
322169689Skan	si->si_udev = udev;
323169689Skan	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
324169689Skan	return (si);
325169689Skan}
326169689Skan
327169689Skanstatic void
328169689Skanfreedev(dev_t dev)
329169689Skan{
330169689Skan
331169689Skan	if (dev->si_flags & SI_STASHED) {
332169689Skan		bzero(dev, sizeof(*dev));
333169689Skan		dev->si_flags |= SI_STASHED;
334169689Skan		LIST_INSERT_HEAD(&dev_free, dev, si_hash);
335169689Skan	} else {
336169689Skan		FREE(dev, M_DEVT);
337169689Skan	}
338169689Skan}
339169689Skan
340169689Skanudev_t
341169689Skandev2udev(dev_t x)
342169689Skan{
343169689Skan	if (x == NODEV)
344169689Skan		return (NOUDEV);
345169689Skan	return (x->si_udev);
346169689Skan}
347169689Skan
348169689Skandev_t
349169689Skanudev2dev(udev_t udev)
350169689Skan{
351169689Skan	struct cdev *si;
352169689Skan	int hash;
353169689Skan
354169689Skan	if (udev == NOUDEV)
355169689Skan		return (NODEV);
356169689Skan	hash = udev % DEVT_HASH;
357169689Skan	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
358169689Skan		if (si->si_udev == udev)
359169689Skan			return (si);
360169689Skan	}
361169689Skan	return (NODEV);
362169689Skan}
363169689Skan
364169689Skanint
365169689Skanuminor(udev_t dev)
366169689Skan{
367169689Skan	return (dev & 0xffff00ff);
368169689Skan}
36990075Sobrien
37090075Sobrienint
371169689Skanumajor(udev_t dev)
372169689Skan{
373169689Skan	return ((dev & 0xff00) >> 8);
374169689Skan}
375169689Skan
376169689Skanudev_t
377169689Skanmakeudev(int x, int y)
378220150Smm{
379220150Smm	return ((x << 8) | y);
380220150Smm}
381220150Smm
382169689Skanstatic void
383169689Skanfind_major(struct cdevsw *devsw)
384169689Skan{
385169689Skan	int i;
386169689Skan
387169689Skan	for (i = NUMCDEVSW - 1; i > 0; i--)
388169689Skan		if (reserved_majors[i] != i)
389169689Skan			break;
390169689Skan	KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
391169689Skan	devsw->d_maj = i;
392169689Skan	reserved_majors[i] = i;
393169689Skan	devsw->d_flags |= D_ALLOCMAJ;
394169689Skan}
395169689Skan
396169689Skanstatic void
39790075Sobrienfini_cdevsw(struct cdevsw *devsw)
398132718Skan{
39990075Sobrien	if (devsw->d_flags & D_ALLOCMAJ) {
40090075Sobrien		reserved_majors[devsw->d_maj] = 0;
401132718Skan		devsw->d_maj = MAJOR_AUTO;
40290075Sobrien		devsw->d_flags &= ~D_ALLOCMAJ;
403117395Skan	} else if (devsw->d_maj == 0)
404117395Skan		devsw->d_maj = 256;
40590075Sobrien	devsw->d_flags &= ~D_INIT;
40690075Sobrien}
40790075Sobrien
40890075Sobrienstatic void
40990075Sobrienprep_cdevsw(struct cdevsw *devsw)
410132718Skan{
41190075Sobrien
41290075Sobrien	devlock();
413132718Skan
41490075Sobrien	if (devsw->d_version != D_VERSION_00) {
41590075Sobrien		printf(
416132718Skan		    "WARNING: Device driver \"%s\" has wrong version %s\n",
41790075Sobrien		    devsw->d_name, "and is disabled.  Recompile KLD module.");
41890075Sobrien		devsw->d_open = dead_open;
41990075Sobrien		devsw->d_close = dead_close;
420132718Skan		devsw->d_read = dead_read;
42190075Sobrien		devsw->d_write = dead_write;
42296263Sobrien		devsw->d_ioctl = dead_ioctl;
42396263Sobrien		devsw->d_poll = dead_poll;
424132718Skan		devsw->d_mmap = dead_mmap;
42596263Sobrien		devsw->d_strategy = dead_strategy;
426169689Skan		devsw->d_dump = dead_dump;
427169689Skan		devsw->d_kqfilter = dead_kqfilter;
428169689Skan	}
429169689Skan
430169689Skan	if (devsw->d_flags & D_TTY) {
431169689Skan		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
432169689Skan		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
433169689Skan		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
434169689Skan		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
435169689Skan		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
43690075Sobrien	}
437132718Skan
43890075Sobrien	if (devsw->d_open == NULL)	devsw->d_open = null_open;
43990075Sobrien	if (devsw->d_close == NULL)	devsw->d_close = null_close;
440132718Skan	if (devsw->d_read == NULL)	devsw->d_read = no_read;
441132718Skan	if (devsw->d_write == NULL)	devsw->d_write = no_write;
44290075Sobrien	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
443169689Skan	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
444169689Skan	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
445169689Skan	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
446169689Skan	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
447169689Skan	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
448169689Skan
449169689Skan	LIST_INIT(&devsw->d_devs);
450169689Skan
451169689Skan	devsw->d_flags |= D_INIT;
452146895Skan
453146895Skan	if (devsw->d_maj == MAJOR_AUTO) {
454146895Skan		find_major(devsw);
455146895Skan	} else {
456146895Skan		if (devsw->d_maj == 256)	/* XXX: tty_cons.c is magic */
457132718Skan			devsw->d_maj = 0;
458132718Skan		KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256,
459132718Skan		    ("Invalid major (%d) in make_dev", devsw->d_maj));
46090075Sobrien		if (reserved_majors[devsw->d_maj] != devsw->d_maj) {
46190075Sobrien			printf("WARNING: driver \"%s\" used %s %d\n",
46290075Sobrien			    devsw->d_name, "unreserved major device number",
463132718Skan			    devsw->d_maj);
46490075Sobrien			reserved_majors[devsw->d_maj] = devsw->d_maj;
465117395Skan		}
466117395Skan	}
467132718Skan	devunlock();
468117395Skan}
469132718Skan
470132718Skandev_t
471132718Skanmake_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
472132718Skan{
473132718Skan	dev_t dev;
474132718Skan	va_list ap;
475132718Skan	int i;
476132718Skan
477132718Skan	KASSERT((minornr & ~0xffff00ff) == 0,
478132718Skan	    ("Invalid minor (0x%x) in make_dev", minornr));
479117395Skan
480132718Skan	if (!(devsw->d_flags & D_INIT))
481117395Skan		prep_cdevsw(devsw);
482132718Skan	dev = makedev(devsw->d_maj, minornr);
483132718Skan	if (dev->si_flags & SI_CHEAPCLONE &&
484132718Skan	    dev->si_flags & SI_NAMED &&
485169689Skan	    dev->si_devsw == devsw) {
486169689Skan		/*
487169689Skan		 * This is allowed as it removes races and generally
488132718Skan		 * simplifies cloning devices.
489132718Skan		 * XXX: still ??
490132718Skan		 */
491169689Skan		return (dev);
492169689Skan	}
493169689Skan	devlock();
494169689Skan	KASSERT(!(dev->si_flags & SI_NAMED),
495169689Skan	    ("make_dev() by driver %s on pre-existing device (maj=%d, min=%d, name=%s)",
496169689Skan	    devsw->d_name, major(dev), minor(dev), devtoname(dev)));
497169689Skan
498169689Skan	va_start(ap, fmt);
499169689Skan	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
500169689Skan	if (i > (sizeof dev->__si_namebuf - 1)) {
501132718Skan		printf("WARNING: Device name truncated! (%s)",
502132718Skan		    dev->__si_namebuf);
503132718Skan	}
504132718Skan	va_end(ap);
505132718Skan	dev->si_devsw = devsw;
506117395Skan	dev->si_uid = uid;
507132718Skan	dev->si_gid = gid;
508117395Skan	dev->si_mode = perms;
509117395Skan	dev->si_flags |= SI_NAMED;
510117395Skan
511132718Skan	LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list);
512117395Skan	devfs_create(dev);
513117395Skan	devunlock();
514117395Skan	return (dev);
515132718Skan}
516117395Skan
517117395Skanint
518132718Skandev_named(dev_t pdev, const char *name)
519117395Skan{
520169689Skan	dev_t cdev;
521169689Skan
522169689Skan	if (strcmp(devtoname(pdev), name) == 0)
523169689Skan		return (1);
524169689Skan	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
525169689Skan		if (strcmp(devtoname(cdev), name) == 0)
526169689Skan			return (1);
527169689Skan	return (0);
528169689Skan}
529169689Skan
530169689Skanvoid
531169689Skandev_depends(dev_t pdev, dev_t cdev)
532169689Skan{
533169689Skan
534169689Skan	devlock();
535169689Skan	cdev->si_parent = pdev;
536169689Skan	cdev->si_flags |= SI_CHILD;
537132718Skan	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
538132718Skan	devunlock();
539132718Skan}
540169689Skan
541169689Skandev_t
542169689Skanmake_dev_alias(dev_t pdev, const char *fmt, ...)
543169689Skan{
544169689Skan	dev_t	dev;
545169689Skan	va_list ap;
546169689Skan	int i;
547169689Skan
548169689Skan	dev = allocdev();
549169689Skan	devlock();
550132718Skan	dev->si_flags |= SI_ALIAS;
551132718Skan	dev->si_flags |= SI_NAMED;
552132718Skan	va_start(ap, fmt);
553132718Skan	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
554132718Skan	if (i > (sizeof dev->__si_namebuf - 1)) {
555132718Skan		printf("WARNING: Device name truncated! (%s)",
556132718Skan		    dev->__si_namebuf);
557132718Skan	}
558132718Skan	va_end(ap);
559132718Skan
560132718Skan	devfs_create(dev);
561132718Skan	devunlock();
562132718Skan	dev_depends(pdev, dev);
563132718Skan	return (dev);
564169689Skan}
565169689Skan
566169689Skanstatic void
567169689Skanidestroy_dev(dev_t dev)
568132718Skan{
569132718Skan	if (!(dev->si_flags & SI_NAMED)) {
570132718Skan		printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
571132718Skan		    major(dev), minor(dev));
572132718Skan		panic("don't do that");
573132718Skan	}
574132718Skan
575132718Skan	devfs_destroy(dev);
576132718Skan
577132718Skan	/* Remove name marking */
578132718Skan	dev->si_flags &= ~SI_NAMED;
579132718Skan
580132718Skan	/* If we are a child, remove us from the parents list */
581132718Skan	if (dev->si_flags & SI_CHILD) {
582132718Skan		LIST_REMOVE(dev, si_siblings);
583132718Skan		dev->si_flags &= ~SI_CHILD;
584132718Skan	}
585132718Skan
586132718Skan	/* Kill our children */
587132718Skan	while (!LIST_EMPTY(&dev->si_children))
588132718Skan		idestroy_dev(LIST_FIRST(&dev->si_children));
589132718Skan
590132718Skan	/* Remove from clone list */
591132718Skan	if (dev->si_flags & SI_CLONELIST) {
592132718Skan		LIST_REMOVE(dev, si_clone);
593132718Skan		dev->si_flags &= ~SI_CLONELIST;
594132718Skan	}
595132718Skan
596132718Skan	if (!(dev->si_flags & SI_ALIAS)) {
597132718Skan		/* Remove from cdevsw list */
598132718Skan		LIST_REMOVE(dev, si_list);
599132718Skan
600169689Skan		/* If cdevsw has no dev_t's, clean it */
601169689Skan		if (LIST_EMPTY(&dev->si_devsw->d_devs))
602169689Skan			fini_cdevsw(dev->si_devsw);
603169689Skan
604132718Skan		LIST_REMOVE(dev, si_hash);
605132718Skan	}
606132718Skan	dev->si_drv1 = 0;
607132718Skan	dev->si_drv2 = 0;
608132718Skan	dev->si_devsw = NULL;
609132718Skan	bzero(&dev->__si_u, sizeof(dev->__si_u));
610132718Skan	dev->si_flags &= ~SI_ALIAS;
611132718Skan	if (dev->si_refcount > 0) {
612132718Skan		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
613169689Skan	} else {
614169689Skan		freedev(dev);
615169689Skan	}
616169689Skan}
617169689Skan
618169689Skanvoid
619169689Skandestroy_dev(dev_t dev)
620169689Skan{
621169689Skan
622169689Skan	devlock();
623169689Skan	idestroy_dev(dev);
624169689Skan	devunlock();
625169689Skan}
626169689Skan
627169689Skanconst char *
628169689Skandevtoname(dev_t dev)
629169689Skan{
630169689Skan	char *p;
631169689Skan	int mynor;
632169689Skan
633169689Skan	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
634169689Skan		p = dev->si_name;
635169689Skan		if (devsw(dev))
636169689Skan			sprintf(p, "#%s/", devsw(dev)->d_name);
637169689Skan		else
638169689Skan			sprintf(p, "#%d/", major(dev));
639169689Skan		p += strlen(p);
640169689Skan		mynor = minor(dev);
641169689Skan		if (mynor < 0 || mynor > 255)
642169689Skan			sprintf(p, "%#x", (u_int)mynor);
643169689Skan		else
644169689Skan			sprintf(p, "%d", mynor);
645169689Skan	}
646169689Skan	return (dev->si_name);
647169689Skan}
648169689Skan
649169689Skanint
650169689Skandev_stdclone(char *name, char **namep, const char *stem, int *unit)
651169689Skan{
652169689Skan	int u, i;
653169689Skan
654169689Skan	i = strlen(stem);
655169689Skan	if (bcmp(stem, name, i) != 0)
656169689Skan		return (0);
657169689Skan	if (!isdigit(name[i]))
658169689Skan		return (0);
659169689Skan	u = 0;
660169689Skan	if (name[i] == '0' && isdigit(name[i+1]))
661169689Skan		return (0);
662169689Skan	while (isdigit(name[i])) {
663169689Skan		u *= 10;
664169689Skan		u += name[i++] - '0';
665169689Skan	}
666169689Skan	if (u > 0xffffff)
667169689Skan		return (0);
668169689Skan	*unit = u;
669169689Skan	if (namep)
670169689Skan		*namep = &name[i];
671132718Skan	if (name[i])
672132718Skan		return (2);
673132718Skan	return (1);
674132718Skan}
675132718Skan
676132718Skan/*
677132718Skan * Helper functions for cloning device drivers.
678132718Skan *
679169689Skan * The objective here is to make it unnecessary for the device drivers to
680169689Skan * use rman or similar to manage their unit number space.  Due to the way
681169689Skan * we do "on-demand" devices, using rman or other "private" methods
682169689Skan * will be very tricky to lock down properly once we lock down this file.
683169689Skan *
684169689Skan * Instead we give the drivers these routines which puts the dev_t's that
685169689Skan * are to be managed on their own list, and gives the driver the ability
686132718Skan * to ask for the first free unit number or a given specified unit number.
687132718Skan *
688132718Skan * In addition these routines support paired devices (pty, nmdm and similar)
689132718Skan * by respecting a number of "flag" bits in the minor number.
690132718Skan *
691132718Skan */
692169689Skan
693169689Skanstruct clonedevs {
694132718Skan	LIST_HEAD(,cdev)	head;
695132718Skan};
696132718Skan
697132718Skanvoid
698132718Skanclone_setup(struct clonedevs **cdp)
699132718Skan{
700169689Skan
701169689Skan	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
702169689Skan	LIST_INIT(&(*cdp)->head);
703169689Skan}
704169689Skan
705169689Skanint
706169689Skanclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, dev_t *dp, u_int extra)
707169689Skan{
708169689Skan	struct clonedevs *cd;
709169689Skan	dev_t dev, dl, de;
710169689Skan	int unit, low, u;
711169689Skan
712169689Skan	KASSERT(*cdp != NULL,
713169689Skan	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
714169689Skan	KASSERT(!(extra & CLONE_UNITMASK),
715169689Skan	    ("Illegal extra bits (0x%x) in clone_create", extra));
716169689Skan	KASSERT(*up <= CLONE_UNITMASK,
717169689Skan	    ("Too high unit (0x%x) in clone_create", *up));
718169689Skan
719169689Skan	if (csw->d_maj == MAJOR_AUTO)
720169689Skan		find_major(csw);
721169689Skan
722169689Skan	/*
723169689Skan	 * Search the list for a lot of things in one go:
724169689Skan	 *   A preexisting match is returned immediately.
725169689Skan	 *   The lowest free unit number if we are passed -1, and the place
726169689Skan	 *	 in the list where we should insert that new element.
727169689Skan	 *   The place to insert a specified unit number, if applicable
728169689Skan	 *       the end of the list.
729169689Skan	 */
730169689Skan	unit = *up;
731169689Skan	low = extra;
732132718Skan	de = dl = NULL;
733132718Skan	cd = *cdp;
734169689Skan	LIST_FOREACH(dev, &cd->head, si_clone) {
735169689Skan		u = dev2unit(dev);
736169689Skan		if (u == (unit | extra)) {
737169689Skan			*dp = dev;
738169689Skan			return (0);
739169689Skan		}
740169689Skan		if (unit == -1 && u == low) {
741169689Skan			low++;
742169689Skan			de = dev;
743169689Skan			continue;
744169689Skan		}
745169689Skan		if (u > (unit | extra)) {
746169689Skan			dl = dev;
747169689Skan			break;
748169689Skan		}
749169689Skan		de = dev;
750169689Skan	}
751169689Skan	if (unit == -1)
752169689Skan		unit = low & CLONE_UNITMASK;
753169689Skan	dev = makedev(csw->d_maj, unit2minor(unit | extra));
754169689Skan	KASSERT(!(dev->si_flags & SI_CLONELIST),
755169689Skan	    ("Dev %p should not be on clonelist", dev));
756169689Skan	if (dl != NULL)
757169689Skan		LIST_INSERT_BEFORE(dl, dev, si_clone);
758169689Skan	else if (de != NULL)
759169689Skan		LIST_INSERT_AFTER(de, dev, si_clone);
760169689Skan	else
761169689Skan		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
762169689Skan	dev->si_flags |= SI_CLONELIST;
763169689Skan	*up = unit;
764169689Skan	return (1);
765169689Skan}
766169689Skan
767169689Skan/*
768169689Skan * Kill everything still on the list.  The driver should already have
769169689Skan * disposed of any softc hung of the dev_t's at this time.
770169689Skan */
771169689Skanvoid
772169689Skanclone_cleanup(struct clonedevs **cdp)
773169689Skan{
774169689Skan	dev_t dev, tdev;
775169689Skan	struct clonedevs *cd;
776169689Skan
777169689Skan	cd = *cdp;
778169689Skan	if (cd == NULL)
779169689Skan		return;
780169689Skan	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
781169689Skan		KASSERT(dev->si_flags & SI_NAMED,
782169689Skan		    ("Driver has goofed in cloning underways udev %x", dev->si_udev));
783169689Skan		destroy_dev(dev);
784169689Skan	}
785169689Skan	free(cd, M_DEVBUF);
786259947Spfg	*cdp = NULL;
787259947Spfg}
788259947Spfg
789259947Spfg/*
790169689Skan * Helper sysctl for devname(3).  We're given a {u}dev_t and return
791169689Skan * the name, if any, registered by the device driver.
792169689Skan */
793169689Skanstatic int
794169689Skansysctl_devname(SYSCTL_HANDLER_ARGS)
795169689Skan{
796169689Skan	int error;
797169689Skan	udev_t ud;
798169689Skan	dev_t dev;
799169689Skan
800169689Skan	error = SYSCTL_IN(req, &ud, sizeof (ud));
801169689Skan	if (error)
802169689Skan		return (error);
803169689Skan	if (ud == NOUDEV)
804169689Skan		return(EINVAL);
805169689Skan	dev = udev2dev(ud);
806169689Skan	if (dev == NODEV)
807169689Skan		error = ENOENT;
808117395Skan	else
809117395Skan		error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
81090075Sobrien	return (error);
81190075Sobrien}
81290075Sobrien
813169689SkanSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
814169689Skan	NULL, 0, sysctl_devname, "", "devname(3) handler");
815169689Skan