mirror of
https://github.com/vmatare/thinkfan.git
synced 2024-09-11 19:47:17 +03:00
Add hwmon model option
On NVME devices a file is available to differentiate them by model. My thinkpad has one internal NVME slot, but I also use external USB-C and Thunderbolt NVME enclosures. The internal slot shows up as hwmon3: `/sys/class/hwmon/hwmon3/device/model` Which contains: `WD_BLACK SN770 1TB` and some trailing white-space characters. This change adds an option to allow you to specify the model with or without the hwmon-name. I have tested both configurations successfully: ``` - hwmon: /sys/class/hwmon name: nvme model: WD_BLACK SN770 1TB indices: [1] ``` and ``` - hwmon: /sys/class/hwmon model: WD_BLACK SN770 1TB indices: [1] ``` Signed-off-by: Bryan Hundven <bryanhundven@gmail.com>
This commit is contained in:
parent
c6e48a95b3
commit
b90cd6e18c
@ -201,7 +201,7 @@ string TpFanDriver::type_name() const
|
||||
|
||||
HwmonFanDriver::HwmonFanDriver(const string &path)
|
||||
: HwmonFanDriver(
|
||||
std::make_shared<HwmonInterface<FanDriver>>(path, nullopt, nullopt),
|
||||
std::make_shared<HwmonInterface<FanDriver>>(path, nullopt, nullopt, nullopt),
|
||||
false,
|
||||
0
|
||||
)
|
||||
|
@ -65,7 +65,6 @@ vector<string> HwmonInterface<HwmonT>::find_files(const string &path, const vect
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
string HwmonInterface<SensorDriver>::filename(int index)
|
||||
{ return "temp" + std::to_string(index) + "_input"; }
|
||||
@ -81,13 +80,13 @@ HwmonInterface<HwmonT>::HwmonInterface()
|
||||
{}
|
||||
|
||||
template<class HwmonT>
|
||||
HwmonInterface<HwmonT>::HwmonInterface(const string &base_path, opt<const string> name, opt<vector<unsigned int>> indices)
|
||||
HwmonInterface<HwmonT>::HwmonInterface(const string &base_path, opt<const string> name, opt<const string> model, opt<vector<unsigned int>> indices)
|
||||
: base_path_(base_path)
|
||||
, name_(name)
|
||||
, model_(model)
|
||||
, indices_(indices)
|
||||
{}
|
||||
|
||||
|
||||
template<class HwmonT>
|
||||
vector<string> HwmonInterface<HwmonT>::find_hwmons_by_name(
|
||||
const string &path,
|
||||
@ -131,6 +130,51 @@ vector<string> HwmonInterface<HwmonT>::find_hwmons_by_name(
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class HwmonT>
|
||||
vector<string> HwmonInterface<HwmonT>::find_hwmons_by_model(
|
||||
const string &path,
|
||||
const string &model,
|
||||
unsigned char depth
|
||||
) {
|
||||
const unsigned char max_depth = 5;
|
||||
vector<string> result;
|
||||
|
||||
ifstream f(path + "/model");
|
||||
if (f.is_open() && f.good()) {
|
||||
string tmp;
|
||||
if (getline(f, tmp)) {
|
||||
tmp = tmp.erase(tmp.find_last_not_of(" \t\n\r\f\v") + 1);
|
||||
if (tmp == model) {
|
||||
result.push_back(path);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depth >= max_depth) {
|
||||
return result; // don't recurse to subdirs
|
||||
}
|
||||
|
||||
struct dirent **entries;
|
||||
int nentries = ::scandir(path.c_str(), &entries, filter_subdirs, nullptr);
|
||||
if (nentries == -1) {
|
||||
return result;
|
||||
}
|
||||
for (int i = 0; i < nentries; i++) {
|
||||
auto subdir = path + "/" + entries[i]->d_name;
|
||||
free(entries[i]);
|
||||
|
||||
struct stat statbuf;
|
||||
int err = stat(path.c_str(), &statbuf);
|
||||
if (err || (statbuf.st_mode & S_IFMT) != S_IFDIR)
|
||||
continue;
|
||||
|
||||
auto found = find_hwmons_by_model(subdir, model, depth + 1);
|
||||
result.insert(result.end(), found.begin(), found.end());
|
||||
}
|
||||
free(entries);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class HwmonT>
|
||||
vector<string> HwmonInterface<HwmonT>::find_hwmons_by_indices(
|
||||
@ -197,7 +241,21 @@ string HwmonInterface<HwmonT>::lookup()
|
||||
}
|
||||
path = paths[0];
|
||||
}
|
||||
|
||||
if (model_) {
|
||||
vector<string> paths = find_hwmons_by_model(path, model_.value(), 1);
|
||||
if (paths.size() != 1) {
|
||||
string msg(path + ": ");
|
||||
if (paths.size() == 0) {
|
||||
msg += "Could not find a hwmon with this model: " + model_.value();
|
||||
} else {
|
||||
msg += MSG_MULTIPLE_HWMONS_FOUND;
|
||||
for (string hwmon_path : paths)
|
||||
msg += " " + hwmon_path;
|
||||
}
|
||||
throw DriverInitError(msg);
|
||||
}
|
||||
path = paths[0];
|
||||
}
|
||||
if (indices_) {
|
||||
found_paths_ = find_hwmons_by_indices(path, indices_.value(), 0);
|
||||
if (found_paths_.size() == 0)
|
||||
|
@ -36,7 +36,7 @@ template<class HwmonT>
|
||||
class HwmonInterface {
|
||||
public:
|
||||
HwmonInterface();
|
||||
HwmonInterface(const string &base_path, opt<const string> name, opt<vector<unsigned int>> indices);
|
||||
HwmonInterface(const string &base_path, opt<const string> name, opt<const string> model, opt<vector<unsigned int>> indices);
|
||||
|
||||
string lookup();
|
||||
|
||||
@ -44,12 +44,14 @@ private:
|
||||
static vector<string> find_files(const string &path, const vector<unsigned int> &indices);
|
||||
static string filename(int index);
|
||||
|
||||
static vector<string> find_hwmons_by_model(const string &path, const string &model, unsigned char depth);
|
||||
static vector<string> find_hwmons_by_name(const string &path, const string &name, unsigned char depth);
|
||||
static vector<string> find_hwmons_by_indices(const string &path, const vector<unsigned int> &indices, unsigned char depth);
|
||||
|
||||
protected:
|
||||
opt<const string> base_path_;
|
||||
opt<const string> name_;
|
||||
opt<const string> model_;
|
||||
opt<vector<unsigned int>> indices_;
|
||||
vector<string> found_paths_;
|
||||
opt<vector<string>::const_iterator> paths_it_;
|
||||
|
@ -135,7 +135,7 @@ void SensorDriver::skip_io_error(const ExpectedError &e)
|
||||
|
||||
HwmonSensorDriver::HwmonSensorDriver(const string &path, bool optional)
|
||||
: HwmonSensorDriver(
|
||||
std::make_shared<HwmonInterface<SensorDriver>>(path, nullopt, nullopt),
|
||||
std::make_shared<HwmonInterface<SensorDriver>>(path, nullopt, nullopt, nullopt),
|
||||
optional,
|
||||
nullopt,
|
||||
0
|
||||
|
@ -92,6 +92,7 @@ The syntax for identifying each type of sensors looks as follows:
|
||||
\f[CB]sensors:
|
||||
\f[CB] \- hwmon: \f[CI]hwmon-path\f[CR] # A path to a sysfs/hwmon sensor
|
||||
\f[CB] name: \f[CI]hwmon-name\f[CR] # Optional entry
|
||||
\f[CB] model: \f[CI]hwmon-model\f[CR] # Optional entry for nvme
|
||||
\f[CB] indices: \f[CI]index-list\f[CR] # Optional entry
|
||||
|
||||
\f[CB] \- chip: \f[CI]chip-name\f[CR] # An lm_sensors/libsensors chip...
|
||||
@ -225,6 +226,14 @@ This method of specifying sensors is particularly useful if the full path to a
|
||||
particular hwmon keeps changing between bootups, e.g. due to changing load order
|
||||
of the driver modules.
|
||||
|
||||
.TP
|
||||
.I hwmon-model
|
||||
The model of a device in a hwmon interface usually found for NVME devices in a
|
||||
file under \*(lqdevice\*(rq called \*(lqmodel\*(rq.
|
||||
For example, you might have an NVME \*(lq/sys/class/hwmon/hwmon3/device/model\*(rq
|
||||
and you might have an external NVME over USB or Thunderbolt that you don't want
|
||||
to monitor or you might have two NVME's.
|
||||
|
||||
.TP
|
||||
.I index-list
|
||||
A YAML list
|
||||
|
@ -102,11 +102,12 @@ bool convert_driver<vector<wtf_ptr<HwmonSensorDriver>>>(
|
||||
|
||||
opt<vector<int>> correction = decode_opt<vector<int>>(node[kw_correction]);
|
||||
opt<const string> name = decode_opt<string>(node[kw_name]);
|
||||
opt<const string> model = decode_opt<string>(node[kw_model]);
|
||||
bool optional = node[kw_optional] ? node[kw_optional].as<bool>() : false;
|
||||
opt<unsigned int> max_errors = decode_opt<unsigned int>(node[kw_max_errors]);
|
||||
opt<vector<unsigned int>> indices = decode_opt<vector<unsigned int>>(node[kw_indices]);
|
||||
|
||||
auto hwmon_iface = std::make_shared<HwmonInterface<SensorDriver>>(path, name, indices);
|
||||
auto hwmon_iface = std::make_shared<HwmonInterface<SensorDriver>>(path, name, model, indices);
|
||||
|
||||
if (indices) {
|
||||
if (correction && correction->size() != indices->size())
|
||||
@ -285,12 +286,13 @@ bool convert_driver<vector<wtf_ptr<HwmonFanDriver>>>(const Node &node, vector<wt
|
||||
|
||||
string path = node[kw_hwmon].as<string>();
|
||||
opt<string> name = decode_opt<string>(node[kw_name]);
|
||||
opt<string> model = decode_opt<string>(node[kw_model]);
|
||||
bool optional = node[kw_optional] ? node[kw_optional].as<bool>() : false;
|
||||
opt<vector<unsigned int>> indices = decode_opt<vector<unsigned int>>(node[kw_indices]);
|
||||
opt<unsigned int> max_errors = decode_opt<unsigned int>(node[kw_max_errors]);
|
||||
|
||||
shared_ptr<HwmonInterface<FanDriver>> hwmon_iface = std::make_shared<HwmonInterface<FanDriver>>(
|
||||
path, name, indices
|
||||
path, name, model, indices
|
||||
);
|
||||
|
||||
if (!indices && optional)
|
||||
|
@ -32,6 +32,7 @@ const string kw_speed("speed");
|
||||
const string kw_upper("upper_limit");
|
||||
const string kw_lower("lower_limit");
|
||||
const string kw_name("name");
|
||||
const string kw_model("model");
|
||||
const string kw_indices("indices");
|
||||
const string kw_correction("correction");
|
||||
const string kw_optional("optional");
|
||||
|
Loading…
Reference in New Issue
Block a user