blob: 110d32d4bb4d2fc2e9705e2c9035ccb3af84ea8d [file] [log] [blame]
Feist, Jamesc95cf672019-08-29 16:10:35 -07001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "utils.hpp"
18
19#include <boost/algorithm/string/replace.hpp>
20#include <boost/asio/steady_timer.hpp>
21#include <iostream>
22#include <sdbusplus/asio/connection.hpp>
23#include <sdbusplus/asio/object_server.hpp>
24#include <sdbusplus/bus/match.hpp>
25#include <string>
26
27extern "C" {
28#include <i2c/smbus.h>
29#include <linux/i2c-dev.h>
30}
31
32constexpr const char* configType =
33 "xyz.openbmc_project.Configuration.Intel_HSBP_CPLD";
34
35boost::asio::io_context io;
36auto conn = std::make_shared<sdbusplus::asio::connection>(io);
37sdbusplus::asio::object_server objServer(conn);
38
39struct Backplane
40{
41
42 Backplane(size_t busIn, size_t addressIn, const std::string& nameIn) :
43 bus(busIn), address(addressIn), name(nameIn)
44 {
45 }
46
47 void run()
48 {
49 file = open(("/dev/i2c-" + std::to_string(bus)).c_str(), O_RDWR);
50 if (file < 0)
51 {
52 std::cerr << "unable to open bus " << bus << "\n";
53 return;
54 }
55
56 if (ioctl(file, I2C_SLAVE_FORCE, address) < 0)
57 {
58 std::cerr << "unable to set address to " << address << "\n";
59 return;
60 }
61
62 hsbpItemIface = objServer.add_interface(
63 "/xyz/openbmc_project/inventory/item/hsbp/" +
64 boost::replace_all_copy(name, " ", "_"),
65 inventory::interface);
66 hsbpItemIface->register_property("Present", present(true));
67 hsbpItemIface->register_property("PrettyName", name);
68 hsbpItemIface->initialize();
69
70 if (!present())
71 {
72 // backplane isn't there
73 return;
74 }
75 }
76
77 bool present(bool update = false)
78 {
79 static bool present = false;
80 if (update)
81 {
82 present = i2c_smbus_read_byte(file) >= 0;
83 }
84 return present;
85 }
86 ~Backplane()
87 {
88 objServer.remove_interface(hsbpItemIface);
89 if (file >= 0)
90 {
91 close(file);
92 }
93 }
94
95 size_t bus;
96 size_t address;
97 int file = -1;
98 std::string name;
99 std::string type;
100
101 std::shared_ptr<sdbusplus::asio::dbus_interface> hsbpItemIface;
102 std::vector<std::shared_ptr<sdbusplus::asio::dbus_interface>>
103 driveItemIfaces;
104};
105
106std::unordered_map<std::string, Backplane> backplanes;
107
108void populate()
109{
110 conn->async_method_call(
111 [](const boost::system::error_code ec, const GetSubTreeType& subtree) {
112 if (ec)
113 {
114 std::cerr << "Error contacting mapper " << ec.message() << "\n";
115 return;
116 }
117 for (const auto& [path, objDict] : subtree)
118 {
119 if (objDict.empty())
120 {
121 continue;
122 }
123
124 const std::string& owner = objDict.begin()->first;
125 conn->async_method_call(
126 [path](const boost::system::error_code ec2,
127 const boost::container::flat_map<
128 std::string, BasicVariantType>& resp) {
129 if (ec2)
130 {
131 std::cerr << "Error Getting Config "
132 << ec2.message() << "\n";
133 return;
134 }
135 backplanes.clear();
136 std::optional<size_t> bus;
137 std::optional<size_t> address;
138 std::optional<std::string> name;
139 for (const auto& [key, value] : resp)
140 {
141 if (key == "Bus")
142 {
143 bus = std::get<uint64_t>(value);
144 }
145 else if (key == "Address")
146 {
147 address = std::get<uint64_t>(value);
148 }
149 else if (key == "Name")
150 {
151 name = std::get<std::string>(value);
152 }
153 }
154 if (!bus || !address || !name)
155 {
156 std::cerr << "Illegal configuration at " << path
157 << "\n";
158 return;
159 }
160 const auto& [backplane, status] = backplanes.emplace(
161 *name, Backplane(*bus, *address, *name));
162 backplane->second.run();
163 },
164 owner, path, "org.freedesktop.DBus.Properties", "GetAll",
165 configType);
166 }
167 },
168 mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
169 0, std::array<const char*, 1>{configType});
170}
171
172int main()
173{
174 boost::asio::steady_timer callbackTimer(io);
175
176 conn->request_name("xyz.openbmc_project.HsbpManager");
177
178 sdbusplus::bus::match::match match(
179 *conn,
180 "type='signal',member='PropertiesChanged',arg0='" +
181 std::string(configType) + "'",
182 [&callbackTimer](sdbusplus::message::message&) {
183 callbackTimer.expires_after(std::chrono::seconds(2));
184 callbackTimer.async_wait([](const boost::system::error_code ec) {
185 if (ec == boost::asio::error::operation_aborted)
186 {
187 // timer was restarted
188 return;
189 }
190 else if (ec)
191 {
192 std::cerr << "Timer error" << ec.message() << "\n";
193 return;
194 }
195 populate();
196 });
197 });
198
199 io.post([]() { populate(); });
200 io.run();
201}