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