xref: /openbmc/dbus-sensors/src/intrusion/ChassisIntrusionSensor.cpp (revision e9a1c9c02a61bfd36e3d83996ea76894af271cee)
1d7be555eSGeorge Liu /*
2d7be555eSGeorge Liu // Copyright (c) 2018 Intel Corporation
3d7be555eSGeorge Liu //
4d7be555eSGeorge Liu // Licensed under the Apache License, Version 2.0 (the "License");
5d7be555eSGeorge Liu // you may not use this file except in compliance with the License.
6d7be555eSGeorge Liu // You may obtain a copy of the License at
7d7be555eSGeorge Liu //
8d7be555eSGeorge Liu //      http://www.apache.org/licenses/LICENSE-2.0
9d7be555eSGeorge Liu //
10d7be555eSGeorge Liu // Unless required by applicable law or agreed to in writing, software
11d7be555eSGeorge Liu // distributed under the License is distributed on an "AS IS" BASIS,
12d7be555eSGeorge Liu // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7be555eSGeorge Liu // See the License for the specific language governing permissions and
14d7be555eSGeorge Liu // limitations under the License.
15d7be555eSGeorge Liu */
16d7be555eSGeorge Liu 
17d7be555eSGeorge Liu #include "ChassisIntrusionSensor.hpp"
18d7be555eSGeorge Liu 
19d7be555eSGeorge Liu #include <fcntl.h>
20d7be555eSGeorge Liu #include <linux/i2c.h>
21d7be555eSGeorge Liu #include <sys/ioctl.h>
22d7be555eSGeorge Liu #include <sys/syslog.h>
23d7be555eSGeorge Liu #include <systemd/sd-journal.h>
24d7be555eSGeorge Liu #include <unistd.h>
25d7be555eSGeorge Liu 
26d7be555eSGeorge Liu #include <Utils.hpp>
27d7be555eSGeorge Liu #include <boost/asio/error.hpp>
28d7be555eSGeorge Liu #include <boost/asio/io_context.hpp>
29d7be555eSGeorge Liu #include <boost/asio/posix/stream_descriptor.hpp>
30d7be555eSGeorge Liu #include <gpiod.hpp>
31*e9a1c9c0SGeorge Liu #include <phosphor-logging/lg2.hpp>
32d7be555eSGeorge Liu #include <sdbusplus/asio/object_server.hpp>
33d7be555eSGeorge Liu 
34d7be555eSGeorge Liu #include <chrono>
35d7be555eSGeorge Liu #include <cstddef>
36d7be555eSGeorge Liu #include <cstdint>
37d7be555eSGeorge Liu #include <filesystem>
38d7be555eSGeorge Liu #include <fstream>
39d7be555eSGeorge Liu #include <iostream>
40d7be555eSGeorge Liu #include <memory>
41d7be555eSGeorge Liu #include <stdexcept>
42d7be555eSGeorge Liu #include <string>
43d7be555eSGeorge Liu #include <utility>
44d7be555eSGeorge Liu #include <vector>
45d7be555eSGeorge Liu 
46d7be555eSGeorge Liu extern "C"
47d7be555eSGeorge Liu {
48d7be555eSGeorge Liu #include <i2c/smbus.h>
49d7be555eSGeorge Liu #include <linux/i2c-dev.h>
50d7be555eSGeorge Liu }
51d7be555eSGeorge Liu 
52d7be555eSGeorge Liu static constexpr bool debug = false;
53d7be555eSGeorge Liu 
54d7be555eSGeorge Liu static constexpr unsigned int defaultPollSec = 1;
55d7be555eSGeorge Liu static constexpr unsigned int sensorFailedPollSec = 5;
56d7be555eSGeorge Liu static unsigned int intrusionSensorPollSec = defaultPollSec;
57d7be555eSGeorge Liu static constexpr const char* hwIntrusionValStr =
58d7be555eSGeorge Liu     "xyz.openbmc_project.Chassis.Intrusion.Status.HardwareIntrusion";
59d7be555eSGeorge Liu static constexpr const char* normalValStr =
60d7be555eSGeorge Liu     "xyz.openbmc_project.Chassis.Intrusion.Status.Normal";
61d7be555eSGeorge Liu static constexpr const char* manualRearmStr =
62d7be555eSGeorge Liu     "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Manual";
63d7be555eSGeorge Liu static constexpr const char* autoRearmStr =
64d7be555eSGeorge Liu     "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Automatic";
65d7be555eSGeorge Liu 
66d7be555eSGeorge Liu // SMLink Status Register
67d7be555eSGeorge Liu const static constexpr size_t pchStatusRegIntrusion = 0x04;
68d7be555eSGeorge Liu 
69d7be555eSGeorge Liu // Status bit field masks
70d7be555eSGeorge Liu const static constexpr size_t pchRegMaskIntrusion = 0x01;
71d7be555eSGeorge Liu 
72d7be555eSGeorge Liu // Value to clear intrusion status hwmon file
73d7be555eSGeorge Liu const static constexpr size_t intrusionStatusHwmonClearValue = 0;
74d7be555eSGeorge Liu 
updateValue(const size_t & value)75d7be555eSGeorge Liu void ChassisIntrusionSensor::updateValue(const size_t& value)
76d7be555eSGeorge Liu {
77d7be555eSGeorge Liu     std::string newValue = value != 0 ? hwIntrusionValStr : normalValStr;
78d7be555eSGeorge Liu 
79d7be555eSGeorge Liu     // Take no action if the hardware status does not change
80d7be555eSGeorge Liu     // Same semantics as Sensor::updateValue(const double&)
81d7be555eSGeorge Liu     if (newValue == mValue)
82d7be555eSGeorge Liu     {
83d7be555eSGeorge Liu         return;
84d7be555eSGeorge Liu     }
85d7be555eSGeorge Liu 
86d7be555eSGeorge Liu     if constexpr (debug)
87d7be555eSGeorge Liu     {
88*e9a1c9c0SGeorge Liu         lg2::info("Update value from '{VALUE}' to '{NEWVALUE}'", "VALUE",
89*e9a1c9c0SGeorge Liu                   mValue, "NEWVALUE", newValue);
90d7be555eSGeorge Liu     }
91d7be555eSGeorge Liu 
92d7be555eSGeorge Liu     // Automatic Rearm mode allows direct update
93d7be555eSGeorge Liu     // Manual Rearm mode requires a rearm action to clear the intrusion
94d7be555eSGeorge Liu     // status
95d7be555eSGeorge Liu     if (!mAutoRearm)
96d7be555eSGeorge Liu     {
97d7be555eSGeorge Liu         if (newValue == normalValStr)
98d7be555eSGeorge Liu         {
99d7be555eSGeorge Liu             // Chassis is first closed from being open. If it has been
100d7be555eSGeorge Liu             // rearmed externally, reset the flag, update mValue and
101d7be555eSGeorge Liu             // return, without having to write "Normal" to DBus property
102d7be555eSGeorge Liu             // (because the rearm action already did).
103d7be555eSGeorge Liu             // Otherwise, return with no more action.
104d7be555eSGeorge Liu             if (mRearmFlag)
105d7be555eSGeorge Liu             {
106d7be555eSGeorge Liu                 mRearmFlag = false;
107d7be555eSGeorge Liu                 mValue = newValue;
108d7be555eSGeorge Liu             }
109d7be555eSGeorge Liu             return;
110d7be555eSGeorge Liu         }
111d7be555eSGeorge Liu     }
112d7be555eSGeorge Liu 
113d7be555eSGeorge Liu     // Flush the rearm flag everytime it allows an update to Dbus
114d7be555eSGeorge Liu     mRearmFlag = false;
115d7be555eSGeorge Liu 
116d7be555eSGeorge Liu     // indicate that it is internal set call
117d7be555eSGeorge Liu     mOverridenState = false;
118d7be555eSGeorge Liu     mInternalSet = true;
119d7be555eSGeorge Liu     mIface->set_property("Status", newValue);
120d7be555eSGeorge Liu     mInternalSet = false;
121d7be555eSGeorge Liu 
122d7be555eSGeorge Liu     mValue = newValue;
123d7be555eSGeorge Liu }
124d7be555eSGeorge Liu 
readSensor()125d7be555eSGeorge Liu int ChassisIntrusionPchSensor::readSensor()
126d7be555eSGeorge Liu {
127d7be555eSGeorge Liu     int32_t statusMask = pchRegMaskIntrusion;
128d7be555eSGeorge Liu     int32_t statusReg = pchStatusRegIntrusion;
129d7be555eSGeorge Liu 
130d7be555eSGeorge Liu     int32_t value = i2c_smbus_read_byte_data(mBusFd, statusReg);
131d7be555eSGeorge Liu     if constexpr (debug)
132d7be555eSGeorge Liu     {
133*e9a1c9c0SGeorge Liu         lg2::info("Pch type: raw value is '{VALUE}'", "VALUE", value);
134d7be555eSGeorge Liu     }
135d7be555eSGeorge Liu 
136d7be555eSGeorge Liu     if (value < 0)
137d7be555eSGeorge Liu     {
138*e9a1c9c0SGeorge Liu         lg2::error("i2c_smbus_read_byte_data failed");
139d7be555eSGeorge Liu         return -1;
140d7be555eSGeorge Liu     }
141d7be555eSGeorge Liu 
142d7be555eSGeorge Liu     // Get status value with mask
143d7be555eSGeorge Liu     value &= statusMask;
144d7be555eSGeorge Liu 
145d7be555eSGeorge Liu     if constexpr (debug)
146d7be555eSGeorge Liu     {
147*e9a1c9c0SGeorge Liu         lg2::info("Pch type: masked raw value is '{VALUE}'", "VALUE", value);
148d7be555eSGeorge Liu     }
149d7be555eSGeorge Liu     return value;
150d7be555eSGeorge Liu }
151d7be555eSGeorge Liu 
pollSensorStatus()152d7be555eSGeorge Liu void ChassisIntrusionPchSensor::pollSensorStatus()
153d7be555eSGeorge Liu {
154d7be555eSGeorge Liu     std::weak_ptr<ChassisIntrusionPchSensor> weakRef = weak_from_this();
155d7be555eSGeorge Liu 
156d7be555eSGeorge Liu     // setting a new experation implicitly cancels any pending async wait
157d7be555eSGeorge Liu     mPollTimer.expires_after(std::chrono::seconds(intrusionSensorPollSec));
158d7be555eSGeorge Liu 
159d7be555eSGeorge Liu     mPollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
160d7be555eSGeorge Liu         // case of being canceled
161d7be555eSGeorge Liu         if (ec == boost::asio::error::operation_aborted)
162d7be555eSGeorge Liu         {
163*e9a1c9c0SGeorge Liu             lg2::error("Timer of intrusion sensor is cancelled");
164d7be555eSGeorge Liu             return;
165d7be555eSGeorge Liu         }
166d7be555eSGeorge Liu 
167d7be555eSGeorge Liu         std::shared_ptr<ChassisIntrusionPchSensor> self = weakRef.lock();
168d7be555eSGeorge Liu         if (!self)
169d7be555eSGeorge Liu         {
170*e9a1c9c0SGeorge Liu             lg2::error("ChassisIntrusionSensor no self");
171d7be555eSGeorge Liu             return;
172d7be555eSGeorge Liu         }
173d7be555eSGeorge Liu 
174d7be555eSGeorge Liu         int value = self->readSensor();
175d7be555eSGeorge Liu         if (value < 0)
176d7be555eSGeorge Liu         {
177d7be555eSGeorge Liu             intrusionSensorPollSec = sensorFailedPollSec;
178d7be555eSGeorge Liu         }
179d7be555eSGeorge Liu         else
180d7be555eSGeorge Liu         {
181d7be555eSGeorge Liu             intrusionSensorPollSec = defaultPollSec;
182d7be555eSGeorge Liu             self->updateValue(value);
183d7be555eSGeorge Liu         }
184d7be555eSGeorge Liu 
185d7be555eSGeorge Liu         // trigger next polling
186d7be555eSGeorge Liu         self->pollSensorStatus();
187d7be555eSGeorge Liu     });
188d7be555eSGeorge Liu }
189d7be555eSGeorge Liu 
readSensor()190d7be555eSGeorge Liu int ChassisIntrusionGpioSensor::readSensor()
191d7be555eSGeorge Liu {
192d7be555eSGeorge Liu     mGpioLine.event_read();
193d7be555eSGeorge Liu     auto value = mGpioLine.get_value();
194d7be555eSGeorge Liu     if constexpr (debug)
195d7be555eSGeorge Liu     {
196*e9a1c9c0SGeorge Liu         lg2::info("Gpio type: raw value is '{VALUE}'", "VALUE", value);
197d7be555eSGeorge Liu     }
198d7be555eSGeorge Liu     return value;
199d7be555eSGeorge Liu }
200d7be555eSGeorge Liu 
pollSensorStatus()201d7be555eSGeorge Liu void ChassisIntrusionGpioSensor::pollSensorStatus()
202d7be555eSGeorge Liu {
203d7be555eSGeorge Liu     mGpioFd.async_wait(
204d7be555eSGeorge Liu         boost::asio::posix::stream_descriptor::wait_read,
205d7be555eSGeorge Liu         [this](const boost::system::error_code& ec) {
206d7be555eSGeorge Liu             if (ec == boost::system::errc::bad_file_descriptor)
207d7be555eSGeorge Liu             {
208d7be555eSGeorge Liu                 return; // we're being destroyed
209d7be555eSGeorge Liu             }
210d7be555eSGeorge Liu 
211d7be555eSGeorge Liu             if (ec)
212d7be555eSGeorge Liu             {
213*e9a1c9c0SGeorge Liu                 lg2::error("Error on GPIO based intrusion sensor wait event");
214d7be555eSGeorge Liu             }
215d7be555eSGeorge Liu             else
216d7be555eSGeorge Liu             {
217d7be555eSGeorge Liu                 int value = readSensor();
218d7be555eSGeorge Liu                 if (value >= 0)
219d7be555eSGeorge Liu                 {
220d7be555eSGeorge Liu                     updateValue(value);
221d7be555eSGeorge Liu                 }
222d7be555eSGeorge Liu                 // trigger next polling
223d7be555eSGeorge Liu                 pollSensorStatus();
224d7be555eSGeorge Liu             }
225d7be555eSGeorge Liu         });
226d7be555eSGeorge Liu }
227d7be555eSGeorge Liu 
readSensor()228d7be555eSGeorge Liu int ChassisIntrusionHwmonSensor::readSensor()
229d7be555eSGeorge Liu {
230d7be555eSGeorge Liu     int value = 0;
231d7be555eSGeorge Liu 
232d7be555eSGeorge Liu     std::fstream stream(mHwmonPath, std::ios::in | std::ios::out);
233d7be555eSGeorge Liu     if (!stream.good())
234d7be555eSGeorge Liu     {
235*e9a1c9c0SGeorge Liu         lg2::error("Error reading status at '{PATH}'", "PATH", mHwmonPath);
236d7be555eSGeorge Liu         return -1;
237d7be555eSGeorge Liu     }
238d7be555eSGeorge Liu 
239d7be555eSGeorge Liu     std::string line;
240d7be555eSGeorge Liu     if (!std::getline(stream, line))
241d7be555eSGeorge Liu     {
242*e9a1c9c0SGeorge Liu         lg2::error("Error reading status at '{PATH}'", "PATH", mHwmonPath);
243d7be555eSGeorge Liu         return -1;
244d7be555eSGeorge Liu     }
245d7be555eSGeorge Liu 
246d7be555eSGeorge Liu     try
247d7be555eSGeorge Liu     {
248d7be555eSGeorge Liu         value = std::stoi(line);
249d7be555eSGeorge Liu         if constexpr (debug)
250d7be555eSGeorge Liu         {
251*e9a1c9c0SGeorge Liu             lg2::info("Hwmon type: raw value is '{VALUE}'", "VALUE", value);
252d7be555eSGeorge Liu         }
253d7be555eSGeorge Liu     }
254d7be555eSGeorge Liu     catch (const std::invalid_argument& e)
255d7be555eSGeorge Liu     {
256*e9a1c9c0SGeorge Liu         lg2::error("Error reading status at '{PATH}': '{ERR}'", "PATH",
257*e9a1c9c0SGeorge Liu                    mHwmonPath, "ERR", e);
258d7be555eSGeorge Liu         return -1;
259d7be555eSGeorge Liu     }
260d7be555eSGeorge Liu 
261d7be555eSGeorge Liu     // Reset chassis intrusion status after every reading
262d7be555eSGeorge Liu     stream << intrusionStatusHwmonClearValue;
263d7be555eSGeorge Liu 
264d7be555eSGeorge Liu     return value;
265d7be555eSGeorge Liu }
266d7be555eSGeorge Liu 
pollSensorStatus()267d7be555eSGeorge Liu void ChassisIntrusionHwmonSensor::pollSensorStatus()
268d7be555eSGeorge Liu {
269d7be555eSGeorge Liu     std::weak_ptr<ChassisIntrusionHwmonSensor> weakRef = weak_from_this();
270d7be555eSGeorge Liu 
271d7be555eSGeorge Liu     // setting a new experation implicitly cancels any pending async wait
272d7be555eSGeorge Liu     mPollTimer.expires_after(std::chrono::seconds(intrusionSensorPollSec));
273d7be555eSGeorge Liu 
274d7be555eSGeorge Liu     mPollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
275d7be555eSGeorge Liu         // case of being canceled
276d7be555eSGeorge Liu         if (ec == boost::asio::error::operation_aborted)
277d7be555eSGeorge Liu         {
278*e9a1c9c0SGeorge Liu             lg2::error("Timer of intrusion sensor is cancelled");
279d7be555eSGeorge Liu             return;
280d7be555eSGeorge Liu         }
281d7be555eSGeorge Liu 
282d7be555eSGeorge Liu         std::shared_ptr<ChassisIntrusionHwmonSensor> self = weakRef.lock();
283d7be555eSGeorge Liu         if (!self)
284d7be555eSGeorge Liu         {
285*e9a1c9c0SGeorge Liu             lg2::error("ChassisIntrusionSensor no self");
286d7be555eSGeorge Liu             return;
287d7be555eSGeorge Liu         }
288d7be555eSGeorge Liu 
289d7be555eSGeorge Liu         int value = self->readSensor();
290d7be555eSGeorge Liu         if (value < 0)
291d7be555eSGeorge Liu         {
292d7be555eSGeorge Liu             intrusionSensorPollSec = sensorFailedPollSec;
293d7be555eSGeorge Liu         }
294d7be555eSGeorge Liu         else
295d7be555eSGeorge Liu         {
296d7be555eSGeorge Liu             intrusionSensorPollSec = defaultPollSec;
297d7be555eSGeorge Liu             self->updateValue(value);
298d7be555eSGeorge Liu         }
299d7be555eSGeorge Liu 
300d7be555eSGeorge Liu         // trigger next polling
301d7be555eSGeorge Liu         self->pollSensorStatus();
302d7be555eSGeorge Liu     });
303d7be555eSGeorge Liu }
304d7be555eSGeorge Liu 
setSensorValue(const std::string & req,std::string & propertyValue)305d7be555eSGeorge Liu int ChassisIntrusionSensor::setSensorValue(const std::string& req,
306d7be555eSGeorge Liu                                            std::string& propertyValue)
307d7be555eSGeorge Liu {
308d7be555eSGeorge Liu     if (!mInternalSet)
309d7be555eSGeorge Liu     {
310d7be555eSGeorge Liu         /*
311d7be555eSGeorge Liu            1. Assuming that setting property in Automatic mode causes
312d7be555eSGeorge Liu            no effect but only event logs and propertiesChanged signal
313d7be555eSGeorge Liu            (because the property will be updated continuously to the
314d7be555eSGeorge Liu            current hardware status anyway), only update Status property
315d7be555eSGeorge Liu            and raise rearm flag in Manual rearm mode.
316d7be555eSGeorge Liu            2. Only accept Normal value from an external call.
317d7be555eSGeorge Liu         */
318d7be555eSGeorge Liu         if (!mAutoRearm && req == normalValStr)
319d7be555eSGeorge Liu         {
320d7be555eSGeorge Liu             mRearmFlag = true;
321d7be555eSGeorge Liu             propertyValue = req;
322d7be555eSGeorge Liu             mOverridenState = true;
323d7be555eSGeorge Liu         }
324d7be555eSGeorge Liu     }
325d7be555eSGeorge Liu     else if (!mOverridenState)
326d7be555eSGeorge Liu     {
327d7be555eSGeorge Liu         propertyValue = req;
328d7be555eSGeorge Liu     }
329d7be555eSGeorge Liu     else
330d7be555eSGeorge Liu     {
331d7be555eSGeorge Liu         return 1;
332d7be555eSGeorge Liu     }
333d7be555eSGeorge Liu     // Send intrusion event to Redfish
334d7be555eSGeorge Liu     if (mValue == normalValStr && propertyValue != normalValStr)
335d7be555eSGeorge Liu     {
336d7be555eSGeorge Liu         sd_journal_send("MESSAGE=%s", "Chassis intrusion assert event",
337d7be555eSGeorge Liu                         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
338d7be555eSGeorge Liu                         "OpenBMC.0.1.ChassisIntrusionDetected", NULL);
339d7be555eSGeorge Liu     }
340d7be555eSGeorge Liu     else if (mValue == hwIntrusionValStr && propertyValue == normalValStr)
341d7be555eSGeorge Liu     {
342d7be555eSGeorge Liu         sd_journal_send("MESSAGE=%s", "Chassis intrusion de-assert event",
343d7be555eSGeorge Liu                         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
344d7be555eSGeorge Liu                         "OpenBMC.0.1.ChassisIntrusionReset", NULL);
345d7be555eSGeorge Liu     }
346d7be555eSGeorge Liu     return 1;
347d7be555eSGeorge Liu }
348d7be555eSGeorge Liu 
start()349d7be555eSGeorge Liu void ChassisIntrusionSensor::start()
350d7be555eSGeorge Liu {
351d7be555eSGeorge Liu     mIface->register_property(
352d7be555eSGeorge Liu         "Status", mValue,
353d7be555eSGeorge Liu         [&](const std::string& req, std::string& propertyValue) {
354d7be555eSGeorge Liu             return setSensorValue(req, propertyValue);
355d7be555eSGeorge Liu         });
356d7be555eSGeorge Liu     std::string rearmStr = mAutoRearm ? autoRearmStr : manualRearmStr;
357d7be555eSGeorge Liu     mIface->register_property("Rearm", rearmStr);
358d7be555eSGeorge Liu     mIface->initialize();
359d7be555eSGeorge Liu     pollSensorStatus();
360d7be555eSGeorge Liu }
361d7be555eSGeorge Liu 
ChassisIntrusionSensor(bool autoRearm,sdbusplus::asio::object_server & objServer)362d7be555eSGeorge Liu ChassisIntrusionSensor::ChassisIntrusionSensor(
363d7be555eSGeorge Liu     bool autoRearm, sdbusplus::asio::object_server& objServer) :
364d7be555eSGeorge Liu     mValue(normalValStr), mAutoRearm(autoRearm), mObjServer(objServer)
365d7be555eSGeorge Liu {
366d7be555eSGeorge Liu     mIface = mObjServer.add_interface("/xyz/openbmc_project/Chassis/Intrusion",
367d7be555eSGeorge Liu                                       "xyz.openbmc_project.Chassis.Intrusion");
368d7be555eSGeorge Liu }
369d7be555eSGeorge Liu 
ChassisIntrusionPchSensor(bool autoRearm,boost::asio::io_context & io,sdbusplus::asio::object_server & objServer,int busId,int slaveAddr)370d7be555eSGeorge Liu ChassisIntrusionPchSensor::ChassisIntrusionPchSensor(
371d7be555eSGeorge Liu     bool autoRearm, boost::asio::io_context& io,
372d7be555eSGeorge Liu     sdbusplus::asio::object_server& objServer, int busId, int slaveAddr) :
373d7be555eSGeorge Liu     ChassisIntrusionSensor(autoRearm, objServer), mPollTimer(io)
374d7be555eSGeorge Liu {
375d7be555eSGeorge Liu     if (busId < 0 || slaveAddr <= 0)
376d7be555eSGeorge Liu     {
377d7be555eSGeorge Liu         throw std::invalid_argument(
378d7be555eSGeorge Liu             "Invalid i2c bus " + std::to_string(busId) + " address " +
379d7be555eSGeorge Liu             std::to_string(slaveAddr) + "\n");
380d7be555eSGeorge Liu     }
381d7be555eSGeorge Liu 
382d7be555eSGeorge Liu     mSlaveAddr = slaveAddr;
383d7be555eSGeorge Liu 
384d7be555eSGeorge Liu     std::string devPath = "/dev/i2c-" + std::to_string(busId);
385d7be555eSGeorge Liu     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
386d7be555eSGeorge Liu     mBusFd = open(devPath.c_str(), O_RDWR | O_CLOEXEC);
387d7be555eSGeorge Liu     if (mBusFd < 0)
388d7be555eSGeorge Liu     {
389d7be555eSGeorge Liu         throw std::invalid_argument("Unable to open " + devPath + "\n");
390d7be555eSGeorge Liu     }
391d7be555eSGeorge Liu 
392d7be555eSGeorge Liu     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
393d7be555eSGeorge Liu     if (ioctl(mBusFd, I2C_SLAVE_FORCE, mSlaveAddr) < 0)
394d7be555eSGeorge Liu     {
395d7be555eSGeorge Liu         throw std::runtime_error("Unable to set device address\n");
396d7be555eSGeorge Liu     }
397d7be555eSGeorge Liu 
398d7be555eSGeorge Liu     unsigned long funcs = 0;
399d7be555eSGeorge Liu 
400d7be555eSGeorge Liu     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
401d7be555eSGeorge Liu     if (ioctl(mBusFd, I2C_FUNCS, &funcs) < 0)
402d7be555eSGeorge Liu     {
403d7be555eSGeorge Liu         throw std::runtime_error("Don't support I2C_FUNCS\n");
404d7be555eSGeorge Liu     }
405d7be555eSGeorge Liu 
406d7be555eSGeorge Liu     if ((funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA) == 0U)
407d7be555eSGeorge Liu     {
408d7be555eSGeorge Liu         throw std::runtime_error(
409d7be555eSGeorge Liu             "Do not have I2C_FUNC_SMBUS_READ_BYTE_DATA \n");
410d7be555eSGeorge Liu     }
411d7be555eSGeorge Liu }
412d7be555eSGeorge Liu 
ChassisIntrusionGpioSensor(bool autoRearm,boost::asio::io_context & io,sdbusplus::asio::object_server & objServer,bool gpioInverted)413d7be555eSGeorge Liu ChassisIntrusionGpioSensor::ChassisIntrusionGpioSensor(
414d7be555eSGeorge Liu     bool autoRearm, boost::asio::io_context& io,
415d7be555eSGeorge Liu     sdbusplus::asio::object_server& objServer, bool gpioInverted) :
416d7be555eSGeorge Liu     ChassisIntrusionSensor(autoRearm, objServer), mGpioInverted(gpioInverted),
417d7be555eSGeorge Liu     mGpioFd(io)
418d7be555eSGeorge Liu {
419d7be555eSGeorge Liu     mGpioLine = gpiod::find_line(mPinName);
420d7be555eSGeorge Liu     if (!mGpioLine)
421d7be555eSGeorge Liu     {
422d7be555eSGeorge Liu         throw std::invalid_argument(
423d7be555eSGeorge Liu             "Error finding gpio pin name: " + mPinName + "\n");
424d7be555eSGeorge Liu     }
425d7be555eSGeorge Liu     mGpioLine.request(
426d7be555eSGeorge Liu         {"ChassisIntrusionSensor", gpiod::line_request::EVENT_BOTH_EDGES,
427d7be555eSGeorge Liu          mGpioInverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
428d7be555eSGeorge Liu 
429d7be555eSGeorge Liu     auto gpioLineFd = mGpioLine.event_get_fd();
430d7be555eSGeorge Liu     if (gpioLineFd < 0)
431d7be555eSGeorge Liu     {
432d7be555eSGeorge Liu         throw std::invalid_argument("Failed to get " + mPinName + " fd\n");
433d7be555eSGeorge Liu     }
434d7be555eSGeorge Liu 
435d7be555eSGeorge Liu     mGpioFd.assign(gpioLineFd);
436d7be555eSGeorge Liu }
437d7be555eSGeorge Liu 
ChassisIntrusionHwmonSensor(bool autoRearm,boost::asio::io_context & io,sdbusplus::asio::object_server & objServer,std::string hwmonName)438d7be555eSGeorge Liu ChassisIntrusionHwmonSensor::ChassisIntrusionHwmonSensor(
439d7be555eSGeorge Liu     bool autoRearm, boost::asio::io_context& io,
440d7be555eSGeorge Liu     sdbusplus::asio::object_server& objServer, std::string hwmonName) :
441d7be555eSGeorge Liu     ChassisIntrusionSensor(autoRearm, objServer),
442d7be555eSGeorge Liu     mHwmonName(std::move(hwmonName)), mPollTimer(io)
443d7be555eSGeorge Liu {
4442e466967SEd Tanous     std::vector<std::filesystem::path> paths;
445d7be555eSGeorge Liu 
4462e466967SEd Tanous     if (!findFiles(std::filesystem::path("/sys/class/hwmon"), mHwmonName,
4472e466967SEd Tanous                    paths))
448d7be555eSGeorge Liu     {
449d7be555eSGeorge Liu         throw std::invalid_argument("Failed to find hwmon path in sysfs\n");
450d7be555eSGeorge Liu     }
451d7be555eSGeorge Liu 
452d7be555eSGeorge Liu     if (paths.empty())
453d7be555eSGeorge Liu     {
454d7be555eSGeorge Liu         throw std::invalid_argument(
455d7be555eSGeorge Liu             "Hwmon file " + mHwmonName + " can't be found in sysfs\n");
456d7be555eSGeorge Liu     }
457d7be555eSGeorge Liu 
458d7be555eSGeorge Liu     if (paths.size() > 1)
459d7be555eSGeorge Liu     {
460*e9a1c9c0SGeorge Liu         lg2::error("Found more than 1 hwmon file to read chassis intrusion"
461*e9a1c9c0SGeorge Liu                    " status. Taking the first one.");
462d7be555eSGeorge Liu     }
463d7be555eSGeorge Liu 
464d7be555eSGeorge Liu     // Expecting only one hwmon file for one given chassis
465d7be555eSGeorge Liu     mHwmonPath = paths[0].string();
466d7be555eSGeorge Liu 
467d7be555eSGeorge Liu     if constexpr (debug)
468d7be555eSGeorge Liu     {
469*e9a1c9c0SGeorge Liu         lg2::info(
470*e9a1c9c0SGeorge Liu             "Found '{NUM_PATHS}' paths for intrusion status. The first path is: '{PATH}'",
471*e9a1c9c0SGeorge Liu             "NUM_PATHS", paths.size(), "PATH", mHwmonPath);
472d7be555eSGeorge Liu     }
473d7be555eSGeorge Liu }
474d7be555eSGeorge Liu 
~ChassisIntrusionSensor()475d7be555eSGeorge Liu ChassisIntrusionSensor::~ChassisIntrusionSensor()
476d7be555eSGeorge Liu {
477d7be555eSGeorge Liu     mObjServer.remove_interface(mIface);
478d7be555eSGeorge Liu }
479d7be555eSGeorge Liu 
~ChassisIntrusionPchSensor()480d7be555eSGeorge Liu ChassisIntrusionPchSensor::~ChassisIntrusionPchSensor()
481d7be555eSGeorge Liu {
482d7be555eSGeorge Liu     mPollTimer.cancel();
483d7be555eSGeorge Liu     if (close(mBusFd) < 0)
484d7be555eSGeorge Liu     {
485*e9a1c9c0SGeorge Liu         lg2::error("Failed to close fd '{FD}'", "FD", mBusFd);
486d7be555eSGeorge Liu     }
487d7be555eSGeorge Liu }
488d7be555eSGeorge Liu 
~ChassisIntrusionGpioSensor()489d7be555eSGeorge Liu ChassisIntrusionGpioSensor::~ChassisIntrusionGpioSensor()
490d7be555eSGeorge Liu {
491d7be555eSGeorge Liu     mGpioFd.close();
492d7be555eSGeorge Liu     if (mGpioLine)
493d7be555eSGeorge Liu     {
494d7be555eSGeorge Liu         mGpioLine.release();
495d7be555eSGeorge Liu     }
496d7be555eSGeorge Liu }
497d7be555eSGeorge Liu 
~ChassisIntrusionHwmonSensor()498d7be555eSGeorge Liu ChassisIntrusionHwmonSensor::~ChassisIntrusionHwmonSensor()
499d7be555eSGeorge Liu {
500d7be555eSGeorge Liu     mPollTimer.cancel();
501d7be555eSGeorge Liu }
502