xref: /freebsd/sys/kern/kern_conf.c (revision a1a4f1a0d87b594d3f17a97dc0127eec1417e6f6)
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  * $FreeBSD$
34  */
35 
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/module.h>
40 #include <sys/malloc.h>
41 #include <sys/conf.h>
42 #include <sys/vnode.h>
43 #include <sys/queue.h>
44 #include <machine/stdarg.h>
45 
46 #define cdevsw_ALLOCSTART	(NUMCDEVSW/2)
47 
48 struct cdevsw 	*cdevsw[NUMCDEVSW];
49 
50 static int	bmaj2cmaj[NUMCDEVSW];
51 
52 MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
53 
54 #define DEVT_HASH 83
55 #define DEVT_STASH 50
56 
57 static struct specinfo devt_stash[DEVT_STASH];
58 
59 static SLIST_HEAD(devt_hash_head, specinfo) dev_hash[DEVT_HASH];
60 
61 devfs_create_t *devfs_create_hook;
62 
63 /*
64  * Routine to convert from character to block device number.
65  *
66  * A minimal stub routine can always return NODEV.
67  */
68 dev_t
69 chrtoblk(dev_t dev)
70 {
71 	struct cdevsw *cd;
72 
73 	if((cd = devsw(dev)) != NULL) {
74           if (cd->d_bmaj != -1)
75 	    return(makebdev(cd->d_bmaj,minor(dev)));
76 	}
77 	return(NODEV);
78 }
79 
80 struct cdevsw *
81 devsw(dev_t dev)
82 {
83 	if (dev->si_devsw)
84 		return (dev->si_devsw);
85         return(cdevsw[major(dev)]);
86 }
87 
88 /*
89  *  Add a cdevsw entry
90  */
91 
92 int
93 cdevsw_add(struct cdevsw *newentry)
94 {
95 	int i;
96 	static int setup;
97 
98 	if (!setup) {
99 		for (i = 0; i < NUMCDEVSW; i++)
100 			if (!bmaj2cmaj[i])
101 				bmaj2cmaj[i] = 254;
102 		setup++;
103 	}
104 
105 	if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
106 		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
107 		    newentry->d_name, newentry->d_maj);
108 		return EINVAL;
109 	}
110 
111 	if (cdevsw[newentry->d_maj]) {
112 		printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
113 		    newentry->d_name, cdevsw[newentry->d_maj]->d_name);
114 	}
115 	cdevsw[newentry->d_maj] = newentry;
116 
117 	if (newentry->d_bmaj >= 0 && newentry->d_bmaj < NUMCDEVSW) {
118 		if (bmaj2cmaj[newentry->d_bmaj] != 254) {
119 			printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n",
120 			    newentry->d_name,
121 			    cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name);
122 		}
123 		bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj;
124 	}
125 
126 	return 0;
127 }
128 
129 /*
130  *  Remove a cdevsw entry
131  */
132 
133 int
134 cdevsw_remove(struct cdevsw *oldentry)
135 {
136 	if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
137 		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
138 		    oldentry->d_name, oldentry->d_maj);
139 		return EINVAL;
140 	}
141 
142 	cdevsw[oldentry->d_maj] = NULL;
143 
144 	if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW)
145 		bmaj2cmaj[oldentry->d_bmaj] = 254;
146 
147 	return 0;
148 }
149 
150 int
151 devsw_module_handler(module_t mod, int what, void* arg)
152 {
153 	struct devsw_module_data* data = (struct devsw_module_data*) arg;
154 	int error = 0;
155 
156 	switch (what) {
157 	case MOD_LOAD:
158 		error = cdevsw_add(data->cdevsw);
159 		if (!error && data->chainevh)
160 			error = data->chainevh(mod, what, data->chainarg);
161 		return error;
162 
163 	case MOD_UNLOAD:
164 		if (data->chainevh) {
165 			error = data->chainevh(mod, what, data->chainarg);
166 			if (error)
167 				return error;
168 		}
169 		cdevsw_remove(data->cdevsw);
170 		return error;
171 	}
172 
173 	if (data->chainevh)
174 		return data->chainevh(mod, what, data->chainarg);
175 	else
176 		return 0;
177 }
178 
179 /*
180  * dev_t and u_dev_t primitives
181  */
182 
183 int
184 major(dev_t x)
185 {
186 	if (x == NODEV)
187 		return NOUDEV;
188 	return((x->si_udev >> 8) & 0xff);
189 }
190 
191 int
192 minor(dev_t x)
193 {
194 	if (x == NODEV)
195 		return NOUDEV;
196 	return(x->si_udev & 0xffff00ff);
197 }
198 
199 int
200 lminor(dev_t x)
201 {
202 	int i;
203 
204 	if (x == NODEV)
205 		return NOUDEV;
206 	i = minor(x);
207 	return ((i & 0xff) | (i >> 8));
208 }
209 
210 dev_t
211 makebdev(int x, int y)
212 {
213 	return (makedev(bmaj2cmaj[x], y));
214 }
215 
216 dev_t
217 makedev(int x, int y)
218 {
219 	struct specinfo *si;
220 	udev_t	udev;
221 	int hash;
222 	static int stashed;
223 
224 	udev = (x << 8) | y;
225 	hash = udev % DEVT_HASH;
226 	SLIST_FOREACH(si, &dev_hash[hash], si_hash) {
227 		if (si->si_udev == udev)
228 			return (si);
229 	}
230 	if (stashed >= DEVT_STASH) {
231 		MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
232 		    M_USE_RESERVE);
233 	} else {
234 		si = devt_stash + stashed++;
235 	}
236 	bzero(si, sizeof(*si));
237 	si->si_udev = udev;
238 	if (y > 256)
239 		sprintf(si->si_name, "#%d/0x%x", x, y);
240 	else
241 		sprintf(si->si_name, "#%d/%d", x, y);
242 	SLIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
243         return (si);
244 }
245 
246 udev_t
247 dev2udev(dev_t x)
248 {
249 	if (x == NODEV)
250 		return NOUDEV;
251 	return (x->si_udev);
252 }
253 
254 udev_t
255 dev2budev(dev_t x)
256 {
257 	if (x == NODEV)
258 		return NOUDEV;
259 	else
260 		return makeudev(devsw(x)->d_bmaj, minor(x));
261 }
262 
263 dev_t
264 udev2dev(udev_t x, int b)
265 {
266 	switch (b) {
267 		case 0:
268 			return makedev(umajor(x), uminor(x));
269 		case 1:
270 			return makebdev(umajor(x), uminor(x));
271 		default:
272 			Debugger("udev2dev(...,X)");
273 			return NODEV;
274 	}
275 }
276 
277 int
278 uminor(udev_t dev)
279 {
280 	return(dev & 0xffff00ff);
281 }
282 
283 int
284 umajor(udev_t dev)
285 {
286 	return((dev & 0xff00) >> 8);
287 }
288 
289 udev_t
290 makeudev(int x, int y)
291 {
292         return ((x << 8) | y);
293 }
294 
295 dev_t
296 make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)
297 {
298 	dev_t	dev;
299 	va_list ap;
300 	int i;
301 
302 	dev = makedev(devsw->d_maj, minor);
303 	va_start(ap, fmt);
304 	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
305 	dev->si_name[i] = '\0';
306 	va_end(ap);
307 	dev->si_devsw = devsw;
308 
309 	if (devfs_create_hook)
310 		devfs_create_hook(dev, uid, gid, perms);
311 	return (dev);
312 }
313 
314 char *
315 devtoname(dev_t dev)
316 {
317 
318 	return (dev->si_name);
319 }
320 
321