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