Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: subr_device.c,v 1.16 2025/10/04 01:12:15 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006, 2021, 2025 The NetBSD Foundation, Inc.
      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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: subr_device.c,v 1.16 2025/10/04 01:12:15 thorpej Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/device.h>
     34 #include <sys/device_impl.h>
     35 #include <sys/kmem.h>
     36 #include <sys/systm.h>
     37 
     38 #include <sys/device_calls.h>
     39 
     40 /* Root device. */
     41 device_t			root_device;
     42 
     43 /*
     44  * devhandle_t accessors / mutators.
     45  */
     46 
     47 static bool
     48 devhandle_is_valid_internal(const devhandle_t * const handlep)
     49 {
     50 	if (handlep->impl == NULL) {
     51 		return false;
     52 	}
     53 	return handlep->impl->type != DEVHANDLE_TYPE_INVALID;
     54 }
     55 
     56 bool
     57 devhandle_is_valid(devhandle_t handle)
     58 {
     59 	return devhandle_is_valid_internal(&handle);
     60 }
     61 
     62 devhandle_t
     63 devhandle_invalid(void)
     64 {
     65 	static const devhandle_t invalid_devhandle = {
     66 		.impl = NULL,
     67 		.uintptr = 0,
     68 	};
     69 	return invalid_devhandle;
     70 }
     71 
     72 devhandle_type_t
     73 devhandle_type(devhandle_t handle)
     74 {
     75 	if (!devhandle_is_valid_internal(&handle)) {
     76 		return DEVHANDLE_TYPE_INVALID;
     77 	}
     78 
     79 	return handle.impl->type;
     80 }
     81 
     82 int
     83 devhandle_compare(devhandle_t handle1, devhandle_t handle2)
     84 {
     85 	devhandle_type_t type1 = devhandle_type(handle1);
     86 	devhandle_type_t type2 = devhandle_type(handle2);
     87 
     88 	if (type1 == DEVHANDLE_TYPE_INVALID) {
     89 		return -1;
     90 	}
     91 	if (type2 == DEVHANDLE_TYPE_INVALID) {
     92 		return 1;
     93 	}
     94 
     95 	if (type1 < type2) {
     96 		return -1;
     97 	}
     98 	if (type1 > type2) {
     99 		return 1;
    100 	}
    101 
    102 	/* For private handles, we also compare the impl pointers. */
    103 	if (type1 == DEVHANDLE_TYPE_PRIVATE) {
    104 		intptr_t impl1 = (intptr_t)handle1.impl;
    105 		intptr_t impl2 = (intptr_t)handle2.impl;
    106 
    107 		if (impl1 < impl2) {
    108 			return -1;
    109 		}
    110 		if (impl1 > impl2) {
    111 			return 1;
    112 		}
    113 	}
    114 
    115 	if (handle1.integer < handle2.integer) {
    116 		return -1;
    117 	}
    118 	if (handle1.integer > handle2.integer) {
    119 		return 1;
    120 	}
    121 
    122 	return 0;
    123 }
    124 
    125 device_call_t
    126 devhandle_lookup_device_call(devhandle_t handle, const char *name,
    127     devhandle_t *call_handlep)
    128 {
    129 	const struct devhandle_impl *impl;
    130 	device_call_t call;
    131 
    132 	/*
    133 	 * The back-end can override the handle to use for the call,
    134 	 * if needed.
    135 	 */
    136 	*call_handlep = handle;
    137 
    138 	for (impl = handle.impl; impl != NULL; impl = impl->super) {
    139 		if (impl->lookup_device_call != NULL) {
    140 			call = impl->lookup_device_call(handle, name,
    141 			    call_handlep);
    142 			if (call != NULL) {
    143 				return call;
    144 			}
    145 		}
    146 	}
    147 	return NULL;
    148 }
    149 
    150 void
    151 devhandle_impl_subclass(struct devhandle_impl *new_impl,
    152     const struct devhandle_impl *super,
    153     device_call_t (*new_lookup)(devhandle_t, const char *, devhandle_t *))
    154 {
    155 	new_impl->type = super->type;
    156 	new_impl->super = super;
    157 	new_impl->lookup_device_call = new_lookup;
    158 }
    159 
    160 /*
    161  * Helper function that provides a short-hand method of the common
    162  * "subclass a device handle" flow.
    163  */
    164 devhandle_t
    165 devhandle_subclass(devhandle_t handle,
    166     struct devhandle_impl *new_impl,
    167     device_call_t (*new_lookup)(devhandle_t, const char *, devhandle_t *))
    168 {
    169 	devhandle_impl_subclass(new_impl, handle.impl, new_lookup);
    170 	handle.impl = new_impl;
    171 
    172 	return handle;
    173 }
    174 
    175 /*
    176  * Accessor functions for the device_t type.
    177  */
    178 
    179 devclass_t
    180 device_class(device_t dev)
    181 {
    182 
    183 	return dev->dv_class;
    184 }
    185 
    186 cfdata_t
    187 device_cfdata(device_t dev)
    188 {
    189 
    190 	return dev->dv_cfdata;
    191 }
    192 
    193 cfdriver_t
    194 device_cfdriver(device_t dev)
    195 {
    196 
    197 	return dev->dv_cfdriver;
    198 }
    199 
    200 cfattach_t
    201 device_cfattach(device_t dev)
    202 {
    203 
    204 	return dev->dv_cfattach;
    205 }
    206 
    207 int
    208 device_unit(device_t dev)
    209 {
    210 
    211 	return dev->dv_unit;
    212 }
    213 
    214 const char *
    215 device_xname(device_t dev)
    216 {
    217 
    218 	return dev->dv_xname;
    219 }
    220 
    221 device_t
    222 device_parent(device_t dev)
    223 {
    224 
    225 	return dev->dv_parent;
    226 }
    227 
    228 bool
    229 device_activation(device_t dev, devact_level_t level)
    230 {
    231 	int active_flags;
    232 
    233 	active_flags = DVF_ACTIVE;
    234 	switch (level) {
    235 	case DEVACT_LEVEL_FULL:
    236 		active_flags |= DVF_CLASS_SUSPENDED;
    237 		/*FALLTHROUGH*/
    238 	case DEVACT_LEVEL_DRIVER:
    239 		active_flags |= DVF_DRIVER_SUSPENDED;
    240 		/*FALLTHROUGH*/
    241 	case DEVACT_LEVEL_BUS:
    242 		active_flags |= DVF_BUS_SUSPENDED;
    243 		break;
    244 	}
    245 
    246 	return (dev->dv_flags & active_flags) == DVF_ACTIVE;
    247 }
    248 
    249 bool
    250 device_is_active(device_t dev)
    251 {
    252 	int active_flags;
    253 
    254 	active_flags = DVF_ACTIVE;
    255 	active_flags |= DVF_CLASS_SUSPENDED;
    256 	active_flags |= DVF_DRIVER_SUSPENDED;
    257 	active_flags |= DVF_BUS_SUSPENDED;
    258 
    259 	return (dev->dv_flags & active_flags) == DVF_ACTIVE;
    260 }
    261 
    262 bool
    263 device_is_enabled(device_t dev)
    264 {
    265 	return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
    266 }
    267 
    268 bool
    269 device_has_power(device_t dev)
    270 {
    271 	int active_flags;
    272 
    273 	active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
    274 
    275 	return (dev->dv_flags & active_flags) == DVF_ACTIVE;
    276 }
    277 
    278 int
    279 device_locator(device_t dev, u_int locnum)
    280 {
    281 
    282 	KASSERT(dev->dv_locators != NULL);
    283 	return dev->dv_locators[locnum];
    284 }
    285 
    286 void *
    287 device_private(device_t dev)
    288 {
    289 
    290 	/*
    291 	 * The reason why device_private(NULL) is allowed is to simplify the
    292 	 * work of a lot of userspace request handlers (i.e., c/bdev
    293 	 * handlers) which grab cfdriver_t->cd_units[n].
    294 	 * It avoids having them test for it to be NULL and only then calling
    295 	 * device_private.
    296 	 */
    297 	return dev == NULL ? NULL : dev->dv_private;
    298 }
    299 
    300 void
    301 device_set_private(device_t dev, void *private)
    302 {
    303 
    304 	KASSERTMSG(dev->dv_private == NULL, "device_set_private(%p, %p):"
    305 	    " device %s already has private set to %p",
    306 	    dev, private, device_xname(dev), device_private(dev));
    307 	KASSERT(private != NULL);
    308 	dev->dv_private = private;
    309 }
    310 
    311 prop_dictionary_t
    312 device_properties(device_t dev)
    313 {
    314 
    315 	return dev->dv_properties;
    316 }
    317 
    318 /*
    319  * device_is_a:
    320  *
    321  *	Returns true if the device is an instance of the specified
    322  *	driver.
    323  */
    324 bool
    325 device_is_a(device_t dev, const char *dname)
    326 {
    327 	if (dev == NULL || dev->dv_cfdriver == NULL) {
    328 		return false;
    329 	}
    330 
    331 	return strcmp(dev->dv_cfdriver->cd_name, dname) == 0;
    332 }
    333 
    334 /*
    335  * device_attached_to_iattr:
    336  *
    337  *	Returns true if the device attached to the specified interface
    338  *	attribute.
    339  */
    340 bool
    341 device_attached_to_iattr(device_t dev, const char *iattr)
    342 {
    343 	cfdata_t cfdata = device_cfdata(dev);
    344 	const struct cfparent *pspec;
    345 
    346 	if (cfdata == NULL || (pspec = cfdata->cf_pspec) == NULL) {
    347 		return false;
    348 	}
    349 
    350 	return strcmp(pspec->cfp_iattr, iattr) == 0;
    351 }
    352 
    353 void
    354 device_set_handle(device_t dev, devhandle_t handle)
    355 {
    356 	dev->dv_handle = handle;
    357 }
    358 
    359 devhandle_t
    360 device_handle(device_t dev)
    361 {
    362 	return dev->dv_handle;
    363 }
    364 
    365 int
    366 device_call_generic(device_t dev, devhandle_t handle,
    367     const struct device_call_generic *gen)
    368 {
    369 	device_call_t call;
    370 	devhandle_t call_handle;
    371 
    372 	call = devhandle_lookup_device_call(handle, gen->name, &call_handle);
    373 	if (call == NULL) {
    374 		return ENOTSUP;
    375 	}
    376 	return call(dev, call_handle, gen->args);
    377 }
    378 
    379 int
    380 device_enumerate_children(device_t dev,
    381     bool (*callback)(device_t, devhandle_t, void *),
    382     void *callback_arg)
    383 {
    384 	struct device_enumerate_children_args args = {
    385 		.callback = callback,
    386 		.callback_arg = callback_arg,
    387 	};
    388 
    389 	return device_call(dev, DEVICE_ENUMERATE_CHILDREN(&args));
    390 }
    391 
    392 /*****************************************************************************
    393  * Device properties infrastructure.
    394  *****************************************************************************/
    395 
    396 static int
    397 device_getprop_dict(device_t dev, struct device_get_property_args *args)
    398 {
    399 	prop_dictionary_t dict = dev->dv_properties;
    400 	prop_object_t propval;
    401 	bool rv;
    402 
    403 	/*
    404 	 * Return ENOENT before any other error so that we can rely
    405 	 * on that error to tell us "property does not exist in this
    406 	 * layer, so go check the platform device tree".
    407 	 */
    408 	propval = prop_dictionary_get(dict, args->prop);
    409 	if (propval == NULL) {
    410 		return ENOENT;
    411 	}
    412 
    413 	/*
    414 	 * Validate the requested type.  Because it can be convenient
    415 	 * to do so (e.g. properties that constain a strlist, maybe that
    416 	 * property was set as a single string), we allow STRING objects
    417 	 * to be requested as DATA.
    418 	 */
    419 	prop_type_t objtype = prop_object_type(propval);
    420 	switch (args->reqtype) {
    421 	case PROP_TYPE_DATA:
    422 		KASSERT(args->buf != NULL);
    423 		KASSERT(args->buflen != 0);
    424 		if (objtype != PROP_TYPE_DATA && objtype != PROP_TYPE_STRING) {
    425 			return EFTYPE;
    426 		}
    427 		break;
    428 
    429 	case PROP_TYPE_UNKNOWN:
    430 		KASSERT(args->buf == NULL);
    431 		KASSERT(args->buflen == 0);
    432 		break;
    433 
    434 	default:
    435 		KASSERT(args->buf != NULL);
    436 		KASSERT(args->buflen != 0);
    437 		if (args->reqtype != objtype) {
    438 			return EFTYPE;
    439 		}
    440 	}
    441 
    442 	args->encoding = _BYTE_ORDER;	/* these are always native */
    443 	args->type = objtype;
    444 
    445 	switch (args->type) {
    446 	case PROP_TYPE_NUMBER:
    447 		/* prop_number_size() returns bits. */
    448 		args->propsize = prop_number_size(propval) >> 3;
    449 		if (args->buf != NULL) {
    450 			KASSERT(args->buflen == sizeof(uint64_t));
    451 			/*
    452 			 * Fetching a -ve value as uint64_t will fail
    453 			 * a range check, so check what we have before
    454 			 * we fetch.  We'll reconcile it based on what
    455 			 * the caller is asking for later.
    456 			 */
    457 			if (prop_number_unsigned(propval)) {
    458 				rv = prop_number_uint64_value(propval,
    459 				    args->buf);
    460 			} else {
    461 				rv = prop_number_int64_value(propval,
    462 				    args->buf);
    463 			}
    464 			if (! rv) {
    465 				return EIO;	/* off the rails */
    466 			}
    467 		}
    468 		break;
    469 
    470 	case PROP_TYPE_STRING:
    471 		/* +1 for trailing NUL */
    472 		args->propsize = prop_string_size(propval) + 1;
    473 		if (args->buf != NULL) {
    474 			if (args->buflen < args->propsize) {
    475 				return EFBIG;
    476 			}
    477 			strlcpy(args->buf, prop_string_value(propval),
    478 			    args->buflen);
    479 		}
    480 		break;
    481 
    482 	case PROP_TYPE_DATA:
    483 		args->propsize = prop_data_size(propval);
    484 		if (args->buf != NULL) {
    485 			if (args->buflen < args->propsize) {
    486 				return EFBIG;
    487 			}
    488 			memcpy(args->buf, prop_data_value(propval),
    489 			    args->propsize);
    490 		}
    491 		break;
    492 
    493 	case PROP_TYPE_BOOL:
    494 		args->propsize = sizeof(bool);
    495 		if (args->buf != NULL) {
    496 			KASSERT(args->buflen == sizeof(bool));
    497 			*(bool *)args->buf = prop_bool_value(propval);
    498 		}
    499 		break;
    500 
    501 	default:
    502 		return EFTYPE;
    503 	}
    504 
    505 	return 0;
    506 }
    507 
    508 static int
    509 device_getprop_internal(device_t dev, struct device_get_property_args *args)
    510 {
    511 	int error;
    512 
    513 	/* Normalize arguments. */
    514 	if (args->buf == NULL || args->buflen == 0) {
    515 		args->buf = NULL;
    516 		args->buflen = 0;
    517 	} else if (args->buflen > SSIZE_MAX) {
    518 		/* Sizes must fit in ssize_t. */
    519 		args->buflen = SSIZE_MAX;
    520 	}
    521 
    522 	/* Poison args->propsize for sanity check later. */
    523 	args->propsize = -1;
    524 
    525 	args->flags = 0;
    526 
    527 	/* Check the device's property dictionary first. */
    528 	error = device_getprop_dict(dev, args);
    529 	if (error != ENOENT) {
    530 		KASSERT(error != 0 ||
    531 			args->encoding == _BYTE_ORDER);
    532 		goto out;
    533 	}
    534 
    535 	/*
    536 	 * Not in the device's property dictionary; check with
    537 	 * the platform device tree.
    538 	 */
    539 	error = device_call(dev, DEVICE_GET_PROPERTY(args));
    540 	KASSERT(error != 0 ||
    541 		(args->encoding == _BIG_ENDIAN ||
    542 		 args->encoding == _LITTLE_ENDIAN));
    543 
    544  out:
    545 	/*
    546 	 * Back-end is expected to return EFBIG if the entire property
    547 	 * does not fit into the provided buffer.  In this case, it is
    548 	 * undefined whether or not the back-end put any data in the
    549 	 * buffer at all, but it *is* expected to return the actual
    550 	 * property size in args->propsize if EFBIG is returned.
    551 	 */
    552 	KASSERT(error != EFBIG || args->propsize >= 0);
    553 
    554 	return error;
    555 }
    556 
    557 static ssize_t
    558 device_getprop_buf_internal(device_t dev, const char *prop, void *buf,
    559     size_t buflen, prop_type_t type)
    560 {
    561 	struct device_get_property_args args = {
    562 		.prop = prop,
    563 		.buf = buf,
    564 		.buflen = buflen,
    565 		.reqtype = type,
    566 	};
    567 	int error;
    568 
    569 	KASSERT(type == PROP_TYPE_DATA || type == PROP_TYPE_STRING);
    570 
    571 	/*
    572 	 * Callers are expeced to provide a valid buffer and length.
    573 	 * Ruthlessly Enforced for DIAGNOSTIC.
    574 	 */
    575 	KASSERT(buf != NULL);
    576 	KASSERT(buflen != 0);
    577 	if (buf == NULL || buflen == 0) {
    578 		return -1;
    579 	}
    580 
    581 	error = device_getprop_internal(dev, &args);
    582 	if (error) {
    583 		return -1;
    584 	}
    585 
    586 	/*
    587 	 * Back-end is expected to return an error if the buffer isn't
    588 	 * large enough for the entire property.  Ruthlessly Enforced
    589 	 * for DIAGNOSTIC.
    590 	 */
    591 	KASSERT(args.buflen <= SSIZE_MAX);
    592 	KASSERT(args.propsize <= (ssize_t)args.buflen);
    593 	if (args.propsize > args.buflen) {
    594 		return -1;
    595 	}
    596 
    597 	return args.propsize;
    598 }
    599 
    600 static void *
    601 device_getprop_alloc_internal(device_t dev, const char *prop, size_t *retsizep,
    602     prop_type_t type)
    603 {
    604 	struct device_get_property_args args = {
    605 		.prop = prop,
    606 		.reqtype = type,
    607 	};
    608 	size_t buflen = 0;
    609 	int error;
    610 
    611 	KASSERT(type == PROP_TYPE_DATA || type == PROP_TYPE_STRING);
    612 
    613 	/* Get the length. */
    614 	error = device_getprop_internal(dev, &args);
    615 	if (error) {
    616 		return NULL;
    617 	}
    618 
    619 	for (;;) {
    620 		/* Check for bogus property size. */
    621 		if (args.propsize <= 0) {
    622 			return NULL;
    623 		}
    624 
    625 		/* Allocate the result buffer. */
    626 		args.buflen = buflen = args.propsize;
    627 		args.buf = kmem_alloc(buflen, KM_SLEEP);
    628 
    629 		/* Get the property. */
    630 		error = device_getprop_internal(dev, &args);
    631 		if ((error == 0 && (ssize_t)args.buflen == args.propsize) ||
    632 		    error != EFBIG) {
    633 			break;
    634 		}
    635 
    636 		/*
    637 		 * We want to allocate an exact-sized buffer, so if
    638 		 * it changed in the short window between getting the
    639 		 * size and allocating the buffer, try again.
    640 		 *
    641 		 * (This is extremely unlikely to happen.)
    642 		 */
    643 		kmem_free(args.buf, buflen);
    644 	}
    645 
    646 	KASSERT(args.buf != NULL);
    647 	KASSERT(args.buflen != 0);
    648 
    649 	if (error) {
    650 		kmem_free(args.buf, args.buflen);
    651 		args.buf = NULL;
    652 	} else if (retsizep != NULL) {
    653 		/* Buffer length should not have been clamped in this case. */
    654 		KASSERT(args.buflen == buflen);
    655 		KASSERT(args.buflen == args.propsize);
    656 		*retsizep = args.buflen;
    657 	}
    658 	return args.buf;
    659 }
    660 
    661 /*
    662  * device_hasprop --
    663  *	Returns true if the device has the specified property.
    664  */
    665 bool
    666 device_hasprop(device_t dev, const char *prop)
    667 {
    668 	return device_getproplen(dev, prop) >= 0;
    669 }
    670 
    671 /*
    672  * device_getproplen --
    673  *	Get the length of the specified property, -1 if the property
    674  *	does not exist.
    675  */
    676 ssize_t
    677 device_getproplen(device_t dev, const char *prop)
    678 {
    679 	struct device_get_property_args args = {
    680 		.prop = prop,
    681 		.reqtype = PROP_TYPE_UNKNOWN,
    682 	};
    683 	int error;
    684 
    685 	error = device_getprop_internal(dev, &args);
    686 	if (error) {
    687 		return -1;
    688 	}
    689 
    690 	return args.propsize;
    691 }
    692 
    693 /*
    694  * device_getpropencoding --
    695  *	Returns the byte order encoding of the specified property, -1
    696  *	if the property does not exist.
    697  *
    698  *	N.B. The encoding is determined by the property's backing store,
    699  *	not by the property itself.
    700  */
    701 int
    702 device_getpropencoding(device_t dev, const char *prop)
    703 {
    704 	struct device_get_property_args args = {
    705 		.prop = prop,
    706 		.reqtype = PROP_TYPE_UNKNOWN,
    707 	};
    708 	int error;
    709 
    710 	error = device_getprop_internal(dev, &args);
    711 	if (error) {
    712 		return -1;
    713 	}
    714 
    715 	return args.encoding;
    716 }
    717 
    718 /*
    719  * device_getproptype --
    720  *	Get the data type of the specified property, PROP_TYPE_UNKNOWN
    721  *	if the property does not exist or if the data type is unspecified.
    722  */
    723 prop_type_t
    724 device_getproptype(device_t dev, const char *prop)
    725 {
    726 	struct device_get_property_args args = {
    727 		.prop = prop,
    728 		.reqtype = PROP_TYPE_UNKNOWN,
    729 	};
    730 	int error;
    731 
    732 	error = device_getprop_internal(dev, &args);
    733 	if (error) {
    734 		return PROP_TYPE_UNKNOWN;
    735 	}
    736 
    737 	return args.type;
    738 }
    739 
    740 
    741 /*
    742  * device_getprop_data --
    743  *	Get the property as a binary data object.
    744  */
    745 ssize_t
    746 device_getprop_data(device_t dev, const char *prop, void *buf, size_t buflen)
    747 {
    748 	return device_getprop_buf_internal(dev, prop, buf, buflen,
    749 	    PROP_TYPE_DATA);
    750 }
    751 
    752 /*
    753  * device_getprop_data_alloc --
    754  *	Convenience wrapper around device_getprop_data() that takes care
    755  *	allocating the buffer.
    756  */
    757 void *
    758 device_getprop_data_alloc(device_t dev, const char *prop, size_t *retsizep)
    759 {
    760 	return device_getprop_alloc_internal(dev, prop, retsizep,
    761 	    PROP_TYPE_DATA);
    762 }
    763 
    764 /*
    765  * device_getprop_string --
    766  *	Get the property as a C string.
    767  */
    768 ssize_t
    769 device_getprop_string(device_t dev, const char *prop, char *buf, size_t buflen)
    770 {
    771 	return device_getprop_buf_internal(dev, prop, buf, buflen,
    772 	    PROP_TYPE_STRING);
    773 }
    774 
    775 /*
    776  * device_getprop_string_alloc --
    777  *	Convenience wrapper around device_getprop_string() that takes care
    778  *	allocating the buffer.
    779  */
    780 char *
    781 device_getprop_string_alloc(device_t dev, const char *prop, size_t *retsizep)
    782 {
    783 	return device_getprop_alloc_internal(dev, prop, retsizep,
    784 	    PROP_TYPE_STRING);
    785 }
    786 
    787 /*
    788  * device_getprop_bool --
    789  *	Get the boolean value of a property.
    790  */
    791 bool
    792 device_getprop_bool(device_t dev, const char *prop)
    793 {
    794 	bool val;
    795 	struct device_get_property_args args = {
    796 		.prop = prop,
    797 		.buf = &val,
    798 		.buflen = sizeof(val),
    799 		.reqtype = PROP_TYPE_BOOL,
    800 	};
    801 	int error;
    802 
    803 	error = device_getprop_internal(dev, &args);
    804 	if (error) {
    805 		/*
    806 		 * If the property exists but is not a boolean type
    807 		 * (EFTYPE), we map this to 'true'; this is the same
    808 		 * behavior that the traditional OpenBoot, OpenFirmware,
    809 		 * and FDT interfaces have.
    810 		 *
    811 		 * If the property does not exist (ENOENT), or there
    812 		 * is some other problem we translate this to 'false'.
    813 		 */
    814 		return error == EFTYPE ? true : false;
    815 	}
    816 	return val;
    817 }
    818 
    819 #define	S8_BIT		__BIT(7)
    820 #define	S8_MASK		__BITS(7,63)
    821 #define	S16_BIT		__BIT(15)
    822 #define	S16_MASK	__BITS(15,63)
    823 #define	S32_BIT		__BIT(31)
    824 #define	S32_MASK	__BITS(31,63)
    825 
    826 static bool
    827 device_getprop_number_sext(struct device_get_property_args *args,
    828     uint64_t *valp)
    829 {
    830 	uint64_t bit, mask;
    831 
    832 	/*
    833 	 * Sign-extend the two's-complement number that occupies
    834 	 * the least-significant propsize bytes in *valp into the
    835 	 * full 64 bits.
    836 	 */
    837 
    838 	switch (args->propsize) {
    839 	case 1:
    840 		bit = S8_BIT;
    841 		mask = S8_MASK;
    842 		break;
    843 
    844 	case 2:
    845 		bit = S16_BIT;
    846 		mask = S16_MASK;
    847 		break;
    848 
    849 	case 4:
    850 		bit = S32_BIT;
    851 		mask = S32_MASK;
    852 		break;
    853 
    854 	case 8:
    855 		return true;
    856 
    857 	default:
    858 		return false;
    859 	}
    860 
    861 	/*
    862 	 * If the sign bit and only the sign bit is set, then extend
    863 	 * the sign bit.  Otherwise, check to see if the number has
    864 	 * already been sign-extended into the full 64 bits.  If any
    865 	 * of the extended sign bits are not set, then we are off the
    866 	 * rails (propsize doesn't match the value we were provided)
    867 	 * and fail the operation.
    868 	 */
    869 
    870 	if ((*valp & mask) == bit) {
    871 		*valp |= mask;
    872 	} else if ((*valp & mask) != mask) {
    873 		/* value doesn't match propsize?? */
    874 		return false;
    875 	}
    876 
    877 	return true;
    878 }
    879 
    880 #undef S8_BIT
    881 #undef S8_MASK
    882 #undef S16_BIT
    883 #undef S16_MASK
    884 #undef S32_BIT
    885 #undef S32_MASK
    886 
    887 static int
    888 device_getprop_int32_internal(device_t dev, const char *prop, int32_t *valp)
    889 {
    890 	int64_t val64;
    891 	struct device_get_property_args args = {
    892 		.prop = prop,
    893 		.buf = &val64,
    894 		.buflen = sizeof(val64),
    895 		.reqtype = PROP_TYPE_NUMBER,
    896 	};
    897 	int error;
    898 
    899 	error = device_getprop_internal(dev, &args);
    900 	if (error) {
    901 		return error;
    902 	}
    903 
    904 	if (! device_getprop_number_sext(&args, (uint64_t *)&val64)) {
    905 		return ERANGE;
    906 	}
    907 
    908 	if (val64 < INT32_MIN || val64 > INT32_MAX) {
    909 		return ERANGE;
    910 	}
    911 
    912 	*valp = (int32_t)val64;
    913 	return 0;
    914 }
    915 
    916 static int
    917 device_getprop_uint32_internal(device_t dev, const char *prop, uint32_t *valp)
    918 {
    919 	uint64_t val64;
    920 	struct device_get_property_args args = {
    921 		.prop = prop,
    922 		.buf = &val64,
    923 		.buflen = sizeof(val64),
    924 		.reqtype = PROP_TYPE_NUMBER,
    925 	};
    926 	int error;
    927 
    928 	error = device_getprop_internal(dev, &args);
    929 	if (error) {
    930 		return error;
    931 	}
    932 
    933 	if (val64 > UINT32_MAX) {
    934 		return ERANGE;
    935 	}
    936 
    937 	*valp = (uint32_t)val64;
    938 	return 0;
    939 }
    940 
    941 static int
    942 device_getprop_int64_internal(device_t dev, const char *prop, int64_t *valp)
    943 {
    944 	int64_t val64;
    945 	struct device_get_property_args args = {
    946 		.prop = prop,
    947 		.buf = &val64,
    948 		.buflen = sizeof(val64),
    949 		.reqtype = PROP_TYPE_NUMBER,
    950 	};
    951 	int error;
    952 
    953 	error = device_getprop_internal(dev, &args);
    954 	if (error) {
    955 		return error;
    956 	}
    957 
    958 	if (! device_getprop_number_sext(&args, &val64)) {
    959 		return ERANGE;
    960 	}
    961 
    962 	*valp = val64;
    963 	return 0;
    964 }
    965 
    966 static int
    967 device_getprop_uint64_internal(device_t dev, const char *prop, uint64_t *valp)
    968 {
    969 	struct device_get_property_args args = {
    970 		.prop = prop,
    971 		.buf = valp,
    972 		.buflen = sizeof(*valp),
    973 		.reqtype = PROP_TYPE_NUMBER,
    974 	};
    975 
    976 	return device_getprop_internal(dev, &args);
    977 }
    978 
    979 #define	TEMPLATE(name)							\
    980 bool									\
    981 device_getprop_ ## name (device_t dev, const char *prop, 		\
    982     name ## _t *valp)							\
    983 {									\
    984 	return device_getprop_ ## name ## _internal(dev, prop, valp)	\
    985 	    == 0;							\
    986 }									\
    987 									\
    988 name ## _t								\
    989 device_getprop_ ## name ## _default(device_t dev, const char *prop,	\
    990     name ## _t defval)							\
    991 {									\
    992 	name ## _t val;							\
    993 									\
    994 	return device_getprop_ ## name ## _internal(dev, prop, &val)	\
    995 	    ? defval : val;						\
    996 }
    997 
    998 /*
    999  * device_getprop_int32 --
   1000  *	Get the specified property as a signed 32-bit integer.
   1001  */
   1002 TEMPLATE(int32)
   1003 __strong_alias(device_getprop_int,device_getprop_int32);
   1004 
   1005 
   1006 /*
   1007  * device_getprop_uint32 --
   1008  *	Get the specified property as an unsigned 32-bit integer.
   1009  */
   1010 TEMPLATE(uint32)
   1011 __strong_alias(device_getprop_uint,device_getprop_uint32);
   1012 
   1013 /*
   1014  * device_getprop_int64 --
   1015  *	Get the specified property as a signed 64-bit integer.
   1016  */
   1017 TEMPLATE(int64)
   1018 
   1019 /*
   1020  * device_getprop_uint64 --
   1021  *	Get the specified property as an unsigned 64-bit integer.
   1022  */
   1023 TEMPLATE(uint64)
   1024 
   1025 #undef TEMPLATE
   1026 
   1027 /*
   1028  * device_setprop_data --
   1029  *	Set the specified binary data property.
   1030  */
   1031 bool
   1032 device_setprop_data(device_t dev, const char *prop, const void *buf, size_t len)
   1033 {
   1034 	return prop_dictionary_set_data(dev->dv_properties, prop, buf, len);
   1035 }
   1036 
   1037 /*
   1038  * device_setprop_string --
   1039  *	Set the specified C string property.
   1040  */
   1041 bool
   1042 device_setprop_string(device_t dev, const char *prop, const char *str)
   1043 {
   1044 	return prop_dictionary_set_string(dev->dv_properties, prop, str);
   1045 }
   1046 
   1047 /*
   1048  * device_setprop_bool --
   1049  *	Set the specified boolean property.
   1050  */
   1051 bool
   1052 device_setprop_bool(device_t dev, const char *prop, bool val)
   1053 {
   1054 	return prop_dictionary_set_bool(dev->dv_properties, prop, val);
   1055 }
   1056 
   1057 /*
   1058  * device_setprop_int32 --
   1059  *	Set the specified 32-bit signed integer property.
   1060  */
   1061 bool
   1062 device_setprop_int32(device_t dev, const char *prop, int32_t val)
   1063 {
   1064 	return prop_dictionary_set_int32(dev->dv_properties, prop, val);
   1065 }
   1066 __strong_alias(device_setprop_int,device_setprop_int32);
   1067 
   1068 /*
   1069  * device_setprop_uint32 --
   1070  *	Set the specified 32-bit unsigned integer property.
   1071  */
   1072 bool
   1073 device_setprop_uint32(device_t dev, const char *prop, uint32_t val)
   1074 {
   1075 	return prop_dictionary_set_uint32(dev->dv_properties, prop, val);
   1076 }
   1077 __strong_alias(device_setprop_uint,device_setprop_uint32);
   1078 
   1079 /*
   1080  * device_setprop_int64 --
   1081  *	Set the specified 64-bit signed integer property.
   1082  */
   1083 bool
   1084 device_setprop_int64(device_t dev, const char *prop, int64_t val)
   1085 {
   1086 	return prop_dictionary_set_int64(dev->dv_properties, prop, val);
   1087 }
   1088 
   1089 /*
   1090  * device_setprop_uint64 --
   1091  *	Set the specified 64-bit unsigned integer property.
   1092  */
   1093 bool
   1094 device_setprop_uint64(device_t dev, const char *prop, uint64_t val)
   1095 {
   1096 	return prop_dictionary_set_uint64(dev->dv_properties, prop, val);
   1097 }
   1098 
   1099 /*
   1100  * device_delprop --
   1101  *	Delete the specified property.
   1102  */
   1103 void
   1104 device_delprop(device_t dev, const char *prop)
   1105 {
   1106 	prop_dictionary_remove(dev->dv_properties, prop);
   1107 }
   1108