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