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