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