Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: subr_device.c,v 1.20 2026/01/04 03:15:42 riastradh 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.20 2026/01/04 03:15:42 riastradh 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 bool
    294 device_has_power(device_t dev)
    295 {
    296 	int active_flags;
    297 
    298 	active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
    299 
    300 	return (dev->dv_flags & active_flags) == DVF_ACTIVE;
    301 }
    302 
    303 int
    304 device_locator(device_t dev, u_int locnum)
    305 {
    306 
    307 	KASSERT(dev->dv_locators != NULL);
    308 	return dev->dv_locators[locnum];
    309 }
    310 
    311 void *
    312 device_private(device_t dev)
    313 {
    314 
    315 	/*
    316 	 * The reason why device_private(NULL) is allowed is to simplify the
    317 	 * work of a lot of userspace request handlers (i.e., c/bdev
    318 	 * handlers) which grab cfdriver_t->cd_units[n].
    319 	 * It avoids having them test for it to be NULL and only then calling
    320 	 * device_private.
    321 	 */
    322 	return dev == NULL ? NULL : dev->dv_private;
    323 }
    324 
    325 void
    326 device_set_private(device_t dev, void *private)
    327 {
    328 
    329 	KASSERTMSG(dev->dv_private == NULL, "device_set_private(%p, %p):"
    330 	    " device %s already has private set to %p",
    331 	    dev, private, device_xname(dev), device_private(dev));
    332 	KASSERT(private != NULL);
    333 	dev->dv_private = private;
    334 }
    335 
    336 prop_dictionary_t
    337 device_properties(device_t dev)
    338 {
    339 
    340 	return dev->dv_properties;
    341 }
    342 
    343 /*
    344  * device_is_a:
    345  *
    346  *	Returns true if the device is an instance of the specified
    347  *	driver.
    348  */
    349 bool
    350 device_is_a(device_t dev, const char *dname)
    351 {
    352 	if (dev == NULL || dev->dv_cfdriver == NULL) {
    353 		return false;
    354 	}
    355 
    356 	return strcmp(dev->dv_cfdriver->cd_name, dname) == 0;
    357 }
    358 
    359 /*
    360  * device_attached_to_iattr:
    361  *
    362  *	Returns true if the device attached to the specified interface
    363  *	attribute.
    364  */
    365 bool
    366 device_attached_to_iattr(device_t dev, const char *iattr)
    367 {
    368 	cfdata_t cfdata = device_cfdata(dev);
    369 	const struct cfparent *pspec;
    370 
    371 	if (cfdata == NULL || (pspec = cfdata->cf_pspec) == NULL) {
    372 		return false;
    373 	}
    374 
    375 	return strcmp(pspec->cfp_iattr, iattr) == 0;
    376 }
    377 
    378 void
    379 device_set_handle(device_t dev, devhandle_t handle)
    380 {
    381 	dev->dv_handle = handle;
    382 }
    383 
    384 devhandle_t
    385 device_handle(device_t dev)
    386 {
    387 	return dev->dv_handle;
    388 }
    389 
    390 int
    391 device_call_generic(device_t dev, devhandle_t handle,
    392     const struct device_call_generic *gen)
    393 {
    394 	device_call_t call;
    395 	devhandle_t call_handle;
    396 
    397 	call = devhandle_lookup_device_call(handle, gen->name, &call_handle);
    398 	if (call == NULL) {
    399 		return SET_ERROR(ENOTSUP);
    400 	}
    401 	return call(dev, call_handle, gen->args);
    402 }
    403 
    404 int
    405 device_enumerate_children(device_t dev,
    406     bool (*callback)(device_t, devhandle_t, void *),
    407     void *callback_arg)
    408 {
    409 	struct device_enumerate_children_args args = {
    410 		.callback = callback,
    411 		.callback_arg = callback_arg,
    412 	};
    413 
    414 	return device_call(dev, DEVICE_ENUMERATE_CHILDREN(&args));
    415 }
    416 
    417 /*****************************************************************************
    418  * Device properties infrastructure.
    419  *****************************************************************************/
    420 
    421 static int
    422 device_getprop_dict(device_t dev, struct device_get_property_args *args)
    423 {
    424 	prop_dictionary_t dict = dev->dv_properties;
    425 	prop_object_t propval;
    426 	bool rv;
    427 
    428 	/*
    429 	 * Return ENOENT before any other error so that we can rely
    430 	 * on that error to tell us "property does not exist in this
    431 	 * layer, so go check the platform device tree".
    432 	 */
    433 	propval = prop_dictionary_get(dict, args->prop);
    434 	if (propval == NULL) {
    435 		return SET_ERROR(ENOENT);
    436 	}
    437 
    438 	/*
    439 	 * Validate the requested type.  Because it can be convenient
    440 	 * to do so (e.g. properties that constain a strlist, maybe that
    441 	 * property was set as a single string), we allow STRING objects
    442 	 * to be requested as DATA.
    443 	 */
    444 	prop_type_t objtype = prop_object_type(propval);
    445 	switch (args->reqtype) {
    446 	case PROP_TYPE_DATA:
    447 		KASSERT(args->buf != NULL);
    448 		KASSERT(args->buflen != 0);
    449 		if (objtype != PROP_TYPE_DATA && objtype != PROP_TYPE_STRING) {
    450 			return SET_ERROR(EFTYPE);
    451 		}
    452 		break;
    453 
    454 	case PROP_TYPE_UNKNOWN:
    455 		KASSERT(args->buf == NULL);
    456 		KASSERT(args->buflen == 0);
    457 		break;
    458 
    459 	default:
    460 		KASSERT(args->buf != NULL);
    461 		KASSERT(args->buflen != 0);
    462 		if (args->reqtype != objtype) {
    463 			return SET_ERROR(EFTYPE);
    464 		}
    465 	}
    466 
    467 	args->encoding = _BYTE_ORDER;	/* these are always native */
    468 	args->type = objtype;
    469 
    470 	switch (args->type) {
    471 	case PROP_TYPE_NUMBER:
    472 		/* prop_number_size() returns bits. */
    473 		args->propsize = prop_number_size(propval) >> 3;
    474 		if (args->buf != NULL) {
    475 			KASSERT(args->buflen == sizeof(uint64_t));
    476 			/*
    477 			 * Fetching a -ve value as uint64_t will fail
    478 			 * a range check, so check what we have before
    479 			 * we fetch.  We'll reconcile it based on what
    480 			 * the caller is asking for later.
    481 			 */
    482 			if (prop_number_unsigned(propval)) {
    483 				rv = prop_number_uint64_value(propval,
    484 				    args->buf);
    485 			} else {
    486 				rv = prop_number_int64_value(propval,
    487 				    args->buf);
    488 			}
    489 			if (! rv) {
    490 				return SET_ERROR(EIO);	/* off the rails */
    491 			}
    492 		}
    493 		break;
    494 
    495 	case PROP_TYPE_STRING:
    496 		/* +1 for trailing NUL */
    497 		args->propsize = prop_string_size(propval) + 1;
    498 		if (args->buf != NULL) {
    499 			if (args->buflen < args->propsize) {
    500 				return SET_ERROR(EFBIG);
    501 			}
    502 			strlcpy(args->buf, prop_string_value(propval),
    503 			    args->buflen);
    504 		}
    505 		break;
    506 
    507 	case PROP_TYPE_DATA:
    508 		args->propsize = prop_data_size(propval);
    509 		if (args->buf != NULL) {
    510 			if (args->buflen < args->propsize) {
    511 				return SET_ERROR(EFBIG);
    512 			}
    513 			memcpy(args->buf, prop_data_value(propval),
    514 			    args->propsize);
    515 		}
    516 		break;
    517 
    518 	case PROP_TYPE_BOOL:
    519 		args->propsize = sizeof(bool);
    520 		if (args->buf != NULL) {
    521 			KASSERT(args->buflen == sizeof(bool));
    522 			*(bool *)args->buf = prop_bool_value(propval);
    523 		}
    524 		break;
    525 
    526 	default:
    527 		return SET_ERROR(EFTYPE);
    528 	}
    529 
    530 	return 0;
    531 }
    532 
    533 static int
    534 device_getprop_internal(device_t dev, struct device_get_property_args *args)
    535 {
    536 	int error;
    537 
    538 	/* Normalize arguments. */
    539 	if (args->buf == NULL || args->buflen == 0) {
    540 		args->buf = NULL;
    541 		args->buflen = 0;
    542 	} else if (args->buflen > SSIZE_MAX) {
    543 		/* Sizes must fit in ssize_t. */
    544 		args->buflen = SSIZE_MAX;
    545 	}
    546 
    547 	/* Poison args->propsize for sanity check later. */
    548 	args->propsize = -1;
    549 
    550 	args->flags = 0;
    551 
    552 	/* Check the device's property dictionary first. */
    553 	error = device_getprop_dict(dev, args);
    554 	if (error != ENOENT) {
    555 		KASSERT(error != 0 ||
    556 			args->encoding == _BYTE_ORDER);
    557 		goto out;
    558 	}
    559 
    560 	/*
    561 	 * Not in the device's property dictionary; check with
    562 	 * the platform device tree.
    563 	 */
    564 	error = device_call(dev, DEVICE_GET_PROPERTY(args));
    565 	KASSERT(error != 0 ||
    566 		(args->encoding == _BIG_ENDIAN ||
    567 		 args->encoding == _LITTLE_ENDIAN));
    568 
    569  out:
    570 	/*
    571 	 * Back-end is expected to return EFBIG if the entire property
    572 	 * does not fit into the provided buffer.  In this case, it is
    573 	 * undefined whether or not the back-end put any data in the
    574 	 * buffer at all, but it *is* expected to return the actual
    575 	 * property size in args->propsize if EFBIG is returned.
    576 	 */
    577 	KASSERT(error != EFBIG || args->propsize >= 0);
    578 
    579 	return error;
    580 }
    581 
    582 static ssize_t
    583 device_getprop_buf_internal(device_t dev, const char *prop, void *buf,
    584     size_t buflen, prop_type_t type)
    585 {
    586 	struct device_get_property_args args = {
    587 		.prop = prop,
    588 		.buf = buf,
    589 		.buflen = buflen,
    590 		.reqtype = type,
    591 	};
    592 	int error;
    593 
    594 	KASSERT(type == PROP_TYPE_DATA || type == PROP_TYPE_STRING);
    595 
    596 	/*
    597 	 * Callers are expeced to provide a valid buffer and length.
    598 	 * Ruthlessly Enforced for DIAGNOSTIC.
    599 	 */
    600 	KASSERT(buf != NULL);
    601 	KASSERT(buflen != 0);
    602 	if (buf == NULL || buflen == 0) {
    603 		return -1;
    604 	}
    605 
    606 	error = device_getprop_internal(dev, &args);
    607 	if (error) {
    608 		return -1;
    609 	}
    610 
    611 	/*
    612 	 * Back-end is expected to return an error if the buffer isn't
    613 	 * large enough for the entire property.  Ruthlessly Enforced
    614 	 * for DIAGNOSTIC.
    615 	 */
    616 	KASSERT(args.buflen <= SSIZE_MAX);
    617 	KASSERT(args.propsize <= (ssize_t)args.buflen);
    618 	if (args.propsize > args.buflen) {
    619 		return -1;
    620 	}
    621 
    622 	return args.propsize;
    623 }
    624 
    625 static void *
    626 device_getprop_alloc_internal(device_t dev, const char *prop, size_t *retsizep,
    627     prop_type_t type)
    628 {
    629 	struct device_get_property_args args = {
    630 		.prop = prop,
    631 		.reqtype = type,
    632 	};
    633 	size_t buflen = 0;
    634 	int error;
    635 
    636 	KASSERT(type == PROP_TYPE_DATA || type == PROP_TYPE_STRING);
    637 
    638 	/* Get the length. */
    639 	error = device_getprop_internal(dev, &args);
    640 	if (error) {
    641 		return NULL;
    642 	}
    643 
    644 	for (;;) {
    645 		/* Check for bogus property size. */
    646 		if (args.propsize <= 0) {
    647 			return NULL;
    648 		}
    649 
    650 		/* Allocate the result buffer. */
    651 		args.buflen = buflen = args.propsize;
    652 		args.buf = kmem_alloc(buflen, KM_SLEEP);
    653 
    654 		/* Get the property. */
    655 		error = device_getprop_internal(dev, &args);
    656 		if ((error == 0 && (ssize_t)args.buflen == args.propsize) ||
    657 		    error != EFBIG) {
    658 			break;
    659 		}
    660 
    661 		/*
    662 		 * We want to allocate an exact-sized buffer, so if
    663 		 * it changed in the short window between getting the
    664 		 * size and allocating the buffer, try again.
    665 		 *
    666 		 * (This is extremely unlikely to happen.)
    667 		 */
    668 		kmem_free(args.buf, buflen);
    669 	}
    670 
    671 	KASSERT(args.buf != NULL);
    672 	KASSERT(args.buflen != 0);
    673 
    674 	if (error) {
    675 		kmem_free(args.buf, args.buflen);
    676 		args.buf = NULL;
    677 	} else if (retsizep != NULL) {
    678 		/* Buffer length should not have been clamped in this case. */
    679 		KASSERT(args.buflen == buflen);
    680 		KASSERT(args.buflen == args.propsize);
    681 		*retsizep = args.buflen;
    682 	}
    683 	return args.buf;
    684 }
    685 
    686 /*
    687  * device_hasprop --
    688  *	Returns true if the device has the specified property.
    689  */
    690 bool
    691 device_hasprop(device_t dev, const char *prop)
    692 {
    693 	return device_getproplen(dev, prop) >= 0;
    694 }
    695 
    696 /*
    697  * device_getproplen --
    698  *	Get the length of the specified property, -1 if the property
    699  *	does not exist.
    700  */
    701 ssize_t
    702 device_getproplen(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.propsize;
    716 }
    717 
    718 /*
    719  * device_getpropencoding --
    720  *	Returns the byte order encoding of the specified property, -1
    721  *	if the property does not exist.
    722  *
    723  *	N.B. The encoding is determined by the property's backing store,
    724  *	not by the property itself.
    725  */
    726 int
    727 device_getpropencoding(device_t dev, const char *prop)
    728 {
    729 	struct device_get_property_args args = {
    730 		.prop = prop,
    731 		.reqtype = PROP_TYPE_UNKNOWN,
    732 	};
    733 	int error;
    734 
    735 	error = device_getprop_internal(dev, &args);
    736 	if (error) {
    737 		return -1;
    738 	}
    739 
    740 	return args.encoding;
    741 }
    742 
    743 /*
    744  * device_getproptype --
    745  *	Get the data type of the specified property, PROP_TYPE_UNKNOWN
    746  *	if the property does not exist or if the data type is unspecified.
    747  */
    748 prop_type_t
    749 device_getproptype(device_t dev, const char *prop)
    750 {
    751 	struct device_get_property_args args = {
    752 		.prop = prop,
    753 		.reqtype = PROP_TYPE_UNKNOWN,
    754 	};
    755 	int error;
    756 
    757 	error = device_getprop_internal(dev, &args);
    758 	if (error) {
    759 		return PROP_TYPE_UNKNOWN;
    760 	}
    761 
    762 	return args.type;
    763 }
    764 
    765 
    766 /*
    767  * device_getprop_data --
    768  *	Get the property as a binary data object.
    769  */
    770 ssize_t
    771 device_getprop_data(device_t dev, const char *prop, void *buf, size_t buflen)
    772 {
    773 	return device_getprop_buf_internal(dev, prop, buf, buflen,
    774 	    PROP_TYPE_DATA);
    775 }
    776 
    777 /*
    778  * device_getprop_data_alloc --
    779  *	Convenience wrapper around device_getprop_data() that takes care
    780  *	allocating the buffer.
    781  */
    782 void *
    783 device_getprop_data_alloc(device_t dev, const char *prop, size_t *retsizep)
    784 {
    785 	return device_getprop_alloc_internal(dev, prop, retsizep,
    786 	    PROP_TYPE_DATA);
    787 }
    788 
    789 /*
    790  * device_getprop_string --
    791  *	Get the property as a C string.
    792  */
    793 ssize_t
    794 device_getprop_string(device_t dev, const char *prop, char *buf, size_t buflen)
    795 {
    796 	return device_getprop_buf_internal(dev, prop, buf, buflen,
    797 	    PROP_TYPE_STRING);
    798 }
    799 
    800 /*
    801  * device_getprop_string_alloc --
    802  *	Convenience wrapper around device_getprop_string() that takes care
    803  *	allocating the buffer.
    804  */
    805 char *
    806 device_getprop_string_alloc(device_t dev, const char *prop, size_t *retsizep)
    807 {
    808 	return device_getprop_alloc_internal(dev, prop, retsizep,
    809 	    PROP_TYPE_STRING);
    810 }
    811 
    812 /*
    813  * device_getprop_bool --
    814  *	Get the boolean value of a property.
    815  */
    816 bool
    817 device_getprop_bool(device_t dev, const char *prop)
    818 {
    819 	bool val;
    820 	struct device_get_property_args args = {
    821 		.prop = prop,
    822 		.buf = &val,
    823 		.buflen = sizeof(val),
    824 		.reqtype = PROP_TYPE_BOOL,
    825 	};
    826 	int error;
    827 
    828 	error = device_getprop_internal(dev, &args);
    829 	if (error) {
    830 		/*
    831 		 * If the property exists but is not a boolean type
    832 		 * (EFTYPE), we map this to 'true'; this is the same
    833 		 * behavior that the traditional OpenBoot, OpenFirmware,
    834 		 * and FDT interfaces have.
    835 		 *
    836 		 * If the property does not exist (ENOENT), or there
    837 		 * is some other problem we translate this to 'false'.
    838 		 */
    839 		return error == EFTYPE ? true : false;
    840 	}
    841 	return val;
    842 }
    843 
    844 #define	S8_BIT		__BIT(7)
    845 #define	S8_MASK		__BITS(7,63)
    846 #define	S16_BIT		__BIT(15)
    847 #define	S16_MASK	__BITS(15,63)
    848 #define	S32_BIT		__BIT(31)
    849 #define	S32_MASK	__BITS(31,63)
    850 
    851 static bool
    852 device_getprop_number_sext(struct device_get_property_args *args,
    853     uint64_t *valp)
    854 {
    855 	uint64_t bit, mask;
    856 
    857 	/*
    858 	 * Sign-extend the two's-complement number that occupies
    859 	 * the least-significant propsize bytes in *valp into the
    860 	 * full 64 bits.
    861 	 */
    862 
    863 	switch (args->propsize) {
    864 	case 1:
    865 		bit = S8_BIT;
    866 		mask = S8_MASK;
    867 		break;
    868 
    869 	case 2:
    870 		bit = S16_BIT;
    871 		mask = S16_MASK;
    872 		break;
    873 
    874 	case 4:
    875 		bit = S32_BIT;
    876 		mask = S32_MASK;
    877 		break;
    878 
    879 	case 8:
    880 		return true;
    881 
    882 	default:
    883 		return false;
    884 	}
    885 
    886 	/*
    887 	 * If the sign bit and only the sign bit is set, then extend
    888 	 * the sign bit.  Otherwise, check to see if the number has
    889 	 * already been sign-extended into the full 64 bits.  If any
    890 	 * of the extended sign bits are not set, then we are off the
    891 	 * rails (propsize doesn't match the value we were provided)
    892 	 * and fail the operation.
    893 	 */
    894 
    895 	if ((*valp & mask) == bit) {
    896 		*valp |= mask;
    897 	} else if ((*valp & mask) != mask) {
    898 		/* value doesn't match propsize?? */
    899 		return false;
    900 	}
    901 
    902 	return true;
    903 }
    904 
    905 #undef S8_BIT
    906 #undef S8_MASK
    907 #undef S16_BIT
    908 #undef S16_MASK
    909 #undef S32_BIT
    910 #undef S32_MASK
    911 
    912 static int
    913 device_getprop_int32_internal(device_t dev, const char *prop, int32_t *valp)
    914 {
    915 	int64_t val64;
    916 	struct device_get_property_args args = {
    917 		.prop = prop,
    918 		.buf = &val64,
    919 		.buflen = sizeof(val64),
    920 		.reqtype = PROP_TYPE_NUMBER,
    921 	};
    922 	int error;
    923 
    924 	error = device_getprop_internal(dev, &args);
    925 	if (error) {
    926 		return error;
    927 	}
    928 
    929 	if (! device_getprop_number_sext(&args, (uint64_t *)&val64)) {
    930 		return SET_ERROR(ERANGE);
    931 	}
    932 
    933 	if (val64 < INT32_MIN || val64 > INT32_MAX) {
    934 		return SET_ERROR(ERANGE);
    935 	}
    936 
    937 	*valp = (int32_t)val64;
    938 	return 0;
    939 }
    940 
    941 static int
    942 device_getprop_uint32_internal(device_t dev, const char *prop, uint32_t *valp)
    943 {
    944 	uint64_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 (val64 > UINT32_MAX) {
    959 		return SET_ERROR(ERANGE);
    960 	}
    961 
    962 	*valp = (uint32_t)val64;
    963 	return 0;
    964 }
    965 
    966 static int
    967 device_getprop_int64_internal(device_t dev, const char *prop, int64_t *valp)
    968 {
    969 	int64_t val64;
    970 	struct device_get_property_args args = {
    971 		.prop = prop,
    972 		.buf = &val64,
    973 		.buflen = sizeof(val64),
    974 		.reqtype = PROP_TYPE_NUMBER,
    975 	};
    976 	int error;
    977 
    978 	error = device_getprop_internal(dev, &args);
    979 	if (error) {
    980 		return error;
    981 	}
    982 
    983 	if (! device_getprop_number_sext(&args, &val64)) {
    984 		return SET_ERROR(ERANGE);
    985 	}
    986 
    987 	*valp = val64;
    988 	return 0;
    989 }
    990 
    991 static int
    992 device_getprop_uint64_internal(device_t dev, const char *prop, uint64_t *valp)
    993 {
    994 	struct device_get_property_args args = {
    995 		.prop = prop,
    996 		.buf = valp,
    997 		.buflen = sizeof(*valp),
    998 		.reqtype = PROP_TYPE_NUMBER,
    999 	};
   1000 
   1001 	return device_getprop_internal(dev, &args);
   1002 }
   1003 
   1004 #define	TEMPLATE(name)							\
   1005 bool									\
   1006 device_getprop_ ## name (device_t dev, const char *prop, 		\
   1007     name ## _t *valp)							\
   1008 {									\
   1009 	return device_getprop_ ## name ## _internal(dev, prop, valp)	\
   1010 	    == 0;							\
   1011 }									\
   1012 									\
   1013 name ## _t								\
   1014 device_getprop_ ## name ## _default(device_t dev, const char *prop,	\
   1015     name ## _t defval)							\
   1016 {									\
   1017 	name ## _t val;							\
   1018 									\
   1019 	return device_getprop_ ## name ## _internal(dev, prop, &val)	\
   1020 	    ? defval : val;						\
   1021 }
   1022 
   1023 /*
   1024  * device_getprop_int32 --
   1025  *	Get the specified property as a signed 32-bit integer.
   1026  */
   1027 TEMPLATE(int32)
   1028 __strong_alias(device_getprop_int,device_getprop_int32);
   1029 __strong_alias(device_getprop_int_default,device_getprop_int32_default);
   1030 
   1031 
   1032 /*
   1033  * device_getprop_uint32 --
   1034  *	Get the specified property as an unsigned 32-bit integer.
   1035  */
   1036 TEMPLATE(uint32)
   1037 __strong_alias(device_getprop_uint,device_getprop_uint32);
   1038 __strong_alias(device_getprop_uint_default,device_getprop_uint32_default);
   1039 
   1040 /*
   1041  * device_getprop_int64 --
   1042  *	Get the specified property as a signed 64-bit integer.
   1043  */
   1044 TEMPLATE(int64)
   1045 
   1046 /*
   1047  * device_getprop_uint64 --
   1048  *	Get the specified property as an unsigned 64-bit integer.
   1049  */
   1050 TEMPLATE(uint64)
   1051 
   1052 #undef TEMPLATE
   1053 
   1054 /*
   1055  * device_setprop_data --
   1056  *	Set the specified binary data property.
   1057  */
   1058 bool
   1059 device_setprop_data(device_t dev, const char *prop, const void *buf, size_t len)
   1060 {
   1061 	return prop_dictionary_set_data(dev->dv_properties, prop, buf, len);
   1062 }
   1063 
   1064 /*
   1065  * device_setprop_string --
   1066  *	Set the specified C string property.
   1067  */
   1068 bool
   1069 device_setprop_string(device_t dev, const char *prop, const char *str)
   1070 {
   1071 	return prop_dictionary_set_string(dev->dv_properties, prop, str);
   1072 }
   1073 
   1074 /*
   1075  * device_setprop_bool --
   1076  *	Set the specified boolean property.
   1077  */
   1078 bool
   1079 device_setprop_bool(device_t dev, const char *prop, bool val)
   1080 {
   1081 	return prop_dictionary_set_bool(dev->dv_properties, prop, val);
   1082 }
   1083 
   1084 /*
   1085  * device_setprop_int32 --
   1086  *	Set the specified 32-bit signed integer property.
   1087  */
   1088 bool
   1089 device_setprop_int32(device_t dev, const char *prop, int32_t val)
   1090 {
   1091 	return prop_dictionary_set_int32(dev->dv_properties, prop, val);
   1092 }
   1093 __strong_alias(device_setprop_int,device_setprop_int32);
   1094 
   1095 /*
   1096  * device_setprop_uint32 --
   1097  *	Set the specified 32-bit unsigned integer property.
   1098  */
   1099 bool
   1100 device_setprop_uint32(device_t dev, const char *prop, uint32_t val)
   1101 {
   1102 	return prop_dictionary_set_uint32(dev->dv_properties, prop, val);
   1103 }
   1104 __strong_alias(device_setprop_uint,device_setprop_uint32);
   1105 
   1106 /*
   1107  * device_setprop_int64 --
   1108  *	Set the specified 64-bit signed integer property.
   1109  */
   1110 bool
   1111 device_setprop_int64(device_t dev, const char *prop, int64_t val)
   1112 {
   1113 	return prop_dictionary_set_int64(dev->dv_properties, prop, val);
   1114 }
   1115 
   1116 /*
   1117  * device_setprop_uint64 --
   1118  *	Set the specified 64-bit unsigned integer property.
   1119  */
   1120 bool
   1121 device_setprop_uint64(device_t dev, const char *prop, uint64_t val)
   1122 {
   1123 	return prop_dictionary_set_uint64(dev->dv_properties, prop, val);
   1124 }
   1125 
   1126 /*
   1127  * device_delprop --
   1128  *	Delete the specified property.
   1129  */
   1130 void
   1131 device_delprop(device_t dev, const char *prop)
   1132 {
   1133 	prop_dictionary_remove(dev->dv_properties, prop);
   1134 }
   1135