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