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