1 /*
2  * Copyright (c) 2021 Travis Geiseblrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #pragma once
9 
10 #include <sys/types.h>
11 #include <dev/bus/pci.h>
12 #include <lk/cpp.h>
13 #include <lk/err.h>
14 
15 #include "device.h"
16 #include "bridge.h"
17 
18 namespace pci {
19 
20 class resource_allocator;
21 
22 // bus device holds a list of devices and a reference to its bridge device
23 class bus {
24 public:
25     bus(pci_location_t loc, bridge *b, bool root_bus = false);
26     ~bus() = default;
27 
28     DISALLOW_COPY_ASSIGN_AND_MOVE(bus);
29 
30     static status_t probe(pci_location_t loc, bridge *bridge, bus **out_bus, bool root_bus = false);
31 
32     // allocate resources for devices on this bus and recursively all of its children
33     status_t allocate_resources(resource_allocator &allocator);
34 
loc()35     pci_location_t loc() const { return loc_; }
bus_num()36     uint bus_num() const { return loc().bus; }
37 
38     void add_device(device *d);
39     void dump(size_t indent = 0);
40 
get_bridge()41     const bridge *get_bridge() const { return b_; }
get_bridge()42     bridge *get_bridge() { return b_; }
43 
44     template <typename F>
45     status_t for_every_device(F func);
46 
47     void add_to_global_list();
48 
49     // master list of busses for easy iteration
50     list_node node = LIST_INITIAL_CLEARED_VALUE;
list_node_ptr()51     list_node *list_node_ptr() { return &node; }
52 
53 private:
54     pci_location_t loc_ = {};
55     bridge *b_ = nullptr;
56     list_node child_devices_ = LIST_INITIAL_VALUE(child_devices_);
57     const bool root_bus_ = false; // changes some of the allocation behavior
58 };
59 
60 // call the provided functor on every device in this bus
61 template <typename F>
for_every_device(F func)62 inline status_t bus::for_every_device(F func) {
63     status_t err = NO_ERROR;
64 
65     device *d;
66     list_for_every_entry(&child_devices_, d, device, node) {
67         err = func(d);
68         if (err != NO_ERROR) {
69             return err;
70         }
71     }
72     return err;
73 }
74 
75 } // namespace pci
76