kern_conf.c revision 67905
1251881Speter/*-
2251881Speter * Parts Copyright (c) 1995 Terrence R. Lambert
3251881Speter * Copyright (c) 1995 Julian R. Elischer
4251881Speter * All rights reserved.
5251881Speter *
6251881Speter * Redistribution and use in source and binary forms, with or without
7251881Speter * modification, are permitted provided that the following conditions
8251881Speter * are met:
9251881Speter * 1. Redistributions of source code must retain the above copyright
10251881Speter *    notice, this list of conditions and the following disclaimer.
11251881Speter * 2. Redistributions in binary form must reproduce the above copyright
12251881Speter *    notice, this list of conditions and the following disclaimer in the
13251881Speter *    documentation and/or other materials provided with the distribution.
14251881Speter * 3. All advertising materials mentioning features or use of this software
15251881Speter *    must display the following acknowledgement:
16251881Speter *      This product includes software developed by Terrence R. Lambert.
17251881Speter * 4. The name Terrence R. Lambert may not be used to endorse or promote
18251881Speter *    products derived from this software without specific prior written
19251881Speter *    permission.
20251881Speter *
21251881Speter * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22251881Speter * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31251881Speter * SUCH DAMAGE.
32251881Speter *
33251881Speter * $FreeBSD: head/sys/kern/kern_conf.c 67905 2000-10-29 19:50:06Z phk $
34251881Speter */
35251881Speter
36251881Speter#include <sys/param.h>
37251881Speter#include <sys/kernel.h>
38251881Speter#include <sys/sysctl.h>
39251881Speter#include <sys/systm.h>
40251881Speter#include <sys/module.h>
41251881Speter#include <sys/malloc.h>
42251881Speter#include <sys/conf.h>
43251881Speter#include <sys/vnode.h>
44251881Speter#include <sys/queue.h>
45251881Speter#include <sys/ctype.h>
46251881Speter#include <machine/stdarg.h>
47251881Speter
48251881Speter#define cdevsw_ALLOCSTART	(NUMCDEVSW/2)
49251881Speter
50251881Speterstruct cdevsw 	*cdevsw[NUMCDEVSW];
51251881Speter
52251881Speterstatic int	bmaj2cmaj[NUMCDEVSW];
53251881Speter
54251881SpeterMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
55251881Speter
56251881Speter/*
57251881Speter * This is the number of hash-buckets.  Experiements with 'real-life'
58251881Speter * udev_t's show that a prime halfway between two powers of two works
59251881Speter * best.
60251881Speter */
61251881Speter#define DEVT_HASH 83
62251881Speter
63251881Speter/* The number of dev_t's we can create before malloc(9) kick in.  */
64251881Speter#define DEVT_STASH 50
65251881Speter
66251881Speterstatic struct specinfo devt_stash[DEVT_STASH];
67251881Speter
68251881Speterstatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH];
69251881Speter
70251881Speterstatic LIST_HEAD(, specinfo) dev_free;
71251881Speter
72251881Speterdevfs_create_t *devfs_create_hook;
73251881Speterdevfs_destroy_t *devfs_destroy_hook;
74251881Speterint devfs_present;
75251881Speter
76251881Speterstatic int free_devt;
77251881SpeterSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
78251881Speter
79251881Speterstruct cdevsw *
80251881Speterdevsw(dev_t dev)
81251881Speter{
82251881Speter	if (dev->si_devsw)
83251881Speter		return (dev->si_devsw);
84251881Speter        return(cdevsw[major(dev)]);
85251881Speter}
86251881Speter
87251881Speter/*
88251881Speter *  Add a cdevsw entry
89251881Speter */
90251881Speter
91251881Speterint
92251881Spetercdevsw_add(struct cdevsw *newentry)
93251881Speter{
94251881Speter	int i;
95251881Speter	static int setup;
96251881Speter
97251881Speter	if (!setup) {
98251881Speter		for (i = 0; i < NUMCDEVSW; i++)
99251881Speter			if (!bmaj2cmaj[i])
100251881Speter				bmaj2cmaj[i] = 254;
101251881Speter		setup++;
102251881Speter	}
103251881Speter
104251881Speter	if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
105251881Speter		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
106251881Speter		    newentry->d_name, newentry->d_maj);
107251881Speter		return (EINVAL);
108251881Speter	}
109251881Speter	if (newentry->d_bmaj >= NUMCDEVSW) {
110251881Speter		printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n",
111251881Speter		    newentry->d_name, newentry->d_bmaj);
112251881Speter		return (EINVAL);
113251881Speter	}
114251881Speter	if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) {
115251881Speter		printf("ERROR: \"%s\" bmaj but is not a disk\n",
116251881Speter		    newentry->d_name);
117251881Speter		return (EINVAL);
118251881Speter	}
119251881Speter
120251881Speter	if (cdevsw[newentry->d_maj]) {
121251881Speter		printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
122251881Speter		    newentry->d_name, cdevsw[newentry->d_maj]->d_name);
123251881Speter	}
124251881Speter
125251881Speter	cdevsw[newentry->d_maj] = newentry;
126251881Speter
127251881Speter	if (newentry->d_bmaj < 0)
128251881Speter		return (0);
129251881Speter
130251881Speter	if (bmaj2cmaj[newentry->d_bmaj] != 254) {
131251881Speter		printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n",
132251881Speter		    newentry->d_name,
133251881Speter		    cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name);
134251881Speter	}
135251881Speter	bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj;
136251881Speter	return (0);
137251881Speter}
138251881Speter
139251881Speter/*
140251881Speter *  Remove a cdevsw entry
141251881Speter */
142251881Speter
143251881Speterint
144251881Spetercdevsw_remove(struct cdevsw *oldentry)
145251881Speter{
146251881Speter	if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
147251881Speter		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
148251881Speter		    oldentry->d_name, oldentry->d_maj);
149251881Speter		return EINVAL;
150251881Speter	}
151251881Speter
152251881Speter	cdevsw[oldentry->d_maj] = NULL;
153251881Speter
154251881Speter	if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW)
155251881Speter		bmaj2cmaj[oldentry->d_bmaj] = 254;
156251881Speter
157251881Speter	return 0;
158251881Speter}
159251881Speter
160251881Speter/*
161251881Speter * dev_t and u_dev_t primitives
162251881Speter */
163251881Speter
164251881Speterint
165251881Spetermajor(dev_t x)
166251881Speter{
167251881Speter	if (x == NODEV)
168251881Speter		return NOUDEV;
169251881Speter	return((x->si_udev >> 8) & 0xff);
170251881Speter}
171251881Speter
172251881Speterint
173251881Speterminor(dev_t x)
174251881Speter{
175251881Speter	if (x == NODEV)
176251881Speter		return NOUDEV;
177251881Speter	return(x->si_udev & 0xffff00ff);
178251881Speter}
179251881Speter
180251881Speterint
181251881Speterdev2unit(dev_t x)
182251881Speter{
183251881Speter	int i;
184251881Speter
185251881Speter	if (x == NODEV)
186251881Speter		return NOUDEV;
187251881Speter	i = minor(x);
188251881Speter	return ((i & 0xff) | (i >> 8));
189251881Speter}
190251881Speter
191251881Speterint
192251881Speterunit2minor(int unit)
193251881Speter{
194251881Speter
195251881Speter	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
196251881Speter}
197251881Speter
198251881Speterdev_t
199251881Spetermakebdev(int x, int y)
200251881Speter{
201251881Speter
202251881Speter	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
203251881Speter		Debugger("makebdev of NOUDEV");
204251881Speter	return (makedev(bmaj2cmaj[x], y));
205251881Speter}
206251881Speter
207251881Speterstatic dev_t
208251881Speterallocdev(void)
209251881Speter{
210251881Speter	static int stashed;
211251881Speter	struct specinfo *si;
212251881Speter
213251881Speter	if (stashed >= DEVT_STASH) {
214251881Speter		MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
215251881Speter		    M_USE_RESERVE);
216251881Speter		bzero(si, sizeof(*si));
217251881Speter	} else if (LIST_FIRST(&dev_free)) {
218251881Speter		si = LIST_FIRST(&dev_free);
219251881Speter		LIST_REMOVE(si, si_hash);
220251881Speter	} else {
221251881Speter		si = devt_stash + stashed++;
222251881Speter		si->si_flags |= SI_STASHED;
223251881Speter	}
224251881Speter	LIST_INIT(&si->si_names);
225251881Speter	return (si);
226251881Speter}
227251881Speter
228251881Speterdev_t
229251881Spetermakedev(int x, int y)
230251881Speter{
231251881Speter	struct specinfo *si;
232251881Speter	udev_t	udev;
233251881Speter	int hash;
234251881Speter
235251881Speter	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
236251881Speter		Debugger("makedev of NOUDEV");
237251881Speter	udev = (x << 8) | y;
238251881Speter	hash = udev % DEVT_HASH;
239251881Speter	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
240251881Speter		if (si->si_udev == udev)
241251881Speter			return (si);
242251881Speter	}
243251881Speter	si = allocdev();
244251881Speter	si->si_udev = udev;
245251881Speter	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
246251881Speter        return (si);
247251881Speter}
248251881Speter
249251881Spetervoid
250251881Speterfreedev(dev_t dev)
251251881Speter{
252251881Speter	dev_t adev;
253251881Speter
254251881Speter	if (!free_devt)
255251881Speter		return;
256251881Speter	if (SLIST_FIRST(&dev->si_hlist))
257251881Speter		return;
258251881Speter	if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
259251881Speter		return;
260251881Speter	while (!LIST_EMPTY(&dev->si_names)) {
261251881Speter		adev = LIST_FIRST(&dev->si_names);
262251881Speter		adev->si_drv1 = NULL;
263251881Speter		freedev(adev);
264251881Speter	}
265251881Speter	LIST_REMOVE(dev, si_hash);
266251881Speter	if (dev->si_flags & SI_STASHED) {
267251881Speter		bzero(dev, sizeof(*dev));
268251881Speter		LIST_INSERT_HEAD(&dev_free, dev, si_hash);
269251881Speter	} else {
270251881Speter		FREE(dev, M_DEVT);
271251881Speter	}
272251881Speter}
273251881Speter
274251881Speterudev_t
275251881Speterdev2udev(dev_t x)
276251881Speter{
277251881Speter	if (x == NODEV)
278251881Speter		return NOUDEV;
279251881Speter	return (x->si_udev);
280251881Speter}
281251881Speter
282251881Speterdev_t
283251881Speterudev2dev(udev_t x, int b)
284251881Speter{
285251881Speter
286251881Speter	if (x == NOUDEV)
287251881Speter		return (NODEV);
288251881Speter	switch (b) {
289251881Speter		case 0:
290251881Speter			return makedev(umajor(x), uminor(x));
291251881Speter		case 1:
292251881Speter			return makebdev(umajor(x), uminor(x));
293251881Speter		default:
294251881Speter			Debugger("udev2dev(...,X)");
295251881Speter			return NODEV;
296251881Speter	}
297251881Speter}
298251881Speter
299251881Speterint
300251881Speteruminor(udev_t dev)
301251881Speter{
302251881Speter	return(dev & 0xffff00ff);
303251881Speter}
304251881Speter
305251881Speterint
306251881Speterumajor(udev_t dev)
307251881Speter{
308251881Speter	return((dev & 0xff00) >> 8);
309251881Speter}
310251881Speter
311251881Speterudev_t
312251881Spetermakeudev(int x, int y)
313251881Speter{
314251881Speter        return ((x << 8) | y);
315251881Speter}
316251881Speter
317251881Speterdev_t
318251881Spetermake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)
319251881Speter{
320251881Speter	dev_t	dev;
321251881Speter	va_list ap;
322251881Speter	int i;
323251881Speter
324251881Speter	dev = makedev(devsw->d_maj, minor);
325251881Speter	if (dev->si_flags & SI_NAMED) {
326251881Speter		printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
327251881Speter		    dev->si_name);
328251881Speter		return (dev);
329251881Speter	}
330251881Speter	va_start(ap, fmt);
331251881Speter	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
332251881Speter	dev->si_name[i] = '\0';
333251881Speter	va_end(ap);
334251881Speter	dev->si_devsw = devsw;
335251881Speter	dev->si_uid = uid;
336251881Speter	dev->si_gid = gid;
337251881Speter	dev->si_mode = perms;
338251881Speter	dev->si_flags |= SI_NAMED;
339251881Speter
340251881Speter	if (devfs_create_hook)
341251881Speter		devfs_create_hook(dev);
342251881Speter	return (dev);
343251881Speter}
344251881Speter
345251881Speterdev_t
346251881Spetermake_dev_alias(dev_t pdev, char *fmt, ...)
347251881Speter{
348251881Speter	dev_t	dev;
349251881Speter	va_list ap;
350251881Speter	int i;
351251881Speter
352251881Speter	dev = allocdev();
353251881Speter	dev->si_flags |= SI_ALIAS;
354251881Speter	dev->si_flags |= SI_NAMED;
355251881Speter	dev->si_drv1 = pdev;
356251881Speter	LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash);
357251881Speter
358251881Speter	va_start(ap, fmt);
359251881Speter	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
360251881Speter	dev->si_name[i] = '\0';
361251881Speter	va_end(ap);
362251881Speter
363251881Speter	if (devfs_create_hook)
364251881Speter		devfs_create_hook(dev);
365251881Speter	return (dev);
366251881Speter}
367251881Speter
368251881Spetervoid
369251881Speterdestroy_dev(dev_t dev)
370251881Speter{
371251881Speter
372251881Speter	if (!(dev->si_flags & SI_NAMED)) {
373251881Speter		printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
374251881Speter		    major(dev), minor(dev));
375251881Speter		return;
376251881Speter	}
377251881Speter
378251881Speter	if (devfs_destroy_hook)
379251881Speter		devfs_destroy_hook(dev);
380251881Speter	dev->si_drv1 = 0;
381251881Speter	dev->si_drv2 = 0;
382251881Speter	dev->si_devsw = 0;
383251881Speter	dev->si_flags &= ~SI_NAMED;
384251881Speter	dev->si_flags &= ~SI_ALIAS;
385251881Speter	freedev(dev);
386251881Speter}
387251881Speter
388251881Speterconst char *
389251881Speterdevtoname(dev_t dev)
390251881Speter{
391251881Speter	char *p;
392251881Speter	int mynor;
393251881Speter
394251881Speter	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
395251881Speter		p = dev->si_name;
396251881Speter		if (devsw(dev))
397251881Speter			sprintf(p, "#%s/", devsw(dev)->d_name);
398251881Speter		else
399251881Speter			sprintf(p, "#%d/", major(dev));
400251881Speter		p += strlen(p);
401251881Speter		mynor = minor(dev);
402251881Speter		if (mynor < 0 || mynor > 255)
403251881Speter			sprintf(p, "%#x", (u_int)mynor);
404251881Speter		else
405251881Speter			sprintf(p, "%d", mynor);
406251881Speter	}
407251881Speter	return (dev->si_name);
408251881Speter}
409251881Speter
410251881Speterint
411251881Speterdev_stdclone(char *name, char **namep, char *stem, int *unit)
412251881Speter{
413251881Speter	int u, i;
414251881Speter
415251881Speter	if (bcmp(stem, name, strlen(stem)) != 0)
416251881Speter		return (0);
417251881Speter	i = strlen(stem);
418251881Speter	if (!isdigit(name[i]))
419251881Speter		return (0);
420251881Speter	u = 0;
421251881Speter	while (isdigit(name[i])) {
422251881Speter		u *= 10;
423251881Speter		u += name[i++] - '0';
424251881Speter	}
425251881Speter	*unit = u;
426251881Speter	if (namep)
427251881Speter		*namep = &name[i];
428251881Speter	if (name[i])
429251881Speter		return (2);
430251881Speter	return (1);
431251881Speter}
432251881Speter
433251881Speter/*
434251881Speter * Helper sysctl for devname(3).  We're given a {u}dev_t and return
435251881Speter * the name, if any, registered by the device driver.
436251881Speter */
437251881Speterstatic int
438251881Spetersysctl_devname(SYSCTL_HANDLER_ARGS)
439251881Speter{
440251881Speter	int error;
441251881Speter	udev_t ud;
442251881Speter	dev_t dev;
443251881Speter
444251881Speter	error = SYSCTL_IN(req, &ud, sizeof (ud));
445251881Speter	if (error)
446251881Speter		return (error);
447251881Speter	dev = makedev(umajor(ud), uminor(ud));
448251881Speter	if (dev->si_name[0] == '\0')
449251881Speter		error = ENOENT;
450251881Speter	else
451251881Speter		error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
452251881Speter	freedev(dev);
453251881Speter	return (error);
454251881Speter}
455251881Speter
456251881SpeterSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
457251881Speter	NULL, 0, sysctl_devname, "", "devname(3) handler");
458251881Speter
459251881Speter