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