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 
7 #include <utility>
8 
9 namespace {
10 
11 template <typename T>
CopyResources(size_t in_count,const T * in_list,fbl::Array<T> * out)12 bool CopyResources(size_t in_count, const T* in_list, fbl::Array<T>* out) {
13     if (!in_count) {
14         return true;
15     }
16     fbl::AllocChecker ac;
17     out->reset(new (&ac) T[in_count], in_count);
18     if (!ac.check()) {
19         return false;
20     }
21     memcpy(out->begin(), in_list, in_count * sizeof(T));
22     return true;
23 }
24 
25 } // namespace
26 
27 namespace platform_bus {
28 
Init(const pbus_dev_t * pdev,uint32_t * next_index)29 zx_status_t DeviceResources::Init(const pbus_dev_t* pdev, uint32_t* next_index) {
30     if (pdev->protocol_count > PROXY_MAX_PROTOCOLS) {
31         return ZX_ERR_INVALID_ARGS;
32     }
33     if (!CopyResources(pdev->mmio_count, pdev->mmio_list, &mmios_) ||
34         !CopyResources(pdev->irq_count, pdev->irq_list, &irqs_) ||
35         !CopyResources(pdev->gpio_count, pdev->gpio_list, &gpios_) ||
36         !CopyResources(pdev->i2c_channel_count, pdev->i2c_channel_list, &i2c_channels_) ||
37         !CopyResources(pdev->clk_count, pdev->clk_list, &clks_) ||
38         !CopyResources(pdev->bti_count, pdev->bti_list, &btis_) ||
39         !CopyResources(pdev->smc_count, pdev->smc_list, &smcs_) ||
40         !CopyResources(pdev->metadata_count, pdev->metadata_list, &metadata_) ||
41         !CopyResources(pdev->boot_metadata_count, pdev->boot_metadata_list, &boot_metadata_) ||
42         !CopyResources(pdev->protocol_count, pdev->protocol_list, &protocols_)) {
43         return ZX_ERR_NO_MEMORY;
44     }
45 
46     if (pdev->child_count) {
47         fbl::AllocChecker ac;
48         children_.reserve(pdev->child_count, &ac);
49         if (!ac.check()) {
50             return ZX_ERR_NO_MEMORY;
51         }
52         for (uint32_t i = 0; i < pdev->child_count; i++) {
53             DeviceResources dr((*next_index)++);
54             auto status = dr.Init(&pdev->child_list[i], next_index);
55             if (status != ZX_OK) {
56                 return status;
57             }
58             children_.push_back(std::move(dr));
59         }
60     }
61 
62     return ZX_OK;
63 }
64 
Init(const pbus_dev_t * pdev)65 zx_status_t DeviceResources::Init(const pbus_dev_t* pdev) {
66     uint32_t next_index = index_ + 1;
67     return Init(pdev, &next_index);
68 }
69 
DeviceCount() const70 size_t DeviceResources::DeviceCount() const {
71     size_t result = 1;
72     for (auto& dr : children_) {
73         result += dr.DeviceCount();
74     }
75     return result;
76 }
77 
BuildDeviceIndex(fbl::Vector<const DeviceResources * > * index) const78 void DeviceResources::BuildDeviceIndex(fbl::Vector<const DeviceResources*>* index) const {
79     index->push_back(this);
80     for (DeviceResources& dr : children_) {
81         dr.BuildDeviceIndex(index);
82     }
83 }
84 
85 } // namespace platform_bus
86