Home | History | Annotate | Line # | Download | only in kern
subr_device.c revision 1.1.2.2
      1 /* $NetBSD: subr_device.c,v 1.1.2.2 2008/01/30 22:08:51 cube Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996, 2000 Christopher G. Demetriou
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *          This product includes software developed for the
     18  *          NetBSD Project.  See http://www.NetBSD.org/ for
     19  *          information about NetBSD.
     20  * 4. The name of the author may not be used to endorse or promote products
     21  *    derived from this software without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  *
     34  * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
     35  */
     36 
     37 /*
     38  * Copyright (c) 1992, 1993
     39  *	The Regents of the University of California.  All rights reserved.
     40  *
     41  * This software was developed by the Computer Systems Engineering group
     42  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     43  * contributed to Berkeley.
     44  *
     45  * All advertising materials mentioning features or use of this software
     46  * must display the following acknowledgement:
     47  *	This product includes software developed by the University of
     48  *	California, Lawrence Berkeley Laboratories.
     49  *
     50  * Redistribution and use in source and binary forms, with or without
     51  * modification, are permitted provided that the following conditions
     52  * are met:
     53  * 1. Redistributions of source code must retain the above copyright
     54  *    notice, this list of conditions and the following disclaimer.
     55  * 2. Redistributions in binary form must reproduce the above copyright
     56  *    notice, this list of conditions and the following disclaimer in the
     57  *    documentation and/or other materials provided with the distribution.
     58  * 3. Neither the name of the University nor the names of its contributors
     59  *    may be used to endorse or promote products derived from this software
     60  *    without specific prior written permission.
     61  *
     62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     72  * SUCH DAMAGE.
     73  *
     74  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
     75  *
     76  *	@(#)subr_autoconf.c	8.3 (Berkeley) 5/17/94
     77  */
     78 
     79 #include <sys/cdefs.h>
     80 __KERNEL_RCSID(0, "$NetBSD: subr_device.c,v 1.1.2.2 2008/01/30 22:08:51 cube Exp $");
     81 
     82 #include <sys/param.h>
     83 #include <sys/device.h>
     84 #include <sys/malloc.h>
     85 
     86 /* list of all devices */
     87 struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
     88 
     89 /*
     90  * device_lookup:
     91  *
     92  *	Look up a device instance for a given driver.
     93  */
     94 void *
     95 device_lookup(cfdriver_t cd, int unit)
     96 {
     97 
     98 	if (unit < 0 || unit >= cd->cd_ndevs)
     99 		return (NULL);
    100 
    101 	return (cd->cd_devs[unit]);
    102 }
    103 
    104 /*
    105  * Accessor functions for the device_t type.
    106  */
    107 devclass_t
    108 device_class(device_t dev)
    109 {
    110 
    111 	return (dev->dv_class);
    112 }
    113 
    114 cfdata_t
    115 device_cfdata(device_t dev)
    116 {
    117 
    118 	return (dev->dv_cfdata);
    119 }
    120 
    121 cfdriver_t
    122 device_cfdriver(device_t dev)
    123 {
    124 
    125 	return (dev->dv_cfdriver);
    126 }
    127 
    128 cfattach_t
    129 device_cfattach(device_t dev)
    130 {
    131 
    132 	return (dev->dv_cfattach);
    133 }
    134 
    135 int
    136 device_unit(device_t dev)
    137 {
    138 
    139 	return (dev->dv_unit);
    140 }
    141 
    142 const char *
    143 device_xname(device_t dev)
    144 {
    145 
    146 	return (dev->dv_xname);
    147 }
    148 
    149 device_t
    150 device_parent(device_t dev)
    151 {
    152 
    153 	return (dev->dv_parent);
    154 }
    155 
    156 bool
    157 device_is_active(device_t dev)
    158 {
    159 	int active_flags;
    160 
    161 	active_flags = DVF_ACTIVE;
    162 	active_flags |= DVF_CLASS_SUSPENDED;
    163 	active_flags |= DVF_DRIVER_SUSPENDED;
    164 	active_flags |= DVF_BUS_SUSPENDED;
    165 
    166 	return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
    167 }
    168 
    169 bool
    170 device_is_enabled(device_t dev)
    171 {
    172 	return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
    173 }
    174 
    175 bool
    176 device_has_power(device_t dev)
    177 {
    178 	int active_flags;
    179 
    180 	active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
    181 
    182 	return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
    183 }
    184 
    185 int
    186 device_locator(device_t dev, u_int locnum)
    187 {
    188 
    189 	KASSERT(dev->dv_locators != NULL);
    190 	return (dev->dv_locators[locnum]);
    191 }
    192 
    193 void *
    194 device_private(device_t dev)
    195 {
    196 
    197 	/*
    198 	 * The reason why device_private(NULL) is allowed is to simplify the
    199 	 * work of a lot of userspace request handlers (i.e., c/bdev
    200 	 * handlers) which grab cfdriver_t->cd_units[n].
    201 	 * It avoids having them test for it to be NULL and only then calling
    202 	 * device_private.
    203 	 */
    204 	return dev == NULL ? NULL : dev->dv_private;
    205 }
    206 
    207 prop_dictionary_t
    208 device_properties(device_t dev)
    209 {
    210 
    211 	return (dev->dv_properties);
    212 }
    213 
    214 /*
    215  * device_is_a:
    216  *
    217  *	Returns true if the device is an instance of the specified
    218  *	driver.
    219  */
    220 bool
    221 device_is_a(device_t dev, const char *dname)
    222 {
    223 
    224 	return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
    225 }
    226 
    227 /*
    228  * Power management related functions.
    229  */
    230 
    231 bool
    232 device_pmf_is_registered(device_t dev)
    233 {
    234 	return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
    235 }
    236 
    237 bool
    238 device_pmf_driver_suspend(device_t dev)
    239 {
    240 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
    241 		return true;
    242 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
    243 		return false;
    244 	if (*dev->dv_driver_suspend != NULL &&
    245 	    !(*dev->dv_driver_suspend)(dev))
    246 		return false;
    247 
    248 	dev->dv_flags |= DVF_DRIVER_SUSPENDED;
    249 	return true;
    250 }
    251 
    252 bool
    253 device_pmf_driver_resume(device_t dev)
    254 {
    255 	if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
    256 		return true;
    257 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
    258 		return false;
    259 	if (*dev->dv_driver_resume != NULL &&
    260 	    !(*dev->dv_driver_resume)(dev))
    261 		return false;
    262 
    263 	dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
    264 	return true;
    265 }
    266 
    267 void
    268 device_pmf_driver_register(device_t dev,
    269     bool (*suspend)(device_t), bool (*resume)(device_t))
    270 {
    271 	dev->dv_driver_suspend = suspend;
    272 	dev->dv_driver_resume = resume;
    273 	dev->dv_flags |= DVF_POWER_HANDLERS;
    274 }
    275 
    276 void
    277 device_pmf_driver_deregister(device_t dev)
    278 {
    279 	dev->dv_driver_suspend = NULL;
    280 	dev->dv_driver_resume = NULL;
    281 	dev->dv_flags &= ~DVF_POWER_HANDLERS;
    282 }
    283 
    284 bool
    285 device_pmf_driver_child_register(device_t dev)
    286 {
    287 	device_t parent = device_parent(dev);
    288 
    289 	if (parent == NULL || parent->dv_driver_child_register == NULL)
    290 		return true;
    291 	return (*parent->dv_driver_child_register)(dev);
    292 }
    293 
    294 void
    295 device_pmf_driver_set_child_register(device_t dev,
    296     bool (*child_register)(device_t))
    297 {
    298 	dev->dv_driver_child_register = child_register;
    299 }
    300 
    301 void *
    302 device_pmf_bus_private(device_t dev)
    303 {
    304 	return dev->dv_bus_private;
    305 }
    306 
    307 bool
    308 device_pmf_bus_suspend(device_t dev)
    309 {
    310 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
    311 		return true;
    312 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
    313 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
    314 		return false;
    315 	if (*dev->dv_bus_suspend != NULL &&
    316 	    !(*dev->dv_bus_suspend)(dev))
    317 		return false;
    318 
    319 	dev->dv_flags |= DVF_BUS_SUSPENDED;
    320 	return true;
    321 }
    322 
    323 bool
    324 device_pmf_bus_resume(device_t dev)
    325 {
    326 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
    327 		return true;
    328 	if (*dev->dv_bus_resume != NULL &&
    329 	    !(*dev->dv_bus_resume)(dev))
    330 		return false;
    331 
    332 	dev->dv_flags &= ~DVF_BUS_SUSPENDED;
    333 	return true;
    334 }
    335 
    336 void
    337 device_pmf_bus_register(device_t dev, void *priv,
    338     bool (*suspend)(device_t), bool (*resume)(device_t),
    339     void (*deregister)(device_t))
    340 {
    341 	dev->dv_bus_private = priv;
    342 	dev->dv_bus_resume = resume;
    343 	dev->dv_bus_suspend = suspend;
    344 	dev->dv_bus_deregister = deregister;
    345 }
    346 
    347 void
    348 device_pmf_bus_deregister(device_t dev)
    349 {
    350 	if (dev->dv_bus_deregister == NULL)
    351 		return;
    352 	(*dev->dv_bus_deregister)(dev);
    353 	dev->dv_bus_private = NULL;
    354 	dev->dv_bus_suspend = NULL;
    355 	dev->dv_bus_resume = NULL;
    356 	dev->dv_bus_deregister = NULL;
    357 }
    358 
    359 void *
    360 device_pmf_class_private(device_t dev)
    361 {
    362 	return dev->dv_class_private;
    363 }
    364 
    365 bool
    366 device_pmf_class_suspend(device_t dev)
    367 {
    368 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
    369 		return true;
    370 	if (*dev->dv_class_suspend != NULL &&
    371 	    !(*dev->dv_class_suspend)(dev))
    372 		return false;
    373 
    374 	dev->dv_flags |= DVF_CLASS_SUSPENDED;
    375 	return true;
    376 }
    377 
    378 bool
    379 device_pmf_class_resume(device_t dev)
    380 {
    381 	if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
    382 		return true;
    383 	if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
    384 	    (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
    385 		return false;
    386 	if (*dev->dv_class_resume != NULL &&
    387 	    !(*dev->dv_class_resume)(dev))
    388 		return false;
    389 
    390 	dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
    391 	return true;
    392 }
    393 
    394 void
    395 device_pmf_class_register(device_t dev, void *priv,
    396     bool (*suspend)(device_t), bool (*resume)(device_t),
    397     void (*deregister)(device_t))
    398 {
    399 	dev->dv_class_private = priv;
    400 	dev->dv_class_suspend = suspend;
    401 	dev->dv_class_resume = resume;
    402 	dev->dv_class_deregister = deregister;
    403 }
    404 
    405 void
    406 device_pmf_class_deregister(device_t dev)
    407 {
    408 	if (dev->dv_class_deregister == NULL)
    409 		return;
    410 	(*dev->dv_class_deregister)(dev);
    411 	dev->dv_class_private = NULL;
    412 	dev->dv_class_suspend = NULL;
    413 	dev->dv_class_resume = NULL;
    414 	dev->dv_class_deregister = NULL;
    415 }
    416 
    417 bool
    418 device_active(device_t dev, devactive_t type)
    419 {
    420 	size_t i;
    421 
    422 	if (dev->dv_activity_count == 0)
    423 		return false;
    424 
    425 	for (i = 0; i < dev->dv_activity_count; ++i)
    426 		(*dev->dv_activity_handlers[i])(dev, type);
    427 
    428 	return true;
    429 }
    430 
    431 bool
    432 device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
    433 {
    434 	void (**new_handlers)(device_t, devactive_t);
    435 	void (**old_handlers)(device_t, devactive_t);
    436 	size_t i, new_size;
    437 	int s;
    438 
    439 	old_handlers = dev->dv_activity_handlers;
    440 
    441 	for (i = 0; i < dev->dv_activity_count; ++i) {
    442 		if (old_handlers[i] == handler)
    443 			panic("Double registering of idle handlers");
    444 	}
    445 
    446 	new_size = dev->dv_activity_count + 1;
    447 	new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF, M_WAITOK);
    448 
    449 	memcpy(new_handlers, old_handlers,
    450 	    sizeof(void *) * dev->dv_activity_count);
    451 	new_handlers[new_size - 1] = handler;
    452 
    453 	s = splhigh();
    454 	dev->dv_activity_count = new_size;
    455 	dev->dv_activity_handlers = new_handlers;
    456 	splx(s);
    457 
    458 	if (old_handlers != NULL)
    459 		free(old_handlers, M_DEVBUF);
    460 
    461 	return true;
    462 }
    463 
    464 void
    465 device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
    466 {
    467 	void (**new_handlers)(device_t, devactive_t);
    468 	void (**old_handlers)(device_t, devactive_t);
    469 	size_t i, new_size;
    470 	int s;
    471 
    472 	old_handlers = dev->dv_activity_handlers;
    473 
    474 	for (i = 0; i < dev->dv_activity_count; ++i) {
    475 		if (old_handlers[i] == handler)
    476 			break;
    477 	}
    478 
    479 	if (i == dev->dv_activity_count)
    480 		return; /* XXX panic? */
    481 
    482 	new_size = dev->dv_activity_count - 1;
    483 
    484 	if (new_size == 0) {
    485 		new_handlers = NULL;
    486 	} else {
    487 		new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF,
    488 		    M_WAITOK);
    489 		memcpy(new_handlers, old_handlers, sizeof(void *) * i);
    490 		memcpy(new_handlers + i, old_handlers + i + 1,
    491 		    sizeof(void *) * (new_size - i));
    492 	}
    493 
    494 	s = splhigh();
    495 	dev->dv_activity_count = new_size;
    496 	dev->dv_activity_handlers = new_handlers;
    497 	splx(s);
    498 
    499 	free(old_handlers, M_DEVBUF);
    500 }
    501