15c589487SBrad Bishop /** 25c589487SBrad Bishop * Copyright © 2017 IBM Corporation 35c589487SBrad Bishop * 45c589487SBrad Bishop * Licensed under the Apache License, Version 2.0 (the "License"); 55c589487SBrad Bishop * you may not use this file except in compliance with the License. 65c589487SBrad Bishop * You may obtain a copy of the License at 75c589487SBrad Bishop * 85c589487SBrad Bishop * http://www.apache.org/licenses/LICENSE-2.0 95c589487SBrad Bishop * 105c589487SBrad Bishop * Unless required by applicable law or agreed to in writing, software 115c589487SBrad Bishop * distributed under the License is distributed on an "AS IS" BASIS, 125c589487SBrad Bishop * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135c589487SBrad Bishop * See the License for the specific language governing permissions and 145c589487SBrad Bishop * limitations under the License. 155c589487SBrad Bishop */ 162d2caa34SMatthew Barth #include "gpio.hpp" 172d2caa34SMatthew Barth 18*c65d91d6SMatt Spinler #include "logging.hpp" 192d2caa34SMatthew Barth #include "rpolicy.hpp" 20*c65d91d6SMatt Spinler #include "sdbusplus.hpp" 212d2caa34SMatthew Barth 225c589487SBrad Bishop #include <phosphor-logging/elog-errors.hpp> 235c589487SBrad Bishop #include <phosphor-logging/elog.hpp> 241cfc2f11SWilliam A. Kennington III #include <sdeventplus/event.hpp> 255c589487SBrad Bishop #include <xyz/openbmc_project/Common/Callout/error.hpp> 26*c65d91d6SMatt Spinler #include <xyz/openbmc_project/Logging/Entry/server.hpp> 272d2caa34SMatthew Barth 282d2caa34SMatthew Barth #include <functional> 292d2caa34SMatthew Barth #include <tuple> 305c589487SBrad Bishop 315c589487SBrad Bishop namespace phosphor 325c589487SBrad Bishop { 335c589487SBrad Bishop namespace fan 345c589487SBrad Bishop { 355c589487SBrad Bishop namespace presence 365c589487SBrad Bishop { 375c589487SBrad Bishop 38*c65d91d6SMatt Spinler const auto loggingService = "xyz.openbmc_project.Logging"; 39*c65d91d6SMatt Spinler const auto loggingPath = "/xyz/openbmc_project/logging"; 40*c65d91d6SMatt Spinler const auto loggingCreateIface = "xyz.openbmc_project.Logging.Create"; 41*c65d91d6SMatt Spinler 422d2caa34SMatthew Barth Gpio::Gpio(const std::string& physDevice, const std::string& device, 435c589487SBrad Bishop unsigned int physPin) : 445c589487SBrad Bishop currentState(false), 452e9788d7SBrad Bishop evdevfd(open(device.c_str(), O_RDONLY | O_NONBLOCK)), 462d2caa34SMatthew Barth evdev(evdevpp::evdev::newFromFD(evdevfd())), phys(physDevice), pin(physPin) 472d2caa34SMatthew Barth {} 485c589487SBrad Bishop 495c589487SBrad Bishop bool Gpio::start() 505c589487SBrad Bishop { 512d2caa34SMatthew Barth source.emplace(sdeventplus::Event::get_default(), evdevfd(), EPOLLIN, 521cfc2f11SWilliam A. Kennington III std::bind(&Gpio::ioCallback, this)); 535c589487SBrad Bishop currentState = present(); 545c589487SBrad Bishop return currentState; 555c589487SBrad Bishop } 565c589487SBrad Bishop 575c589487SBrad Bishop void Gpio::stop() 585c589487SBrad Bishop { 591cfc2f11SWilliam A. Kennington III source.reset(); 605c589487SBrad Bishop } 615c589487SBrad Bishop 625c589487SBrad Bishop bool Gpio::present() 635c589487SBrad Bishop { 645c589487SBrad Bishop return evdev.fetch(EV_KEY, pin) != 0; 655c589487SBrad Bishop } 665c589487SBrad Bishop 675c589487SBrad Bishop void Gpio::fail() 685c589487SBrad Bishop { 695c589487SBrad Bishop using namespace sdbusplus::xyz::openbmc_project::Common::Callout::Error; 705c589487SBrad Bishop using namespace phosphor::logging; 715c589487SBrad Bishop using namespace xyz::openbmc_project::Common::Callout; 725c589487SBrad Bishop 735c589487SBrad Bishop report<sdbusplus::xyz::openbmc_project::Common::Callout::Error::GPIO>( 742d2caa34SMatthew Barth GPIO::CALLOUT_GPIO_NUM(pin), GPIO::CALLOUT_ERRNO(0), 755c589487SBrad Bishop GPIO::CALLOUT_DEVICE_PATH(phys.c_str())); 765c589487SBrad Bishop } 775c589487SBrad Bishop 781cfc2f11SWilliam A. Kennington III void Gpio::ioCallback() 795c589487SBrad Bishop { 805c589487SBrad Bishop unsigned int type, code, value; 815c589487SBrad Bishop 825c589487SBrad Bishop std::tie(type, code, value) = evdev.next(); 835c589487SBrad Bishop if (type != EV_KEY || code != pin) 845c589487SBrad Bishop { 855c589487SBrad Bishop return; 865c589487SBrad Bishop } 875c589487SBrad Bishop 885c589487SBrad Bishop bool newState = value != 0; 895c589487SBrad Bishop 905c589487SBrad Bishop if (currentState != newState) 915c589487SBrad Bishop { 9211083ecaSBrad Bishop getPolicy().stateChanged(newState, *this); 935c589487SBrad Bishop currentState = newState; 945c589487SBrad Bishop } 955c589487SBrad Bishop } 96*c65d91d6SMatt Spinler 97*c65d91d6SMatt Spinler void Gpio::logConflict(const std::string& fanInventoryPath) const 98*c65d91d6SMatt Spinler { 99*c65d91d6SMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Logging::server; 100*c65d91d6SMatt Spinler std::map<std::string, std::string> ad; 101*c65d91d6SMatt Spinler Entry::Level severity = Entry::Level::Informational; 102*c65d91d6SMatt Spinler 103*c65d91d6SMatt Spinler static constexpr auto errorName = 104*c65d91d6SMatt Spinler "xyz.openbmc_project.Fan.Presence.Error.Detection"; 105*c65d91d6SMatt Spinler 106*c65d91d6SMatt Spinler ad.emplace("_PID", std::to_string(getpid())); 107*c65d91d6SMatt Spinler ad.emplace("CALLOUT_INVENTORY_PATH", fanInventoryPath); 108*c65d91d6SMatt Spinler ad.emplace("GPIO_NUM", std::to_string(pin)); 109*c65d91d6SMatt Spinler ad.emplace("GPIO_DEVICE_PATH", (phys.c_str())); 110*c65d91d6SMatt Spinler 111*c65d91d6SMatt Spinler getLogger().log( 112*c65d91d6SMatt Spinler fmt::format("GPIO presence detect for fan {} said not present but " 113*c65d91d6SMatt Spinler "other methods indicated present", 114*c65d91d6SMatt Spinler fanInventoryPath)); 115*c65d91d6SMatt Spinler try 116*c65d91d6SMatt Spinler { 117*c65d91d6SMatt Spinler util::SDBusPlus::callMethod(loggingService, loggingPath, 118*c65d91d6SMatt Spinler loggingCreateIface, "Create", errorName, 119*c65d91d6SMatt Spinler severity, ad); 120*c65d91d6SMatt Spinler } 121*c65d91d6SMatt Spinler catch (const util::DBusError& e) 122*c65d91d6SMatt Spinler { 123*c65d91d6SMatt Spinler getLogger().log( 124*c65d91d6SMatt Spinler fmt::format("Call to create a {} error for fan {} failed: {}", 125*c65d91d6SMatt Spinler errorName, fanInventoryPath, e.what()), 126*c65d91d6SMatt Spinler Logger::error); 127*c65d91d6SMatt Spinler } 128*c65d91d6SMatt Spinler } 129*c65d91d6SMatt Spinler 1305c589487SBrad Bishop } // namespace presence 1315c589487SBrad Bishop } // namespace fan 1325c589487SBrad Bishop } // namespace phosphor 133