FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_devsw.c
1 /* $NetBSD: subr_devsw.c,v 1.7 2003/07/14 14:59:02 lukem 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@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 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.7 2003/07/14 14:59:02 lukem Exp $");
40
41 /*
42 * New device switch framework is developing.
43 * So debug options are always turned on.
44 */
45 #ifndef DEVSW_DEBUG
46 #define DEVSW_DEBUG
47 #endif /* DEVSW_DEBUG */
48
49 #include <sys/param.h>
50 #include <sys/conf.h>
51 #include <sys/malloc.h>
52 #include <sys/systm.h>
53
54 #ifdef DEVSW_DEBUG
55 #define DPRINTF(x) printf x
56 #else /* DEVSW_DEBUG */
57 #define DPRINTF(x)
58 #endif /* DEVSW_DEBUG */
59
60 #define MAXDEVSW 4096 /* the maximum of major device number */
61 #define BDEVSW_SIZE (sizeof(struct bdevsw *))
62 #define CDEVSW_SIZE (sizeof(struct cdevsw *))
63 #define DEVSWCONV_SIZE (sizeof(struct devsw_conv))
64
65 extern const struct bdevsw **bdevsw, *bdevsw0[];
66 extern const struct cdevsw **cdevsw, *cdevsw0[];
67 extern struct devsw_conv *devsw_conv, devsw_conv0[];
68 extern const int sys_bdevsws, sys_cdevsws;
69 extern int max_bdevsws, max_cdevsws, max_devsw_convs;
70
71 static int bdevsw_attach(const char *, const struct bdevsw *, int *);
72 static int cdevsw_attach(const char *, const struct cdevsw *, int *);
73
74 int
75 devsw_attach(const char *devname, const struct bdevsw *bdev, int *bmajor,
76 const struct cdevsw *cdev, int *cmajor)
77 {
78 struct devsw_conv *conv;
79 char *name;
80 int error, i;
81
82 if (devname == NULL || cdev == NULL)
83 return (EINVAL);
84
85 for (i = 0 ; i < max_devsw_convs ; i++) {
86 conv = &devsw_conv[i];
87 if (conv->d_name == NULL || strcmp(devname, conv->d_name) != 0)
88 continue;
89
90 if (*bmajor < 0)
91 *bmajor = conv->d_bmajor;
92 if (*cmajor < 0)
93 *cmajor = conv->d_cmajor;
94
95 if (*bmajor != conv->d_bmajor || *cmajor != conv->d_cmajor)
96 return (EINVAL);
97 if ((*bmajor >= 0 && bdev == NULL) || *cmajor < 0)
98 return (EINVAL);
99
100 if ((*bmajor >= 0 && bdevsw[*bmajor] != NULL) ||
101 cdevsw[*cmajor] != NULL)
102 return (EEXIST);
103
104 if (bdev != NULL)
105 bdevsw[*bmajor] = bdev;
106 cdevsw[*cmajor] = cdev;
107
108 return (0);
109 }
110
111 error = bdevsw_attach(devname, bdev, bmajor);
112 if (error != 0)
113 return (error);
114 error = cdevsw_attach(devname, cdev, cmajor);
115 if (error != 0) {
116 devsw_detach(bdev, NULL);
117 return (error);
118 }
119
120 for (i = 0 ; i < max_devsw_convs ; i++) {
121 if (devsw_conv[i].d_name == NULL)
122 break;
123 }
124 if (i == max_devsw_convs) {
125 struct devsw_conv *newptr;
126 int old, new;
127
128 old = max_devsw_convs;
129 new = old + 1;
130
131 newptr = malloc(new * DEVSWCONV_SIZE, M_DEVBUF, M_NOWAIT);
132 if (newptr == NULL) {
133 devsw_detach(bdev, cdev);
134 return (ENOMEM);
135 }
136 newptr[old].d_name = NULL;
137 newptr[old].d_bmajor = -1;
138 newptr[old].d_cmajor = -1;
139 memcpy(newptr, devsw_conv, old * DEVSWCONV_SIZE);
140 if (devsw_conv != devsw_conv0)
141 free(devsw_conv, M_DEVBUF);
142 devsw_conv = newptr;
143 max_devsw_convs = new;
144 }
145
146 i = strlen(devname) + 1;
147 name = malloc(i, M_DEVBUF, M_NOWAIT);
148 if (name == NULL) {
149 devsw_detach(bdev, cdev);
150 return (ENOMEM);
151 }
152 strlcpy(name, devname, i);
153
154 devsw_conv[i].d_name = name;
155 devsw_conv[i].d_bmajor = *bmajor;
156 devsw_conv[i].d_cmajor = *cmajor;
157
158 return (0);
159 }
160
161 static int
162 bdevsw_attach(const char *devname, const struct bdevsw *devsw, int *devmajor)
163 {
164 int bmajor, i;
165
166 if (devsw == NULL)
167 return (0);
168
169 if (*devmajor < 0) {
170 for (bmajor = sys_bdevsws ; bmajor < max_bdevsws ; bmajor++) {
171 if (bdevsw[bmajor] != NULL)
172 continue;
173 for (i = 0 ; i < max_devsw_convs ; i++) {
174 if (devsw_conv[i].d_bmajor == bmajor)
175 break;
176 }
177 if (i != max_devsw_convs)
178 continue;
179 break;
180 }
181 *devmajor = bmajor;
182 }
183 if (*devmajor >= MAXDEVSW) {
184 #ifdef DEVSW_DEBUG
185 panic("bdevsw_attach: block majors exhausted");
186 #endif /* DEVSW_DEBUG */
187 return (ENOMEM);
188 }
189
190 if (*devmajor >= max_bdevsws) {
191 const struct bdevsw **newptr;
192 int old, new;
193
194 old = max_bdevsws;
195 new = *devmajor + 1;
196
197 newptr = malloc(new * BDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
198 if (newptr == NULL)
199 return (ENOMEM);
200 memset(newptr + old, 0, (new - old) * BDEVSW_SIZE);
201 if (old != 0) {
202 memcpy(newptr, bdevsw, old * BDEVSW_SIZE);
203 if (bdevsw != bdevsw0)
204 free(bdevsw, M_DEVBUF);
205 }
206 bdevsw = newptr;
207 max_bdevsws = new;
208 }
209
210 if (bdevsw[*devmajor] != NULL)
211 return (EEXIST);
212
213 bdevsw[*devmajor] = devsw;
214
215 return (0);
216 }
217
218 static int
219 cdevsw_attach(const char *devname, const struct cdevsw *devsw, int *devmajor)
220 {
221 int cmajor, i;
222
223 if (*devmajor < 0) {
224 for (cmajor = sys_cdevsws ; cmajor < max_cdevsws ; cmajor++) {
225 if (cdevsw[cmajor] != NULL)
226 continue;
227 for (i = 0 ; i < max_devsw_convs ; i++) {
228 if (devsw_conv[i].d_cmajor == cmajor)
229 break;
230 }
231 if (i != max_devsw_convs)
232 continue;
233 break;
234 }
235 *devmajor = cmajor;
236 }
237 if (*devmajor >= MAXDEVSW) {
238 #ifdef DEVSW_DEBUG
239 panic("cdevsw_attach: character majors exhausted");
240 #endif /* DEVSW_DEBUG */
241 return (ENOMEM);
242 }
243
244 if (*devmajor >= max_cdevsws) {
245 const struct cdevsw **newptr;
246 int old, new;
247
248 old = max_cdevsws;
249 new = *devmajor + 1;
250
251 newptr = malloc(new * CDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
252 if (newptr == NULL)
253 return (ENOMEM);
254 memset(newptr + old, 0, (new - old) * CDEVSW_SIZE);
255 if (old != 0) {
256 memcpy(newptr, cdevsw, old * CDEVSW_SIZE);
257 if (cdevsw != cdevsw0)
258 free(cdevsw, M_DEVBUF);
259 }
260 cdevsw = newptr;
261 max_cdevsws = new;
262 }
263
264 if (cdevsw[*devmajor] != NULL)
265 return (EEXIST);
266
267 cdevsw[*devmajor] = devsw;
268
269 return (0);
270 }
271
272 void
273 devsw_detach(const struct bdevsw *bdev, const struct cdevsw *cdev)
274 {
275 int i;
276
277 if (bdev != NULL) {
278 for (i = 0 ; i < max_bdevsws ; i++) {
279 if (bdevsw[i] != bdev)
280 continue;
281 bdevsw[i] = NULL;
282 break;
283 }
284 }
285 if (cdev != NULL) {
286 for (i = 0 ; i < max_cdevsws ; i++) {
287 if (cdevsw[i] != cdev)
288 continue;
289 cdevsw[i] = NULL;
290 break;
291 }
292 }
293 }
294
295 const struct bdevsw *
296 bdevsw_lookup(dev_t dev)
297 {
298 int bmajor;
299
300 if (dev == NODEV)
301 return (NULL);
302 bmajor = major(dev);
303 if (bmajor < 0 || bmajor >= max_bdevsws)
304 return (NULL);
305
306 return (bdevsw[bmajor]);
307 }
308
309 const struct cdevsw *
310 cdevsw_lookup(dev_t dev)
311 {
312 int cmajor;
313
314 if (dev == NODEV)
315 return (NULL);
316 cmajor = major(dev);
317 if (cmajor < 0 || cmajor >= max_cdevsws)
318 return (NULL);
319
320 return (cdevsw[cmajor]);
321 }
322
323 int
324 bdevsw_lookup_major(const struct bdevsw *bdev)
325 {
326 int bmajor;
327
328 for (bmajor = 0 ; bmajor < max_bdevsws ; bmajor++) {
329 if (bdevsw[bmajor] == bdev)
330 return (bmajor);
331 }
332
333 return (-1);
334 }
335
336 int
337 cdevsw_lookup_major(const struct cdevsw *cdev)
338 {
339 int cmajor;
340
341 for (cmajor = 0 ; cmajor < max_cdevsws ; cmajor++) {
342 if (cdevsw[cmajor] == cdev)
343 return (cmajor);
344 }
345
346 return (-1);
347 }
348
349 /*
350 * Convert from block major number to name.
351 */
352 const char *
353 devsw_blk2name(int bmajor)
354 {
355 int cmajor, i;
356
357 if (bmajor < 0 || bmajor >= max_bdevsws || bdevsw[bmajor] == NULL)
358 return (NULL);
359
360 for (i = 0 ; i < max_devsw_convs ; i++) {
361 if (devsw_conv[i].d_bmajor != bmajor)
362 continue;
363 cmajor = devsw_conv[i].d_cmajor;
364 if (cmajor < 0 || cmajor >= max_cdevsws ||
365 cdevsw[cmajor] == NULL)
366 return (NULL);
367 return (devsw_conv[i].d_name);
368 }
369
370 return (NULL);
371 }
372
373 /*
374 * Convert from device name to block major number.
375 */
376 int
377 devsw_name2blk(const char *name, char *devname, size_t devnamelen)
378 {
379 struct devsw_conv *conv;
380 int bmajor, i;
381
382 if (name == NULL)
383 return (-1);
384
385 for (i = 0 ; i < max_devsw_convs ; i++) {
386 size_t len;
387
388 conv = &devsw_conv[i];
389 if (conv->d_name == NULL)
390 continue;
391 len = strlen(conv->d_name);
392 if (strncmp(conv->d_name, name, len) != 0)
393 continue;
394 if (*(name +len) && !isdigit(*(name + len)))
395 continue;
396 bmajor = conv->d_bmajor;
397 if (bmajor < 0 || bmajor >= max_bdevsws ||
398 bdevsw[bmajor] == NULL)
399 break;
400 if (devname != NULL) {
401 #ifdef DEVSW_DEBUG
402 if (strlen(conv->d_name) >= devnamelen)
403 printf("devsw_name2blk: too short buffer");
404 #endif /* DEVSW_DEBUG */
405 strncpy(devname, conv->d_name, devnamelen);
406 devname[devnamelen - 1] = '\0';
407 }
408 return (bmajor);
409 }
410
411 return (-1);
412 }
413
414 /*
415 * Convert from character dev_t to block dev_t.
416 */
417 dev_t
418 devsw_chr2blk(dev_t cdev)
419 {
420 int bmajor, cmajor, i;
421
422 if (cdevsw_lookup(cdev) == NULL)
423 return (NODEV);
424
425 cmajor = major(cdev);
426
427 for (i = 0 ; i < max_devsw_convs ; i++) {
428 if (devsw_conv[i].d_cmajor != cmajor)
429 continue;
430 bmajor = devsw_conv[i].d_bmajor;
431 if (bmajor < 0 || bmajor >= max_bdevsws ||
432 bdevsw[bmajor] == NULL)
433 return (NODEV);
434 return (makedev(bmajor, minor(cdev)));
435 }
436
437 return (NODEV);
438 }
439
440 /*
441 * Convert from block dev_t to character dev_t.
442 */
443 dev_t
444 devsw_blk2chr(dev_t bdev)
445 {
446 int bmajor, cmajor, i;
447
448 if (bdevsw_lookup(bdev) == NULL)
449 return (NODEV);
450
451 bmajor = major(bdev);
452
453 for (i = 0 ; i < max_devsw_convs ; i++) {
454 if (devsw_conv[i].d_bmajor != bmajor)
455 continue;
456 cmajor = devsw_conv[i].d_cmajor;
457 if (cmajor < 0 || cmajor >= max_cdevsws ||
458 cdevsw[cmajor] == NULL)
459 return (NODEV);
460 return (makedev(cmajor, minor(bdev)));
461 }
462
463 return (NODEV);
464 }
Cache object: a288d8cf7f70388f7d81d2b5f9957abd
|