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