Home | History | Annotate | Line # | Download | only in kern
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