xref: /freebsd/sys/kern/kern_conf.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
1 /*-
2  * Parts Copyright (c) 1995 Terrence R. Lambert
3  * Copyright (c) 1995 Julian R. Elischer
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Terrence R. Lambert.
17  * 4. The name Terrence R. Lambert may not be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $Id: kern_conf.c,v 1.26 1998/06/26 18:14:25 phk Exp $
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/module.h>
39 #include <sys/conf.h>
40 #include <sys/vnode.h>
41 
42 #define NUMBDEV 128
43 #define NUMCDEV 256
44 #define bdevsw_ALLOCSTART	(NUMBDEV/2)
45 #define cdevsw_ALLOCSTART	(NUMCDEV/2)
46 
47 struct cdevsw 	*bdevsw[NUMBDEV];
48 int	nblkdev = NUMBDEV;
49 struct cdevsw 	*cdevsw[NUMCDEV];
50 int	nchrdev = NUMCDEV;
51 
52 /*
53  * Routine to convert from character to block device number.
54  *
55  * A minimal stub routine can always return NODEV.
56  */
57 dev_t
58 chrtoblk(dev_t dev)
59 {
60 	struct bdevsw *bd;
61 	struct cdevsw *cd;
62 
63 	if(cd = cdevsw[major(dev)]) {
64           if (cd->d_bmaj != -1)
65 	    return(makedev(cd->d_bmaj,minor(dev)));
66 	}
67 	return(NODEV);
68 }
69 
70 /*
71  * (re)place an entry in the bdevsw or cdevsw table
72  * return the slot used in major(*descrip)
73  */
74 static int
75 bdevsw_add(dev_t *descrip,
76 		struct cdevsw *newentry,
77 		struct cdevsw **oldentry)
78 {
79 	int i ;
80 
81 	if ( (int)*descrip == NODEV) {	/* auto (0 is valid) */
82 		/*
83 		 * Search the table looking for a slot...
84 		 */
85 		for (i = bdevsw_ALLOCSTART; i < nblkdev; i++)
86 			if (bdevsw[i] == NULL)
87 				break;		/* found one! */
88 		/* out of allocable slots? */
89 		if (i >= nblkdev) {
90 			return ENFILE;
91 		}
92 	} else {				/* assign */
93 		i = major(*descrip);
94 		if (i < 0 || i >= nblkdev) {
95 			return EINVAL;
96 		}
97 	}
98 
99 	/* maybe save old */
100         if (oldentry) {
101 		*oldentry = bdevsw[i];
102 	}
103 	if (newentry) {
104 		newentry->d_bmaj = i;
105 	}
106 	/* replace with new */
107 	bdevsw[i] = newentry;
108 
109 	/* done!  let them know where we put it */
110 	*descrip = makedev(i,0);
111 	return 0;
112 }
113 
114 int
115 cdevsw_add(dev_t *descrip,
116 		struct cdevsw *newentry,
117 		struct cdevsw **oldentry)
118 {
119 	int i ;
120 
121 	if ( (int)*descrip == NODEV) {	/* auto (0 is valid) */
122 		/*
123 		 * Search the table looking for a slot...
124 		 */
125 		for (i = cdevsw_ALLOCSTART; i < nchrdev; i++)
126 			if (cdevsw[i] == NULL)
127 				break;		/* found one! */
128 		/* out of allocable slots? */
129 		if (i >= nchrdev) {
130 			return ENFILE;
131 		}
132 	} else {				/* assign */
133 		i = major(*descrip);
134 		if (i < 0 || i >= nchrdev) {
135 			return EINVAL;
136 		}
137 	}
138 
139 	/* maybe save old */
140         if (oldentry) {
141 		*oldentry = cdevsw[i];
142 	}
143 	if (newentry) {
144 		newentry->d_bmaj = -1;
145 		newentry->d_maj = i;
146 	}
147 	/* replace with new */
148 	cdevsw[i] = newentry;
149 
150 	/* done!  let them know where we put it */
151 	*descrip = makedev(i,0);
152 	return 0;
153 }
154 
155 /*
156  * note must call cdevsw_add before bdevsw_add due to d_bmaj hack.
157  */
158 void
159 cdevsw_add_generic(int bdev, int cdev, struct cdevsw *cdevsw)
160 {
161 	dev_t dev;
162 
163 	dev = makedev(cdev, 0);
164 	cdevsw_add(&dev, cdevsw, NULL);
165 	dev = makedev(bdev, 0);
166 	bdevsw_add(&dev, cdevsw, NULL);
167 }
168 
169 int
170 cdevsw_module_handler(module_t mod, modeventtype_t what, void* arg)
171 {
172 	struct cdevsw_module_data* data = (struct cdevsw_module_data*) arg;
173 	int error;
174 
175 	switch (what) {
176 	case MOD_LOAD:
177 		if (error = cdevsw_add(&data->dev, data->cdevsw, NULL))
178 			return error;
179 		break;
180 
181 	case MOD_UNLOAD:
182 		if (error = cdevsw_add(&data->dev, NULL, NULL))
183 			return error;
184 		break;
185 	}
186 
187 	if (data->chainevh)
188 		return data->chainevh(mod, what, data->chainarg);
189 	else
190 		return 0;
191 }
192 
193 int
194 bdevsw_module_handler(module_t mod, modeventtype_t what, void* arg)
195 {
196 	struct bdevsw_module_data* data = (struct bdevsw_module_data*) arg;
197 	int error;
198 
199 	switch (what) {
200 	case MOD_LOAD:
201 		if (error = cdevsw_add(&data->cdev, data->cdevsw, NULL))
202 			return error;
203 		if (error = bdevsw_add(&data->bdev, data->cdevsw, NULL)) {
204 			cdevsw_add(&data->bdev, NULL, NULL);
205 			return error;
206 		}
207 		break;
208 
209 	case MOD_UNLOAD:
210 		if (error = bdevsw_add(&data->bdev, NULL, NULL))
211 			return error;
212 		if (error = cdevsw_add(&data->cdev, NULL, NULL))
213 			return error;
214 		break;
215 	}
216 
217 	if (data->chainevh)
218 		return data->chainevh(mod, what, data->chainarg);
219 	else
220 		return 0;
221 }
222