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