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