blob: f2b7b2954525e49ab948aeb00dead76b746aa312 [file] [log] [blame]
James Feist3cb5fec2018-01-23 14:41:51 -08001/*
2// Copyright (c) 2018 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#include <boost/container/flat_map.hpp>
19#include <ctime>
20#include <dbus/connection.hpp>
21#include <dbus/endpoint.hpp>
22#include <dbus/message.hpp>
23#include <dbus/properties.hpp>
24#include <fcntl.h>
25#include <fstream>
26#include <future>
James Feistb5320a72018-01-24 12:28:12 -080027#include <linux/i2c-dev-user.h>
James Feist3cb5fec2018-01-23 14:41:51 -080028#include <iostream>
29#include <sys/ioctl.h>
James Feist3f8a2782018-02-12 09:24:42 -080030#include <regex>
James Feist4131aea2018-03-09 09:47:30 -080031#include <sys/inotify.h>
James Feist3cb5fec2018-01-23 14:41:51 -080032
33namespace fs = std::experimental::filesystem;
34static constexpr bool DEBUG = false;
35static size_t UNKNOWN_BUS_OBJECT_COUNT = 0;
36
37const static constexpr char *BASEBOARD_FRU_LOCATION =
38 "/etc/fru/baseboard.fru.bin";
39
James Feist4131aea2018-03-09 09:47:30 -080040const static constexpr char *I2C_DEV_LOCATION = "/dev";
41
James Feist3cb5fec2018-01-23 14:41:51 -080042static constexpr std::array<const char *, 5> FRU_AREAS = {
43 "INTERNAL", "CHASSIS", "BOARD", "PRODUCT", "MULTIRECORD"};
James Feist918e18c2018-02-13 15:51:07 -080044const static constexpr char *POWER_OBJECT_NAME = "/org/openbmc/control/power0";
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -070045const static std::regex NON_ASCII_REGEX("[^\x01-\x7f]");
James Feist3cb5fec2018-01-23 14:41:51 -080046using DeviceMap = boost::container::flat_map<int, std::vector<char>>;
47using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>;
48
James Feistc95cb142018-02-26 10:41:42 -080049static bool isMuxBus(size_t bus)
50{
51 return is_symlink(std::experimental::filesystem::path(
52 "/sys/bus/i2c/devices/i2c-" + std::to_string(bus) + "/mux_device"));
53}
54
James Feist3cb5fec2018-01-23 14:41:51 -080055int get_bus_frus(int file, int first, int last, int bus,
56 std::shared_ptr<DeviceMap> devices)
57{
58 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> block_data;
59
60 for (int ii = first; ii <= last; ii++)
61 {
62 // Set slave address
63 if (ioctl(file, I2C_SLAVE_FORCE, ii) < 0)
64 {
65 std::cerr << "device at bus " << bus << "register " << ii
66 << "busy\n";
67 continue;
68 }
69 // probe
70 else if (i2c_smbus_read_byte(file) < 0)
71 {
72 continue;
73 }
74
75 if (DEBUG)
76 {
77 std::cout << "something at bus " << bus << "addr " << ii << "\n";
78 }
79 if (i2c_smbus_read_i2c_block_data(file, 0x0, 0x8, block_data.data()) <
80 0)
81 {
82 std::cerr << "failed to read bus " << bus << " address " << ii
83 << "\n";
84 continue;
85 }
86 size_t sum = 0;
87 for (int jj = 0; jj < 7; jj++)
88 {
89 sum += block_data[jj];
90 }
91 sum = (256 - sum) & 0xFF;
92
93 // check the header checksum
94 if (sum == block_data[7])
95 {
96 std::vector<char> device;
97 device.insert(device.end(), block_data.begin(),
98 block_data.begin() + 8);
99
100 for (int jj = 1; jj <= FRU_AREAS.size(); jj++)
101 {
102 auto area_offset = device[jj];
103 if (area_offset != 0)
104 {
105 area_offset *= 8;
106 if (i2c_smbus_read_i2c_block_data(file, area_offset, 0x8,
107 block_data.data()) < 0)
108 {
109 std::cerr << "failed to read bus " << bus << " address "
110 << ii << "\n";
111 return -1;
112 }
113 int length = block_data[1] * 8;
114 device.insert(device.end(), block_data.begin(),
115 block_data.begin() + 8);
116 length -= 8;
117 area_offset += 8;
118
119 while (length > 0)
120 {
121 auto to_get = std::min(0x20, length);
122 if (i2c_smbus_read_i2c_block_data(
123 file, area_offset, to_get, block_data.data()) <
124 0)
125 {
126 std::cerr << "failed to read bus " << bus
127 << " address " << ii << "\n";
128 return -1;
129 }
130 device.insert(device.end(), block_data.begin(),
131 block_data.begin() + to_get);
132 area_offset += to_get;
133 length -= to_get;
134 }
135 }
136 }
137 (*devices).emplace(ii, device);
138 }
139 }
140
141 return 0;
142}
143
144static BusMap FindI2CDevices(const std::vector<fs::path> &i2cBuses)
145{
James Feist918e18c2018-02-13 15:51:07 -0800146 std::vector<std::future<void>> futures;
James Feist3cb5fec2018-01-23 14:41:51 -0800147 BusMap busMap;
148 for (auto &i2cBus : i2cBuses)
149 {
150 auto busnum = i2cBus.string();
151 auto lastDash = busnum.rfind(std::string("-"));
152 // delete everything before dash inclusive
153 if (lastDash != std::string::npos)
154 {
155 busnum.erase(0, lastDash + 1);
156 }
157 auto bus = std::stoi(busnum);
158
159 auto file = open(i2cBus.c_str(), O_RDWR);
160 if (file < 0)
161 {
162 std::cerr << "unable to open i2c device " << i2cBus.string()
163 << "\n";
164 continue;
165 }
166 unsigned long funcs = 0;
167
168 if (ioctl(file, I2C_FUNCS, &funcs) < 0)
169 {
170 std::cerr
171 << "Error: Could not get the adapter functionality matrix bus"
172 << bus << "\n";
173 continue;
174 }
175 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE) ||
176 !(I2C_FUNC_SMBUS_READ_I2C_BLOCK))
177 {
178 std::cerr << "Error: Can't use SMBus Receive Byte command bus "
179 << bus << "\n";
180 continue;
181 }
182 auto &device = busMap[bus];
183 device = std::make_shared<DeviceMap>();
184
James Feistc95cb142018-02-26 10:41:42 -0800185 // don't scan muxed buses async as don't want to confuse the mux
186 if (isMuxBus(bus))
187 {
188 get_bus_frus(file, 0x03, 0x77, bus, device);
189 close(file);
190 }
191 else
192 {
193 // todo: call with boost asio?
194 futures.emplace_back(
195 std::async(std::launch::async, [file, device, bus] {
196 // i2cdetect by default uses the range 0x03 to 0x77, as
197 // this is
198 // what we
199 // have tested with, use this range. Could be changed in
200 // future.
201 get_bus_frus(file, 0x03, 0x77, bus, device);
202 close(file);
203 }));
204 }
James Feist3cb5fec2018-01-23 14:41:51 -0800205 }
206 for (auto &fut : futures)
207 {
208 fut.get(); // wait for all scans
209 }
210 return busMap;
211}
212
213static const std::tm intelEpoch(void)
214{
215 std::tm val = {0};
216 val.tm_year = 1996 - 1900;
217 return val;
218}
219
220bool formatFru(const std::vector<char> &fruBytes,
221 boost::container::flat_map<std::string, std::string> &result)
222{
223 static const std::vector<const char *> CHASSIS_FRU_AREAS = {
224 "PART_NUMBER", "SERIAL_NUMBER", "CHASSIS_INFO_AM1", "CHASSIS_INFO_AM2"};
225
226 static const std::vector<const char *> BOARD_FRU_AREAS = {
227 "MANUFACTURER", "PRODUCT_NAME", "SERIAL_NUMBER", "PART_NUMBER",
228 "VERSION_ID"};
229
230 static const std::vector<const char *> PRODUCT_FRU_AREAS = {
231 "MANUFACTURER", "PRODUCT_NAME", "PART_NUMBER",
232 "PRODUCT_VERSION", "PRODUCT_SERIAL_NUMBER", "ASSET_TAG"};
233
234 size_t sum = 0;
235
236 if (fruBytes.size() < 8)
237 {
238 return false;
239 }
240 std::vector<char>::const_iterator fruAreaOffsetField = fruBytes.begin();
241 result["Common Format Version"] =
242 std::to_string(static_cast<int>(*fruAreaOffsetField));
243
244 const std::vector<const char *> *fieldData;
245
246 for (auto &area : FRU_AREAS)
247 {
248 fruAreaOffsetField++;
249 if (fruAreaOffsetField >= fruBytes.end())
250 {
251 return false;
252 }
253 size_t offset = (*fruAreaOffsetField) * 8;
254
255 if (offset > 1)
256 {
257 // +2 to skip format and length
258 std::vector<char>::const_iterator fruBytesIter =
259 fruBytes.begin() + offset + 2;
260
261 if (fruBytesIter >= fruBytes.end())
262 {
263 return false;
264 }
265
266 if (area == "CHASSIS")
267 {
268 result["CHASSIS_TYPE"] =
269 std::to_string(static_cast<int>(*fruBytesIter));
270 fruBytesIter += 1;
271 fieldData = &CHASSIS_FRU_AREAS;
272 }
273 else if (area == "BOARD")
274 {
275 result["BOARD_LANGUAGE_CODE"] =
276 std::to_string(static_cast<int>(*fruBytesIter));
277 fruBytesIter += 1;
278 if (fruBytesIter >= fruBytes.end())
279 {
280 return false;
281 }
282
283 unsigned int minutes = *fruBytesIter |
284 *(fruBytesIter + 1) << 8 |
285 *(fruBytesIter + 2) << 16;
286 std::tm fruTime = intelEpoch();
287 time_t timeValue = mktime(&fruTime);
288 timeValue += minutes * 60;
289 fruTime = *gmtime(&timeValue);
290
291 result["BOARD_MANUFACTURE_DATE"] = asctime(&fruTime);
292 result["BOARD_MANUFACTURE_DATE"]
293 .pop_back(); // remove trailing null
294 fruBytesIter += 3;
295 fieldData = &BOARD_FRU_AREAS;
296 }
297 else if (area == "PRODUCT")
298 {
299 result["PRODUCT_LANGUAGE_CODE"] =
300 std::to_string(static_cast<int>(*fruBytesIter));
301 fruBytesIter += 1;
302 fieldData = &PRODUCT_FRU_AREAS;
303 }
304 else
305 {
306 continue;
307 }
308 for (auto &field : *fieldData)
309 {
310 if (fruBytesIter >= fruBytes.end())
311 {
312 return false;
313 }
314
315 size_t length = *fruBytesIter & 0x3f;
316 fruBytesIter += 1;
317
318 if (fruBytesIter >= fruBytes.end())
319 {
320 return false;
321 }
322
323 result[std::string(area) + "_" + field] =
324 std::string(fruBytesIter, fruBytesIter + length);
325 fruBytesIter += length;
326 if (fruBytesIter >= fruBytes.end())
327 {
328 std::cerr << "Warning Fru Length Mismatch:\n ";
329 for (auto &c : fruBytes)
330 {
331 std::cerr << c;
332 }
333 std::cerr << "\n";
334 if (DEBUG)
335 {
336 for (auto &keyPair : result)
337 {
338 std::cerr << keyPair.first << " : "
339 << keyPair.second << "\n";
340 }
341 }
342 return false;
343 }
344 }
345 }
346 }
347
348 return true;
349}
350
351void AddFruObjectToDbus(
352 std::shared_ptr<dbus::connection> dbusConn, std::vector<char> &device,
353 dbus::DbusObjectServer &objServer,
354 boost::container::flat_map<std::pair<size_t, size_t>,
355 std::shared_ptr<dbus::DbusObject>>
356 &dbusObjectMap,
357 int bus, size_t address)
358{
359 boost::container::flat_map<std::string, std::string> formattedFru;
360 if (!formatFru(device, formattedFru))
361 {
362 std::cerr << "failed to format fru for device at bus " << std::hex
363 << bus << "address " << address << "\n";
364 return;
365 }
366 auto productNameFind = formattedFru.find("BOARD_PRODUCT_NAME");
367 std::string productName;
368 if (productNameFind == formattedFru.end())
369 {
370 productNameFind = formattedFru.find("PRODUCT_PRODUCT_NAME");
371 }
372 if (productNameFind != formattedFru.end())
373 {
374 productName = productNameFind->second;
James Feist3f8a2782018-02-12 09:24:42 -0800375 std::regex illegalObject("[^A-Za-z0-9_]");
376 productName = std::regex_replace(productName, illegalObject, "_");
James Feist3cb5fec2018-01-23 14:41:51 -0800377 }
378 else
379 {
380 productName = "UNKNOWN" + std::to_string(UNKNOWN_BUS_OBJECT_COUNT);
381 UNKNOWN_BUS_OBJECT_COUNT++;
382 }
383
James Feist918e18c2018-02-13 15:51:07 -0800384 productName = "/xyz/openbmc_project/FruDevice/" + productName;
385
386 // avoid duplicates by checking to see if on a mux
James Feist79e9c0b2018-03-15 15:21:17 -0700387 if (bus > 0)
James Feist918e18c2018-02-13 15:51:07 -0800388 {
James Feist79e9c0b2018-03-15 15:21:17 -0700389 size_t index = 0;
James Feist918e18c2018-02-13 15:51:07 -0800390 for (auto const &busObj : dbusObjectMap)
391 {
James Feist79e9c0b2018-03-15 15:21:17 -0700392 if ((busObj.second->object_name == productName))
James Feist918e18c2018-02-13 15:51:07 -0800393 {
James Feist79e9c0b2018-03-15 15:21:17 -0700394 if (isMuxBus(bus) && address == busObj.first.second)
395 {
396 continue;
397 }
398 // add underscore _index for the same object path on dbus
399 std::string strIndex = std::to_string(index);
400 if (index > 0)
401 {
402 productName.substr(0, productName.size() - strIndex.size());
403 }
404 else
405 {
406 productName += "_";
407 }
408 productName += std::to_string(index++);
James Feist918e18c2018-02-13 15:51:07 -0800409 }
410 }
411 }
412 auto object = objServer.add_object(productName);
James Feist3cb5fec2018-01-23 14:41:51 -0800413 dbusObjectMap[std::pair<size_t, size_t>(bus, address)] = object;
414
415 auto iface = std::make_shared<dbus::DbusInterface>(
416 "xyz.openbmc_project.FruDevice", dbusConn);
417 object->register_interface(iface);
418 for (auto &property : formattedFru)
419 {
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -0700420 std::regex_replace(property.second.begin(), property.second.begin(),
421 property.second.end(), NON_ASCII_REGEX, "_");
James Feist3cb5fec2018-01-23 14:41:51 -0800422 iface->set_property(property.first, property.second);
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -0700423 if (DEBUG)
424 {
425 std::cout << property.first << ": " << property.second << "\n";
426 }
James Feist3cb5fec2018-01-23 14:41:51 -0800427 }
428 // baseboard can set this to -1 to not set a bus / address
429 if (bus > 0)
430 {
431 std::stringstream data;
432 data << "0x" << std::hex << bus;
433 iface->set_property("BUS", data.str());
434 data.str("");
435 data << "0x" << std::hex << address;
436 iface->set_property("ADDRESS", data.str());
437 }
438}
439
440static bool readBaseboardFru(std::vector<char> &baseboardFru)
441{
442 // try to read baseboard fru from file
443 std::ifstream baseboardFruFile(BASEBOARD_FRU_LOCATION, std::ios::binary);
444 if (baseboardFruFile.good())
445 {
446 baseboardFruFile.seekg(0, std::ios_base::end);
447 std::streampos fileSize = baseboardFruFile.tellg();
448 baseboardFru.resize(fileSize);
449 baseboardFruFile.seekg(0, std::ios_base::beg);
450 baseboardFruFile.read(baseboardFru.data(), fileSize);
451 }
452 else
453 {
454 return false;
455 }
456 return true;
457}
458
James Feist918e18c2018-02-13 15:51:07 -0800459void rescanBusses(boost::container::flat_map<std::pair<size_t, size_t>,
460 std::shared_ptr<dbus::DbusObject>>
461 &dbusObjectMap,
462 std::shared_ptr<dbus::connection> systemBus,
James Feist4131aea2018-03-09 09:47:30 -0800463 dbus::DbusObjectServer &objServer,
464 std::atomic_bool &pendingCallback)
James Feist918e18c2018-02-13 15:51:07 -0800465{
James Feist918e18c2018-02-13 15:51:07 -0800466
James Feist4131aea2018-03-09 09:47:30 -0800467 do
James Feist918e18c2018-02-13 15:51:07 -0800468 {
James Feist4131aea2018-03-09 09:47:30 -0800469 auto devDir = fs::path("/dev/");
470 auto matchString = std::string("i2c*");
471 std::vector<fs::path> i2cBuses;
472 pendingCallback = false;
James Feist918e18c2018-02-13 15:51:07 -0800473
James Feist4131aea2018-03-09 09:47:30 -0800474 if (!find_files(devDir, matchString, i2cBuses, 0))
James Feist918e18c2018-02-13 15:51:07 -0800475 {
James Feist4131aea2018-03-09 09:47:30 -0800476 std::cerr << "unable to find i2c devices\n";
477 return;
James Feist918e18c2018-02-13 15:51:07 -0800478 }
James Feist4131aea2018-03-09 09:47:30 -0800479 // scanning muxes in reverse order seems to have adverse effects
480 // sorting this list seems to be a fix for that
481 std::sort(i2cBuses.begin(), i2cBuses.end());
482 BusMap busMap = FindI2CDevices(i2cBuses);
483
484 for (auto &busObj : dbusObjectMap)
485 {
486 objServer.remove_object(busObj.second);
487 }
488
489 dbusObjectMap.clear();
490 UNKNOWN_BUS_OBJECT_COUNT = 0;
491
492 for (auto &devicemap : busMap)
493 {
494 for (auto &device : *devicemap.second)
495 {
496 AddFruObjectToDbus(systemBus, device.second, objServer,
497 dbusObjectMap, devicemap.first,
498 device.first);
499 }
500 }
501 // todo, get this from a more sensable place
502 std::vector<char> baseboardFru;
503 if (readBaseboardFru(baseboardFru))
504 {
505 AddFruObjectToDbus(systemBus, baseboardFru, objServer,
506 dbusObjectMap, -1, -1);
507 }
508 } while (pendingCallback);
James Feist918e18c2018-02-13 15:51:07 -0800509}
510
James Feist3cb5fec2018-01-23 14:41:51 -0800511int main(int argc, char **argv)
512{
513 auto devDir = fs::path("/dev/");
514 auto matchString = std::string("i2c*");
515 std::vector<fs::path> i2cBuses;
516
517 if (!find_files(devDir, matchString, i2cBuses, 0))
518 {
519 std::cerr << "unable to find i2c devices\n";
520 return 1;
521 }
James Feist3cb5fec2018-01-23 14:41:51 -0800522
523 boost::asio::io_service io;
524 auto systemBus = std::make_shared<dbus::connection>(io, dbus::bus::system);
525 dbus::DbusObjectServer objServer(systemBus);
526 systemBus->request_name("com.intel.FruDevice");
527
528 // this is a map with keys of pair(bus number, adddress) and values of the
529 // object on dbus
530 boost::container::flat_map<std::pair<size_t, size_t>,
531 std::shared_ptr<dbus::DbusObject>>
532 dbusObjectMap;
533
James Feist3cb5fec2018-01-23 14:41:51 -0800534 auto iface = std::make_shared<dbus::DbusInterface>(
535 "xyz.openbmc_project.FruDeviceManager", systemBus);
James Feist3cb5fec2018-01-23 14:41:51 -0800536
James Feist918e18c2018-02-13 15:51:07 -0800537 std::atomic_bool threadRunning(false);
James Feist4131aea2018-03-09 09:47:30 -0800538 std::atomic_bool pendingCallback(false);
James Feist918e18c2018-02-13 15:51:07 -0800539 std::future<void> future;
540
James Feist3cb5fec2018-01-23 14:41:51 -0800541 iface->register_method("ReScan", [&]() {
James Feist4131aea2018-03-09 09:47:30 -0800542 bool notRunning = false;
543 if (threadRunning.compare_exchange_strong(notRunning, true))
James Feist3cb5fec2018-01-23 14:41:51 -0800544 {
James Feist918e18c2018-02-13 15:51:07 -0800545 future = std::async(std::launch::async, [&] {
James Feist4131aea2018-03-09 09:47:30 -0800546 rescanBusses(dbusObjectMap, systemBus, objServer,
547 pendingCallback);
James Feist918e18c2018-02-13 15:51:07 -0800548 threadRunning = false;
549 });
James Feist3cb5fec2018-01-23 14:41:51 -0800550 }
James Feist4131aea2018-03-09 09:47:30 -0800551 else
552 {
553 pendingCallback = true;
554 }
James Feist3cb5fec2018-01-23 14:41:51 -0800555 return std::tuple<>(); // this is a bug in boost-dbus, needs some sort
556 // of return
557 });
558
James Feist918e18c2018-02-13 15:51:07 -0800559 dbus::match powerChange(systemBus,
560 "type='signal',path_namespace='" +
561 std::string(POWER_OBJECT_NAME) + "'");
562
563 dbus::filter filter(systemBus, [](dbus::message &m) {
564 auto member = m.get_member();
565 return member == "PropertiesChanged";
566 });
567 std::function<void(boost::system::error_code, dbus::message)> eventHandler =
568 [&](boost::system::error_code ec, dbus::message s) {
569 boost::container::flat_map<std::string, dbus::dbus_variant> values;
570 std::string objectName;
571 s.unpack(objectName, values);
572 auto findPgood = values.find("pgood");
573 if (findPgood != values.end())
574 {
James Feist4131aea2018-03-09 09:47:30 -0800575 bool notRunning = false;
576 if (threadRunning.compare_exchange_strong(notRunning, true))
James Feist918e18c2018-02-13 15:51:07 -0800577 {
James Feist918e18c2018-02-13 15:51:07 -0800578 future = std::async(std::launch::async, [&] {
James Feist4131aea2018-03-09 09:47:30 -0800579 rescanBusses(dbusObjectMap, systemBus, objServer,
580 pendingCallback);
James Feist918e18c2018-02-13 15:51:07 -0800581 threadRunning = false;
582 });
583 }
James Feist4131aea2018-03-09 09:47:30 -0800584 else
585 {
586 pendingCallback = true;
587 }
James Feist918e18c2018-02-13 15:51:07 -0800588 }
589 filter.async_dispatch(eventHandler);
590
591 };
592 filter.async_dispatch(eventHandler);
James Feist4131aea2018-03-09 09:47:30 -0800593 int fd = inotify_init();
594 int wd = inotify_add_watch(fd, I2C_DEV_LOCATION,
595 IN_CREATE | IN_MOVED_TO | IN_DELETE);
596 std::array<char, 4096> readBuffer;
597 std::string pendingBuffer;
598 // monitor for new i2c devices
599 boost::asio::posix::stream_descriptor dirWatch(io, fd);
600 std::function<void(const boost::system::error_code, std::size_t)>
601 watchI2cBusses = [&](const boost::system::error_code &ec,
602 std::size_t bytes_transferred) {
603 if (ec)
604 {
605 std::cout << "Callback Error " << ec << "\n";
606 return;
607 }
608 pendingBuffer += std::string(readBuffer.data(), bytes_transferred);
609 bool devChange = false;
610 while (pendingBuffer.size() > sizeof(inotify_event))
611 {
612 const inotify_event *iEvent =
613 reinterpret_cast<const inotify_event *>(
614 pendingBuffer.data());
615 switch (iEvent->mask)
616 {
617 case IN_CREATE:
618 case IN_MOVED_TO:
619 case IN_DELETE:
620 if (boost::starts_with(std::string(iEvent->name), "i2c"))
621 {
622 devChange = true;
623 }
624 }
625
626 pendingBuffer.erase(0, sizeof(inotify_event) + iEvent->len);
627 }
628 bool notRunning = false;
629 if (devChange &&
630 threadRunning.compare_exchange_strong(notRunning, true))
631 {
632 future = std::async(std::launch::async, [&] {
633 std::this_thread::sleep_for(std::chrono::seconds(2));
634 rescanBusses(dbusObjectMap, systemBus, objServer,
635 pendingCallback);
636 threadRunning = false;
637 });
638 }
639 else if (devChange)
640 {
641 pendingCallback = true;
642 }
643 dirWatch.async_read_some(boost::asio::buffer(readBuffer),
644 watchI2cBusses);
645 };
646
647 dirWatch.async_read_some(boost::asio::buffer(readBuffer), watchI2cBusses);
648
649 // run the intial scan
650 rescanBusses(dbusObjectMap, systemBus, objServer, pendingCallback);
651
652 auto object = std::make_shared<dbus::DbusObject>(
653 systemBus, "/xyz/openbmc_project/FruDevice");
654 objServer.register_object(object);
655 object->register_interface(iface);
James Feist918e18c2018-02-13 15:51:07 -0800656
James Feist3cb5fec2018-01-23 14:41:51 -0800657 io.run();
658 return 0;
659}