| /** |
| * Copyright © 2017 IBM Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "gpio.hpp" |
| |
| #include "logging.hpp" |
| #include "rpolicy.hpp" |
| #include "sdbusplus.hpp" |
| |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/elog.hpp> |
| #include <sdeventplus/event.hpp> |
| #include <xyz/openbmc_project/Common/Callout/error.hpp> |
| #include <xyz/openbmc_project/Logging/Entry/server.hpp> |
| |
| #include <functional> |
| #include <tuple> |
| |
| namespace phosphor |
| { |
| namespace fan |
| { |
| namespace presence |
| { |
| |
| const auto loggingService = "xyz.openbmc_project.Logging"; |
| const auto loggingPath = "/xyz/openbmc_project/logging"; |
| const auto loggingCreateIface = "xyz.openbmc_project.Logging.Create"; |
| |
| Gpio::Gpio(const std::string& physDevice, const std::string& device, |
| unsigned int physPin) : |
| currentState(false), evdevfd(open(device.c_str(), O_RDONLY | O_NONBLOCK)), |
| evdev(evdevpp::evdev::newFromFD(evdevfd())), phys(physDevice), pin(physPin) |
| {} |
| |
| bool Gpio::start() |
| { |
| source.emplace(sdeventplus::Event::get_default(), evdevfd(), EPOLLIN, |
| std::bind(&Gpio::ioCallback, this)); |
| currentState = present(); |
| return currentState; |
| } |
| |
| void Gpio::stop() |
| { |
| source.reset(); |
| } |
| |
| bool Gpio::present() |
| { |
| return evdev.fetch(EV_KEY, pin) != 0; |
| } |
| |
| void Gpio::fail() |
| { |
| using namespace sdbusplus::xyz::openbmc_project::Common::Callout::Error; |
| using namespace phosphor::logging; |
| using namespace xyz::openbmc_project::Common::Callout; |
| |
| report<sdbusplus::xyz::openbmc_project::Common::Callout::Error::GPIO>( |
| GPIO::CALLOUT_GPIO_NUM(pin), GPIO::CALLOUT_ERRNO(0), |
| GPIO::CALLOUT_DEVICE_PATH(phys.c_str())); |
| } |
| |
| void Gpio::ioCallback() |
| { |
| unsigned int type, code, value; |
| |
| std::tie(type, code, value) = evdev.next(); |
| if (type != EV_KEY || code != pin) |
| { |
| return; |
| } |
| |
| bool newState = value != 0; |
| |
| if (currentState != newState) |
| { |
| getPolicy().stateChanged(newState, *this); |
| currentState = newState; |
| } |
| } |
| |
| void Gpio::logConflict(const std::string& fanInventoryPath) const |
| { |
| using namespace sdbusplus::xyz::openbmc_project::Logging::server; |
| std::map<std::string, std::string> ad; |
| Entry::Level severity = Entry::Level::Informational; |
| |
| static constexpr auto errorName = |
| "xyz.openbmc_project.Fan.Presence.Error.Detection"; |
| |
| ad.emplace("_PID", std::to_string(getpid())); |
| ad.emplace("CALLOUT_INVENTORY_PATH", fanInventoryPath); |
| ad.emplace("GPIO_NUM", std::to_string(pin)); |
| ad.emplace("GPIO_DEVICE_PATH", (phys.c_str())); |
| |
| getLogger().log( |
| std::format("GPIO presence detect for fan {} said not present but " |
| "other methods indicated present", |
| fanInventoryPath)); |
| try |
| { |
| util::SDBusPlus::callMethod(loggingService, loggingPath, |
| loggingCreateIface, "Create", errorName, |
| severity, ad); |
| } |
| catch (const util::DBusError& e) |
| { |
| getLogger().log( |
| std::format("Call to create a {} error for fan {} failed: {}", |
| errorName, fanInventoryPath, e.what()), |
| Logger::error); |
| } |
| } |
| |
| } // namespace presence |
| } // namespace fan |
| } // namespace phosphor |