blob: 52c254a595b44a95053a8709a2e1728f0ece0e59 [file] [log] [blame]
Qiang XUe28d1fa2019-02-27 13:50:56 +08001/*
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
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "ChassisIntrusionSensor.hpp"
18
Qiang XUe28d1fa2019-02-27 13:50:56 +080019#include <fcntl.h>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070020#include <linux/i2c.h>
Qiang XUe28d1fa2019-02-27 13:50:56 +080021#include <sys/ioctl.h>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070022#include <sys/syslog.h>
Matt Simmering79a160b2022-11-14 16:50:48 -080023#include <systemd/sd-journal.h>
Qiang XUe28d1fa2019-02-27 13:50:56 +080024#include <unistd.h>
25
Chau Lycebb28c2022-10-21 10:01:52 +000026#include <Utils.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070027#include <boost/asio/error.hpp>
Ed Tanous1f978632023-02-28 18:16:39 -080028#include <boost/asio/io_context.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070029#include <boost/asio/posix/stream_descriptor.hpp>
30#include <gpiod.hpp>
James Feist38fb5982020-05-28 10:09:54 -070031#include <sdbusplus/asio/object_server.hpp>
32
Qiang XUe28d1fa2019-02-27 13:50:56 +080033#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070034#include <cstddef>
35#include <cstdint>
36#include <filesystem>
Chau Lycebb28c2022-10-21 10:01:52 +000037#include <fstream>
Qiang XUe28d1fa2019-02-27 13:50:56 +080038#include <iostream>
Patrick Venture96e97db2019-10-31 13:44:38 -070039#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070040#include <stdexcept>
Qiang XUe28d1fa2019-02-27 13:50:56 +080041#include <string>
Ed Tanous8a57ec02020-10-09 12:46:52 -070042#include <utility>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070043#include <vector>
Qiang XUe28d1fa2019-02-27 13:50:56 +080044
James Feist38fb5982020-05-28 10:09:54 -070045extern "C"
46{
Qiang XUe28d1fa2019-02-27 13:50:56 +080047#include <i2c/smbus.h>
48#include <linux/i2c-dev.h>
49}
50
Ed Tanous8a57ec02020-10-09 12:46:52 -070051static constexpr bool debug = false;
Qiang XUe28d1fa2019-02-27 13:50:56 +080052
Chau Lycebb28c2022-10-21 10:01:52 +000053static constexpr unsigned int defaultPollSec = 1;
54static constexpr unsigned int sensorFailedPollSec = 5;
55static unsigned int intrusionSensorPollSec = defaultPollSec;
Chau Lyb318dca2022-10-26 04:12:52 +000056static constexpr const char* hwIntrusionValStr =
57 "xyz.openbmc_project.Chassis.Intrusion.Status.HardwareIntrusion";
58static constexpr const char* normalValStr =
59 "xyz.openbmc_project.Chassis.Intrusion.Status.Normal";
60static constexpr const char* manualRearmStr =
61 "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Manual";
62static constexpr const char* autoRearmStr =
63 "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Automatic";
Qiang XUe28d1fa2019-02-27 13:50:56 +080064
65// SMLink Status Register
66const static constexpr size_t pchStatusRegIntrusion = 0x04;
67
68// Status bit field masks
69const static constexpr size_t pchRegMaskIntrusion = 0x01;
70
Chau Ly95f49932023-04-19 09:44:55 +000071// Value to clear intrusion status hwmon file
72const static constexpr size_t intrusionStatusHwmonClearValue = 0;
73
Chau Lycebb28c2022-10-21 10:01:52 +000074void ChassisIntrusionSensor::updateValue(const size_t& value)
Qiang XUe28d1fa2019-02-27 13:50:56 +080075{
Chau Lycebb28c2022-10-21 10:01:52 +000076 std::string newValue = value != 0 ? hwIntrusionValStr : normalValStr;
77
Chau Lyb318dca2022-10-26 04:12:52 +000078 // Take no action if the hardware status does not change
Josh Lehan833661a2020-03-04 17:35:41 -080079 // Same semantics as Sensor::updateValue(const double&)
80 if (newValue == mValue)
81 {
82 return;
83 }
84
Chau Lycebb28c2022-10-21 10:01:52 +000085 if constexpr (debug)
86 {
87 std::cout << "Update value from " << mValue << " to " << newValue
88 << "\n";
89 }
90
Chau Lyb318dca2022-10-26 04:12:52 +000091 // Automatic Rearm mode allows direct update
92 // Manual Rearm mode requires a rearm action to clear the intrusion
93 // status
94 if (!mAutoRearm)
95 {
96 if (newValue == normalValStr)
97 {
98 // Chassis is first closed from being open. If it has been
99 // rearmed externally, reset the flag, update mValue and
100 // return, without having to write "Normal" to DBus property
101 // (because the rearm action already did).
102 // Otherwise, return with no more action.
103 if (mRearmFlag)
104 {
105 mRearmFlag = false;
106 mValue = newValue;
107 }
108 return;
109 }
110 }
111
112 // Flush the rearm flag everytime it allows an update to Dbus
113 mRearmFlag = false;
114
Qiang XUe28d1fa2019-02-27 13:50:56 +0800115 // indicate that it is internal set call
Chau Lyb318dca2022-10-26 04:12:52 +0000116 mOverridenState = false;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800117 mInternalSet = true;
118 mIface->set_property("Status", newValue);
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530119 mInternalSet = false;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800120
121 mValue = newValue;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800122}
123
Chau Lycebb28c2022-10-21 10:01:52 +0000124int ChassisIntrusionPchSensor::readSensor()
Qiang XUe28d1fa2019-02-27 13:50:56 +0800125{
Ed Tanous8a57ec02020-10-09 12:46:52 -0700126 int32_t statusMask = pchRegMaskIntrusion;
127 int32_t statusReg = pchStatusRegIntrusion;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800128
Chau Lycebb28c2022-10-21 10:01:52 +0000129 int32_t value = i2c_smbus_read_byte_data(mBusFd, statusReg);
130 if constexpr (debug)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800131 {
Chau Lycebb28c2022-10-21 10:01:52 +0000132 std::cout << "Pch type: raw value is " << value << "\n";
Qiang XUe28d1fa2019-02-27 13:50:56 +0800133 }
134
Chau Lycebb28c2022-10-21 10:01:52 +0000135 if (value < 0)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800136 {
137 std::cerr << "i2c_smbus_read_byte_data failed \n";
138 return -1;
139 }
140
141 // Get status value with mask
Chau Lycebb28c2022-10-21 10:01:52 +0000142 value &= statusMask;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800143
Chau Lycebb28c2022-10-21 10:01:52 +0000144 if constexpr (debug)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800145 {
Chau Lycebb28c2022-10-21 10:01:52 +0000146 std::cout << "Pch type: masked raw value is " << value << "\n";
Qiang XUe28d1fa2019-02-27 13:50:56 +0800147 }
Chau Lycebb28c2022-10-21 10:01:52 +0000148 return value;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800149}
150
Chau Lycebb28c2022-10-21 10:01:52 +0000151void ChassisIntrusionPchSensor::pollSensorStatus()
Qiang XUe28d1fa2019-02-27 13:50:56 +0800152{
Chau Lycebb28c2022-10-21 10:01:52 +0000153 std::weak_ptr<ChassisIntrusionPchSensor> weakRef = weak_from_this();
Chau Ly95f49932023-04-19 09:44:55 +0000154
Qiang XUe28d1fa2019-02-27 13:50:56 +0800155 // setting a new experation implicitly cancels any pending async wait
Ed Tanous83db50c2023-03-01 10:20:24 -0800156 mPollTimer.expires_after(std::chrono::seconds(intrusionSensorPollSec));
Qiang XUe28d1fa2019-02-27 13:50:56 +0800157
Chau Lycebb28c2022-10-21 10:01:52 +0000158 mPollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
Qiang XUe28d1fa2019-02-27 13:50:56 +0800159 // case of being canceled
Chau Lycebb28c2022-10-21 10:01:52 +0000160 if (ec == boost::asio::error::operation_aborted)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800161 {
Chau Lycebb28c2022-10-21 10:01:52 +0000162 std::cerr << "Timer of intrusion sensor is cancelled\n";
Qiang XUe28d1fa2019-02-27 13:50:56 +0800163 return;
164 }
Chau Ly95f49932023-04-19 09:44:55 +0000165
Chau Lycebb28c2022-10-21 10:01:52 +0000166 std::shared_ptr<ChassisIntrusionPchSensor> self = weakRef.lock();
167 if (!self)
168 {
169 std::cerr << "ChassisIntrusionSensor no self\n";
170 return;
171 }
Chau Ly95f49932023-04-19 09:44:55 +0000172
Chau Lycebb28c2022-10-21 10:01:52 +0000173 int value = self->readSensor();
174 if (value < 0)
175 {
176 intrusionSensorPollSec = sensorFailedPollSec;
177 }
178 else
179 {
180 intrusionSensorPollSec = defaultPollSec;
181 self->updateValue(value);
182 }
Chau Ly95f49932023-04-19 09:44:55 +0000183
Chau Lycebb28c2022-10-21 10:01:52 +0000184 // trigger next polling
185 self->pollSensorStatus();
Qiang XUe28d1fa2019-02-27 13:50:56 +0800186 });
187}
188
Chau Lycebb28c2022-10-21 10:01:52 +0000189int ChassisIntrusionGpioSensor::readSensor()
Qiang XUe28d1fa2019-02-27 13:50:56 +0800190{
ZhikuiRenba8a8bf2020-01-09 15:55:43 -0800191 mGpioLine.event_read();
192 auto value = mGpioLine.get_value();
Chau Lycebb28c2022-10-21 10:01:52 +0000193 if constexpr (debug)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800194 {
Chau Lycebb28c2022-10-21 10:01:52 +0000195 std::cout << "Gpio type: raw value is " << value << "\n";
Qiang XUe28d1fa2019-02-27 13:50:56 +0800196 }
Chau Lycebb28c2022-10-21 10:01:52 +0000197 return value;
Qiang XUe28d1fa2019-02-27 13:50:56 +0800198}
199
Chau Lycebb28c2022-10-21 10:01:52 +0000200void ChassisIntrusionGpioSensor::pollSensorStatus()
Qiang XUe28d1fa2019-02-27 13:50:56 +0800201{
Ed Tanousbb679322022-05-16 16:10:00 -0700202 mGpioFd.async_wait(boost::asio::posix::stream_descriptor::wait_read,
203 [this](const boost::system::error_code& ec) {
204 if (ec == boost::system::errc::bad_file_descriptor)
205 {
206 return; // we're being destroyed
207 }
Chau Ly95f49932023-04-19 09:44:55 +0000208
Ed Tanousbb679322022-05-16 16:10:00 -0700209 if (ec)
210 {
211 std::cerr << "Error on GPIO based intrusion sensor wait event\n";
212 }
213 else
214 {
Chau Lycebb28c2022-10-21 10:01:52 +0000215 int value = readSensor();
216 if (value >= 0)
217 {
218 updateValue(value);
219 }
220 // trigger next polling
221 pollSensorStatus();
Ed Tanousbb679322022-05-16 16:10:00 -0700222 }
Ed Tanousbb679322022-05-16 16:10:00 -0700223 });
Qiang XUe28d1fa2019-02-27 13:50:56 +0800224}
225
Chau Ly95f49932023-04-19 09:44:55 +0000226int ChassisIntrusionHwmonSensor::readSensor()
227{
228 int value = 0;
229
230 std::fstream stream(mHwmonPath, std::ios::in | std::ios::out);
231 if (!stream.good())
232 {
233 std::cerr << "Error reading status at " << mHwmonPath << "\n";
234 return -1;
235 }
236
237 std::string line;
238 if (!std::getline(stream, line))
239 {
240 std::cerr << "Error reading status at " << mHwmonPath << "\n";
241 return -1;
242 }
243
244 try
245 {
246 value = std::stoi(line);
247 if constexpr (debug)
248 {
249 std::cout << "Hwmon type: raw value is " << value << "\n";
250 }
251 }
252 catch (const std::invalid_argument& e)
253 {
254 std::cerr << "Error reading status at " << mHwmonPath << " : "
255 << e.what() << "\n";
256 return -1;
257 }
258
259 // Reset chassis intrusion status after every reading
260 stream << intrusionStatusHwmonClearValue;
261
262 return value;
263}
264
265void ChassisIntrusionHwmonSensor::pollSensorStatus()
266{
267 std::weak_ptr<ChassisIntrusionHwmonSensor> weakRef = weak_from_this();
268
269 // setting a new experation implicitly cancels any pending async wait
270 mPollTimer.expires_after(std::chrono::seconds(intrusionSensorPollSec));
271
272 mPollTimer.async_wait([weakRef](const boost::system::error_code& ec) {
273 // case of being canceled
274 if (ec == boost::asio::error::operation_aborted)
275 {
276 std::cerr << "Timer of intrusion sensor is cancelled\n";
277 return;
278 }
279
280 std::shared_ptr<ChassisIntrusionHwmonSensor> self = weakRef.lock();
281 if (!self)
282 {
283 std::cerr << "ChassisIntrusionSensor no self\n";
284 return;
285 }
286
287 int value = self->readSensor();
288 if (value < 0)
289 {
290 intrusionSensorPollSec = sensorFailedPollSec;
291 }
292 else
293 {
294 intrusionSensorPollSec = defaultPollSec;
295 self->updateValue(value);
296 }
297
298 // trigger next polling
299 self->pollSensorStatus();
300 });
301}
302
Qiang XUe28d1fa2019-02-27 13:50:56 +0800303int ChassisIntrusionSensor::setSensorValue(const std::string& req,
304 std::string& propertyValue)
305{
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530306 if (!mInternalSet)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800307 {
Chau Lyb318dca2022-10-26 04:12:52 +0000308 /*
309 1. Assuming that setting property in Automatic mode causes
310 no effect but only event logs and propertiesChanged signal
311 (because the property will be updated continuously to the
312 current hardware status anyway), only update Status property
313 and raise rearm flag in Manual rearm mode.
314 2. Only accept Normal value from an external call.
315 */
316 if (!mAutoRearm && req == normalValStr)
317 {
318 mRearmFlag = true;
319 propertyValue = req;
320 mOverridenState = true;
321 }
Qiang XUe28d1fa2019-02-27 13:50:56 +0800322 }
Richard Marian Thomaiyaraf6b87c2019-04-03 23:54:28 +0530323 else if (!mOverridenState)
324 {
325 propertyValue = req;
326 }
Chau Lyb318dca2022-10-26 04:12:52 +0000327 else
328 {
329 return 1;
330 }
331 // Send intrusion event to Redfish
332 if (mValue == normalValStr && propertyValue != normalValStr)
333 {
334 sd_journal_send("MESSAGE=%s", "Chassis intrusion assert event",
335 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
336 "OpenBMC.0.1.ChassisIntrusionDetected", NULL);
337 }
338 else if (mValue == hwIntrusionValStr && propertyValue == normalValStr)
339 {
340 sd_journal_send("MESSAGE=%s", "Chassis intrusion de-assert event",
341 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
342 "OpenBMC.0.1.ChassisIntrusionReset", NULL);
343 }
Qiang XUe28d1fa2019-02-27 13:50:56 +0800344 return 1;
345}
346
Chau Lycebb28c2022-10-21 10:01:52 +0000347void ChassisIntrusionSensor::start()
Qiang XUe28d1fa2019-02-27 13:50:56 +0800348{
Chau Lycebb28c2022-10-21 10:01:52 +0000349 mIface->register_property(
350 "Status", mValue,
351 [&](const std::string& req, std::string& propertyValue) {
352 return setSensorValue(req, propertyValue);
Patrick Williams597e8422023-10-20 11:19:01 -0500353 });
Chau Lyb318dca2022-10-26 04:12:52 +0000354 std::string rearmStr = mAutoRearm ? autoRearmStr : manualRearmStr;
355 mIface->register_property("Rearm", rearmStr);
Chau Lycebb28c2022-10-21 10:01:52 +0000356 mIface->initialize();
357 pollSensorStatus();
Qiang XUe28d1fa2019-02-27 13:50:56 +0800358}
359
360ChassisIntrusionSensor::ChassisIntrusionSensor(
Chau Lyb318dca2022-10-26 04:12:52 +0000361 bool autoRearm, sdbusplus::asio::object_server& objServer) :
362 mValue(normalValStr),
363 mAutoRearm(autoRearm), mObjServer(objServer)
Chau Lycebb28c2022-10-21 10:01:52 +0000364{
365 mIface = mObjServer.add_interface("/xyz/openbmc_project/Chassis/Intrusion",
366 "xyz.openbmc_project.Chassis.Intrusion");
367}
368
369ChassisIntrusionPchSensor::ChassisIntrusionPchSensor(
Chau Lyb318dca2022-10-26 04:12:52 +0000370 bool autoRearm, boost::asio::io_context& io,
371 sdbusplus::asio::object_server& objServer, int busId, int slaveAddr) :
372 ChassisIntrusionSensor(autoRearm, objServer),
Chau Lycebb28c2022-10-21 10:01:52 +0000373 mPollTimer(io)
374{
375 if (busId < 0 || slaveAddr <= 0)
376 {
377 throw std::invalid_argument("Invalid i2c bus " + std::to_string(busId) +
378 " address " + std::to_string(slaveAddr) +
379 "\n");
380 }
Chau Ly95f49932023-04-19 09:44:55 +0000381
Chau Lycebb28c2022-10-21 10:01:52 +0000382 mSlaveAddr = slaveAddr;
Chau Ly95f49932023-04-19 09:44:55 +0000383
Chau Lycebb28c2022-10-21 10:01:52 +0000384 std::string devPath = "/dev/i2c-" + std::to_string(busId);
385 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
386 mBusFd = open(devPath.c_str(), O_RDWR | O_CLOEXEC);
387 if (mBusFd < 0)
388 {
389 throw std::invalid_argument("Unable to open " + devPath + "\n");
390 }
391
392 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
393 if (ioctl(mBusFd, I2C_SLAVE_FORCE, mSlaveAddr) < 0)
394 {
395 throw std::runtime_error("Unable to set device address\n");
396 }
397
398 unsigned long funcs = 0;
399
400 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
401 if (ioctl(mBusFd, I2C_FUNCS, &funcs) < 0)
402 {
403 throw std::runtime_error("Don't support I2C_FUNCS\n");
404 }
405
406 if ((funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA) == 0U)
407 {
408 throw std::runtime_error(
409 "Do not have I2C_FUNC_SMBUS_READ_BYTE_DATA \n");
410 }
411}
412
413ChassisIntrusionGpioSensor::ChassisIntrusionGpioSensor(
Chau Lyb318dca2022-10-26 04:12:52 +0000414 bool autoRearm, boost::asio::io_context& io,
415 sdbusplus::asio::object_server& objServer, bool gpioInverted) :
416 ChassisIntrusionSensor(autoRearm, objServer),
Chau Lycebb28c2022-10-21 10:01:52 +0000417 mGpioInverted(gpioInverted), mGpioFd(io)
418{
419 mGpioLine = gpiod::find_line(mPinName);
420 if (!mGpioLine)
421 {
422 throw std::invalid_argument("Error finding gpio pin name: " + mPinName +
423 "\n");
424 }
425 mGpioLine.request(
426 {"ChassisIntrusionSensor", gpiod::line_request::EVENT_BOTH_EDGES,
427 mGpioInverted ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
428
429 auto gpioLineFd = mGpioLine.event_get_fd();
430 if (gpioLineFd < 0)
431 {
432 throw std::invalid_argument("Failed to get " + mPinName + " fd\n");
433 }
Chau Ly95f49932023-04-19 09:44:55 +0000434
Chau Lycebb28c2022-10-21 10:01:52 +0000435 mGpioFd.assign(gpioLineFd);
436}
Qiang XUe28d1fa2019-02-27 13:50:56 +0800437
Chau Ly95f49932023-04-19 09:44:55 +0000438ChassisIntrusionHwmonSensor::ChassisIntrusionHwmonSensor(
Chau Lyb318dca2022-10-26 04:12:52 +0000439 bool autoRearm, boost::asio::io_context& io,
440 sdbusplus::asio::object_server& objServer, std::string hwmonName) :
441 ChassisIntrusionSensor(autoRearm, objServer),
Chau Ly95f49932023-04-19 09:44:55 +0000442 mHwmonName(std::move(hwmonName)), mPollTimer(io)
443{
444 std::vector<fs::path> paths;
445
446 if (!findFiles(fs::path("/sys/class/hwmon"), mHwmonName, paths))
447 {
448 throw std::invalid_argument("Failed to find hwmon path in sysfs\n");
449 }
450
451 if (paths.empty())
452 {
453 throw std::invalid_argument("Hwmon file " + mHwmonName +
454 " can't be found in sysfs\n");
455 }
456
457 if (paths.size() > 1)
458 {
459 std::cerr << "Found more than 1 hwmon file to read chassis intrusion"
460 << " status. Taking the first one. \n";
461 }
462
463 // Expecting only one hwmon file for one given chassis
464 mHwmonPath = paths[0].string();
465
466 if constexpr (debug)
467 {
468 std::cout << "Found " << paths.size()
469 << " paths for intrusion status \n"
470 << " The first path is: " << mHwmonPath << "\n";
471 }
472}
473
Qiang XUe28d1fa2019-02-27 13:50:56 +0800474ChassisIntrusionSensor::~ChassisIntrusionSensor()
475{
Chau Lycebb28c2022-10-21 10:01:52 +0000476 mObjServer.remove_interface(mIface);
477}
478
479ChassisIntrusionPchSensor::~ChassisIntrusionPchSensor()
480{
481 mPollTimer.cancel();
482 if (close(mBusFd) < 0)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800483 {
Chau Lycebb28c2022-10-21 10:01:52 +0000484 std::cerr << "Failed to close fd " << std::to_string(mBusFd);
Qiang XUe28d1fa2019-02-27 13:50:56 +0800485 }
Chau Lycebb28c2022-10-21 10:01:52 +0000486}
487
488ChassisIntrusionGpioSensor::~ChassisIntrusionGpioSensor()
489{
490 mGpioFd.close();
491 if (mGpioLine)
Qiang XUe28d1fa2019-02-27 13:50:56 +0800492 {
Chau Lycebb28c2022-10-21 10:01:52 +0000493 mGpioLine.release();
Qiang XUe28d1fa2019-02-27 13:50:56 +0800494 }
495}
Chau Ly95f49932023-04-19 09:44:55 +0000496
497ChassisIntrusionHwmonSensor::~ChassisIntrusionHwmonSensor()
498{
499 mPollTimer.cancel();
500}