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