kern_conf.c revision 50092
111126Sjulian/*-
211126Sjulian * Parts Copyright (c) 1995 Terrence R. Lambert
311126Sjulian * Copyright (c) 1995 Julian R. Elischer
411126Sjulian * All rights reserved.
511126Sjulian *
611126Sjulian * Redistribution and use in source and binary forms, with or without
711126Sjulian * modification, are permitted provided that the following conditions
811126Sjulian * are met:
911126Sjulian * 1. Redistributions of source code must retain the above copyright
1011126Sjulian *    notice, this list of conditions and the following disclaimer.
1111126Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211126Sjulian *    notice, this list of conditions and the following disclaimer in the
1311126Sjulian *    documentation and/or other materials provided with the distribution.
1411126Sjulian * 3. All advertising materials mentioning features or use of this software
1511126Sjulian *    must display the following acknowledgement:
1611126Sjulian *      This product includes software developed by Terrence R. Lambert.
1711126Sjulian * 4. The name Terrence R. Lambert may not be used to endorse or promote
1811126Sjulian *    products derived from this software without specific prior written
1911126Sjulian *    permission.
2011126Sjulian *
2111126Sjulian * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
2211126Sjulian * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2311126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2411126Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
2511126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2611126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2711126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2811126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2911126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3011126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3111126Sjulian * SUCH DAMAGE.
3211126Sjulian *
3350092Sjulian * $Id: kern_conf.c,v 1.58 1999/08/17 20:25:50 billf Exp $
3411126Sjulian */
3511126Sjulian
3650092Sjulian#include "opt_devfs.h"
3750092Sjulian
3811126Sjulian#include <sys/param.h>
3948936Sphk#include <sys/kernel.h>
4011127Sjulian#include <sys/systm.h>
4136735Sdfr#include <sys/module.h>
4248936Sphk#include <sys/malloc.h>
4311126Sjulian#include <sys/conf.h>
4412954Sjulian#include <sys/vnode.h>
4548936Sphk#include <sys/queue.h>
4649535Sphk#include <machine/stdarg.h>
4750092Sjulian#ifdef	DEVFS
4850092Sjulian#include <sys/devfsext.h>
4950092Sjulian#endif	/* DEVFS */
5011126Sjulian
5150092Sjulian
5247640Sphk#define cdevsw_ALLOCSTART	(NUMCDEVSW/2)
5312954Sjulian
5447640Sphkstruct cdevsw 	*cdevsw[NUMCDEVSW];
5512954Sjulian
5648936Sphkstatic int	bmaj2cmaj[NUMCDEVSW];
5746635Sphk
5848936SphkMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
5948936Sphk
6048936Sphk#define DEVT_HASH 83
6148936Sphk#define DEVT_STASH 50
6248936Sphk
6348936Sphkstatic struct specinfo devt_stash[DEVT_STASH];
6448936Sphk
6548936Sphkstatic SLIST_HEAD(devt_hash_head, specinfo) dev_hash[DEVT_HASH];
6648936Sphk
6711126Sjulian/*
6812954Sjulian * Routine to convert from character to block device number.
6912954Sjulian *
7012954Sjulian * A minimal stub routine can always return NODEV.
7112954Sjulian */
7212954Sjuliandev_t
7312954Sjulianchrtoblk(dev_t dev)
7412954Sjulian{
7512954Sjulian	struct cdevsw *cd;
7612954Sjulian
7746676Sphk	if((cd = devsw(dev)) != NULL) {
7837389Sjulian          if (cd->d_bmaj != -1)
7948864Sphk	    return(makebdev(cd->d_bmaj,minor(dev)));
8012954Sjulian	}
8112954Sjulian	return(NODEV);
8212954Sjulian}
8312954Sjulian
8447640Sphkstruct cdevsw *
8547640Sphkdevsw(dev_t dev)
8647640Sphk{
8749679Sphk	if (dev->si_devsw)
8849679Sphk		return (dev->si_devsw);
8947640Sphk        return(cdevsw[major(dev)]);
9047640Sphk}
9147640Sphk
9247640Sphk/*
9347640Sphk *  Add a cdevsw entry
9447640Sphk */
9547640Sphk
9637389Sjulianint
9747640Sphkcdevsw_add(struct cdevsw *newentry)
9817264Sphk{
9947028Sphk	int i;
10047028Sphk	static int setup;
10117264Sphk
10247028Sphk	if (!setup) {
10347640Sphk		for (i = 0; i < NUMCDEVSW; i++)
10447028Sphk			if (!bmaj2cmaj[i])
10548936Sphk				bmaj2cmaj[i] = 254;
10647028Sphk		setup++;
10747028Sphk	}
10847028Sphk
10947640Sphk	if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
11047640Sphk		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
11147640Sphk		    newentry->d_name, newentry->d_maj);
11247640Sphk		return EINVAL;
11337389Sjulian	}
11417264Sphk
11548510Sphk	if (cdevsw[newentry->d_maj]) {
11648510Sphk		printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
11748510Sphk		    newentry->d_name, cdevsw[newentry->d_maj]->d_name);
11848510Sphk	}
11947640Sphk	cdevsw[newentry->d_maj] = newentry;
12037389Sjulian
12148510Sphk	if (newentry->d_bmaj >= 0 && newentry->d_bmaj < NUMCDEVSW) {
12248936Sphk		if (bmaj2cmaj[newentry->d_bmaj] != 254) {
12348510Sphk			printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n",
12448510Sphk			    newentry->d_name,
12548510Sphk			    cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name);
12648510Sphk		}
12747640Sphk		bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj;
12848510Sphk	}
12947640Sphk
13037389Sjulian	return 0;
13137389Sjulian}
13237389Sjulian
13348211Sgrog/*
13448211Sgrog *  Remove a cdevsw entry
13548211Sgrog */
13648211Sgrog
13736735Sdfrint
13848211Sgrogcdevsw_remove(struct cdevsw *oldentry)
13948211Sgrog{
14048211Sgrog	if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
14148211Sgrog		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
14248211Sgrog		    oldentry->d_name, oldentry->d_maj);
14348211Sgrog		return EINVAL;
14448211Sgrog	}
14548211Sgrog
14648211Sgrog	cdevsw[oldentry->d_maj] = NULL;
14748211Sgrog
14848211Sgrog	if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW)
14949504Sgrog		bmaj2cmaj[oldentry->d_bmaj] = 254;
15048211Sgrog
15148211Sgrog	return 0;
15248211Sgrog}
15348211Sgrog
15448211Sgrogint
15546635Sphkdevsw_module_handler(module_t mod, int what, void* arg)
15636735Sdfr{
15746635Sphk	struct devsw_module_data* data = (struct devsw_module_data*) arg;
15848240Sdfr	int error = 0;
15936735Sdfr
16036735Sdfr	switch (what) {
16136735Sdfr	case MOD_LOAD:
16247640Sphk		error = cdevsw_add(data->cdevsw);
16344975Sdfr		if (!error && data->chainevh)
16444975Sdfr			error = data->chainevh(mod, what, data->chainarg);
16544975Sdfr		return error;
16636735Sdfr
16736735Sdfr	case MOD_UNLOAD:
16844975Sdfr		if (data->chainevh) {
16944975Sdfr			error = data->chainevh(mod, what, data->chainarg);
17044975Sdfr			if (error)
17144975Sdfr				return error;
17244975Sdfr		}
17348240Sdfr		cdevsw_remove(data->cdevsw);
17444975Sdfr		return error;
17536735Sdfr	}
17636735Sdfr
17736735Sdfr	if (data->chainevh)
17836735Sdfr		return data->chainevh(mod, what, data->chainarg);
17936735Sdfr	else
18036735Sdfr		return 0;
18136735Sdfr}
18247028Sphk
18347028Sphk/*
18447028Sphk * dev_t and u_dev_t primitives
18547028Sphk */
18647028Sphk
18747028Sphkint
18847028Sphkmajor(dev_t x)
18947028Sphk{
19048936Sphk	if (x == NODEV)
19148936Sphk		return NOUDEV;
19248936Sphk	return((x->si_udev >> 8) & 0xff);
19347028Sphk}
19447028Sphk
19547028Sphkint
19647028Sphkminor(dev_t x)
19747028Sphk{
19848936Sphk	if (x == NODEV)
19948936Sphk		return NOUDEV;
20048936Sphk	return(x->si_udev & 0xffff00ff);
20147028Sphk}
20247028Sphk
20349826Sphkint
20449826Sphklminor(dev_t x)
20549826Sphk{
20649826Sphk	int i;
20749826Sphk
20849826Sphk	if (x == NODEV)
20949826Sphk		return NOUDEV;
21049826Sphk	i = minor(x);
21149826Sphk	return ((i & 0xff) | (i >> 8));
21249826Sphk}
21349826Sphk
21447028Sphkdev_t
21547680Sphkmakebdev(int x, int y)
21647680Sphk{
21748892Sphk	return (makedev(bmaj2cmaj[x], y));
21847680Sphk}
21947680Sphk
22047680Sphkdev_t
22147028Sphkmakedev(int x, int y)
22247028Sphk{
22348936Sphk	struct specinfo *si;
22448936Sphk	udev_t	udev;
22548936Sphk	int hash;
22648936Sphk	static int stashed;
22748936Sphk
22848936Sphk	udev = (x << 8) | y;
22948936Sphk	hash = udev % DEVT_HASH;
23048936Sphk	SLIST_FOREACH(si, &dev_hash[hash], si_hash) {
23148936Sphk		if (si->si_udev == udev)
23248936Sphk			return (si);
23348936Sphk	}
23448936Sphk	if (stashed >= DEVT_STASH) {
23548936Sphk		MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
23648936Sphk		    M_USE_RESERVE);
23748936Sphk	} else {
23848936Sphk		si = devt_stash + stashed++;
23948936Sphk	}
24048936Sphk	bzero(si, sizeof(*si));
24148936Sphk	si->si_udev = udev;
24248936Sphk	si->si_bsize_phys = DEV_BSIZE;
24348936Sphk	si->si_bsize_best = BLKDEV_IOSIZE;
24448936Sphk	si->si_bsize_max = MAXBSIZE;
24549535Sphk	if (y > 256)
24649535Sphk		sprintf(si->si_name, "#%d/0x%x", x, y);
24749535Sphk	else
24849535Sphk		sprintf(si->si_name, "#%d/%d", x, y);
24948936Sphk	SLIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
25048936Sphk        return (si);
25147028Sphk}
25247028Sphk
25347028Sphkudev_t
25447028Sphkdev2udev(dev_t x)
25547028Sphk{
25648936Sphk	if (x == NODEV)
25748936Sphk		return NOUDEV;
25848936Sphk	return (x->si_udev);
25947028Sphk}
26047028Sphk
26148948Sgreenudev_t
26248948Sgreendev2budev(dev_t x)
26348948Sgreen{
26448949Sgreen	if (x == NODEV)
26548948Sgreen		return NOUDEV;
26648948Sgreen	else
26748948Sgreen		return makeudev(devsw(x)->d_bmaj, minor(x));
26848948Sgreen}
26948948Sgreen
27047028Sphkdev_t
27147028Sphkudev2dev(udev_t x, int b)
27247028Sphk{
27348864Sphk	switch (b) {
27448864Sphk		case 0:
27548864Sphk			return makedev(umajor(x), uminor(x));
27648864Sphk		case 1:
27748864Sphk			return makebdev(umajor(x), uminor(x));
27848864Sphk		default:
27948864Sphk			Debugger("udev2dev(...,X)");
28048864Sphk			return NODEV;
28148864Sphk	}
28247028Sphk}
28347028Sphk
28447028Sphkint
28547028Sphkuminor(udev_t dev)
28647028Sphk{
28747028Sphk	return(dev & 0xffff00ff);
28847028Sphk}
28947028Sphk
29047028Sphkint
29147028Sphkumajor(udev_t dev)
29247028Sphk{
29347028Sphk	return((dev & 0xff00) >> 8);
29447028Sphk}
29547028Sphk
29647028Sphkudev_t
29748859Sphkmakeudev(int x, int y)
29847028Sphk{
29947028Sphk        return ((x << 8) | y);
30047028Sphk}
30147028Sphk
30249535Sphkdev_t
30349535Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)
30449535Sphk{
30549535Sphk	dev_t	dev;
30649535Sphk	va_list ap;
30749535Sphk	int i;
30849535Sphk
30949535Sphk	dev = makedev(devsw->d_maj, minor);
31049535Sphk	va_start(ap, fmt);
31149535Sphk	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
31249535Sphk	dev->si_name[i] = '\0';
31349535Sphk	va_end(ap);
31449535Sphk	dev->si_devsw = devsw;
31550092Sjulian
31650092Sjulian#ifdef	DEVFS
31750092Sjulian        dev->si_devfs = devfs_add_devswf(devsw, minor, DV_CHR,
31850092Sjulian	    uid, gid, perms, dev->si_name);
31950092Sjulian	/* XXX HACK .. name may not start in 'r' */
32050092Sjulian	if ((devsw->d_bmaj != -1)
32150092Sjulian	&& (*dev->si_name == 'r')
32250092Sjulian	&& ((devsw->d_flags & D_TYPEMASK) == D_DISK))  {
32350092Sjulian        	dev->si_devfs = devfs_add_devswf(devsw, minor, DV_BLK,
32450092Sjulian	    				uid, gid, perms, dev->si_name + 1);
32550092Sjulian	}
32650092Sjulian#endif /* DEVFS */
32749535Sphk	return (dev);
32849535Sphk}
32949535Sphk
33049982Sbillfchar *
33149982Sbillfdevtoname(dev_t dev)
33249982Sbillf{
33349982Sbillf
33449982Sbillf	return (dev->si_name);
33549982Sbillf}
33649982Sbillf
337