The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_devsw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: cedb6bd5642dbd97b576f9f0f10a4300


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.