1 /* $NetBSD: subr_devsw.c,v 1.5 2003/02/01 11:12:35 mrg 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 size_t len; 383 384 conv = &devsw_conv[i]; 385 if (conv->d_name == NULL) 386 continue; 387 len = strlen(conv->d_name); 388 if (strncmp(conv->d_name, name, len) != 0) 389 continue; 390 if (*(name +len) && !isdigit(*(name + len))) 391 continue; 392 bmajor = conv->d_bmajor; 393 if (bmajor < 0 || bmajor >= max_bdevsws || 394 bdevsw[bmajor] == NULL) 395 break; 396 if (devname != NULL) { 397 #ifdef DEVSW_DEBUG 398 if (strlen(conv->d_name) >= devnamelen) 399 printf("devsw_name2blk: too short buffer"); 400 #endif /* DEVSW_DEBUG */ 401 strncpy(devname, conv->d_name, devnamelen); 402 devname[devnamelen - 1] = '\0'; 403 } 404 return (bmajor); 405 } 406 407 return (-1); 408 } 409 410 /* 411 * Convert from character dev_t to block dev_t. 412 */ 413 dev_t 414 devsw_chr2blk(dev_t cdev) 415 { 416 int bmajor, cmajor, i; 417 418 if (cdevsw_lookup(cdev) == NULL) 419 return (NODEV); 420 421 cmajor = major(cdev); 422 423 for (i = 0 ; i < max_devsw_convs ; i++) { 424 if (devsw_conv[i].d_cmajor != cmajor) 425 continue; 426 bmajor = devsw_conv[i].d_bmajor; 427 if (bmajor < 0 || bmajor >= max_bdevsws || 428 bdevsw[bmajor] == NULL) 429 return (NODEV); 430 return (makedev(bmajor, minor(cdev))); 431 } 432 433 return (NODEV); 434 } 435 436 /* 437 * Convert from block dev_t to character dev_t. 438 */ 439 dev_t 440 devsw_blk2chr(dev_t bdev) 441 { 442 int bmajor, cmajor, i; 443 444 if (bdevsw_lookup(bdev) == NULL) 445 return (NODEV); 446 447 bmajor = major(bdev); 448 449 for (i = 0 ; i < max_devsw_convs ; i++) { 450 if (devsw_conv[i].d_bmajor != bmajor) 451 continue; 452 cmajor = devsw_conv[i].d_cmajor; 453 if (cmajor < 0 || cmajor >= max_cdevsws || 454 cdevsw[cmajor] == NULL) 455 return (NODEV); 456 return (makedev(cmajor, minor(bdev))); 457 } 458 459 return (NODEV); 460 } 461