xref: /openbmc/phosphor-buttons/src/main.cpp (revision 31ce375e7e71ff6b3da460dc63c1ab4f16cf4df6)
1 /*
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 "button_config.hpp"
18 #include "button_factory.hpp"
19 
20 #include <nlohmann/json.hpp>
21 #include <phosphor-logging/elog-errors.hpp>
22 #include <phosphor-logging/lg2.hpp>
23 
24 #include <fstream>
25 
main(void)26 int main(void)
27 {
28     nlohmann::json gpioDefs;
29     nlohmann::json cpldDefs;
30 
31     int ret = 0;
32 
33     lg2::info("Start Phosphor buttons service...");
34 
35     sd_event* event = nullptr;
36     ret = sd_event_default(&event);
37     if (ret < 0)
38     {
39         lg2::error("Error creating a default sd_event handler");
40         return ret;
41     }
42     EventPtr eventP{event};
43     event = nullptr;
44 
45     sdbusplus::bus_t bus = sdbusplus::bus::new_default();
46     sdbusplus::server::manager_t objManager{
47         bus, "/xyz/openbmc_project/Chassis/Buttons"};
48 
49     bus.request_name("xyz.openbmc_project.Chassis.Buttons");
50     std::vector<std::unique_ptr<ButtonIface>> buttonInterfaces;
51 
52     std::ifstream gpios{gpioDefFile};
53     auto configDefJson = nlohmann::json::parse(gpios, nullptr, true);
54     gpioDefs = configDefJson["gpio_definitions"];
55     cpldDefs = configDefJson["cpld_definitions"];
56 
57     // load cpld config from gpio defs json file and create button interface
58     for (const auto& cpldConfig : cpldDefs)
59     {
60         std::string formFactorName = cpldConfig["name"];
61 
62         ButtonConfig buttonCfg;
63         buttonCfg.type = ConfigType::cpld;
64         buttonCfg.formFactorName = formFactorName;
65         buttonCfg.extraJsonInfo = cpldConfig;
66 
67         CpldInfo cpldCfg;
68         cpldCfg.registerName = cpldConfig["register_name"];
69 
70         cpldCfg.i2cAddress = cpldConfig["i2c_address"].get<int>();
71         cpldCfg.i2cBus = cpldConfig["i2c_bus"].get<int>();
72         buttonCfg.cpld = cpldCfg;
73 
74         auto tempButtonIf = ButtonFactory::instance().createInstance(
75             formFactorName, bus, eventP, buttonCfg);
76         if (tempButtonIf)
77         {
78             buttonInterfaces.emplace_back(std::move(tempButtonIf));
79         }
80     }
81 
82     // load gpio config from gpio defs json file and create button interface
83     // objects based on the button form factor type
84 
85     for (const auto& gpioConfig : gpioDefs)
86     {
87         std::string formFactorName = gpioConfig["name"];
88         ButtonConfig buttonCfg;
89         buttonCfg.formFactorName = formFactorName;
90         buttonCfg.extraJsonInfo = gpioConfig;
91         buttonCfg.type = ConfigType::gpio;
92 
93         /* The following code checks if the gpio config read
94         from json file is single gpio config or group gpio config,
95         based on that further data is processed. */
96         lg2::debug("Found button config : {FORM_FACTOR_NAME}",
97                    "FORM_FACTOR_NAME", buttonCfg.formFactorName);
98         if (gpioConfig.contains("group_gpio_config"))
99         {
100             const auto& groupGpio = gpioConfig["group_gpio_config"];
101 
102             for (const auto& config : groupGpio)
103             {
104                 GpioInfo gpioCfg;
105                 if (gpioConfig.contains("pin"))
106                 {
107                     // When "pin" key is used, parse as alphanumeric
108                     gpioCfg.number = getGpioNum(gpioConfig.at("pin"));
109                 }
110                 else
111                 {
112                     // Without "pin", "num" is assumed and parsed as an integer
113                     gpioCfg.number = gpioConfig.at("num").get<uint32_t>();
114                 }
115                 gpioCfg.direction = config["direction"];
116                 gpioCfg.name = config["name"];
117                 gpioCfg.polarity = (config["polarity"] == "active_high")
118                                        ? GpioPolarity::activeHigh
119                                        : GpioPolarity::activeLow;
120                 buttonCfg.gpios.push_back(gpioCfg);
121             }
122         }
123         else
124         {
125             GpioInfo gpioCfg;
126             if (gpioConfig.contains("pin"))
127             {
128                 // When "pin" key is used, parse as alphanumeric
129                 gpioCfg.number = getGpioNum(gpioConfig.at("pin"));
130             }
131             else
132             {
133                 // Without "pin", "num" is assumed and parsed as an integer
134                 gpioCfg.number = gpioConfig.at("num").get<uint32_t>();
135             }
136             gpioCfg.direction = gpioConfig["direction"];
137             buttonCfg.gpios.push_back(gpioCfg);
138         }
139         auto tempButtonIf = ButtonFactory::instance().createInstance(
140             formFactorName, bus, eventP, buttonCfg);
141         /* There are additional gpio configs present in some platforms
142          that are not supported in phosphor-buttons.
143         But they may be used by other applications. so skipping such configs
144         if present in gpio_defs.json file*/
145         if (tempButtonIf)
146         {
147             buttonInterfaces.emplace_back(std::move(tempButtonIf));
148         }
149     }
150 
151     try
152     {
153         bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
154         ret = sd_event_loop(eventP.get());
155         if (ret < 0)
156         {
157             lg2::error("Error occurred during the sd_event_loop : {RESULT}",
158                        "RESULT", ret);
159         }
160     }
161     catch (const std::exception& e)
162     {
163         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
164         ret = -1;
165     }
166     return ret;
167 }
168