subr_devsw.c revision 1.1.2.5 1 /* $NetBSD: subr_devsw.c,v 1.1.2.5 2002/05/22 10:57:12 gehenna 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;
67
68 int
69 devsw_attach(const char *devname, const struct bdevsw *bdev, int *bmajor,
70 const struct cdevsw *cdev, int *cmajor)
71 {
72 int i;
73
74 if (devname == NULL || cdev == NULL)
75 return (EINVAL);
76
77 if (bdevsw_lookup_major(bdev) != -1 ||
78 cdevsw_lookup_major(cdev) != -1)
79 return (EEXIST);
80
81 if (*cmajor < 0) {
82 for (i = 0 ; i < max_cdevsws ; i++) {
83 if (devsw_conv[i].d_name == NULL ||
84 strcmp(devname, devsw_conv[i].d_name) != 0)
85 continue;
86 *cmajor = i;
87 if (devsw_conv[i].d_bmajor != -1) {
88 if (bdev == NULL)
89 return (EINVAL);
90 if (*bmajor != -1 &&
91 *bmajor != devsw_conv[i].d_bmajor)
92 return (EINVAL);
93 *bmajor = devsw_conv[i].d_bmajor;
94 }
95 break;
96 }
97 }
98
99 if (bdev != NULL) {
100 if (*bmajor < 0) {
101 for (i = sys_bdevsws ; i < max_bdevsws ; i++) {
102 int j;
103
104 if (bdevsw[i] != NULL)
105 continue;
106 for (j = sys_cdevsws ; j < max_cdevsws ; j++) {
107 if (i == devsw_conv[i].d_bmajor)
108 break;
109 }
110 if (j != max_cdevsws)
111 continue;
112 *bmajor = i;
113 break;
114 }
115 if (*bmajor < 0)
116 *bmajor = max_bdevsws;
117 if (*bmajor >= MAXDEVSW)
118 return (EINVAL);
119 }
120
121 if (*bmajor >= max_bdevsws) {
122 int old = max_bdevsws, new = *bmajor + 1;
123 const struct bdevsw **newptr;
124
125 newptr = malloc(new * BDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
126 if (newptr == NULL)
127 return (ENOMEM);
128 memset(newptr + old, 0, (new - old) * BDEVSW_SIZE);
129 if (old != 0) {
130 memcpy(newptr, bdevsw, old * BDEVSW_SIZE);
131 if (bdevsw != bdevsw0)
132 free(bdevsw, M_DEVBUF);
133 }
134 bdevsw = newptr;
135 max_bdevsws = new;
136 }
137
138 if (bdevsw[*bmajor] != NULL)
139 return (EEXIST);
140 }
141
142 if (*cmajor < 0) {
143 for (i = sys_cdevsws ; i < max_cdevsws ; i++) {
144 if (cdevsw[i] != NULL || devsw_conv[i].d_name != NULL)
145 continue;
146 *cmajor = i;
147 break;
148 }
149 if (*cmajor < 0)
150 *cmajor = max_cdevsws;
151 if (*cmajor >= MAXDEVSW)
152 return (EINVAL);
153 }
154
155 if (*cmajor >= max_cdevsws) {
156 int old = max_cdevsws, new = *cmajor + 1;
157 const struct cdevsw **newptr;
158 struct devsw_conv *newconv;
159
160 newptr = malloc(new * CDEVSW_SIZE, M_DEVBUF, M_NOWAIT);
161 if (newptr == NULL)
162 return (ENOMEM);
163 memset(newptr + old, 0, (new - old) * CDEVSW_SIZE);
164 if (old != 0) {
165 memcpy(newptr, cdevsw, old * CDEVSW_SIZE);
166 if (cdevsw != cdevsw0)
167 free(cdevsw, M_DEVBUF);
168 }
169 cdevsw = newptr;
170 max_cdevsws = new;
171
172 newconv = malloc(new * DEVSWCONV_SIZE, M_DEVBUF, M_NOWAIT);
173 if (newconv == NULL)
174 return (ENOMEM);
175 for (i = old ; i < new ; i++) {
176 newconv[i].d_name = NULL;
177 newconv[i].d_bmajor = -1;
178 }
179 if (old != 0) {
180 memcpy(newconv, devsw_conv, old * DEVSWCONV_SIZE);
181 if (devsw_conv != devsw_conv0)
182 free(devsw_conv, M_DEVBUF);
183 }
184 devsw_conv = newconv;
185 }
186
187 if (cdevsw[*cmajor] != NULL)
188 return (EEXIST);
189
190 if (devsw_conv[*cmajor].d_name == NULL) {
191 char *name;
192 name = malloc(strlen(devname) + 1, M_DEVBUF, M_NOWAIT);
193 if (name == NULL)
194 return (ENOMEM);
195 strcpy(name, devname);
196 devsw_conv[*cmajor].d_name = name;
197 }
198
199 if (bdev != NULL) {
200 bdevsw[*bmajor] = bdev;
201 devsw_conv[*cmajor].d_bmajor = *bmajor;
202 }
203 cdevsw[*cmajor] = cdev;
204
205 return (0);
206 }
207
208 void
209 devsw_detach(const struct bdevsw *bdev, const struct cdevsw *cdev)
210 {
211 int i;
212
213 if (bdev != NULL) {
214 for (i = 0 ; i < max_bdevsws ; i++) {
215 if (bdevsw[i] != bdev)
216 continue;
217 bdevsw[i] = NULL;
218 break;
219 }
220 }
221 if (cdev != NULL) {
222 for (i = 0 ; i < max_cdevsws ; i++) {
223 if (cdevsw[i] != cdev)
224 continue;
225 cdevsw[i] = NULL;
226 break;
227 }
228 }
229 }
230
231 const struct bdevsw *
232 bdevsw_lookup(dev_t dev)
233 {
234 int bmajor;
235
236 if (dev == NODEV)
237 return (NULL);
238 bmajor = major(dev);
239 if (bmajor < 0 || bmajor >= max_bdevsws)
240 return (NULL);
241
242 return (bdevsw[bmajor]);
243 }
244
245 const struct cdevsw *
246 cdevsw_lookup(dev_t dev)
247 {
248 int cmajor;
249
250 if (dev == NODEV)
251 return (NULL);
252 cmajor = major(dev);
253 if (cmajor < 0 || cmajor >= max_cdevsws)
254 return (NULL);
255
256 return (cdevsw[cmajor]);
257 }
258
259 int
260 bdevsw_lookup_major(const struct bdevsw *bdev)
261 {
262 int bmajor;
263
264 for (bmajor = 0 ; bmajor < max_bdevsws ; bmajor++) {
265 if (bdevsw[bmajor] == bdev)
266 return (bmajor);
267 }
268
269 return (-1);
270 }
271
272 int
273 cdevsw_lookup_major(const struct cdevsw *cdev)
274 {
275 int cmajor;
276
277 for (cmajor = 0 ; cmajor < max_cdevsws ; cmajor++) {
278 if (cdevsw[cmajor] == cdev)
279 return (cmajor);
280 }
281
282 return (-1);
283 }
284
285 /*
286 * Convert from block major number to name.
287 */
288 const char *
289 devsw_blk2name(int bmajor)
290 {
291 int i;
292
293 if (bmajor < 0 || bmajor >= max_bdevsws)
294 return (NULL);
295 if (bdevsw[bmajor] == NULL)
296 return (NULL);
297
298 for (i = 0 ; i < max_cdevsws ; i++) {
299 if (devsw_conv[i].d_bmajor != bmajor)
300 continue;
301 if (cdevsw[i] == NULL)
302 return (NULL);
303 return (devsw_conv[i].d_name);
304 }
305
306 return (NULL);
307 }
308
309 /*
310 * Convert from device name to block major number.
311 */
312 int
313 devsw_name2blk(const char *name, char *devname, size_t devnamelen)
314 {
315 struct devsw_conv *conv;
316 int bmajor, i;
317
318 if (name == NULL)
319 return (-1);
320
321 for (i = 0 ; i < max_cdevsws ; i++) {
322 conv = &devsw_conv[i];
323 if (conv->d_name == NULL)
324 continue;
325 if (strncmp(conv->d_name, name, strlen(conv->d_name)) != 0)
326 continue;
327 bmajor = conv->d_bmajor;
328 if (bmajor < 0 || bmajor >= max_bdevsws ||
329 bdevsw[bmajor] == NULL)
330 return (-1);
331 if (devname != NULL) {
332 #ifdef DEVSW_DEBUG
333 if (strlen(conv->d_name) >= devnamelen)
334 printf("devsw_debug: too short buffer");
335 #endif /* DEVSW_DEBUG */
336 strncpy(devname, name, devnamelen);
337 devname[devnamelen - 1] = '\0';
338 }
339 return (bmajor);
340 }
341
342 return (-1);
343 }
344
345 /*
346 * Convert from character dev_t to block dev_t.
347 */
348 dev_t
349 devsw_chr2blk(dev_t cdev)
350 {
351 int bmajor;
352
353 if (cdevsw_lookup(cdev) == NULL)
354 return (NODEV);
355
356 bmajor = devsw_conv[major(cdev)].d_bmajor;
357 if (bmajor < 0 || bmajor >= max_bdevsws || bdevsw[bmajor] == NULL)
358 return (NODEV);
359
360 return (makedev(bmajor, minor(cdev)));
361 };
362
363 /*
364 * Convert from block dev_t to character dev_t.
365 */
366 dev_t
367 devsw_blk2chr(dev_t bdev)
368 {
369 int bmajor, i;
370
371 if (bdevsw_lookup(bdev) == NULL)
372 return (NODEV);
373
374 bmajor = major(bdev);
375
376 for (i = 0 ; i < max_cdevsws ; i++) {
377 if (devsw_conv[i].d_bmajor != bmajor)
378 continue;
379 if (cdevsw[i] == NULL)
380 return (NODEV);
381 return (makedev(i, minor(bdev)));
382 }
383
384 return (NODEV);
385 }
386