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