xref: /openbmc/phosphor-modbus/rtu/port/usb_port.cpp (revision 7f9d41ddfad8c74d51fa1cf4a591b7f085254396)
1 #include "usb_port.hpp"
2 
3 #include "common/entity_manager_interface.hpp"
4 #include "port_factory.hpp"
5 
6 #include <fcntl.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 #include <xyz/openbmc_project/Configuration/USBPort/client.hpp>
10 
11 #include <filesystem>
12 #include <format>
13 #include <optional>
14 #include <regex>
15 
16 namespace phosphor::modbus::rtu::port
17 {
18 
19 PHOSPHOR_LOG2_USING;
20 
21 using USBPortConfigIntf =
22     sdbusplus::client::xyz::openbmc_project::configuration::USBPort<>;
23 
24 namespace config
25 {
26 
27 struct USBPortConfig : public PortFactoryConfig
28 {
29     std::string address = "unknown";
30     uint16_t port = 0;
31     uint16_t interface = 0;
32 };
33 
34 } // namespace config
35 
36 static auto getDevicePath(const config::Config& inConfig) -> std::string
37 {
38     namespace fs = std::filesystem;
39     auto config = static_cast<const config::USBPortConfig&>(inConfig);
40     std::regex pattern(
41         std::format("platform-{}\\.usb-usb.*{}-port{}", config.address,
42                     config.interface, config.port));
43     fs::path searchDir = "/dev/serial/by-path/";
44 
45     for (const auto& entry : fs::recursive_directory_iterator(searchDir))
46     {
47         if (entry.is_symlink())
48         {
49             auto filePath = entry.path();
50             if (std::regex_search(filePath.filename().string(), pattern))
51             {
52                 return ("/dev/" +
53                         fs::read_symlink(filePath).filename().string());
54             }
55         }
56     }
57 
58     throw std::runtime_error("Failed to get device path");
59 }
60 
61 USBPort::USBPort(sdbusplus::async::context& ctx,
62                  config::PortFactoryConfig& config) :
63     BasePort(ctx, config, getDevicePath(config))
64 {
65     info("USB port {NAME} created successfully", "NAME", config.name);
66 }
67 
68 auto USBPort::getConfig(sdbusplus::async::context& ctx,
69                         const sdbusplus::message::object_path& objectPath)
70     -> sdbusplus::async::task<std::optional<config::PortFactoryConfig>>
71 {
72     config::USBPortConfig config = {};
73 
74     auto properties =
75         co_await USBPortConfigIntf(ctx)
76             .service(entity_manager::EntityManagerInterface::serviceName)
77             .path(objectPath.str)
78             .properties();
79 
80     auto res = updateBaseConfig(config, properties);
81     if (!res)
82     {
83         co_return std::nullopt;
84     }
85 
86     config.address = properties.device_address;
87     config.port = properties.port;
88     config.interface = properties.device_interface;
89 
90     debug(
91         "USB port config: {NAME} {PORT_TYPE} {PORT_MODE} {ADDRESS} {PORT} {INTERFACE} {BAUD_RATE} {RTS_DELAY}",
92         "NAME", config.name, "PORT_TYPE", config.portType, "PORT_MODE",
93         config.portMode, "ADDRESS", config.address, "PORT", config.port,
94         "INTERFACE", config.interface, "BAUD_RATE", config.baudRate,
95         "RTS_DELAY", config.rtsDelay);
96     co_return config;
97 }
98 
99 } // namespace phosphor::modbus::rtu::port
100