| #include "usb_monitor.hpp" |
| |
| #include <sdbusplus/asio/connection.hpp> |
| #include <sdbusplus/asio/object_server.hpp> |
| #include <stdplus/print.hpp> |
| |
| #include <atomic> |
| #include <chrono> |
| #include <csignal> |
| #include <iostream> |
| #include <map> |
| #include <sstream> |
| #include <string_view> |
| #include <thread> |
| |
| #define SERVICE_NAME "xyz.openbmc_project.UsbDevices" |
| #define OBJECT_PATH "/xyz/openbmc_project/usbdevices" |
| |
| struct DbusContext |
| { |
| sdbusplus::asio::object_server& objectServer; |
| std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>>& |
| dIfaceMap; |
| }; |
| |
| void addUsbInfToDbus( |
| usbdevice::UsbInterface& usbInfInfo, |
| sdbusplus::asio::object_server& objectServer, |
| std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>>& |
| dIfaceMap) |
| { |
| sdbusplus::message::object_path objPath( |
| std::string(OBJECT_PATH) + "/" + usbInfInfo.name); |
| std::shared_ptr<sdbusplus::asio::dbus_interface> iface = |
| objectServer.add_interface(objPath, SERVICE_NAME); |
| iface->register_property("RootHubPath", usbInfInfo.rootHubPath, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("Product", usbInfInfo.product, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("VID", usbInfInfo.vendorId, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("PID", usbInfInfo.productId, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("UsbPort", usbInfInfo.port, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("Configuration", usbInfInfo.configuration, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("InterfaceString", usbInfInfo.interfaceString, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("InterfaceNum", usbInfInfo.interfaceNum, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("InterfaceClass", usbInfInfo.interfaceClass, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("InterfaceSubclass", usbInfInfo.interfaceSubclass, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->register_property("InterfaceProtocol", usbInfInfo.interfaceProtocol, |
| sdbusplus::asio::PropertyPermission::readOnly); |
| iface->initialize(); |
| dIfaceMap.emplace(usbInfInfo.interfacePath, std::move(iface)); |
| stdplus::println(stdout, "Added USB interface {}", |
| usbInfInfo.interfacePath); |
| } |
| |
| void removeUsbIfaceFromDbus( |
| std::string_view infPath, sdbusplus::asio::object_server& objectServer, |
| std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>>& |
| dIfaceMap) |
| { |
| auto it = dIfaceMap.find(infPath.data()); |
| if (it == dIfaceMap.end()) |
| { |
| stdplus::println(stderr, "Removed interface {} not found under Dbus", |
| infPath); |
| return; |
| } |
| |
| std::shared_ptr<sdbusplus::asio::dbus_interface> iface = it->second; |
| objectServer.remove_interface(iface); |
| dIfaceMap.erase(it); |
| stdplus::println(stdout, "Removed USB interface: {}", infPath); |
| } |
| |
| void onUsbAdd(usbdevice::UsbInterface& usbInf, void* context) |
| { |
| if (context == nullptr) |
| { |
| return; |
| } |
| DbusContext* dbCtx = static_cast<DbusContext*>(context); |
| addUsbInfToDbus(usbInf, dbCtx->objectServer, dbCtx->dIfaceMap); |
| } |
| |
| void onUsbRemove(std::string_view infPath, void* context) |
| { |
| if (context == nullptr) |
| { |
| return; |
| } |
| DbusContext* dbCtx = static_cast<DbusContext*>(context); |
| removeUsbIfaceFromDbus(infPath, dbCtx->objectServer, dbCtx->dIfaceMap); |
| } |
| |
| int main() |
| { |
| boost::asio::io_context io; |
| auto conn = std::make_shared<sdbusplus::asio::connection>(io); |
| conn->request_name(SERVICE_NAME); |
| |
| auto objectServer = |
| sdbusplus::asio::object_server(conn, /*skipManager=*/true); |
| objectServer.add_manager(OBJECT_PATH); |
| |
| auto monitor = usbdevice::UsbMonitor::create(io); |
| if (!monitor) |
| { |
| return -1; |
| } |
| |
| stdplus::println(stdout, "Enumerating devices ---"); |
| |
| std::vector<usbdevice::UsbInterface> usbInterfaces = |
| monitor->getEndpoints(); |
| if (usbInterfaces.empty()) |
| { |
| std::cout << "No existing USB interfaces found.\n"; |
| } |
| |
| std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> |
| dIfaceMap; |
| for (auto inf : usbInterfaces) |
| { |
| addUsbInfToDbus(inf, objectServer, dIfaceMap); |
| } |
| |
| DbusContext context = {objectServer, dIfaceMap}; |
| int ret = monitor->monitor(onUsbAdd, onUsbRemove, &context); |
| if (ret != 0) |
| { |
| stdplus::println(stderr, "Failed to start USB monitor: {}", ret); |
| return -1; |
| } |
| |
| stdplus::println(stdout, "Monitoring started"); |
| |
| io.run(); |
| return 0; |
| } |