Enable group gpio configuration
This change adds support to configure single
as well as group gpio config using a single api(configGroupGpio()).
This change is introduced to support the button/input
interfaces which has multiple gpios associated with them.
As an improvement reading of gpio def json file is
done once in main function rather than reading it
everytime before creating the button interface object.
Signed-off-by: Naveen Moses <naveen.mosess@hcl.com>
Change-Id: Ib73dda618c78fd2f14b5d3432fd04c9f4cd2dd9b
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..77c5e8a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,65 @@
+# phosphor-buttons
+
+Phosphor-buttons has a collection of IO event handler interfaces
+for physical inputs which are part of OCP front panel.
+
+It defines an individual dbus interface object for each physical
+button/switch inputs such as power button, reset button etc.
+Each of this button interfaces monitors it's associated io for event changes and calls
+the respective event handlers.
+
+## Gpio defs config
+ In order to monitor a button/input interface the
+respective gpio config details should be mentioned in the
+gpio defs json file - "/etc/default/obmc/gpio/gpio_defs.json"
+
+ 1. The button interface type name.
+ 2. An array consists of single or multiple
+ gpio configs associated with the specific button interface.
+
+## example gpio def Json config
+
+{
+ "gpio_definitions": [
+ {
+ "name": "POWER_BUTTON",
+ "gpio_config" :[
+ {
+ "pin": "D0",
+ "direction": "both"
+ }
+ ]
+ },
+ {
+ "name": "RESET_BUTTON",
+ "gpio_config" :[
+ {
+ "pin": "AB0",
+ "direction": "both"
+ }
+ ]
+ },
+ {
+ "name" : "HOST_SELECTOR",
+
+ "gpio_config" : [
+ {
+ "pin": "AA4",
+ "direction": "both"
+ },
+ {
+ "pin": "AA5",
+ "direction": "both"
+ },
+ {
+ "pin": "AA6",
+ "direction": "both"
+ },
+ {
+ "pin": "AA7",
+ "direction": "both"
+ }
+ ]
+ },
+
+}
diff --git a/inc/gpio.hpp b/inc/gpio.hpp
index ca83082..ba4b8ad 100644
--- a/inc/gpio.hpp
+++ b/inc/gpio.hpp
@@ -16,13 +16,40 @@
#pragma once
#include <sdbusplus/bus.hpp>
+#include <string>
+#include <vector>
-int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus);
-void closeGpio(int fd);
-bool gpioDefined(const std::string& gpioName);
-
-template <typename T>
-bool hasGpio()
+// this struct has the gpio config for single gpio
+struct gpioInfo
{
- return gpioDefined(T::getGpioName());
-}
+ int fd; // io fd mapped with the gpio
+ uint32_t number;
+ std::string direction;
+};
+
+// this struct represents button interface
+struct buttonConfig
+{
+ std::string formFactorName; // name of the button interface
+ std::vector<gpioInfo> gpios; // holds single or group gpio config
+ // corresponding to button interface
+};
+
+/**
+ * @brief iterates over the list of gpios and configures gpios them
+ * config which is set from gpio defs json file.
+ * The fd of the configured gpio is stored in buttonConfig.gpios container
+ * @return int returns 0 on successful config of all gpios
+ */
+
+int configGroupGpio(sdbusplus::bus::bus& bus, buttonConfig& buttonCfg);
+
+/**
+ * @brief configures and initializes the single gpio
+ * @return int returns 0 on successful config of all gpios
+ */
+
+int configGpio(sdbusplus::bus::bus& bus, gpioInfo& gpioConfig);
+
+uint32_t getGpioNum(const std::string& gpioPin);
+void closeGpio(int fd);
diff --git a/inc/id_button.hpp b/inc/id_button.hpp
index 8116185..cb32125 100644
--- a/inc/id_button.hpp
+++ b/inc/id_button.hpp
@@ -32,17 +32,20 @@
{
IDButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
+ buttonConfig& buttonCfg,
sd_event_io_handler_t handler = IDButton::EventHandler) :
sdbusplus::server::object::object<
sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::ID>(
bus, path),
- fd(-1), bus(bus), event(event), callbackHandler(handler)
+ fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
+ callbackHandler(handler)
{
int ret = -1;
- // config gpio
- ret = ::configGpio(ID_BUTTON, &fd, bus);
+ // config group gpio based on the gpio defs read from the json file
+ ret = configGroupGpio(bus, buttonIFConfig);
+
if (ret < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -50,6 +53,9 @@
throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
IOError();
}
+ // initialize the button io fd from the buttonConfig
+ // which has fd stored when configGroupGpio is called
+ fd = buttonIFConfig.gpios[0].fd;
char buf;
::read(fd, &buf, sizeof(buf));
@@ -73,7 +79,7 @@
void simPress() override;
- static const char* getGpioName()
+ static const std::string getGpioName()
{
return ID_BUTTON;
}
@@ -142,6 +148,7 @@
private:
int fd;
+ buttonConfig buttonIFConfig;
sdbusplus::bus::bus& bus;
EventPtr& event;
sd_event_io_handler_t callbackHandler;
diff --git a/inc/power_button.hpp b/inc/power_button.hpp
index e71d9f1..283b149 100644
--- a/inc/power_button.hpp
+++ b/inc/power_button.hpp
@@ -33,17 +33,20 @@
{
PowerButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
+ buttonConfig& buttonCfg,
sd_event_io_handler_t handler = PowerButton::EventHandler) :
sdbusplus::server::object::object<
sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Power>(
bus, path),
- fd(-1), bus(bus), event(event), callbackHandler(handler)
+ fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
+ callbackHandler(handler)
{
int ret = -1;
- // config gpio
- ret = ::configGpio(POWER_BUTTON, &fd, bus);
+ // config group gpio based on the gpio defs read from the json file
+ ret = configGroupGpio(bus, buttonIFConfig);
+
if (ret < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -52,6 +55,10 @@
IOError();
}
+ // initialize the button io fd from the buttonConfig
+ // which has fd stored when configGroupGpio is called
+ fd = buttonIFConfig.gpios[0].fd;
+
char buf;
::read(fd, &buf, sizeof(buf));
@@ -75,7 +82,7 @@
void simPress() override;
void simLongPress() override;
- static const char* getGpioName()
+ static const std::string getGpioName()
{
return POWER_BUTTON;
}
@@ -168,6 +175,7 @@
private:
int fd;
+ buttonConfig buttonIFConfig; // button iface io details
sdbusplus::bus::bus& bus;
EventPtr& event;
sd_event_io_handler_t callbackHandler;
diff --git a/inc/reset_button.hpp b/inc/reset_button.hpp
index 5066bb1..478628b 100644
--- a/inc/reset_button.hpp
+++ b/inc/reset_button.hpp
@@ -32,17 +32,20 @@
{
ResetButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
+ buttonConfig& buttonCfg,
sd_event_io_handler_t handler = ResetButton::EventHandler) :
sdbusplus::server::object::object<
sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>(
bus, path),
- fd(-1), bus(bus), event(event), callbackHandler(handler)
+ fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
+ callbackHandler(handler)
{
int ret = -1;
- // config gpio
- ret = ::configGpio(RESET_BUTTON, &fd, bus);
+ // config group gpio based on the gpio defs read from the json file
+ ret = configGroupGpio(bus, buttonIFConfig);
+
if (ret < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
@@ -51,6 +54,10 @@
IOError();
}
+ // initialize the button io fd from the buttonConfig
+ // which has fd stored when configGroupGpio is called
+ fd = buttonIFConfig.gpios[0].fd;
+
char buf;
::read(fd, &buf, sizeof(buf));
@@ -73,7 +80,7 @@
void simPress() override;
- static const char* getGpioName()
+ static const std::string getGpioName()
{
return RESET_BUTTON;
}
@@ -142,6 +149,7 @@
private:
int fd;
+ buttonConfig buttonIFConfig; // button iface io details
sdbusplus::bus::bus& bus;
EventPtr& event;
sd_event_io_handler_t callbackHandler;
diff --git a/src/gpio.cpp b/src/gpio.cpp
index 28eef92..0538800 100644
--- a/src/gpio.cpp
+++ b/src/gpio.cpp
@@ -25,12 +25,9 @@
#include <fstream>
#include <gpioplus/utility/aspeed.hpp>
#include <nlohmann/json.hpp>
-#include <optional>
#include <phosphor-logging/log.hpp>
-#include <tuple>
const std::string gpioDev = "/sys/class/gpio";
-static constexpr auto gpioDefs = "/etc/default/obmc/gpio/gpio_defs.json";
using namespace phosphor::logging;
namespace fs = std::experimental::filesystem;
@@ -86,75 +83,35 @@
return getGpioBase() + offset;
}
-bool gpioDefined(const std::string& gpioName)
+int configGroupGpio(sdbusplus::bus::bus& bus, buttonConfig& buttonIFConfig)
{
- try
+ int result = 0;
+ // iterate the list of gpios from the button interface config
+ // and initialize them
+ for (auto& gpioCfg : buttonIFConfig.gpios)
{
- std::ifstream gpios{gpioDefs};
- auto json = nlohmann::json::parse(gpios, nullptr, true);
- auto defs = json["gpio_definitions"];
-
- auto gpio =
- std::find_if(defs.begin(), defs.end(), [&gpioName](const auto g) {
- return gpioName == g["name"];
- });
-
- if (gpio != defs.end())
+ result = configGpio(bus, gpioCfg);
+ if (result < 0)
{
- return true;
+
+ std::string errorMsg =
+ "Error configuring gpio: GPIO_NUM=" +
+ std::to_string(gpioCfg.number) +
+ ",BUTTON_NAME=" + buttonIFConfig.formFactorName;
+ log<level::ERR>(errorMsg.c_str());
+
+ break;
}
}
- catch (const std::exception& e)
- {
- log<level::ERR>("Error parsing GPIO JSON", entry("ERROR=%s", e.what()),
- entry("GPIO_NAME=%s", gpioName.c_str()));
- }
- return false;
+
+ return result;
}
-std::optional<std::tuple<int, std::string>>
- getGpioConfig(const std::string& gpioName)
+int configGpio(sdbusplus::bus::bus& bus, gpioInfo& gpioConfig)
{
- try
- {
- std::ifstream gpios{gpioDefs};
- auto json = nlohmann::json::parse(gpios, nullptr, true);
- auto defs = json["gpio_definitions"];
-
- auto gpio =
- std::find_if(defs.begin(), defs.end(), [&gpioName](const auto g) {
- return gpioName == g["name"];
- });
-
- if (gpio != defs.end())
- {
- return std::make_tuple(getGpioNum((*gpio)["pin"]),
- (*gpio)["direction"]);
- }
- else
- {
- log<level::ERR>("Unable to find GPIO in the definitions",
- entry("GPIO_NAME=%s", gpioName.c_str()));
- }
- }
- catch (const std::exception& e)
- {
- log<level::ERR>("Error parsing GPIO JSON", entry("ERROR=%s", e.what()),
- entry("GPIO_NAME=%s", gpioName.c_str()));
- }
- return {};
-}
-
-int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus)
-{
- auto config = getGpioConfig(gpioName);
- if (!config)
- {
- return -1;
- }
-
- auto [gpioNum, gpioDirection] = *config;
+ auto gpioNum = gpioConfig.number;
+ auto gpioDirection = gpioConfig.direction;
std::string devPath{gpioDev};
@@ -286,13 +243,15 @@
devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
- *fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK);
+ auto fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK);
- if (*fd < 0)
+ if (fd < 0)
{
log<level::ERR>("open error!");
return -1;
}
+ gpioConfig.fd = fd;
+
return 0;
}
diff --git a/src/main.cpp b/src/main.cpp
index 27f9b6f..ca7fbaa 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -14,10 +14,16 @@
// limitations under the License.
*/
+#include "gpio.hpp"
#include "id_button.hpp"
#include "power_button.hpp"
#include "reset_button.hpp"
+#include <fstream>
+#include <nlohmann/json.hpp>
+
+static constexpr auto gpioDefFile = "/etc/default/obmc/gpio/gpio_defs.json";
+
int main(int argc, char* argv[])
{
int ret = 0;
@@ -42,22 +48,47 @@
bus.request_name("xyz.openbmc_project.Chassis.Buttons");
+ std::ifstream gpios{gpioDefFile};
+ auto json = nlohmann::json::parse(gpios, nullptr, true);
+ auto gpioDefs = json["gpio_definitions"];
+
+ // load gpio config from gpio defs json file and create button interface
+ // objects based on the button form factor type
std::unique_ptr<PowerButton> pb;
- if (hasGpio<PowerButton>())
- {
- pb = std::make_unique<PowerButton>(bus, POWER_DBUS_OBJECT_NAME, eventP);
- }
-
std::unique_ptr<ResetButton> rb;
- if (hasGpio<ResetButton>())
- {
- rb = std::make_unique<ResetButton>(bus, RESET_DBUS_OBJECT_NAME, eventP);
- }
-
std::unique_ptr<IDButton> ib;
- if (hasGpio<IDButton>())
+
+ for (auto groupGpioConfig : gpioDefs)
{
- ib = std::make_unique<IDButton>(bus, ID_DBUS_OBJECT_NAME, eventP);
+ std::string formFactorName = groupGpioConfig["name"];
+ buttonConfig buttonCfg;
+ auto groupGpio = groupGpioConfig["gpio_config"];
+
+ for (auto gpioConfig : groupGpio)
+ {
+ gpioInfo gpioCfg;
+ gpioCfg.number = getGpioNum(gpioConfig["pin"]);
+ gpioCfg.direction = gpioConfig["direction"];
+ buttonCfg.formFactorName = formFactorName;
+ buttonCfg.gpios.push_back(gpioCfg);
+ }
+ if (buttonCfg.formFactorName == PowerButton::getGpioName())
+ {
+ pb = std::make_unique<PowerButton>(bus, POWER_DBUS_OBJECT_NAME,
+ eventP, buttonCfg);
+ }
+
+ if (buttonCfg.formFactorName == ResetButton::getGpioName())
+ {
+ rb = std::make_unique<ResetButton>(bus, RESET_DBUS_OBJECT_NAME,
+ eventP, buttonCfg);
+ }
+
+ if (buttonCfg.formFactorName == IDButton::getGpioName())
+ {
+ ib = std::make_unique<IDButton>(bus, ID_DBUS_OBJECT_NAME, eventP,
+ buttonCfg);
+ }
}
try