138a93a8aSMatthew Barth #pragma once 238a93a8aSMatthew Barth 338a93a8aSMatthew Barth #include "types.hpp" 4336f18a5SMatthew Barth #include "sdbusplus.hpp" 538a93a8aSMatthew Barth #include <phosphor-logging/log.hpp> 638a93a8aSMatthew Barth 738a93a8aSMatthew Barth namespace phosphor 838a93a8aSMatthew Barth { 938a93a8aSMatthew Barth namespace fan 1038a93a8aSMatthew Barth { 1138a93a8aSMatthew Barth namespace control 1238a93a8aSMatthew Barth { 1338a93a8aSMatthew Barth class Zone; 1438a93a8aSMatthew Barth 15336f18a5SMatthew Barth using namespace phosphor::fan; 165a302576SMatthew Barth using namespace sdbusplus::bus::match; 1738a93a8aSMatthew Barth using namespace phosphor::logging; 1838a93a8aSMatthew Barth 1938a93a8aSMatthew Barth /** 2038a93a8aSMatthew Barth * @brief Create a handler function object 2138a93a8aSMatthew Barth * 2238a93a8aSMatthew Barth * @param[in] handler - The handler being created 2338a93a8aSMatthew Barth * 2438a93a8aSMatthew Barth * @return - The created handler function object 2538a93a8aSMatthew Barth */ 2638a93a8aSMatthew Barth template <typename T> 2738a93a8aSMatthew Barth auto make_handler(T&& handler) 2838a93a8aSMatthew Barth { 2938a93a8aSMatthew Barth return Handler(std::forward<T>(handler)); 3038a93a8aSMatthew Barth } 3138a93a8aSMatthew Barth 3238a93a8aSMatthew Barth /** 3317d1fe23SMatthew Barth * @brief Create an action function object 3417d1fe23SMatthew Barth * 3517d1fe23SMatthew Barth * @param[in] action - The action being created 3617d1fe23SMatthew Barth * 3717d1fe23SMatthew Barth * @return - The created action function object 3817d1fe23SMatthew Barth */ 3917d1fe23SMatthew Barth template <typename T> 4017d1fe23SMatthew Barth auto make_action(T&& action) 4117d1fe23SMatthew Barth { 4217d1fe23SMatthew Barth return Action(std::forward<T>(action)); 4317d1fe23SMatthew Barth } 4417d1fe23SMatthew Barth 4517d1fe23SMatthew Barth /** 4638a93a8aSMatthew Barth * @struct Property Changed 4738a93a8aSMatthew Barth * @brief A match filter functor for Dbus property value changed signals 4838a93a8aSMatthew Barth * 4938a93a8aSMatthew Barth * @tparam T - The type of the property value 5038a93a8aSMatthew Barth * @tparam U - The type of the handler 5138a93a8aSMatthew Barth */ 5238a93a8aSMatthew Barth template <typename T, typename U> 5338a93a8aSMatthew Barth struct PropertyChanged 5438a93a8aSMatthew Barth { 5538a93a8aSMatthew Barth PropertyChanged() = delete; 5638a93a8aSMatthew Barth ~PropertyChanged() = default; 5738a93a8aSMatthew Barth PropertyChanged(const PropertyChanged&) = default; 5838a93a8aSMatthew Barth PropertyChanged& operator=(const PropertyChanged&) = default; 5938a93a8aSMatthew Barth PropertyChanged(PropertyChanged&&) = default; 6038a93a8aSMatthew Barth PropertyChanged& operator=(PropertyChanged&&) = default; 61336f18a5SMatthew Barth PropertyChanged(const char* path, 62336f18a5SMatthew Barth const char* iface, 6338a93a8aSMatthew Barth const char* property, 6438a93a8aSMatthew Barth U&& handler) : 65336f18a5SMatthew Barth _path(path), 6638a93a8aSMatthew Barth _iface(iface), 6738a93a8aSMatthew Barth _property(property), 6838a93a8aSMatthew Barth _handler(std::forward<U>(handler)) { } 6938a93a8aSMatthew Barth 7038a93a8aSMatthew Barth /** @brief Run signal handler function 7138a93a8aSMatthew Barth * 7238a93a8aSMatthew Barth * Extract the property from the PropertiesChanged 73336f18a5SMatthew Barth * message (or read the property when the message is null) 74336f18a5SMatthew Barth * and run the handler function. 7538a93a8aSMatthew Barth */ 76336f18a5SMatthew Barth void operator()(sdbusplus::bus::bus& bus, 7738a93a8aSMatthew Barth sdbusplus::message::message& msg, 7838a93a8aSMatthew Barth Zone& zone) const 7938a93a8aSMatthew Barth { 80336f18a5SMatthew Barth if (msg) 81336f18a5SMatthew Barth { 8238a93a8aSMatthew Barth std::map<std::string, sdbusplus::message::variant<T>> properties; 83d5cfdbe0SMatthew Barth std::string iface; 8438a93a8aSMatthew Barth 8538a93a8aSMatthew Barth msg.read(iface); 86d5cfdbe0SMatthew Barth if (iface != _iface) 8738a93a8aSMatthew Barth { 8838a93a8aSMatthew Barth return; 8938a93a8aSMatthew Barth } 9038a93a8aSMatthew Barth 9138a93a8aSMatthew Barth msg.read(properties); 9238a93a8aSMatthew Barth auto it = properties.find(_property); 9338a93a8aSMatthew Barth if (it == properties.cend()) 9438a93a8aSMatthew Barth { 9538a93a8aSMatthew Barth log<level::ERR>("Unable to find property on interface", 9638a93a8aSMatthew Barth entry("PROPERTY=%s", _property), 97e65f617cSMatthew Barth entry("INTERFACE=%s", _iface), 98e65f617cSMatthew Barth entry("PATH=%s", _path)); 9938a93a8aSMatthew Barth return; 10038a93a8aSMatthew Barth } 10138a93a8aSMatthew Barth 10238a93a8aSMatthew Barth _handler(zone, std::forward<T>(it->second.template get<T>())); 10338a93a8aSMatthew Barth } 104336f18a5SMatthew Barth else 105336f18a5SMatthew Barth { 106336f18a5SMatthew Barth try 107336f18a5SMatthew Barth { 108c72b8911SMatthew Barth auto service = zone.getService(_path, _iface); 109336f18a5SMatthew Barth auto val = util::SDBusPlus::getProperty<T>(bus, 110c72b8911SMatthew Barth service, 111336f18a5SMatthew Barth _path, 112336f18a5SMatthew Barth _iface, 113336f18a5SMatthew Barth _property); 114336f18a5SMatthew Barth _handler(zone, std::forward<T>(val)); 115336f18a5SMatthew Barth } 116*ba7b5feaSMatt Spinler catch (const util::DBusError& e) 117336f18a5SMatthew Barth { 118336f18a5SMatthew Barth // Property will not be used unless a property changed 119336f18a5SMatthew Barth // signal message is received for this property. 120336f18a5SMatthew Barth log<level::INFO>( 121336f18a5SMatthew Barth "Property not used, unless PropertyChanged signal received", 122336f18a5SMatthew Barth entry("PATH=%s", _path), 123336f18a5SMatthew Barth entry("INTERFACE=%s", _iface), 124336f18a5SMatthew Barth entry("PROPERTY=%s", _property)); 125336f18a5SMatthew Barth } 126336f18a5SMatthew Barth } 127336f18a5SMatthew Barth } 12838a93a8aSMatthew Barth 12938a93a8aSMatthew Barth private: 130336f18a5SMatthew Barth const char* _path; 13138a93a8aSMatthew Barth const char* _iface; 13238a93a8aSMatthew Barth const char* _property; 13338a93a8aSMatthew Barth U _handler; 13438a93a8aSMatthew Barth }; 13538a93a8aSMatthew Barth 13638a93a8aSMatthew Barth /** 13738a93a8aSMatthew Barth * @brief Used to process a Dbus property changed signal event 13838a93a8aSMatthew Barth * 139336f18a5SMatthew Barth * @param[in] path - Object path 140336f18a5SMatthew Barth * @param[in] iface - Object interface 141336f18a5SMatthew Barth * @param[in] property - Object property 14238a93a8aSMatthew Barth * @param[in] handler - Handler function to perform 14338a93a8aSMatthew Barth * 14438a93a8aSMatthew Barth * @tparam T - The type of the property 14538a93a8aSMatthew Barth * @tparam U - The type of the handler 14638a93a8aSMatthew Barth */ 14738a93a8aSMatthew Barth template <typename T, typename U> 148336f18a5SMatthew Barth auto propertySignal(const char* path, 149336f18a5SMatthew Barth const char* iface, 15038a93a8aSMatthew Barth const char* property, 15138a93a8aSMatthew Barth U&& handler) 15238a93a8aSMatthew Barth { 153336f18a5SMatthew Barth return PropertyChanged<T, U>(path, 154336f18a5SMatthew Barth iface, 155336f18a5SMatthew Barth property, 156336f18a5SMatthew Barth std::forward<U>(handler)); 15738a93a8aSMatthew Barth } 15838a93a8aSMatthew Barth 159eb639c57SMatthew Barth /** 160eb639c57SMatthew Barth * @struct Interface Added 161eb639c57SMatthew Barth * @brief A match filter functor for Dbus interface added signals 162eb639c57SMatthew Barth * 163eb639c57SMatthew Barth * @tparam T - The type of the property value 164eb639c57SMatthew Barth * @tparam U - The type of the handler 165eb639c57SMatthew Barth */ 166eb639c57SMatthew Barth template <typename T, typename U> 167eb639c57SMatthew Barth struct InterfaceAdded 168eb639c57SMatthew Barth { 169eb639c57SMatthew Barth InterfaceAdded() = delete; 170eb639c57SMatthew Barth ~InterfaceAdded() = default; 171eb639c57SMatthew Barth InterfaceAdded(const InterfaceAdded&) = default; 172eb639c57SMatthew Barth InterfaceAdded& operator=(const InterfaceAdded&) = default; 173eb639c57SMatthew Barth InterfaceAdded(InterfaceAdded&&) = default; 174eb639c57SMatthew Barth InterfaceAdded& operator=(InterfaceAdded&&) = default; 175eb639c57SMatthew Barth InterfaceAdded(const char* path, 176eb639c57SMatthew Barth const char* iface, 177eb639c57SMatthew Barth const char* property, 178eb639c57SMatthew Barth U&& handler) : 179eb639c57SMatthew Barth _path(path), 180eb639c57SMatthew Barth _iface(iface), 181eb639c57SMatthew Barth _property(property), 182eb639c57SMatthew Barth _handler(std::forward<U>(handler)) { } 183eb639c57SMatthew Barth 184eb639c57SMatthew Barth /** @brief Run signal handler function 185eb639c57SMatthew Barth * 186eb639c57SMatthew Barth * Extract the property from the InterfacesAdded 187eb639c57SMatthew Barth * message and run the handler function. 188eb639c57SMatthew Barth */ 189eb639c57SMatthew Barth void operator()(sdbusplus::bus::bus&, 190eb639c57SMatthew Barth sdbusplus::message::message& msg, 191eb639c57SMatthew Barth Zone& zone) const 192eb639c57SMatthew Barth { 193336f18a5SMatthew Barth if (msg) 194336f18a5SMatthew Barth { 195eb639c57SMatthew Barth std::map<std::string, 196eb639c57SMatthew Barth std::map<std::string, 197eb639c57SMatthew Barth sdbusplus::message::variant<T>>> intfProp; 198eb639c57SMatthew Barth sdbusplus::message::object_path op; 199eb639c57SMatthew Barth 200eb639c57SMatthew Barth msg.read(op); 201d5cfdbe0SMatthew Barth if (static_cast<const std::string&>(op) != _path) 202eb639c57SMatthew Barth { 203eb639c57SMatthew Barth // Object path does not match this handler's path 204eb639c57SMatthew Barth return; 205eb639c57SMatthew Barth } 206eb639c57SMatthew Barth 207eb639c57SMatthew Barth msg.read(intfProp); 208eb639c57SMatthew Barth auto itIntf = intfProp.find(_iface); 209eb639c57SMatthew Barth if (itIntf == intfProp.cend()) 210eb639c57SMatthew Barth { 211eb639c57SMatthew Barth // Interface not found on this handler's path 212eb639c57SMatthew Barth return; 213eb639c57SMatthew Barth } 214eb639c57SMatthew Barth auto itProp = itIntf->second.find(_property); 215eb639c57SMatthew Barth if (itProp == itIntf->second.cend()) 216eb639c57SMatthew Barth { 217eb639c57SMatthew Barth // Property not found on this handler's path 218eb639c57SMatthew Barth return; 219eb639c57SMatthew Barth } 220eb639c57SMatthew Barth 221eb639c57SMatthew Barth _handler(zone, std::forward<T>(itProp->second.template get<T>())); 222eb639c57SMatthew Barth } 223336f18a5SMatthew Barth } 224eb639c57SMatthew Barth 225eb639c57SMatthew Barth private: 226eb639c57SMatthew Barth const char* _path; 227eb639c57SMatthew Barth const char* _iface; 228eb639c57SMatthew Barth const char* _property; 229eb639c57SMatthew Barth U _handler; 230eb639c57SMatthew Barth }; 231eb639c57SMatthew Barth 232eb639c57SMatthew Barth /** 233eb639c57SMatthew Barth * @brief Used to process a Dbus interface added signal event 234eb639c57SMatthew Barth * 235eb639c57SMatthew Barth * @param[in] path - Object path 236eb639c57SMatthew Barth * @param[in] iface - Object interface 237eb639c57SMatthew Barth * @param[in] property - Object property 238eb639c57SMatthew Barth * @param[in] handler - Handler function to perform 239eb639c57SMatthew Barth * 240eb639c57SMatthew Barth * @tparam T - The type of the property 241eb639c57SMatthew Barth * @tparam U - The type of the handler 242eb639c57SMatthew Barth */ 243eb639c57SMatthew Barth template <typename T, typename U> 244eb639c57SMatthew Barth auto objectSignal(const char* path, 245eb639c57SMatthew Barth const char* iface, 246eb639c57SMatthew Barth const char* property, 247eb639c57SMatthew Barth U&& handler) 248eb639c57SMatthew Barth { 249eb639c57SMatthew Barth return InterfaceAdded<T, U>(path, 250eb639c57SMatthew Barth iface, 251eb639c57SMatthew Barth property, 252eb639c57SMatthew Barth std::forward<U>(handler)); 253eb639c57SMatthew Barth } 254eb639c57SMatthew Barth 2558fa02dabSMatthew Barth /** 2561499a5c3SMatthew Barth * @struct Interface Removed 2571499a5c3SMatthew Barth * @brief A match filter functor for Dbus interface removed signals 2581499a5c3SMatthew Barth * 2591499a5c3SMatthew Barth * @tparam U - The type of the handler 2601499a5c3SMatthew Barth */ 2611499a5c3SMatthew Barth template <typename U> 2621499a5c3SMatthew Barth struct InterfaceRemoved 2631499a5c3SMatthew Barth { 2641499a5c3SMatthew Barth InterfaceRemoved() = delete; 2651499a5c3SMatthew Barth ~InterfaceRemoved() = default; 2661499a5c3SMatthew Barth InterfaceRemoved(const InterfaceRemoved&) = default; 2671499a5c3SMatthew Barth InterfaceRemoved& operator=(const InterfaceRemoved&) = default; 2681499a5c3SMatthew Barth InterfaceRemoved(InterfaceRemoved&&) = default; 2691499a5c3SMatthew Barth InterfaceRemoved& operator=(InterfaceRemoved&&) = default; 2701499a5c3SMatthew Barth InterfaceRemoved(const char* path, 2711499a5c3SMatthew Barth const char* iface, 2721499a5c3SMatthew Barth U&& handler) : 2731499a5c3SMatthew Barth _path(path), 2741499a5c3SMatthew Barth _iface(iface), 2751499a5c3SMatthew Barth _handler(std::forward<U>(handler)) { } 2761499a5c3SMatthew Barth 2771499a5c3SMatthew Barth /** @brief Run signal handler function 2781499a5c3SMatthew Barth * 2791499a5c3SMatthew Barth * Extract the property from the InterfacesRemoved 2801499a5c3SMatthew Barth * message and run the handler function. 2811499a5c3SMatthew Barth */ 2821499a5c3SMatthew Barth void operator()(sdbusplus::bus::bus&, 2831499a5c3SMatthew Barth sdbusplus::message::message& msg, 2841499a5c3SMatthew Barth Zone& zone) const 2851499a5c3SMatthew Barth { 2861499a5c3SMatthew Barth if (msg) 2871499a5c3SMatthew Barth { 2881499a5c3SMatthew Barth std::vector<std::string> intfs; 2891499a5c3SMatthew Barth sdbusplus::message::object_path op; 2901499a5c3SMatthew Barth 2911499a5c3SMatthew Barth msg.read(op); 2921499a5c3SMatthew Barth if (static_cast<const std::string&>(op) != _path) 2931499a5c3SMatthew Barth { 2941499a5c3SMatthew Barth // Object path does not match this handler's path 2951499a5c3SMatthew Barth return; 2961499a5c3SMatthew Barth } 2971499a5c3SMatthew Barth 2981499a5c3SMatthew Barth msg.read(intfs); 2991499a5c3SMatthew Barth auto itIntf = std::find(intfs.begin(), intfs.end(), _iface); 3001499a5c3SMatthew Barth if (itIntf == intfs.cend()) 3011499a5c3SMatthew Barth { 3021499a5c3SMatthew Barth // Interface not found on this handler's path 3031499a5c3SMatthew Barth return; 3041499a5c3SMatthew Barth } 3051499a5c3SMatthew Barth 3061499a5c3SMatthew Barth _handler(zone); 3071499a5c3SMatthew Barth } 3081499a5c3SMatthew Barth } 3091499a5c3SMatthew Barth 3101499a5c3SMatthew Barth private: 3111499a5c3SMatthew Barth const char* _path; 3121499a5c3SMatthew Barth const char* _iface; 3131499a5c3SMatthew Barth U _handler; 3141499a5c3SMatthew Barth }; 3151499a5c3SMatthew Barth 3161499a5c3SMatthew Barth /** 3171499a5c3SMatthew Barth * @brief Used to process a Dbus interface removed signal event 3181499a5c3SMatthew Barth * 3191499a5c3SMatthew Barth * @param[in] path - Object path 3201499a5c3SMatthew Barth * @param[in] iface - Object interface 3211499a5c3SMatthew Barth * @param[in] handler - Handler function to perform 3221499a5c3SMatthew Barth * 3231499a5c3SMatthew Barth * @tparam U - The type of the handler 3241499a5c3SMatthew Barth */ 3251499a5c3SMatthew Barth template <typename U> 3261499a5c3SMatthew Barth auto objectSignal(const char* path, 3271499a5c3SMatthew Barth const char* iface, 3281499a5c3SMatthew Barth U&& handler) 3291499a5c3SMatthew Barth { 3301499a5c3SMatthew Barth return InterfaceRemoved<U>(path, 3311499a5c3SMatthew Barth iface, 3321499a5c3SMatthew Barth std::forward<U>(handler)); 3331499a5c3SMatthew Barth } 3341499a5c3SMatthew Barth 3351499a5c3SMatthew Barth /** 3368fa02dabSMatthew Barth * @struct Name Owner Changed 3378fa02dabSMatthew Barth * @brief A match filter functor for Dbus name owner changed signals 3388fa02dabSMatthew Barth * 3398fa02dabSMatthew Barth * @tparam U - The type of the handler 3408fa02dabSMatthew Barth */ 3418fa02dabSMatthew Barth template <typename U> 3428fa02dabSMatthew Barth struct NameOwnerChanged 3438fa02dabSMatthew Barth { 3448fa02dabSMatthew Barth NameOwnerChanged() = delete; 3458fa02dabSMatthew Barth ~NameOwnerChanged() = default; 3468fa02dabSMatthew Barth NameOwnerChanged(const NameOwnerChanged&) = default; 3478fa02dabSMatthew Barth NameOwnerChanged& operator=(const NameOwnerChanged&) = default; 3488fa02dabSMatthew Barth NameOwnerChanged(NameOwnerChanged&&) = default; 3498fa02dabSMatthew Barth NameOwnerChanged& operator=(NameOwnerChanged&&) = default; 3508fa02dabSMatthew Barth NameOwnerChanged(const char* path, 3518fa02dabSMatthew Barth const char* iface, 3528fa02dabSMatthew Barth U&& handler) : 3538fa02dabSMatthew Barth _path(path), 3548fa02dabSMatthew Barth _iface(iface), 3558fa02dabSMatthew Barth _handler(std::forward<U>(handler)) { } 3568fa02dabSMatthew Barth 3578fa02dabSMatthew Barth /** @brief Run signal handler function 3588fa02dabSMatthew Barth * 3598fa02dabSMatthew Barth * Extract the name owner from the NameOwnerChanged 3608fa02dabSMatthew Barth * message (or read the name owner when the message is null) 3618fa02dabSMatthew Barth * and run the handler function. 3628fa02dabSMatthew Barth */ 3638fa02dabSMatthew Barth void operator()(sdbusplus::bus::bus& bus, 3648fa02dabSMatthew Barth sdbusplus::message::message& msg, 3658fa02dabSMatthew Barth Zone& zone) const 3668fa02dabSMatthew Barth { 3675a302576SMatthew Barth std::string name; 3685a302576SMatthew Barth bool hasOwner = false; 3698fa02dabSMatthew Barth if (msg) 3708fa02dabSMatthew Barth { 3715a302576SMatthew Barth // Handle NameOwnerChanged signals 3725a302576SMatthew Barth msg.read(name); 3735a302576SMatthew Barth 3745a302576SMatthew Barth std::string oldOwn; 3755a302576SMatthew Barth msg.read(oldOwn); 3765a302576SMatthew Barth 3775a302576SMatthew Barth std::string newOwn; 3785a302576SMatthew Barth msg.read(newOwn); 3795a302576SMatthew Barth if (!newOwn.empty()) 3805a302576SMatthew Barth { 3815a302576SMatthew Barth hasOwner = true; 3825a302576SMatthew Barth } 3838fa02dabSMatthew Barth } 3848fa02dabSMatthew Barth else 3858fa02dabSMatthew Barth { 3865a302576SMatthew Barth try 3875a302576SMatthew Barth { 3885a302576SMatthew Barth // Initialize NameOwnerChanged data store with service name 389c72b8911SMatthew Barth name = zone.getService(_path, _iface); 3905a302576SMatthew Barth hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 3915a302576SMatthew Barth bus, 3925a302576SMatthew Barth "org.freedesktop.DBus", 3935a302576SMatthew Barth "/org/freedesktop/DBus", 3945a302576SMatthew Barth "org.freedesktop.DBus", 3955a302576SMatthew Barth "NameHasOwner", 3965a302576SMatthew Barth name); 3978fa02dabSMatthew Barth } 398*ba7b5feaSMatt Spinler catch (const util::DBusMethodError& e) 3995a302576SMatthew Barth { 4005a302576SMatthew Barth // Failed to get service name owner state 4015a302576SMatthew Barth hasOwner = false; 4025a302576SMatthew Barth } 4035a302576SMatthew Barth } 4045a302576SMatthew Barth 4055a302576SMatthew Barth _handler(zone, name, hasOwner); 4068fa02dabSMatthew Barth } 4078fa02dabSMatthew Barth 4088fa02dabSMatthew Barth private: 4098fa02dabSMatthew Barth const char* _path; 4108fa02dabSMatthew Barth const char* _iface; 4118fa02dabSMatthew Barth U _handler; 4128fa02dabSMatthew Barth }; 4138fa02dabSMatthew Barth 4148fa02dabSMatthew Barth /** 4158fa02dabSMatthew Barth * @brief Used to process a Dbus name owner changed signal event 4168fa02dabSMatthew Barth * 4178fa02dabSMatthew Barth * @param[in] path - Object path 4188fa02dabSMatthew Barth * @param[in] iface - Object interface 4198fa02dabSMatthew Barth * @param[in] handler - Handler function to perform 4208fa02dabSMatthew Barth * 4218fa02dabSMatthew Barth * @tparam U - The type of the handler 4228fa02dabSMatthew Barth * 4238fa02dabSMatthew Barth * @return - The NameOwnerChanged signal struct 4248fa02dabSMatthew Barth */ 4258fa02dabSMatthew Barth template <typename U> 4268fa02dabSMatthew Barth auto ownerSignal(const char* path, 4278fa02dabSMatthew Barth const char* iface, 4288fa02dabSMatthew Barth U&& handler) 4298fa02dabSMatthew Barth { 4308fa02dabSMatthew Barth return NameOwnerChanged<U>(path, 4318fa02dabSMatthew Barth iface, 4328fa02dabSMatthew Barth std::forward<U>(handler)); 4338fa02dabSMatthew Barth } 4348fa02dabSMatthew Barth 43538a93a8aSMatthew Barth } // namespace control 43638a93a8aSMatthew Barth } // namespace fan 43738a93a8aSMatthew Barth } // namespace phosphor 438