subr_devsw.c revision 1.4 1 /* $NetBSD: subr_devsw.c,v 1.4 2002/09/15 14:29:01 tsutsui Exp $ */
2 /*-
3 * Copyright (c) 2001,2002 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by MAEKAWA Masahide <gehenna (at) NetBSD.org>.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * New device switch framework is developing.
40 * So debug options are always turned on.
41 */
42 #ifndef DEVSW_DEBUG
43 #define DEVSW_DEBUG
44 #endif /* DEVSW_DEBUG */
45
46 #include <sys/param.h>
47 #include <sys/conf.h>
48 #include <sys/malloc.h>
49 #include <sys/systm.h>
50
51 #ifdef DEVSW_DEBUG
52 #define DPRINTF(x) printf x
53 #else /* DEVSW_DEBUG */
54 #define DPRINTF(x)
55 #endif /* DEVSW_DEBUG */
56
57 #define MAXDEVSW 4096 /* the maximum of major device number */
58 #define BDEVSW_SIZE (sizeof(struct bdevsw *))
59 #define CDEVSW_SIZE (sizeof(struct cdevsw *))
60 #define DEVSWCONV_SIZE (sizeof(struct devsw_conv))
61
62 extern const struct bdevsw **bdevsw, *bdevsw0[];
63 extern const struct cdevsw **cdevsw, *cdevsw0[];
64 extern struct devsw_conv *devsw_conv, devsw_conv0[];
65 extern const int sys_bdevsws, sys_cdevsws;
66 extern int max_bdevsws, max_cdevsws, max_devsw_convs;
67
68 static int bdevsw_attach(const char *, const struct bdevsw *, int *);
69 static int cdevsw_attach(const char *, const struct cdevsw *, int *);
70
71 int
72 devsw_attach(const char *devname, const struct bdevsw *bdev, int *bmajor,
73 const struct cdevsw *cdev, int *cmajor)
74 {
75 struct devsw_conv *conv;
76 char *name;
77 int error, i;
78
79 if (devname == NULL || cdev == NULL)
80 return (EINVAL);
81
82 for (i = 0 ; i < max_devsw_convs ; i++) {
83 conv = &devsw_conv[i];
84 if (conv->d_name == NULL || strcmp(devname, conv->d_name) != 0)
85 continue;
86
87 if (*bmajor < 0)
88 *bmajor = conv->d_bmajor;
89 if (*cmajor < 0)
90 *cmajor = conv->d_cmajor;
91
92 if (*bmajor != conv->d_bmajor || *cmajor != conv->d_cmajor)
93 return (EINVAL);
94 if ((*bmajor >= 0 && bdev == NULL) || *cmajor < 0)
95 return (EINVAL);
96
97 if ((*bmajor >= 0 && bdevsw[*bmajor] != NULL) ||
98 cdevsw[*cmajor] != NULL)
99 return (EEXIST);
100
101 if (bdev != NULL)
102 bdevsw[*bmajor] = bdev;
103 cdevsw[*cmajor] = cdev;
104
105 return (0);
106 }
107
108 error = bdevsw_attach(devname, bdev, bmajor);
109 if (error != 0)
110 return (error);
111 error = cdevsw_attach(devname, cdev, cmajor);
112 if (error != 0) {
113 devsw_detach(bdev, NULL);
114 return (error);
115 }
116
117 for (i = 0 ; i < max_devsw_convs ; i++) {
118 if (devsw_conv[i].d_name == NULL)
119 break;
120 }
121 if (i == max_devsw_convs) {
122 struct devsw_conv *newptr;
123 int old, new;
124
125 old = max_devsw_convs;
126 new = old + 1;
127
128 newptr = malloc(new * DEVSWCONV_SIZE, M_DEVBUF, M_NOWAIT);
129 if (newptr == NULL) {
130 devsw_detach(bdev, cdev);
131 return (ENOMEM);
132 }
133 newptr[old].d_name = NULL;
134 newptr[old].d_bmajor = -1;
135 newptr[old].d_cmajor = -1;
136 memcpy(newptr, devsw_conv, old * DEVSWCONV_SIZE);
137 if (devsw_conv != devsw_conv0)
138 free(devsw_conv, M_DEVBUF);
139 devsw_conv = newptr;
140 max_devsw_convs = new;
141 }
142
143 name = malloc(strlen(devname) + 1, M_DEVBUF, M_NOWAIT);
144 if (name == NULL) {
145 devsw_detach(bdev, cdev);
146 return (ENOMEM);
147 }
148 strcpy(name, devname);
149
150 devsw_conv[i].d_name = name;
151 devsw_conv[i].d_bmajor = *bmajor;
152 devsw_conv[i].d_cmajor = *cmajor;
153
154 return (0);
155 }
156
157 static int
158 bdevsw_attach(const char *devname, const struct bdevsw *devsw, int *devmajor)
159 {
160 int bmajor, i;
161
162 if (devsw == NULL)
163 return (0);
164
165 if (*devmajor < 0) {
166 for (bmajor = sys_bdevsws ; bmajor < max_bdevsws ; bmajor++) {
167 if (bdevsw[bmajor] != NULL)
168 continue;
169 for (i = 0 ; i < max_devsw_convs ; i++) {
170 if (devsw_conv[i].d_bmajor == bmajor)
171 break;
172 }
173 if (i != max_devsw_convs)
174 continue;
175 break;
176 }
177 *devmajor = bmajor;
178 }
179 if (*devmajor >= MAXDEVSW) {
180 #ifdef DEVSW_DEBUG
181 panic("bdevsw_attach: block majors exhausted");
182 #endif /* DEVSW_DEBUG */
183 return (ENOMEM);
184 }
185
186 if (*devmajor >= max_bdevsws) {
187 const struct bdevsw **newptr;
188 int old, new;
189
190 old = max_bdevsws;
191 new = *devmajor + 1;
192
193 newptr = malloc(new * BDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
194 if (newptr == NULL)
195 return (ENOMEM);
196 memset(newptr + old, 0, (new - old) * BDEVSW_SIZE);
197 if (old != 0) {
198 memcpy(newptr, bdevsw, old * BDEVSW_SIZE);
199 if (bdevsw != bdevsw0)
200 free(bdevsw, M_DEVBUF);
201 }
202 bdevsw = newptr;
203 max_bdevsws = new;
204 }
205
206 if (bdevsw[*devmajor] != NULL)
207 return (EEXIST);
208
209 bdevsw[*devmajor] = devsw;
210
211 return (0);
212 }
213
214 static int
215 cdevsw_attach(const char *devname, const struct cdevsw *devsw, int *devmajor)
216 {
217 int cmajor, i;
218
219 if (*devmajor < 0) {
220 for (cmajor = sys_cdevsws ; cmajor < max_cdevsws ; cmajor++) {
221 if (cdevsw[cmajor] != NULL)
222 continue;
223 for (i = 0 ; i < max_devsw_convs ; i++) {
224 if (devsw_conv[i].d_cmajor == cmajor)
225 break;
226 }
227 if (i != max_devsw_convs)
228 continue;
229 break;
230 }
231 *devmajor = cmajor;
232 }
233 if (*devmajor >= MAXDEVSW) {
234 #ifdef DEVSW_DEBUG
235 panic("cdevsw_attach: character majors exhausted");
236 #endif /* DEVSW_DEBUG */
237 return (ENOMEM);
238 }
239
240 if (*devmajor >= max_cdevsws) {
241 const struct cdevsw **newptr;
242 int old, new;
243
244 old = max_cdevsws;
245 new = *devmajor + 1;
246
247 newptr = malloc(new * CDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
248 if (newptr == NULL)
249 return (ENOMEM);
250 memset(newptr + old, 0, (new - old) * CDEVSW_SIZE);
251 if (old != 0) {
252 memcpy(newptr, cdevsw, old * CDEVSW_SIZE);
253 if (cdevsw != cdevsw0)
254 free(cdevsw, M_DEVBUF);
255 }
256 cdevsw = newptr;
257 max_cdevsws = new;
258 }
259
260 if (cdevsw[*devmajor] != NULL)
261 return (EEXIST);
262
263 cdevsw[*devmajor] = devsw;
264
265 return (0);
266 }
267
268 void
269 devsw_detach(const struct bdevsw *bdev, const struct cdevsw *cdev)
270 {
271 int i;
272
273 if (bdev != NULL) {
274 for (i = 0 ; i < max_bdevsws ; i++) {
275 if (bdevsw[i] != bdev)
276 continue;
277 bdevsw[i] = NULL;
278 break;
279 }
280 }
281 if (cdev != NULL) {
282 for (i = 0 ; i < max_cdevsws ; i++) {
283 if (cdevsw[i] != cdev)
284 continue;
285 cdevsw[i] = NULL;
286 break;
287 }
288 }
289 }
290
291 const struct bdevsw *
292 bdevsw_lookup(dev_t dev)
293 {
294 int bmajor;
295
296 if (dev == NODEV)
297 return (NULL);
298 bmajor = major(dev);
299 if (bmajor < 0 || bmajor >= max_bdevsws)
300 return (NULL);
301
302 return (bdevsw[bmajor]);
303 }
304
305 const struct cdevsw *
306 cdevsw_lookup(dev_t dev)
307 {
308 int cmajor;
309
310 if (dev == NODEV)
311 return (NULL);
312 cmajor = major(dev);
313 if (cmajor < 0 || cmajor >= max_cdevsws)
314 return (NULL);
315
316 return (cdevsw[cmajor]);
317 }
318
319 int
320 bdevsw_lookup_major(const struct bdevsw *bdev)
321 {
322 int bmajor;
323
324 for (bmajor = 0 ; bmajor < max_bdevsws ; bmajor++) {
325 if (bdevsw[bmajor] == bdev)
326 return (bmajor);
327 }
328
329 return (-1);
330 }
331
332 int
333 cdevsw_lookup_major(const struct cdevsw *cdev)
334 {
335 int cmajor;
336
337 for (cmajor = 0 ; cmajor < max_cdevsws ; cmajor++) {
338 if (cdevsw[cmajor] == cdev)
339 return (cmajor);
340 }
341
342 return (-1);
343 }
344
345 /*
346 * Convert from block major number to name.
347 */
348 const char *
349 devsw_blk2name(int bmajor)
350 {
351 int cmajor, i;
352
353 if (bmajor < 0 || bmajor >= max_bdevsws || bdevsw[bmajor] == NULL)
354 return (NULL);
355
356 for (i = 0 ; i < max_devsw_convs ; i++) {
357 if (devsw_conv[i].d_bmajor != bmajor)
358 continue;
359 cmajor = devsw_conv[i].d_cmajor;
360 if (cmajor < 0 || cmajor >= max_cdevsws ||
361 cdevsw[cmajor] == NULL)
362 return (NULL);
363 return (devsw_conv[i].d_name);
364 }
365
366 return (NULL);
367 }
368
369 /*
370 * Convert from device name to block major number.
371 */
372 int
373 devsw_name2blk(const char *name, char *devname, size_t devnamelen)
374 {
375 struct devsw_conv *conv;
376 int bmajor, i;
377
378 if (name == NULL)
379 return (-1);
380
381 for (i = 0 ; i < max_devsw_convs ; i++) {
382 conv = &devsw_conv[i];
383 if (conv->d_name == NULL)
384 continue;
385 if (strncmp(conv->d_name, name, strlen(conv->d_name)) != 0)
386 continue;
387 bmajor = conv->d_bmajor;
388 if (bmajor < 0 || bmajor >= max_bdevsws ||
389 bdevsw[bmajor] == NULL)
390 return (-1);
391 if (devname != NULL) {
392 #ifdef DEVSW_DEBUG
393 if (strlen(conv->d_name) >= devnamelen)
394 printf("devsw_name2blk: too short buffer");
395 #endif /* DEVSW_DEBUG */
396 strncpy(devname, conv->d_name, devnamelen);
397 devname[devnamelen - 1] = '\0';
398 }
399 return (bmajor);
400 }
401
402 return (-1);
403 }
404
405 /*
406 * Convert from character dev_t to block dev_t.
407 */
408 dev_t
409 devsw_chr2blk(dev_t cdev)
410 {
411 int bmajor, cmajor, i;
412
413 if (cdevsw_lookup(cdev) == NULL)
414 return (NODEV);
415
416 cmajor = major(cdev);
417
418 for (i = 0 ; i < max_devsw_convs ; i++) {
419 if (devsw_conv[i].d_cmajor != cmajor)
420 continue;
421 bmajor = devsw_conv[i].d_bmajor;
422 if (bmajor < 0 || bmajor >= max_bdevsws ||
423 bdevsw[bmajor] == NULL)
424 return (NODEV);
425 return (makedev(bmajor, minor(cdev)));
426 }
427
428 return (NODEV);
429 }
430
431 /*
432 * Convert from block dev_t to character dev_t.
433 */
434 dev_t
435 devsw_blk2chr(dev_t bdev)
436 {
437 int bmajor, cmajor, i;
438
439 if (bdevsw_lookup(bdev) == NULL)
440 return (NODEV);
441
442 bmajor = major(bdev);
443
444 for (i = 0 ; i < max_devsw_convs ; i++) {
445 if (devsw_conv[i].d_bmajor != bmajor)
446 continue;
447 cmajor = devsw_conv[i].d_cmajor;
448 if (cmajor < 0 || cmajor >= max_cdevsws ||
449 cdevsw[cmajor] == NULL)
450 return (NODEV);
451 return (makedev(cmajor, minor(bdev)));
452 }
453
454 return (NODEV);
455 }
456