| 449 | */ |
| 450 | template <typename Callback> |
| 451 | [[nodiscard]] auto ForEachCompatibleNode(const char* compatible, |
| 452 | Callback&& callback) const |
| 453 | -> Expected<void> { |
| 454 | assert(fdt_header_ != nullptr && "fdt_header_ is null"); |
| 455 | |
| 456 | int offset = -1; |
| 457 | while (true) { |
| 458 | offset = fdt_node_offset_by_compatible(fdt_header_, offset, compatible); |
| 459 | if (offset < 0) { |
| 460 | if (offset == -FDT_ERR_NOTFOUND) { |
| 461 | break; |
| 462 | } |
| 463 | return std::unexpected(Error(ErrorCode::kFdtParseFailed)); |
| 464 | } |
| 465 | |
| 466 | const char* node_name = fdt_get_name(fdt_header_, offset, nullptr); |
| 467 | if (node_name == nullptr) { |
| 468 | continue; |
| 469 | } |
| 470 | |
| 471 | uint64_t mmio_base = 0; |
| 472 | size_t mmio_size = 0; |
| 473 | int reg_len = 0; |
| 474 | const auto* reg_prop = |
| 475 | fdt_get_property(fdt_header_, offset, "reg", ®_len); |
| 476 | if (reg_prop != nullptr && |
| 477 | static_cast<size_t>(reg_len) >= 2 * sizeof(uint64_t)) { |
| 478 | const auto* reg = reinterpret_cast<const uint64_t*>(reg_prop->data); |
| 479 | mmio_base = fdt64_to_cpu(reg[0]); |
| 480 | mmio_size = fdt64_to_cpu(reg[1]); |
| 481 | } |
| 482 | |
| 483 | uint32_t irq = 0; |
| 484 | int irq_len = 0; |
| 485 | const auto* irq_prop = |
| 486 | fdt_get_property(fdt_header_, offset, "interrupts", &irq_len); |
| 487 | if (irq_prop != nullptr && |
| 488 | static_cast<size_t>(irq_len) >= sizeof(uint32_t)) { |
| 489 | const auto* interrupts = |
| 490 | reinterpret_cast<const uint32_t*>(irq_prop->data); |
| 491 | irq = fdt32_to_cpu(interrupts[0]); |
| 492 | } |
| 493 | |
| 494 | if (!callback(offset, node_name, mmio_base, mmio_size, irq)) { |
| 495 | break; |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | return {}; |
| 500 | } |
| 501 | |
| 502 | /** |
| 503 | * @brief 遍历 FDT 中所有"叶设备"节点,自动跳过基础设施节点。 |