kern_conf.c revision 142702
1167802Sjkim/*-
2167802Sjkim * Copyright (c) 1999-2002 Poul-Henning Kamp
3167802Sjkim * All rights reserved.
4167802Sjkim *
5167802Sjkim * Redistribution and use in source and binary forms, with or without
6167802Sjkim * modification, are permitted provided that the following conditions
7217365Sjkim * are met:
8217365Sjkim * 1. Redistributions of source code must retain the above copyright
9167802Sjkim *    notice, this list of conditions and the following disclaimer.
10167802Sjkim * 2. Redistributions in binary form must reproduce the above copyright
11217365Sjkim *    notice, this list of conditions and the following disclaimer in the
12217365Sjkim *    documentation and/or other materials provided with the distribution.
13217365Sjkim *
14217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24217365Sjkim * SUCH DAMAGE.
25167802Sjkim */
26217365Sjkim
27217365Sjkim#include <sys/cdefs.h>
28217365Sjkim__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 142702 2005-02-27 21:52:42Z phk $");
29167802Sjkim
30217365Sjkim#include <sys/param.h>
31217365Sjkim#include <sys/kernel.h>
32217365Sjkim#include <sys/systm.h>
33217365Sjkim#include <sys/bio.h>
34217365Sjkim#include <sys/lock.h>
35217365Sjkim#include <sys/mutex.h>
36217365Sjkim#include <sys/sysctl.h>
37217365Sjkim#include <sys/module.h>
38217365Sjkim#include <sys/malloc.h>
39217365Sjkim#include <sys/conf.h>
40217365Sjkim#include <sys/vnode.h>
41217365Sjkim#include <sys/queue.h>
42217365Sjkim#include <sys/poll.h>
43167802Sjkim#include <sys/ctype.h>
44167802Sjkim#include <sys/tty.h>
45193529Sjkim#include <machine/stdarg.h>
46193529Sjkim
47193529Sjkimstatic MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
48193529Sjkim
49193529Sjkim/* Built at compile time from sys/conf/majors */
50193529Sjkimextern unsigned char reserved_majors[256];
51193529Sjkim
52193529Sjkim/*
53167802Sjkim * This is the number of hash-buckets.  Experiments with 'real-life'
54167802Sjkim * dev_t's show that a prime halfway between two powers of two works
55167802Sjkim * best.
56167802Sjkim */
57167802Sjkim#define DEVT_HASH 83
58167802Sjkim
59167802Sjkimstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
60167802Sjkim
61167802Sjkimstatic struct mtx devmtx;
62167802Sjkimstatic void freedev(struct cdev *dev);
63167802Sjkimstatic struct cdev *newdev(int x, int y, struct cdev *);
64167802Sjkimstatic void destroy_devl(struct cdev *dev);
65167802Sjkim
66167802Sjkimvoid
67167802Sjkimdev_lock(void)
68167802Sjkim{
69167802Sjkim	if (!mtx_initialized(&devmtx))
70167802Sjkim		mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
71167802Sjkim	mtx_lock(&devmtx);
72167802Sjkim}
73167802Sjkim
74167802Sjkimvoid
75167802Sjkimdev_unlock(void)
76167802Sjkim{
77167802Sjkim
78167802Sjkim	mtx_unlock(&devmtx);
79167802Sjkim}
80167802Sjkim
81167802Sjkimvoid
82167802Sjkimdev_ref(struct cdev *dev)
83167802Sjkim{
84167802Sjkim
85167802Sjkim	mtx_assert(&devmtx, MA_OWNED);
86167802Sjkim	dev->si_refcount++;
87167802Sjkim}
88167802Sjkim
89167802Sjkimvoid
90167802Sjkimdev_rel(struct cdev *dev)
91167802Sjkim{
92167802Sjkim	int flag = 0;
93167802Sjkim
94167802Sjkim	mtx_assert(&devmtx, MA_NOTOWNED);
95167802Sjkim	dev_lock();
96167802Sjkim	dev->si_refcount--;
97167802Sjkim	KASSERT(dev->si_refcount >= 0,
98167802Sjkim	    ("dev_rel(%s) gave negative count", devtoname(dev)));
99167802Sjkim	if (dev->si_usecount == 0 &&
100167802Sjkim	    (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
101167802Sjkim	if (dev->si_devsw == NULL && dev->si_refcount == 0) {
102167802Sjkim		LIST_REMOVE(dev, si_list);
103167802Sjkim		flag = 1;
104167802Sjkim	}
105167802Sjkim	dev_unlock();
106167802Sjkim	if (flag)
107167802Sjkim		freedev(dev);
108167802Sjkim}
109167802Sjkim
110167802Sjkimstruct cdevsw *
111167802Sjkimdev_refthread(struct cdev *dev)
112167802Sjkim{
113167802Sjkim	struct cdevsw *csw;
114198237Sjkim
115167802Sjkim	mtx_assert(&devmtx, MA_NOTOWNED);
116167802Sjkim	dev_lock();
117167802Sjkim	csw = dev->si_devsw;
118167802Sjkim	if (csw != NULL)
119167802Sjkim		dev->si_threadcount++;
120167802Sjkim	dev_unlock();
121167802Sjkim	return (csw);
122167802Sjkim}
123167802Sjkim
124167802Sjkimvoid
125167802Sjkimdev_relthread(struct cdev *dev)
126167802Sjkim{
127167802Sjkim
128167802Sjkim	mtx_assert(&devmtx, MA_NOTOWNED);
129167802Sjkim	dev_lock();
130167802Sjkim	dev->si_threadcount--;
131167802Sjkim	dev_unlock();
132167802Sjkim}
133167802Sjkim
134167802Sjkimint
135167802Sjkimnullop(void)
136167802Sjkim{
137167802Sjkim
138167802Sjkim	return (0);
139167802Sjkim}
140167802Sjkim
141167802Sjkimint
142167802Sjkimeopnotsupp(void)
143167802Sjkim{
144167802Sjkim
145167802Sjkim	return (EOPNOTSUPP);
146167802Sjkim}
147167802Sjkim
148198237Sjkimstatic int
149167802Sjkimenxio(void)
150167802Sjkim{
151167802Sjkim	return (ENXIO);
152167802Sjkim}
153167802Sjkim
154167802Sjkimstatic int
155167802Sjkimenodev(void)
156167802Sjkim{
157167802Sjkim	return (ENODEV);
158167802Sjkim}
159167802Sjkim
160167802Sjkim/* Define a dead_cdevsw for use when devices leave unexpectedly. */
161167802Sjkim
162167802Sjkim#define dead_open	(d_open_t *)enxio
163167802Sjkim#define dead_close	(d_close_t *)enxio
164167802Sjkim#define dead_read	(d_read_t *)enxio
165167802Sjkim#define dead_write	(d_write_t *)enxio
166167802Sjkim#define dead_ioctl	(d_ioctl_t *)enxio
167167802Sjkim#define dead_poll	(d_poll_t *)enodev
168167802Sjkim#define dead_mmap	(d_mmap_t *)enodev
169167802Sjkim
170167802Sjkimstatic void
171167802Sjkimdead_strategy(struct bio *bp)
172167802Sjkim{
173167802Sjkim
174167802Sjkim	biofinish(bp, NULL, ENXIO);
175167802Sjkim}
176167802Sjkim
177167802Sjkim#define dead_dump	(dumper_t *)enxio
178167802Sjkim#define dead_kqfilter	(d_kqfilter_t *)enxio
179167802Sjkim
180167802Sjkimstatic struct cdevsw dead_cdevsw = {
181167802Sjkim	.d_version =	D_VERSION,
182193529Sjkim	.d_flags =	D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
183167802Sjkim	.d_open =	dead_open,
184167802Sjkim	.d_close =	dead_close,
185167802Sjkim	.d_read =	dead_read,
186167802Sjkim	.d_write =	dead_write,
187167802Sjkim	.d_ioctl =	dead_ioctl,
188167802Sjkim	.d_poll =	dead_poll,
189167802Sjkim	.d_mmap =	dead_mmap,
190167802Sjkim	.d_strategy =	dead_strategy,
191167802Sjkim	.d_name =	"dead",
192167802Sjkim	.d_maj =	255,
193167802Sjkim	.d_dump =	dead_dump,
194193529Sjkim	.d_kqfilter =	dead_kqfilter
195193529Sjkim};
196167802Sjkim
197167802Sjkim/* Default methods if driver does not specify method */
198167802Sjkim
199167802Sjkim#define null_open	(d_open_t *)nullop
200167802Sjkim#define null_close	(d_close_t *)nullop
201167802Sjkim#define no_read		(d_read_t *)enodev
202167802Sjkim#define no_write	(d_write_t *)enodev
203167802Sjkim#define no_ioctl	(d_ioctl_t *)enodev
204167802Sjkim#define no_mmap		(d_mmap_t *)enodev
205167802Sjkim#define no_kqfilter	(d_kqfilter_t *)enodev
206167802Sjkim
207167802Sjkimstatic void
208167802Sjkimno_strategy(struct bio *bp)
209193529Sjkim{
210167802Sjkim
211167802Sjkim	biofinish(bp, NULL, ENODEV);
212167802Sjkim}
213167802Sjkim
214167802Sjkimstatic int
215167802Sjkimno_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
216167802Sjkim{
217167802Sjkim	/*
218167802Sjkim	 * Return true for read/write.  If the user asked for something
219167802Sjkim	 * special, return POLLNVAL, so that clients have a way of
220167802Sjkim	 * determining reliably whether or not the extended
221167802Sjkim	 * functionality is present without hard-coding knowledge
222167802Sjkim	 * of specific filesystem implementations.
223167802Sjkim	 * Stay in sync with vop_nopoll().
224167802Sjkim	 */
225167802Sjkim	if (events & ~POLLSTANDARD)
226167802Sjkim		return (POLLNVAL);
227167802Sjkim
228167802Sjkim	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
229167802Sjkim}
230167802Sjkim
231167802Sjkim#define no_dump		(dumper_t *)enodev
232167802Sjkim
233167802Sjkim/*
234167802Sjkim * struct cdev * and u_dev_t primitives
235167802Sjkim */
236193529Sjkim
237167802Sjkimint
238167802Sjkimmajor(struct cdev *x)
239167802Sjkim{
240167802Sjkim	if (x == NULL)
241167802Sjkim		return NODEV;
242167802Sjkim	return((x->si_udev >> 8) & 0xff);
243167802Sjkim}
244167802Sjkim
245167802Sjkimint
246167802Sjkimminor(struct cdev *x)
247193529Sjkim{
248193529Sjkim	if (x == NULL)
249167802Sjkim		return NODEV;
250167802Sjkim	return(x->si_udev & MAXMINOR);
251167802Sjkim}
252167802Sjkim
253167802Sjkimint
254167802Sjkimdev2unit(struct cdev *x)
255167802Sjkim{
256167802Sjkim
257167802Sjkim	if (x == NULL)
258167802Sjkim		return NODEV;
259167802Sjkim	return (minor2unit(minor(x)));
260167802Sjkim}
261167802Sjkim
262193529Sjkimint
263167802Sjkimminor2unit(int _minor)
264167802Sjkim{
265167802Sjkim
266167802Sjkim	KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
267167802Sjkim	return ((_minor & 0xff) | (_minor >> 8));
268167802Sjkim}
269167802Sjkim
270167802Sjkimint
271167802Sjkimunit2minor(int unit)
272167802Sjkim{
273167802Sjkim
274167802Sjkim	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
275167802Sjkim	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
276167802Sjkim}
277167802Sjkim
278167802Sjkimstatic struct cdev *
279167802Sjkimallocdev(void)
280167802Sjkim{
281167802Sjkim	struct cdev *si;
282167802Sjkim
283167802Sjkim	si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK);
284167802Sjkim	si->si_name = si->__si_namebuf;
285167802Sjkim	LIST_INIT(&si->si_children);
286167802Sjkim	LIST_INIT(&si->si_alist);
287167802Sjkim	return (si);
288167802Sjkim}
289167802Sjkim
290167802Sjkimstatic struct cdev *
291167802Sjkimnewdev(int x, int y, struct cdev *si)
292167802Sjkim{
293167802Sjkim	struct cdev *si2;
294167802Sjkim	dev_t	udev;
295167802Sjkim	int hash;
296167802Sjkim
297167802Sjkim	mtx_assert(&devmtx, MA_OWNED);
298167802Sjkim	if (x == umajor(NODEV) && y == uminor(NODEV))
299167802Sjkim		panic("newdev of NODEV");
300167802Sjkim	udev = (x << 8) | y;
301167802Sjkim	hash = udev % DEVT_HASH;
302167802Sjkim	LIST_FOREACH(si2, &dev_hash[hash], si_hash) {
303167802Sjkim		if (si2->si_udev == udev) {
304167802Sjkim			freedev(si);
305167802Sjkim			return (si2);
306167802Sjkim		}
307167802Sjkim	}
308167802Sjkim	si->si_udev = udev;
309167802Sjkim	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
310167802Sjkim	return (si);
311167802Sjkim}
312167802Sjkim
313167802Sjkimstatic void
314167802Sjkimfreedev(struct cdev *dev)
315167802Sjkim{
316167802Sjkim
317167802Sjkim	free(dev, M_DEVT);
318167802Sjkim}
319167802Sjkim
320167802Sjkimdev_t
321167802Sjkimdev2udev(struct cdev *x)
322167802Sjkim{
323167802Sjkim	if (x == NULL)
324167802Sjkim		return (NODEV);
325167802Sjkim	return (x->si_udev);
326167802Sjkim}
327167802Sjkim
328167802Sjkimstruct cdev *
329167802Sjkimfindcdev(dev_t udev)
330167802Sjkim{
331167802Sjkim	struct cdev *si;
332167802Sjkim	int hash;
333167802Sjkim
334167802Sjkim	mtx_assert(&devmtx, MA_NOTOWNED);
335167802Sjkim	if (udev == NODEV)
336167802Sjkim		return (NULL);
337167802Sjkim	dev_lock();
338167802Sjkim	hash = udev % DEVT_HASH;
339167802Sjkim	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
340167802Sjkim		if (si->si_udev == udev)
341167802Sjkim			break;
342167802Sjkim	}
343167802Sjkim	dev_unlock();
344167802Sjkim	return (si);
345167802Sjkim}
346167802Sjkim
347167802Sjkimint
348167802Sjkimuminor(dev_t dev)
349167802Sjkim{
350167802Sjkim	return (dev & MAXMINOR);
351167802Sjkim}
352167802Sjkim
353167802Sjkimint
354167802Sjkimumajor(dev_t dev)
355167802Sjkim{
356167802Sjkim	return ((dev & ~MAXMINOR) >> 8);
357167802Sjkim}
358167802Sjkim
359167802Sjkimstatic void
360167802Sjkimfind_major(struct cdevsw *devsw)
361167802Sjkim{
362167802Sjkim	int i;
363167802Sjkim
364167802Sjkim	for (i = NUMCDEVSW - 1; i > 0; i--)
365167802Sjkim		if (reserved_majors[i] != i)
366198237Sjkim			break;
367167802Sjkim	KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
368167802Sjkim	devsw->d_maj = i;
369167802Sjkim	reserved_majors[i] = i;
370167802Sjkim	devsw->d_flags |= D_ALLOCMAJ;
371167802Sjkim}
372167802Sjkim
373167802Sjkimstatic void
374167802Sjkimfini_cdevsw(struct cdevsw *devsw)
375167802Sjkim{
376167802Sjkim	if (devsw->d_flags & D_ALLOCMAJ) {
377167802Sjkim		reserved_majors[devsw->d_maj] = 0;
378167802Sjkim		devsw->d_maj = MAJOR_AUTO;
379167802Sjkim		devsw->d_flags &= ~D_ALLOCMAJ;
380167802Sjkim	}
381167802Sjkim	devsw->d_flags &= ~D_INIT;
382167802Sjkim}
383167802Sjkim
384167802Sjkimstatic void
385167802Sjkimprep_cdevsw(struct cdevsw *devsw)
386167802Sjkim{
387167802Sjkim
388167802Sjkim	dev_lock();
389167802Sjkim
390167802Sjkim	if (devsw->d_version != D_VERSION_00) {
391167802Sjkim		printf(
392167802Sjkim		    "WARNING: Device driver \"%s\" has wrong version %s\n",
393167802Sjkim		    devsw->d_name, "and is disabled.  Recompile KLD module.");
394167802Sjkim		devsw->d_open = dead_open;
395167802Sjkim		devsw->d_close = dead_close;
396167802Sjkim		devsw->d_read = dead_read;
397167802Sjkim		devsw->d_write = dead_write;
398167802Sjkim		devsw->d_ioctl = dead_ioctl;
399198237Sjkim		devsw->d_poll = dead_poll;
400167802Sjkim		devsw->d_mmap = dead_mmap;
401193529Sjkim		devsw->d_strategy = dead_strategy;
402193529Sjkim		devsw->d_dump = dead_dump;
403193529Sjkim		devsw->d_kqfilter = dead_kqfilter;
404167802Sjkim	}
405167802Sjkim
406167802Sjkim	if (devsw->d_flags & D_TTY) {
407167802Sjkim		if (devsw->d_ioctl == NULL)	devsw->d_ioctl = ttyioctl;
408167802Sjkim		if (devsw->d_read == NULL)	devsw->d_read = ttyread;
409167802Sjkim		if (devsw->d_write == NULL)	devsw->d_write = ttywrite;
410167802Sjkim		if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = ttykqfilter;
411167802Sjkim		if (devsw->d_poll == NULL)	devsw->d_poll = ttypoll;
412167802Sjkim	}
413167802Sjkim
414167802Sjkim	if (devsw->d_open == NULL)	devsw->d_open = null_open;
415167802Sjkim	if (devsw->d_close == NULL)	devsw->d_close = null_close;
416167802Sjkim	if (devsw->d_read == NULL)	devsw->d_read = no_read;
417167802Sjkim	if (devsw->d_write == NULL)	devsw->d_write = no_write;
418167802Sjkim	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = no_ioctl;
419167802Sjkim	if (devsw->d_poll == NULL)	devsw->d_poll = no_poll;
420167802Sjkim	if (devsw->d_mmap == NULL)	devsw->d_mmap = no_mmap;
421167802Sjkim	if (devsw->d_strategy == NULL)	devsw->d_strategy = no_strategy;
422167802Sjkim	if (devsw->d_dump == NULL)	devsw->d_dump = no_dump;
423167802Sjkim	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = no_kqfilter;
424167802Sjkim
425167802Sjkim	LIST_INIT(&devsw->d_devs);
426167802Sjkim
427167802Sjkim	devsw->d_flags |= D_INIT;
428167802Sjkim
429167802Sjkim	if (devsw->d_maj == MAJOR_AUTO) {
430167802Sjkim		find_major(devsw);
431167802Sjkim	} else {
432167802Sjkim		KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256,
433167802Sjkim		    ("Invalid major (%d) in make_dev", devsw->d_maj));
434167802Sjkim		if (reserved_majors[devsw->d_maj] != devsw->d_maj) {
435167802Sjkim			printf("WARNING: driver \"%s\" used %s %d\n",
436167802Sjkim			    devsw->d_name, "unreserved major device number",
437167802Sjkim			    devsw->d_maj);
438167802Sjkim			reserved_majors[devsw->d_maj] = devsw->d_maj;
439167802Sjkim		}
440167802Sjkim	}
441167802Sjkim	dev_unlock();
442167802Sjkim}
443167802Sjkim
444167802Sjkimstruct cdev *
445167802Sjkimmake_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
446167802Sjkim{
447167802Sjkim	struct cdev *dev;
448167802Sjkim	va_list ap;
449167802Sjkim	int i;
450167802Sjkim
451167802Sjkim	KASSERT((minornr & ~MAXMINOR) == 0,
452167802Sjkim	    ("Invalid minor (0x%x) in make_dev", minornr));
453167802Sjkim
454167802Sjkim	if (!(devsw->d_flags & D_INIT))
455167802Sjkim		prep_cdevsw(devsw);
456167802Sjkim	dev = allocdev();
457167802Sjkim	dev_lock();
458167802Sjkim	dev = newdev(devsw->d_maj, minornr, dev);
459167802Sjkim	if (dev->si_flags & SI_CHEAPCLONE &&
460167802Sjkim	    dev->si_flags & SI_NAMED &&
461167802Sjkim	    dev->si_devsw == devsw) {
462167802Sjkim		/*
463198237Sjkim		 * This is allowed as it removes races and generally
464167802Sjkim		 * simplifies cloning devices.
465167802Sjkim		 * XXX: still ??
466167802Sjkim		 */
467167802Sjkim		dev_unlock();
468209746Sjkim		return (dev);
469167802Sjkim	}
470167802Sjkim	KASSERT(!(dev->si_flags & SI_NAMED),
471167802Sjkim	    ("make_dev() by driver %s on pre-existing device (maj=%d, min=%d, name=%s)",
472167802Sjkim	    devsw->d_name, major(dev), minor(dev), devtoname(dev)));
473167802Sjkim
474198237Sjkim	va_start(ap, fmt);
475167802Sjkim	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
476167802Sjkim	if (i > (sizeof dev->__si_namebuf - 1)) {
477167802Sjkim		printf("WARNING: Device name truncated! (%s)\n",
478198237Sjkim		    dev->__si_namebuf);
479167802Sjkim	}
480167802Sjkim	va_end(ap);
481167802Sjkim
482167802Sjkim	dev->si_devsw = devsw;
483167802Sjkim	dev->si_uid = uid;
484167802Sjkim	dev->si_gid = gid;
485167802Sjkim	dev->si_mode = perms;
486167802Sjkim	dev->si_flags |= SI_NAMED;
487167802Sjkim
488167802Sjkim	LIST_INSERT_HEAD(&devsw->d_devs, dev, si_list);
489167802Sjkim	devfs_create(dev);
490167802Sjkim	dev_unlock();
491167802Sjkim	return (dev);
492167802Sjkim}
493167802Sjkim
494198237Sjkimint
495167802Sjkimdev_named(struct cdev *pdev, const char *name)
496167802Sjkim{
497167802Sjkim	struct cdev *cdev;
498167802Sjkim
499167802Sjkim	if (strcmp(devtoname(pdev), name) == 0)
500167802Sjkim		return (1);
501167802Sjkim	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
502167802Sjkim		if (strcmp(devtoname(cdev), name) == 0)
503198237Sjkim			return (1);
504167802Sjkim	return (0);
505167802Sjkim}
506167802Sjkim
507198237Sjkimvoid
508167802Sjkimdev_depends(struct cdev *pdev, struct cdev *cdev)
509167802Sjkim{
510167802Sjkim
511167802Sjkim	dev_lock();
512167802Sjkim	cdev->si_parent = pdev;
513167802Sjkim	cdev->si_flags |= SI_CHILD;
514167802Sjkim	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
515167802Sjkim	dev_unlock();
516167802Sjkim}
517167802Sjkim
518167802Sjkimstruct cdev *
519167802Sjkimmake_dev_alias(struct cdev *pdev, const char *fmt, ...)
520167802Sjkim{
521167802Sjkim	struct cdev *dev;
522167802Sjkim	va_list ap;
523167802Sjkim	int i;
524167802Sjkim
525167802Sjkim	dev = allocdev();
526167802Sjkim	dev_lock();
527167802Sjkim	dev->si_flags |= SI_ALIAS;
528167802Sjkim	dev->si_flags |= SI_NAMED;
529167802Sjkim	va_start(ap, fmt);
530167802Sjkim	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
531167802Sjkim	if (i > (sizeof dev->__si_namebuf - 1)) {
532167802Sjkim		printf("WARNING: Device name truncated! (%s)\n",
533167802Sjkim		    dev->__si_namebuf);
534167802Sjkim	}
535167802Sjkim	va_end(ap);
536167802Sjkim
537167802Sjkim	devfs_create(dev);
538198237Sjkim	dev_unlock();
539167802Sjkim	dev_depends(pdev, dev);
540167802Sjkim	return (dev);
541167802Sjkim}
542167802Sjkim
543167802Sjkimstatic void
544167802Sjkimdestroy_devl(struct cdev *dev)
545167802Sjkim{
546167802Sjkim	struct cdevsw *csw;
547167802Sjkim
548198237Sjkim	mtx_assert(&devmtx, MA_OWNED);
549167802Sjkim	KASSERT(dev->si_flags & SI_NAMED,
550167802Sjkim	    ("WARNING: Driver mistake: destroy_dev on %d/%d\n",
551167802Sjkim	    major(dev), minor(dev)));
552193529Sjkim
553193529Sjkim	devfs_destroy(dev);
554193529Sjkim
555167802Sjkim	/* Remove name marking */
556167802Sjkim	dev->si_flags &= ~SI_NAMED;
557167802Sjkim
558167802Sjkim	/* If we are a child, remove us from the parents list */
559167802Sjkim	if (dev->si_flags & SI_CHILD) {
560167802Sjkim		LIST_REMOVE(dev, si_siblings);
561167802Sjkim		dev->si_flags &= ~SI_CHILD;
562167802Sjkim	}
563167802Sjkim
564167802Sjkim	/* Kill our children */
565167802Sjkim	while (!LIST_EMPTY(&dev->si_children))
566167802Sjkim		destroy_devl(LIST_FIRST(&dev->si_children));
567167802Sjkim
568167802Sjkim	/* Remove from clone list */
569167802Sjkim	if (dev->si_flags & SI_CLONELIST) {
570167802Sjkim		LIST_REMOVE(dev, si_clone);
571167802Sjkim		dev->si_flags &= ~SI_CLONELIST;
572167802Sjkim	}
573167802Sjkim
574167802Sjkim	csw = dev->si_devsw;
575167802Sjkim	dev->si_devsw = NULL;	/* already NULL for SI_ALIAS */
576167802Sjkim	while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
577167802Sjkim		printf("Purging %lu threads from %s\n",
578167802Sjkim		    dev->si_threadcount, devtoname(dev));
579167802Sjkim		csw->d_purge(dev);
580167802Sjkim		msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
581167802Sjkim	}
582167802Sjkim	if (csw != NULL && csw->d_purge != NULL)
583167802Sjkim		printf("All threads purged from %s\n", devtoname(dev));
584167802Sjkim
585167802Sjkim	dev->si_drv1 = 0;
586167802Sjkim	dev->si_drv2 = 0;
587193529Sjkim	bzero(&dev->__si_u, sizeof(dev->__si_u));
588193529Sjkim
589193529Sjkim	if (!(dev->si_flags & SI_ALIAS)) {
590167802Sjkim		/* Remove from cdevsw list */
591167802Sjkim		LIST_REMOVE(dev, si_list);
592167802Sjkim
593167802Sjkim		/* If cdevsw has no struct cdev *'s, clean it */
594167802Sjkim		if (LIST_EMPTY(&csw->d_devs))
595167802Sjkim			fini_cdevsw(csw);
596167802Sjkim
597167802Sjkim		LIST_REMOVE(dev, si_hash);
598167802Sjkim	}
599167802Sjkim	dev->si_flags &= ~SI_ALIAS;
600167802Sjkim
601167802Sjkim	if (dev->si_refcount > 0) {
602167802Sjkim		LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
603167802Sjkim	} else {
604167802Sjkim		freedev(dev);
605167802Sjkim	}
606167802Sjkim}
607167802Sjkim
608167802Sjkimvoid
609167802Sjkimdestroy_dev(struct cdev *dev)
610167802Sjkim{
611167802Sjkim
612193529Sjkim	dev_lock();
613193529Sjkim	destroy_devl(dev);
614193529Sjkim	dev_unlock();
615193529Sjkim}
616193529Sjkim
617193529Sjkimconst char *
618193529Sjkimdevtoname(struct cdev *dev)
619167802Sjkim{
620167802Sjkim	char *p;
621167802Sjkim	struct cdevsw *csw;
622167802Sjkim	int mynor;
623167802Sjkim
624167802Sjkim	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
625167802Sjkim		p = dev->si_name;
626167802Sjkim		sprintf(p, "#%d", major(dev));
627167802Sjkim		p += strlen(p);
628167802Sjkim		csw = dev_refthread(dev);
629167802Sjkim		if (csw != NULL) {
630167802Sjkim			sprintf(p, "(%s)", csw->d_name);
631167802Sjkim			dev_relthread(dev);
632167802Sjkim		}
633167802Sjkim		p += strlen(p);
634167802Sjkim		mynor = minor(dev);
635167802Sjkim		if (mynor < 0 || mynor > 255)
636167802Sjkim			sprintf(p, "/%#x", (u_int)mynor);
637167802Sjkim		else
638167802Sjkim			sprintf(p, "/%d", mynor);
639167802Sjkim	}
640167802Sjkim	return (dev->si_name);
641167802Sjkim}
642167802Sjkim
643167802Sjkimint
644167802Sjkimdev_stdclone(char *name, char **namep, const char *stem, int *unit)
645167802Sjkim{
646193529Sjkim	int u, i;
647193529Sjkim
648193529Sjkim	i = strlen(stem);
649167802Sjkim	if (bcmp(stem, name, i) != 0)
650193529Sjkim		return (0);
651193529Sjkim	if (!isdigit(name[i]))
652193529Sjkim		return (0);
653193529Sjkim	u = 0;
654193529Sjkim	if (name[i] == '0' && isdigit(name[i+1]))
655193529Sjkim		return (0);
656193529Sjkim	while (isdigit(name[i])) {
657193529Sjkim		u *= 10;
658193529Sjkim		u += name[i++] - '0';
659193529Sjkim	}
660193529Sjkim	if (u > 0xffffff)
661193529Sjkim		return (0);
662193529Sjkim	*unit = u;
663193529Sjkim	if (namep)
664193529Sjkim		*namep = &name[i];
665193529Sjkim	if (name[i])
666193529Sjkim		return (2);
667193529Sjkim	return (1);
668193529Sjkim}
669193529Sjkim
670193529Sjkim/*
671193529Sjkim * Helper functions for cloning device drivers.
672193529Sjkim *
673193529Sjkim * The objective here is to make it unnecessary for the device drivers to
674193529Sjkim * use rman or similar to manage their unit number space.  Due to the way
675193529Sjkim * we do "on-demand" devices, using rman or other "private" methods
676193529Sjkim * will be very tricky to lock down properly once we lock down this file.
677167802Sjkim *
678167802Sjkim * Instead we give the drivers these routines which puts the struct cdev *'s
679167802Sjkim * that are to be managed on their own list, and gives the driver the ability
680167802Sjkim * to ask for the first free unit number or a given specified unit number.
681167802Sjkim *
682167802Sjkim * In addition these routines support paired devices (pty, nmdm and similar)
683167802Sjkim * by respecting a number of "flag" bits in the minor number.
684167802Sjkim *
685167802Sjkim */
686167802Sjkim
687167802Sjkimstruct clonedevs {
688167802Sjkim	LIST_HEAD(,cdev)	head;
689167802Sjkim};
690167802Sjkim
691167802Sjkimvoid
692167802Sjkimclone_setup(struct clonedevs **cdp)
693167802Sjkim{
694167802Sjkim
695167802Sjkim	*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
696167802Sjkim	LIST_INIT(&(*cdp)->head);
697167802Sjkim}
698167802Sjkim
699167802Sjkimint
700167802Sjkimclone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra)
701167802Sjkim{
702167802Sjkim	struct clonedevs *cd;
703167802Sjkim	struct cdev *dev, *ndev, *dl, *de;
704167802Sjkim	int unit, low, u;
705167802Sjkim
706167802Sjkim	KASSERT(*cdp != NULL,
707167802Sjkim	    ("clone_setup() not called in driver \"%s\"", csw->d_name));
708167802Sjkim	KASSERT(!(extra & CLONE_UNITMASK),
709167802Sjkim	    ("Illegal extra bits (0x%x) in clone_create", extra));
710167802Sjkim	KASSERT(*up <= CLONE_UNITMASK,
711167802Sjkim	    ("Too high unit (0x%x) in clone_create", *up));
712167802Sjkim
713167802Sjkim	if (csw->d_maj == MAJOR_AUTO)
714167802Sjkim		find_major(csw);
715167802Sjkim
716167802Sjkim	/*
717193529Sjkim	 * Search the list for a lot of things in one go:
718167802Sjkim	 *   A preexisting match is returned immediately.
719167802Sjkim	 *   The lowest free unit number if we are passed -1, and the place
720167802Sjkim	 *	 in the list where we should insert that new element.
721167802Sjkim	 *   The place to insert a specified unit number, if applicable
722193529Sjkim	 *       the end of the list.
723212761Sjkim	 */
724167802Sjkim	unit = *up;
725167802Sjkim	ndev = allocdev();
726167802Sjkim	dev_lock();
727167802Sjkim	low = extra;
728167802Sjkim	de = dl = NULL;
729167802Sjkim	cd = *cdp;
730167802Sjkim	LIST_FOREACH(dev, &cd->head, si_clone) {
731167802Sjkim		KASSERT(dev->si_flags & SI_CLONELIST,
732167802Sjkim		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
733167802Sjkim		u = dev2unit(dev);
734167802Sjkim		if (u == (unit | extra)) {
735167802Sjkim			*dp = dev;
736167802Sjkim			freedev(ndev);
737167802Sjkim			dev_unlock();
738167802Sjkim			return (0);
739167802Sjkim		}
740167802Sjkim		if (unit == -1 && u == low) {
741167802Sjkim			low++;
742167802Sjkim			de = dev;
743167802Sjkim			continue;
744167802Sjkim		}
745167802Sjkim		if (u > (unit | extra)) {
746167802Sjkim			dl = dev;
747167802Sjkim			break;
748167802Sjkim		}
749167802Sjkim	}
750167802Sjkim	if (unit == -1)
751167802Sjkim		unit = low & CLONE_UNITMASK;
752167802Sjkim	dev = newdev(csw->d_maj, unit2minor(unit | extra), ndev);
753167802Sjkim	if (dev->si_flags & SI_CLONELIST) {
754167802Sjkim		printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
755167802Sjkim		printf("unit=%d\n", unit);
756167802Sjkim		LIST_FOREACH(dev, &cd->head, si_clone) {
757167802Sjkim			printf("\t%p %s\n", dev, dev->si_name);
758167802Sjkim		}
759167802Sjkim		panic("foo");
760167802Sjkim	}
761167802Sjkim	KASSERT(!(dev->si_flags & SI_CLONELIST),
762167802Sjkim	    ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
763167802Sjkim	if (dl != NULL)
764167802Sjkim		LIST_INSERT_BEFORE(dl, dev, si_clone);
765167802Sjkim	else if (de != NULL)
766167802Sjkim		LIST_INSERT_AFTER(de, dev, si_clone);
767167802Sjkim	else
768167802Sjkim		LIST_INSERT_HEAD(&cd->head, dev, si_clone);
769167802Sjkim	dev->si_flags |= SI_CLONELIST;
770167802Sjkim	*up = unit;
771167802Sjkim	dev_unlock();
772167802Sjkim	return (1);
773167802Sjkim}
774167802Sjkim
775167802Sjkim/*
776167802Sjkim * Kill everything still on the list.  The driver should already have
777167802Sjkim * disposed of any softc hung of the struct cdev *'s at this time.
778167802Sjkim */
779167802Sjkimvoid
780167802Sjkimclone_cleanup(struct clonedevs **cdp)
781167802Sjkim{
782167802Sjkim	struct cdev *dev, *tdev;
783167802Sjkim	struct clonedevs *cd;
784167802Sjkim
785167802Sjkim	cd = *cdp;
786198237Sjkim	if (cd == NULL)
787167802Sjkim		return;
788167802Sjkim	dev_lock();
789167802Sjkim	LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
790167802Sjkim		KASSERT(dev->si_flags & SI_CLONELIST,
791167802Sjkim		    ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
792167802Sjkim		KASSERT(dev->si_flags & SI_NAMED,
793167802Sjkim		    ("Driver has goofed in cloning underways udev %x", dev->si_udev));
794167802Sjkim		destroy_devl(dev);
795167802Sjkim	}
796167802Sjkim	dev_unlock();
797167802Sjkim	free(cd, M_DEVBUF);
798167802Sjkim	*cdp = NULL;
799193529Sjkim}
800193529Sjkim
801193529Sjkim/*
802193529Sjkim * Helper sysctl for devname(3).  We're given a struct cdev * and return
803193529Sjkim * the name, if any, registered by the device driver.
804193529Sjkim */
805193529Sjkimstatic int
806193529Sjkimsysctl_devname(SYSCTL_HANDLER_ARGS)
807193529Sjkim{
808193529Sjkim	int error;
809193529Sjkim	dev_t ud;
810193529Sjkim	struct cdev *dev;
811193529Sjkim
812212761Sjkim	error = SYSCTL_IN(req, &ud, sizeof (ud));
813212761Sjkim	if (error)
814212761Sjkim		return (error);
815212761Sjkim	if (ud == NODEV)
816193529Sjkim		return(EINVAL);
817193529Sjkim	dev = findcdev(ud);
818212761Sjkim	if (dev == NULL)
819193529Sjkim		error = ENOENT;
820193529Sjkim	else
821167802Sjkim		error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
822167802Sjkim	return (error);
823167802Sjkim}
824167802Sjkim
825167802SjkimSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
826167802Sjkim	NULL, 0, sysctl_devname, "", "devname(3) handler");
827167802Sjkim