1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "device-resources.h"
6
7namespace {
8
9template <typename T>
10bool CopyResources(size_t in_count, const T* in_list, fbl::Array<T>* out) {
11    if (!in_count) {
12        return true;
13    }
14    fbl::AllocChecker ac;
15    out->reset(new (&ac) T[in_count], in_count);
16    if (!ac.check()) {
17        return false;
18    }
19    memcpy(out->begin(), in_list, in_count * sizeof(T));
20    return true;
21}
22
23} // namespace
24
25namespace platform_bus {
26
27zx_status_t DeviceResources::Init(const pbus_dev_t* pdev, uint32_t* next_index) {
28    if (pdev->protocol_count > PROXY_MAX_PROTOCOLS) {
29        return ZX_ERR_INVALID_ARGS;
30    }
31    if (!CopyResources(pdev->mmio_count, pdev->mmios, &mmios_) ||
32        !CopyResources(pdev->irq_count, pdev->irqs, &irqs_) ||
33        !CopyResources(pdev->gpio_count, pdev->gpios, &gpios_) ||
34        !CopyResources(pdev->i2c_channel_count, pdev->i2c_channels, &i2c_channels_) ||
35        !CopyResources(pdev->clk_count, pdev->clks, &clks_) ||
36        !CopyResources(pdev->bti_count, pdev->btis, &btis_) ||
37        !CopyResources(pdev->metadata_count, pdev->metadata, &metadata_) ||
38        !CopyResources(pdev->boot_metadata_count, pdev->boot_metadata, &boot_metadata_) ||
39        !CopyResources(pdev->protocol_count, pdev->protocols, &protocols_)) {
40        return ZX_ERR_NO_MEMORY;
41    }
42
43    if (pdev->child_count) {
44        fbl::AllocChecker ac;
45        children_.reserve(pdev->child_count, &ac);
46        if (!ac.check()) {
47            return ZX_ERR_NO_MEMORY;
48        }
49        for (uint32_t i = 0; i < pdev->child_count; i++) {
50            DeviceResources dr((*next_index)++);
51            auto status = dr.Init(&pdev->children[i], next_index);
52            if (status != ZX_OK) {
53                return status;
54            }
55            children_.push_back(fbl::move(dr));
56        }
57    }
58
59    return ZX_OK;
60}
61
62zx_status_t DeviceResources::Init(const pbus_dev_t* pdev) {
63    uint32_t next_index = index_ + 1;
64    return Init(pdev, &next_index);
65}
66
67size_t DeviceResources::DeviceCount() const {
68    size_t result = 1;
69    for (auto& dr : children_) {
70        result += dr.DeviceCount();
71    }
72    return result;
73}
74
75void DeviceResources::BuildDeviceIndex(fbl::Vector<const DeviceResources*>* index) const {
76    index->push_back(this);
77    for (DeviceResources& dr : children_) {
78        dr.BuildDeviceIndex(index);
79    }
80}
81
82} // namespace platform_bus
83