mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-04 04:04:17 +01:00
Chore: run clang-format
```bash find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) ! -path "src/3rdparty/*" -print0 | xargs -0 clang-format -i ```
This commit is contained in:
@@ -5,8 +5,7 @@
|
||||
|
||||
#define FF_BATTERY_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFBatteryResult
|
||||
{
|
||||
typedef struct FFBatteryResult {
|
||||
FFstrbuf manufacturer;
|
||||
FFstrbuf manufactureDate;
|
||||
FFstrbuf modelName;
|
||||
|
||||
@@ -7,31 +7,29 @@
|
||||
#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api"
|
||||
#define FF_TERMUX_API_PARAM "BatteryStatus"
|
||||
|
||||
static inline void wrapYyjsonFree(yyjson_doc** doc)
|
||||
{
|
||||
static inline void wrapYyjsonFree(yyjson_doc** doc) {
|
||||
assert(doc);
|
||||
if (*doc)
|
||||
if (*doc) {
|
||||
yyjson_doc_free(*doc);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
if(ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
FF_TERMUX_API_PATH,
|
||||
FF_TERMUX_API_PARAM,
|
||||
NULL
|
||||
}))
|
||||
if (ffProcessAppendStdOut(&buffer, (char* const[]) {FF_TERMUX_API_PATH, FF_TERMUX_API_PARAM, NULL})) {
|
||||
return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed";
|
||||
}
|
||||
|
||||
yyjson_doc* __attribute__((__cleanup__(wrapYyjsonFree))) doc = yyjson_read_opts(buffer.chars, buffer.length, 0, NULL, NULL);
|
||||
if (!doc)
|
||||
if (!doc) {
|
||||
return "Failed to parse battery info";
|
||||
}
|
||||
|
||||
yyjson_val* root = yyjson_doc_get_root(doc);
|
||||
if (!yyjson_is_obj(root))
|
||||
if (!yyjson_is_obj(root)) {
|
||||
return "Battery info result is not a JSON object";
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
@@ -46,50 +44,54 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results)
|
||||
|
||||
battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage"));
|
||||
const char* acStatus = yyjson_get_str(yyjson_obj_get(root, "plugged"));
|
||||
if (acStatus)
|
||||
{
|
||||
if (ffStrEquals(acStatus, "PLUGGED_AC"))
|
||||
if (acStatus) {
|
||||
if (ffStrEquals(acStatus, "PLUGGED_AC")) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected, ");
|
||||
else if (ffStrEquals(acStatus, "PLUGGED_USB"))
|
||||
} else if (ffStrEquals(acStatus, "PLUGGED_USB")) {
|
||||
ffStrbufAppendS(&battery->status, "USB Connected, ");
|
||||
else if (ffStrEquals(acStatus, "PLUGGED_WIRELESS"))
|
||||
} else if (ffStrEquals(acStatus, "PLUGGED_WIRELESS")) {
|
||||
ffStrbufAppendS(&battery->status, "Wireless Connected, ");
|
||||
}
|
||||
}
|
||||
const char* status = yyjson_get_str(yyjson_obj_get(root, "status"));
|
||||
if (status)
|
||||
{
|
||||
if (ffStrEquals(status, "CHARGING"))
|
||||
if (status) {
|
||||
if (ffStrEquals(status, "CHARGING")) {
|
||||
ffStrbufAppendS(&battery->status, "Charging");
|
||||
else if (ffStrEquals(status, "DISCHARGING"))
|
||||
} else if (ffStrEquals(status, "DISCHARGING")) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging");
|
||||
}
|
||||
}
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
|
||||
if(options->temp)
|
||||
if (options->temp) {
|
||||
battery->temperature = yyjson_get_num(yyjson_obj_get(root, "temperature"));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results) {
|
||||
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
|
||||
if (ffProcessAppendStdOut(&buf, (char* []) {
|
||||
"/system/bin/dumpsys",
|
||||
"battery",
|
||||
NULL,
|
||||
}) != NULL || buf.length == 0)
|
||||
if (ffProcessAppendStdOut(&buf, (char*[]) {
|
||||
"/system/bin/dumpsys",
|
||||
"battery",
|
||||
NULL,
|
||||
}) != NULL ||
|
||||
buf.length == 0) {
|
||||
return "Executing `/system/bin/dumpsys battery` failed"; // Only works in `adb shell`, or when rooted
|
||||
}
|
||||
|
||||
if (!ffStrbufStartsWithS(&buf, "Current Battery Service state:\n"))
|
||||
if (!ffStrbufStartsWithS(&buf, "Current Battery Service state:\n")) {
|
||||
return "Invalid `/system/bin/dumpsys battery` result";
|
||||
}
|
||||
|
||||
const char* start = buf.chars + strlen("Current Battery Service state:\n");
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate();
|
||||
if (!ffParsePropLines(start, "present: ", &temp) || !ffStrbufEqualS(&temp, "true"))
|
||||
if (!ffParsePropLines(start, "present: ", &temp) || !ffStrbufEqualS(&temp, "true")) {
|
||||
return NULL;
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
@@ -104,45 +106,50 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
ffStrbufInit(&battery->serial);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
|
||||
if (ffParsePropLines(start, "AC powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
|
||||
if (ffParsePropLines(start, "AC powered: ", &temp) && ffStrbufEqualS(&temp, "true")) {
|
||||
ffStrbufAppendS(&battery->status, "AC powered");
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (ffParsePropLines(start, "USB powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
|
||||
{
|
||||
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
|
||||
if (ffParsePropLines(start, "USB powered: ", &temp) && ffStrbufEqualS(&temp, "true")) {
|
||||
if (battery->status.length) {
|
||||
ffStrbufAppendS(&battery->status, ", ");
|
||||
}
|
||||
ffStrbufAppendS(&battery->status, "USB powered");
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (ffParsePropLines(start, "Wireless powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
|
||||
{
|
||||
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
|
||||
if (ffParsePropLines(start, "Wireless powered: ", &temp) && ffStrbufEqualS(&temp, "true")) {
|
||||
if (battery->status.length) {
|
||||
ffStrbufAppendS(&battery->status, ", ");
|
||||
}
|
||||
ffStrbufAppendS(&battery->status, "Wireless powered");
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
{
|
||||
double level = 0, scale = 0;
|
||||
if (ffParsePropLines(start, "level: ", &temp))
|
||||
if (ffParsePropLines(start, "level: ", &temp)) {
|
||||
level = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (ffParsePropLines(start, "scale: ", &temp))
|
||||
if (ffParsePropLines(start, "scale: ", &temp)) {
|
||||
scale = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (level > 0 && scale > 0)
|
||||
if (level > 0 && scale > 0) {
|
||||
battery->capacity = level * 100 / scale;
|
||||
}
|
||||
}
|
||||
|
||||
if(options->temp)
|
||||
{
|
||||
if (ffParsePropLines(start, "temperature: ", &temp))
|
||||
{
|
||||
if (options->temp) {
|
||||
if (ffParsePropLines(start, "temperature: ", &temp)) {
|
||||
battery->temperature = ffStrbufToDouble(&temp, FF_BATTERY_TEMP_UNSET);
|
||||
if (battery->temperature != FF_BATTERY_TEMP_UNSET)
|
||||
if (battery->temperature != FF_BATTERY_TEMP_UNSET) {
|
||||
battery->temperature /= 10.0; // Android returns temperature in tenths of a degree
|
||||
}
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
}
|
||||
@@ -152,10 +159,10 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
const char* error = parseTermuxApi(options, results);
|
||||
if (error && parseDumpsys(options, results) == NULL)
|
||||
if (error && parseDumpsys(options, results) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -6,27 +6,29 @@
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/pwr_mgt/IOPM.h>
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess)
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) {
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
}
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryBattery = registryEntry;
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL;
|
||||
if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int currentCapacity, maxCapacity;
|
||||
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0)
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0)
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool boolValue;
|
||||
|
||||
@@ -44,13 +46,14 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial);
|
||||
ffCfDictGetString(properties, CFSTR(kIOPMPSManufacturerKey), &battery->manufacturer);
|
||||
|
||||
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue)
|
||||
{
|
||||
if (!battery->manufacturer.length)
|
||||
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue) {
|
||||
if (!battery->manufacturer.length) {
|
||||
ffStrbufAppendS(&battery->manufacturer, "Apple Inc.");
|
||||
}
|
||||
ffStrbufAppendS(&battery->technology, "Lithium");
|
||||
if (!battery->modelName.length)
|
||||
if (!battery->modelName.length) {
|
||||
ffStrbufAppendS(&battery->modelName, "Built-in");
|
||||
}
|
||||
}
|
||||
|
||||
int32_t cycleCount = 0;
|
||||
@@ -58,43 +61,39 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount;
|
||||
|
||||
battery->timeRemaining = -1;
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSExternalConnectedKey), &boolValue) == NULL)
|
||||
{
|
||||
if (boolValue)
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSExternalConnectedKey), &boolValue) == NULL) {
|
||||
if (boolValue) {
|
||||
ffStrbufAppendS(&battery->status, "AC connected, ");
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
ffCfDictGetInt(properties, CFSTR("AvgTimeToEmpty"), &battery->timeRemaining); // in minutes
|
||||
if (battery->timeRemaining < 0 || battery->timeRemaining >= 0xFFFF)
|
||||
if (battery->timeRemaining < 0 || battery->timeRemaining >= 0xFFFF) {
|
||||
battery->timeRemaining = -1;
|
||||
else
|
||||
} else {
|
||||
battery->timeRemaining *= 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSIsChargingKey), &boolValue) == NULL && boolValue)
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSIsChargingKey), &boolValue) == NULL && boolValue) {
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSAtCriticalLevelKey), &boolValue) == NULL && boolValue)
|
||||
}
|
||||
if (ffCfDictGetBool(properties, CFSTR(kIOPMPSAtCriticalLevelKey), &boolValue) == NULL && boolValue) {
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
}
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
|
||||
int sbdsManufactureDate = 0;
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSManufactureDateKey), &sbdsManufactureDate) == NULL)
|
||||
{
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSManufactureDateKey), &sbdsManufactureDate) == NULL) {
|
||||
int day = sbdsManufactureDate & 0b11111;
|
||||
int month = (sbdsManufactureDate >> 5) & 0b1111;
|
||||
int year = (sbdsManufactureDate >> 9) + 1800;
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
CFDictionaryRef batteryData;
|
||||
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL)
|
||||
{
|
||||
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL) {
|
||||
char manufactureDate[sizeof(uint64_t)];
|
||||
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL)
|
||||
{
|
||||
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL) {
|
||||
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
|
||||
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
|
||||
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
|
||||
@@ -104,13 +103,13 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
}
|
||||
}
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (options->temp) {
|
||||
int64_t temp;
|
||||
if (!ffCfDictGetInt64(properties, CFSTR(kIOPMPSBatteryTemperatureKey), &temp))
|
||||
if (!ffCfDictGetInt64(properties, CFSTR(kIOPMPSBatteryTemperatureKey), &temp)) {
|
||||
battery->temperature = (double) temp / 10 - 273.15;
|
||||
else
|
||||
} else {
|
||||
ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,29 +8,31 @@
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
//https://www.freebsd.org/cgi/man.cgi?acpi_battery(4)
|
||||
//https://gitlab.xfce.org/panel-plugins/xfce4-battery-plugin/-/blob/master/panel-plugin/libacpi.c
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) {
|
||||
// https://www.freebsd.org/cgi/man.cgi?acpi_battery(4)
|
||||
// https://gitlab.xfce.org/panel-plugins/xfce4-battery-plugin/-/blob/master/panel-plugin/libacpi.c
|
||||
|
||||
int units = ffSysctlGetInt("hw.acpi.battery.units", -100);
|
||||
if (units < 0)
|
||||
if (units < 0) {
|
||||
return "sysctlbyname(\"hw.acpi.battery.units\") failed";
|
||||
}
|
||||
|
||||
if(units == 0)
|
||||
if (units == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int acpifd = open("/dev/acpi", O_RDONLY | O_CLOEXEC);
|
||||
if(acpifd < 0)
|
||||
if (acpifd < 0) {
|
||||
return "open(\"/dev/acpi\", O_RDONLY | O_CLOEXEC) failed";
|
||||
}
|
||||
|
||||
for(int i = 0; i < units; ++i)
|
||||
{
|
||||
for (int i = 0; i < units; ++i) {
|
||||
union acpi_battery_ioctl_arg battio;
|
||||
battio.unit = i;
|
||||
|
||||
if(ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) < 0 || (battio.battinfo.state == ACPI_BATT_STAT_NOT_PRESENT))
|
||||
if (ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) < 0 || (battio.battinfo.state == ACPI_BATT_STAT_NOT_PRESENT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
@@ -42,54 +44,49 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
ffStrbufInit(&battery->serial);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
battery->timeRemaining = -1;
|
||||
if (battio.battinfo.min > 0)
|
||||
if (battio.battinfo.min > 0) {
|
||||
battery->timeRemaining = battio.battinfo.min * 60;
|
||||
battery->capacity = battio.battinfo.cap;
|
||||
if(battio.battinfo.state == ACPI_BATT_STAT_INVALID)
|
||||
{
|
||||
ffStrbufAppendS(&battery->status, "Unknown, ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(battio.battinfo.state & ACPI_BATT_STAT_DISCHARG)
|
||||
battery->capacity = battio.battinfo.cap;
|
||||
if (battio.battinfo.state == ACPI_BATT_STAT_INVALID) {
|
||||
ffStrbufAppendS(&battery->status, "Unknown, ");
|
||||
} else {
|
||||
if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
else if(battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
|
||||
} else if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
if(battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
|
||||
}
|
||||
if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL) {
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
}
|
||||
}
|
||||
|
||||
int acadStatus;
|
||||
if (ioctl(acpifd, ACPIIO_ACAD_GET_STATUS, &acadStatus) >= 0 && acadStatus)
|
||||
{
|
||||
if (ioctl(acpifd, ACPIIO_ACAD_GET_STATUS, &acadStatus) >= 0 && acadStatus) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
}
|
||||
|
||||
#ifdef ACPIIO_BATT_GET_BIX
|
||||
#ifdef ACPIIO_BATT_GET_BIX
|
||||
battio.unit = i;
|
||||
if (ioctl(acpifd, ACPIIO_BATT_GET_BIX, &battio) >= 0)
|
||||
{
|
||||
if (ioctl(acpifd, ACPIIO_BATT_GET_BIX, &battio) >= 0) {
|
||||
ffStrbufAppendS(&battery->manufacturer, battio.bix.oeminfo);
|
||||
ffStrbufAppendS(&battery->modelName, battio.bix.model);
|
||||
ffStrbufAppendS(&battery->technology, battio.bix.type);
|
||||
ffStrbufAppendS(&battery->serial, battio.bix.serial);
|
||||
battery->cycleCount = battio.bix.cycles;
|
||||
}
|
||||
#elif defined(ACPIIO_BATT_GET_BIF)
|
||||
#elif defined(ACPIIO_BATT_GET_BIF)
|
||||
battio.unit = i;
|
||||
if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) >= 0)
|
||||
{
|
||||
if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) >= 0) {
|
||||
ffStrbufAppendS(&battery->manufacturer, battio.bif.oeminfo);
|
||||
ffStrbufAppendS(&battery->modelName, battio.bif.model);
|
||||
ffStrbufAppendS(&battery->technology, battio.bif.type);
|
||||
ffStrbufAppendS(&battery->serial, battio.bif.serial);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -6,22 +6,26 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const char* parseBattery(int dfd, const char* battId, FFlist* results)
|
||||
{
|
||||
const char* parseBattery(int dfd, const char* battId, FFlist* results) {
|
||||
FF_AUTO_CLOSE_FD int fd = openat(dfd, battId, O_RDWR);
|
||||
if (fd < 0) return "openat() failed";
|
||||
if (fd < 0) {
|
||||
return "openat() failed";
|
||||
}
|
||||
|
||||
acpi_battery_info basic = {};
|
||||
if (ioctl(fd, GET_BATTERY_INFO, &basic, sizeof(basic)) != 0)
|
||||
if (ioctl(fd, GET_BATTERY_INFO, &basic, sizeof(basic)) != 0) {
|
||||
return "ioctl(GET_BATTERY_INFO) failed";
|
||||
}
|
||||
acpi_extended_battery_info extended = {};
|
||||
if (ioctl(fd, GET_EXTENDED_BATTERY_INFO, &extended, sizeof(extended)) != 0)
|
||||
if (ioctl(fd, GET_EXTENDED_BATTERY_INFO, &extended, sizeof(extended)) != 0) {
|
||||
return "ioctl(GET_EXTENDED_BATTERY_INFO) failed";
|
||||
}
|
||||
|
||||
if (extended.last_full_charge == (uint32)-1)
|
||||
if (extended.last_full_charge == (uint32) -1) {
|
||||
return "Skipped";
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(results);
|
||||
ffStrbufInitS(&battery->modelName, extended.model_number);
|
||||
ffStrbufInitS(&battery->manufacturer, extended.oem_info);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
@@ -33,29 +37,35 @@ const char* parseBattery(int dfd, const char* battId, FFlist* results)
|
||||
battery->timeRemaining = -1;
|
||||
battery->capacity = (double) basic.capacity * 100. / (double) extended.last_full_charge;
|
||||
|
||||
if (basic.state & BATTERY_DISCHARGING)
|
||||
if (basic.state & BATTERY_DISCHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
if (basic.state & BATTERY_CHARGING)
|
||||
}
|
||||
if (basic.state & BATTERY_CHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
if (basic.state & BATTERY_CRITICAL_STATE)
|
||||
}
|
||||
if (basic.state & BATTERY_CRITICAL_STATE) {
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
if (basic.state & BATTERY_NOT_CHARGING)
|
||||
}
|
||||
if (basic.state & BATTERY_NOT_CHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected, ");
|
||||
}
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) {
|
||||
FF_AUTO_CLOSE_DIR DIR* dir = opendir("/dev/power/acpi_battery/");
|
||||
if (!dir) return "opendir(/dev/power/acpi_battery) failed";
|
||||
if (!dir) {
|
||||
return "opendir(/dev/power/acpi_battery) failed";
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)))
|
||||
{
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
parseBattery(dirfd(dir), entry->d_name, results);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,142 +8,143 @@
|
||||
|
||||
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power
|
||||
|
||||
static bool checkAc(const char* id, FFstrbuf* tmpBuffer)
|
||||
{
|
||||
if (ffStrStartsWith(id, "BAT"))
|
||||
static bool checkAc(const char* id, FFstrbuf* tmpBuffer) {
|
||||
if (ffStrStartsWith(id, "BAT")) {
|
||||
ffStrbufSetS(tmpBuffer, "/sys/class/power_supply/ADP1/online");
|
||||
else if (ffStrStartsWith(id, "macsmc-battery"))
|
||||
} else if (ffStrStartsWith(id, "macsmc-battery")) {
|
||||
ffStrbufSetS(tmpBuffer, "/sys/class/power_supply/macsmc-ac/online");
|
||||
else
|
||||
} else {
|
||||
ffStrbufClear(tmpBuffer);
|
||||
}
|
||||
|
||||
char online = '\0';
|
||||
return ffReadFileData(tmpBuffer->chars, 1, &online) == 1 && online == '1';
|
||||
}
|
||||
|
||||
static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFlist* results) {
|
||||
FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate();
|
||||
|
||||
// type must exist and be "Battery"
|
||||
if (!ffReadFileBufferRelative(dfd, "type", &tmpBuffer))
|
||||
if (!ffReadFileBufferRelative(dfd, "type", &tmpBuffer)) {
|
||||
return;
|
||||
}
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery"))
|
||||
if (!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scope may not exist or must not be "Device"
|
||||
if (ffReadFileBufferRelative(dfd, "scope", &tmpBuffer))
|
||||
if (ffReadFileBufferRelative(dfd, "scope", &tmpBuffer)) {
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
}
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device"))
|
||||
if (ffStrbufIgnCaseEqualS(&tmpBuffer, "Device")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// capacity must exist and be not empty
|
||||
// This is expensive in my laptop
|
||||
if (!ffReadFileBufferRelative(dfd, "capacity", &tmpBuffer))
|
||||
if (!ffReadFileBufferRelative(dfd, "capacity", &tmpBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FFBatteryResult* result = ffListAdd(results);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer, 0);
|
||||
|
||||
//At this point, we have a battery. Try to get as much values as possible.
|
||||
// At this point, we have a battery. Try to get as much values as possible.
|
||||
|
||||
ffStrbufInit(&result->manufacturer);
|
||||
if (ffReadFileBufferRelative(dfd, "manufacturer", &result->manufacturer))
|
||||
if (ffReadFileBufferRelative(dfd, "manufacturer", &result->manufacturer)) {
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
else if (ffStrEquals(id, "macsmc-battery")) // asahi
|
||||
} else if (ffStrEquals(id, "macsmc-battery")) { // asahi
|
||||
ffStrbufSetStatic(&result->manufacturer, "Apple Inc.");
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->modelName);
|
||||
if (ffReadFileBufferRelative(dfd, "model_name", &result->modelName))
|
||||
if (ffReadFileBufferRelative(dfd, "model_name", &result->modelName)) {
|
||||
ffStrbufTrimRightSpace(&result->modelName);
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->technology);
|
||||
if (ffReadFileBufferRelative(dfd, "technology", &result->technology))
|
||||
if (ffReadFileBufferRelative(dfd, "technology", &result->technology)) {
|
||||
ffStrbufTrimRightSpace(&result->technology);
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->status);
|
||||
if (ffReadFileBufferRelative(dfd, "status", &result->status))
|
||||
if (ffReadFileBufferRelative(dfd, "status", &result->status)) {
|
||||
ffStrbufTrimRightSpace(&result->status);
|
||||
}
|
||||
|
||||
// Unknown, Charging, Discharging, Not charging, Full
|
||||
|
||||
result->timeRemaining = -1;
|
||||
if (ffStrbufEqualS(&result->status, "Discharging"))
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "time_to_empty_now", &tmpBuffer))
|
||||
if (ffStrbufEqualS(&result->status, "Discharging")) {
|
||||
if (ffReadFileBufferRelative(dfd, "time_to_empty_now", &tmpBuffer)) {
|
||||
result->timeRemaining = (int32_t) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
else
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "charge_now", &tmpBuffer))
|
||||
{
|
||||
} else {
|
||||
if (ffReadFileBufferRelative(dfd, "charge_now", &tmpBuffer)) {
|
||||
int64_t chargeNow = ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (chargeNow > 0)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "current_now", &tmpBuffer))
|
||||
{
|
||||
if (chargeNow > 0) {
|
||||
if (ffReadFileBufferRelative(dfd, "current_now", &tmpBuffer)) {
|
||||
int64_t currentNow = ffStrbufToSInt(&tmpBuffer, INT64_MIN);
|
||||
if (currentNow < 0) currentNow = -currentNow;
|
||||
if (currentNow > 0)
|
||||
if (currentNow < 0) {
|
||||
currentNow = -currentNow;
|
||||
}
|
||||
if (currentNow > 0) {
|
||||
result->timeRemaining = (int32_t) ((chargeNow * 3600) / currentNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkAc(id, &tmpBuffer))
|
||||
if (checkAc(id, &tmpBuffer)) {
|
||||
ffStrbufAppendS(&result->status, ", AC Connected");
|
||||
}
|
||||
else if (ffStrbufEqualS(&result->status, "Not charging") || ffStrbufEqualS(&result->status, "Full"))
|
||||
}
|
||||
} else if (ffStrbufEqualS(&result->status, "Not charging") || ffStrbufEqualS(&result->status, "Full")) {
|
||||
ffStrbufSetStatic(&result->status, "AC Connected");
|
||||
else if (ffStrbufEqualS(&result->status, "Charging"))
|
||||
} else if (ffStrbufEqualS(&result->status, "Charging")) {
|
||||
ffStrbufAppendS(&result->status, ", AC Connected");
|
||||
else if (ffStrbufEqualS(&result->status, "Unknown"))
|
||||
{
|
||||
} else if (ffStrbufEqualS(&result->status, "Unknown")) {
|
||||
ffStrbufClear(&result->status);
|
||||
if (checkAc(id, &tmpBuffer))
|
||||
if (checkAc(id, &tmpBuffer)) {
|
||||
ffStrbufAppendS(&result->status, "AC Connected");
|
||||
}
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "capacity_level", &tmpBuffer))
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "capacity_level", &tmpBuffer)) {
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
if (ffStrbufEqualS(&tmpBuffer, "Critical"))
|
||||
{
|
||||
if (result->status.length)
|
||||
if (ffStrbufEqualS(&tmpBuffer, "Critical")) {
|
||||
if (result->status.length) {
|
||||
ffStrbufAppendS(&result->status, ", Critical");
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetStatic(&result->status, "Critical");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->serial);
|
||||
if (ffReadFileBufferRelative(dfd, "serial_number", &result->serial))
|
||||
if (ffReadFileBufferRelative(dfd, "serial_number", &result->serial)) {
|
||||
ffStrbufTrimRightSpace(&result->serial);
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "cycle_count", &tmpBuffer))
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "cycle_count", &tmpBuffer)) {
|
||||
int64_t cycleCount = ffStrbufToSInt(&tmpBuffer, 0);
|
||||
result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount;
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->manufactureDate);
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_year", &tmpBuffer))
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_year", &tmpBuffer)) {
|
||||
int year = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (year > 0)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_month", &tmpBuffer))
|
||||
{
|
||||
if (year > 0) {
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_month", &tmpBuffer)) {
|
||||
int month = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (month > 0)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_day", &tmpBuffer))
|
||||
{
|
||||
if (month > 0) {
|
||||
if (ffReadFileBufferRelative(dfd, "manufacture_day", &tmpBuffer)) {
|
||||
int day = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (day > 0)
|
||||
if (day > 0) {
|
||||
ffStrbufSetF(&result->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,31 +152,32 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
}
|
||||
|
||||
result->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "temp", &tmpBuffer))
|
||||
{
|
||||
if (options->temp) {
|
||||
if (ffReadFileBufferRelative(dfd, "temp", &tmpBuffer)) {
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer, FF_BATTERY_TEMP_UNSET);
|
||||
if (result->temperature != FF_BATTERY_TEMP_UNSET)
|
||||
if (result->temperature != FF_BATTERY_TEMP_UNSET) {
|
||||
result->temperature /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/power_supply/");
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return "opendir(\"/sys/class/power_supply/\") == NULL";
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int dfd = openat(dirfd(dirp), entry->d_name, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
|
||||
if (dfd > 0) parseBattery(dfd, entry->d_name, options, results);
|
||||
if (dfd > 0) {
|
||||
parseBattery(dfd, entry->d_name, options, results);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -14,67 +14,66 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) {
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
if (fd < 0) {
|
||||
return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
}
|
||||
|
||||
prop_dictionary_t root = NULL;
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) {
|
||||
return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
|
||||
}
|
||||
|
||||
bool acConnected = false;
|
||||
{
|
||||
prop_array_t acad = prop_dictionary_get(root, "acpiacad0");
|
||||
if (acad)
|
||||
{
|
||||
if (acad) {
|
||||
prop_dictionary_t dict = prop_array_get(acad, 0);
|
||||
prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &acConnected);
|
||||
}
|
||||
}
|
||||
|
||||
prop_object_iterator_t itKey = prop_dictionary_iterator(root);
|
||||
for (prop_dictionary_keysym_t key; (key = prop_object_iterator_next(itKey)) != NULL; )
|
||||
{
|
||||
if (!ffStrStartsWith(prop_dictionary_keysym_value(key), "acpibat")) continue;
|
||||
for (prop_dictionary_keysym_t key; (key = prop_object_iterator_next(itKey)) != NULL;) {
|
||||
if (!ffStrStartsWith(prop_dictionary_keysym_value(key), "acpibat")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
prop_array_t bat = prop_dictionary_get_keysym(root, key);
|
||||
uint32_t max = 0, curr = 0, dischargeRate = 0;
|
||||
bool charging = false, critical = false;
|
||||
prop_object_iterator_t iter = prop_array_iterator(bat);
|
||||
for (prop_dictionary_t dict; (dict = prop_object_iterator_next(iter)) != NULL;)
|
||||
{
|
||||
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY)
|
||||
for (prop_dictionary_t dict; (dict = prop_object_iterator_next(iter)) != NULL;) {
|
||||
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* desc = NULL;
|
||||
if (!prop_dictionary_get_string(dict, "description", &desc))
|
||||
if (!prop_dictionary_get_string(dict, "description", &desc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ffStrEquals(desc, "present"))
|
||||
{
|
||||
if (ffStrEquals(desc, "present")) {
|
||||
int value = 0;
|
||||
if (prop_dictionary_get_int(dict, "cur-value", &value) && value == 0)
|
||||
if (prop_dictionary_get_int(dict, "cur-value", &value) && value == 0) {
|
||||
continue;
|
||||
}
|
||||
else if (ffStrEquals(desc, "charging"))
|
||||
{
|
||||
}
|
||||
} else if (ffStrEquals(desc, "charging")) {
|
||||
prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &charging);
|
||||
}
|
||||
else if (ffStrEquals(desc, "charge"))
|
||||
{
|
||||
} else if (ffStrEquals(desc, "charge")) {
|
||||
prop_dictionary_get_uint32(dict, "max-value", &max);
|
||||
prop_dictionary_get_uint32(dict, "cur-value", &curr);
|
||||
const char* state = NULL;
|
||||
if (prop_dictionary_get_string(dict, "state", &state) && ffStrEquals(state, "critical"))
|
||||
if (prop_dictionary_get_string(dict, "state", &state) && ffStrEquals(state, "critical")) {
|
||||
critical = true;
|
||||
}
|
||||
else if (ffStrEquals(desc, "discharge rate"))
|
||||
}
|
||||
} else if (ffStrEquals(desc, "discharge rate")) {
|
||||
prop_dictionary_get_uint(dict, "cur-value", &dischargeRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (max > 0)
|
||||
{
|
||||
if (max > 0) {
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
@@ -87,17 +86,18 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
battery->timeRemaining = -1;
|
||||
|
||||
battery->capacity = (double) curr / (double) max * 100.;
|
||||
if (charging)
|
||||
if (charging) {
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
else if (dischargeRate)
|
||||
{
|
||||
} else if (dischargeRate) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
battery->timeRemaining = (int32_t)((double)curr / dischargeRate * 3600);
|
||||
battery->timeRemaining = (int32_t) ((double) curr / dischargeRate * 3600);
|
||||
}
|
||||
if (critical)
|
||||
if (critical) {
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
if (acConnected)
|
||||
}
|
||||
if (acConnected) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected");
|
||||
}
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "battery.h"
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
FF_UNUSED(options, results)
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -6,19 +6,22 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result) {
|
||||
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (devfd < 0) return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
|
||||
if (devfd < 0) {
|
||||
return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
|
||||
}
|
||||
|
||||
struct apm_power_info info = {};
|
||||
|
||||
if (ioctl(devfd, APM_IOC_GETPOWER, &info) < 0)
|
||||
if (ioctl(devfd, APM_IOC_GETPOWER, &info) < 0) {
|
||||
return "ioctl(APM_IOC_GETPOWER) failed";
|
||||
}
|
||||
|
||||
if (info.battery_state == APM_BATTERY_ABSENT)
|
||||
if (info.battery_state == APM_BATTERY_ABSENT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(result);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
@@ -32,19 +35,19 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
ffStrbufInit(&battery->serial);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
|
||||
if (info.ac_state == APM_AC_ON)
|
||||
if (info.ac_state == APM_AC_ON) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected");
|
||||
else if (info.ac_state == APM_AC_BACKUP)
|
||||
} else if (info.ac_state == APM_AC_BACKUP) {
|
||||
ffStrbufAppendS(&battery->status, "Backup In Use");
|
||||
else if (info.ac_state == APM_AC_OFF)
|
||||
{
|
||||
} else if (info.ac_state == APM_AC_OFF) {
|
||||
battery->timeRemaining = (int) info.minutes_left * 60;
|
||||
ffStrbufAppendS(&battery->status, "Discharging");
|
||||
}
|
||||
|
||||
if (info.battery_state == APM_BATT_CRITICAL || info.battery_state == APM_BATT_CHARGING)
|
||||
{
|
||||
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
|
||||
if (info.battery_state == APM_BATT_CRITICAL || info.battery_state == APM_BATT_CHARGING) {
|
||||
if (battery->status.length) {
|
||||
ffStrbufAppendS(&battery->status, ", ");
|
||||
}
|
||||
ffStrbufAppendS(&battery->status, info.battery_state == APM_BATT_CRITICAL ? "Critical" : "Charging");
|
||||
}
|
||||
|
||||
|
||||
@@ -12,129 +12,145 @@
|
||||
#include <devguid.h>
|
||||
#include <cfgmgr32.h>
|
||||
|
||||
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
//https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
|
||||
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results) {
|
||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
|
||||
ULONG cchDeviceInterfaces = 0;
|
||||
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID)&GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS)
|
||||
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID) &GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS) {
|
||||
return "CM_Get_Device_Interface_List_SizeW() failed";
|
||||
}
|
||||
|
||||
if (cchDeviceInterfaces <= 1)
|
||||
if (cchDeviceInterfaces <= 1) {
|
||||
return NULL; // Not found
|
||||
}
|
||||
|
||||
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*)malloc(cchDeviceInterfaces * sizeof(wchar_t));
|
||||
cr = CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS)
|
||||
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*) malloc(cchDeviceInterfaces * sizeof(wchar_t));
|
||||
cr = CM_Get_Device_Interface_ListW((LPGUID) &GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS) {
|
||||
return "CM_Get_Device_Interface_ListW() failed";
|
||||
}
|
||||
|
||||
for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1)
|
||||
{
|
||||
for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1) {
|
||||
HANDLE FF_AUTO_CLOSE_FD hBattery =
|
||||
CreateFileW(pDeviceInterface, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if(hBattery == INVALID_HANDLE_VALUE)
|
||||
if (hBattery == INVALID_HANDLE_VALUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BATTERY_QUERY_INFORMATION bqi = { .InformationLevel = BatteryInformation };
|
||||
BATTERY_QUERY_INFORMATION bqi = {.InformationLevel = BatteryInformation};
|
||||
|
||||
DWORD dwWait = 0;
|
||||
DWORD dwOut;
|
||||
|
||||
if(!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_TAG, &dwWait, sizeof(dwWait), &bqi.BatteryTag, sizeof(bqi.BatteryTag), &dwOut, NULL) && bqi.BatteryTag)
|
||||
if (!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_TAG, &dwWait, sizeof(dwWait), &bqi.BatteryTag, sizeof(bqi.BatteryTag), &dwOut, NULL) && bqi.BatteryTag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BATTERY_INFORMATION bi = {0};
|
||||
if(!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi, sizeof(bi), &dwOut, NULL))
|
||||
if (!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi, sizeof(bi), &dwOut, NULL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!(bi.Capabilities & BATTERY_SYSTEM_BATTERY))
|
||||
if (!(bi.Capabilities & BATTERY_SYSTEM_BATTERY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(results);
|
||||
|
||||
if(memcmp(bi.Chemistry, "PbAc", 4) == 0)
|
||||
if (memcmp(bi.Chemistry, "PbAc", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Lead Acid");
|
||||
else if(memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0)
|
||||
} else if (memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Lithium Ion");
|
||||
else if(memcmp(bi.Chemistry, "NiCd", 4) == 0)
|
||||
} else if (memcmp(bi.Chemistry, "NiCd", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Cadmium");
|
||||
else if(memcmp(bi.Chemistry, "NiMH", 4) == 0)
|
||||
} else if (memcmp(bi.Chemistry, "NiMH", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Metal Hydride");
|
||||
else if(memcmp(bi.Chemistry, "NiZn", 4) == 0)
|
||||
} else if (memcmp(bi.Chemistry, "NiZn", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Zinc");
|
||||
else if(memcmp(bi.Chemistry, "RAM\0", 4) == 0)
|
||||
} else if (memcmp(bi.Chemistry, "RAM\0", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Rechargeable Alkaline-Manganese");
|
||||
else
|
||||
} else {
|
||||
ffStrbufInitStatic(&battery->technology, "Unknown");
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->modelName);
|
||||
bqi.InformationLevel = BatteryDeviceName;
|
||||
wchar_t name[64];
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) {
|
||||
ffStrbufSetWS(&battery->modelName, name);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
bqi.InformationLevel = BatteryManufactureName;
|
||||
wchar_t name[64];
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) {
|
||||
ffStrbufSetWS(&battery->manufacturer, name);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
bqi.InformationLevel = BatteryManufactureDate;
|
||||
BATTERY_MANUFACTURE_DATE date;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL)) {
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year < 1000 ? date.Year + 1900 : date.Year, date.Month, date.Day);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->serial);
|
||||
bqi.InformationLevel = BatterySerialNumber;
|
||||
wchar_t name[64];
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) {
|
||||
ffStrbufSetWS(&battery->serial, name);
|
||||
}
|
||||
}
|
||||
|
||||
battery->cycleCount = bi.CycleCount;
|
||||
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if(options->temp)
|
||||
{
|
||||
if (options->temp) {
|
||||
bqi.InformationLevel = BatteryTemperature;
|
||||
ULONG temp;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL)) {
|
||||
battery->temperature = temp / 10.0 - 273.15;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
bqi.InformationLevel = BatteryEstimatedTime;
|
||||
ULONG time;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &time, sizeof(time), &dwOut, NULL))
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &time, sizeof(time), &dwOut, NULL)) {
|
||||
battery->timeRemaining = time == BATTERY_UNKNOWN_TIME ? -1 : (int32_t) time;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
BATTERY_STATUS bs;
|
||||
BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag };
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0)
|
||||
BATTERY_WAIT_STATUS bws = {.BatteryTag = bqi.BatteryTag};
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0) {
|
||||
battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity;
|
||||
else
|
||||
} else {
|
||||
battery->capacity = 0;
|
||||
}
|
||||
|
||||
ffStrbufInit(&battery->status);
|
||||
if(bs.PowerState & BATTERY_POWER_ON_LINE)
|
||||
if (bs.PowerState & BATTERY_POWER_ON_LINE) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected, ");
|
||||
if(bs.PowerState & BATTERY_DISCHARGING)
|
||||
}
|
||||
if (bs.PowerState & BATTERY_DISCHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
if(bs.PowerState & BATTERY_CHARGING)
|
||||
}
|
||||
if (bs.PowerState & BATTERY_CHARGING) {
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
if(bs.PowerState & BATTERY_CRITICAL)
|
||||
}
|
||||
if (bs.PowerState & BATTERY_CRITICAL) {
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
}
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
}
|
||||
@@ -142,42 +158,42 @@ static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct FFSmbiosPortableBattery
|
||||
{
|
||||
typedef struct FFSmbiosPortableBattery {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
// 2.1+
|
||||
uint8_t Location; // string
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t ManufactureDate; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t DeviceName; // string
|
||||
uint8_t DeviceChemistry; // enum
|
||||
uint16_t DesignCapacity; // varies
|
||||
uint16_t DesignVoltage; // varies
|
||||
uint8_t SbdsVersionNumber; // string
|
||||
uint8_t Location; // string
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t ManufactureDate; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t DeviceName; // string
|
||||
uint8_t DeviceChemistry; // enum
|
||||
uint16_t DesignCapacity; // varies
|
||||
uint16_t DesignVoltage; // varies
|
||||
uint8_t SbdsVersionNumber; // string
|
||||
uint8_t MaximumErrorInBatteryData; // varies
|
||||
|
||||
// 2.2+
|
||||
uint16_t SbdsSerialNumber; // varies
|
||||
uint16_t SbdsManufactureDate; // varies
|
||||
uint8_t SbdsDeviceChemistry; // string
|
||||
uint16_t SbdsSerialNumber; // varies
|
||||
uint16_t SbdsManufactureDate; // varies
|
||||
uint8_t SbdsDeviceChemistry; // string
|
||||
uint8_t DesignCapacityMultiplier; // varies
|
||||
uint16_t OEMSpecific; // varies
|
||||
uint16_t OEMSpecific; // varies
|
||||
} __attribute__((__packed__)) FFSmbiosPortableBattery;
|
||||
|
||||
static_assert(offsetof(FFSmbiosPortableBattery, OEMSpecific) == 0x16,
|
||||
"FFSmbiosPortableBattery: Wrong struct alignment");
|
||||
|
||||
static const char* detectBySmbios(FFBatteryResult* battery)
|
||||
{
|
||||
static const char* detectBySmbios(FFBatteryResult* battery) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*smbiosTable)[FF_SMBIOS_TYPE_PORTABLE_BATTERY];
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "Portable battery section is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
@@ -186,50 +202,57 @@ static const char* detectBySmbios(FFBatteryResult* battery)
|
||||
ffStrbufSetStatic(&battery->manufacturer, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&battery->manufacturer);
|
||||
|
||||
if (data->ManufactureDate)
|
||||
{
|
||||
if (data->ManufactureDate) {
|
||||
ffStrbufSetStatic(&battery->manufactureDate, ffSmbiosLocateString(strings, data->ManufactureDate));
|
||||
ffCleanUpSmbiosValue(&battery->manufactureDate);
|
||||
}
|
||||
else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate))
|
||||
{
|
||||
} else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate)) {
|
||||
int day = data->SbdsManufactureDate & 0b11111;
|
||||
int month = (data->SbdsManufactureDate >> 5) & 0b1111;
|
||||
int year = (data->SbdsManufactureDate >> 9) + 1800;
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
|
||||
switch (data->DeviceChemistry)
|
||||
{
|
||||
case 0x01: ffStrbufSetStatic(&battery->technology, "Other"); break;
|
||||
case 0x02: ffStrbufSetStatic(&battery->technology, "Unknown"); break;
|
||||
case 0x03: ffStrbufSetStatic(&battery->technology, "Lead Acid"); break;
|
||||
case 0x04: ffStrbufSetStatic(&battery->technology, "Nickel Cadmium"); break;
|
||||
case 0x05: ffStrbufSetStatic(&battery->technology, "Nickel metal hydride"); break;
|
||||
case 0x06: ffStrbufSetStatic(&battery->technology, "Lithium-ion"); break;
|
||||
case 0x07: ffStrbufSetStatic(&battery->technology, "Zinc air"); break;
|
||||
case 0x08: ffStrbufSetStatic(&battery->technology, "Lithium Polymer"); break;
|
||||
switch (data->DeviceChemistry) {
|
||||
case 0x01:
|
||||
ffStrbufSetStatic(&battery->technology, "Other");
|
||||
break;
|
||||
case 0x02:
|
||||
ffStrbufSetStatic(&battery->technology, "Unknown");
|
||||
break;
|
||||
case 0x03:
|
||||
ffStrbufSetStatic(&battery->technology, "Lead Acid");
|
||||
break;
|
||||
case 0x04:
|
||||
ffStrbufSetStatic(&battery->technology, "Nickel Cadmium");
|
||||
break;
|
||||
case 0x05:
|
||||
ffStrbufSetStatic(&battery->technology, "Nickel metal hydride");
|
||||
break;
|
||||
case 0x06:
|
||||
ffStrbufSetStatic(&battery->technology, "Lithium-ion");
|
||||
break;
|
||||
case 0x07:
|
||||
ffStrbufSetStatic(&battery->technology, "Zinc air");
|
||||
break;
|
||||
case 0x08:
|
||||
ffStrbufSetStatic(&battery->technology, "Lithium Polymer");
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->SerialNumber)
|
||||
{
|
||||
if (data->SerialNumber) {
|
||||
ffStrbufSetStatic(&battery->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&battery->serial);
|
||||
}
|
||||
else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsSerialNumber))
|
||||
{
|
||||
} else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsSerialNumber)) {
|
||||
ffStrbufSetF(&battery->serial, "%4X", data->SbdsSerialNumber);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) {
|
||||
SYSTEM_BATTERY_STATE info;
|
||||
if (NT_SUCCESS(NtPowerInformation(SystemBatteryState, NULL, 0, &info, sizeof(info))) && info.BatteryPresent)
|
||||
{
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
if (NT_SUCCESS(NtPowerInformation(SystemBatteryState, NULL, 0, &info, sizeof(info))) && info.BatteryPresent) {
|
||||
FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(results);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
@@ -241,15 +264,14 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
battery->timeRemaining = info.EstimatedTime == BATTERY_UNKNOWN_TIME ? -1 : (int32_t) info.EstimatedTime;
|
||||
|
||||
battery->capacity = info.RemainingCapacity * 100.0 / info.MaxCapacity;
|
||||
if(info.AcOnLine)
|
||||
{
|
||||
if (info.AcOnLine) {
|
||||
ffStrbufAppendS(&battery->status, "AC Connected");
|
||||
if(info.Charging)
|
||||
if (info.Charging) {
|
||||
ffStrbufAppendS(&battery->status, ", Charging");
|
||||
}
|
||||
else if(info.Discharging)
|
||||
}
|
||||
} else if (info.Discharging) {
|
||||
ffStrbufAppendS(&battery->status, "Discharging");
|
||||
|
||||
}
|
||||
|
||||
detectBySmbios(battery);
|
||||
|
||||
@@ -258,8 +280,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
return "NtPowerInformation(SystemBatteryState) failed";
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
return options->useSetupApi
|
||||
? detectWithCmApi(options, results)
|
||||
: detectWithNtApi(options, results);
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bios/option.h"
|
||||
|
||||
typedef struct FFBiosResult
|
||||
{
|
||||
typedef struct FFBiosResult {
|
||||
FFstrbuf date;
|
||||
FFstrbuf release;
|
||||
FFstrbuf vendor;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "bios.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
if (!ffSettingsGetAndroidProperty("ro.bootloader", &bios->version))
|
||||
const char* ffDetectBios(FFBiosResult* bios) {
|
||||
if (!ffSettingsGetAndroidProperty("ro.bootloader", &bios->version)) {
|
||||
ffSettingsGetAndroidProperty("ro.boot.bootloader", &bios->version);
|
||||
}
|
||||
|
||||
if (ffStrbufIgnCaseEqualS(&bios->version, "unknown"))
|
||||
if (ffStrbufIgnCaseEqualS(&bios->version, "unknown")) {
|
||||
ffStrbufClear(&bios->version);
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&bios->type, "Bootloader");
|
||||
|
||||
|
||||
@@ -3,31 +3,33 @@
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
#ifndef __aarch64__
|
||||
const char* ffDetectBios(FFBiosResult* bios) {
|
||||
#ifndef __aarch64__
|
||||
|
||||
//https://github.com/osquery/osquery/blob/master/osquery/tables/system/darwin/smbios_tables.cpp
|
||||
//For Intel
|
||||
// https://github.com/osquery/osquery/blob/master/osquery/tables/system/darwin/smbios_tables.cpp
|
||||
// For Intel
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceRom = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/rom");
|
||||
if (!deviceRom)
|
||||
if (!deviceRom) {
|
||||
return "IODeviceTree:/rom not found";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceRomProps = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(deviceRom, &deviceRomProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
if (IORegistryEntryCreateCFProperties(deviceRom, &deviceRomProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) {
|
||||
return "IORegistryEntryCreateCFProperties(deviceRom) failed";
|
||||
}
|
||||
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("vendor"), &bios->vendor);
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("version"), &bios->version);
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("release-date"), &bios->date);
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
//For arm64
|
||||
// For arm64
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t device = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/");
|
||||
if (!device)
|
||||
if (!device) {
|
||||
return "IODeviceTree:/ not found";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFDataRef manufacturer = IORegistryEntryCreateCFProperty(device, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
ffCfStrGetString(manufacturer, &bios->vendor);
|
||||
@@ -35,23 +37,21 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
ffCfStrGetString(timeStamp, &bios->date);
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (deviceChosen)
|
||||
{
|
||||
if (deviceChosen) {
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmwareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (systemFirmwareVersion)
|
||||
{
|
||||
if (systemFirmwareVersion) {
|
||||
ffCfStrGetString(systemFirmwareVersion, &bios->version);
|
||||
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
|
||||
if (index != bios->version.length)
|
||||
{
|
||||
if (index != bios->version.length) {
|
||||
ffStrbufAppendNS(&bios->type, index, bios->version.chars);
|
||||
ffStrbufRemoveSubstr(&bios->version, 0, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bios->type.length)
|
||||
if (!bios->type.length) {
|
||||
ffStrbufSetStatic(&bios->type, "iBoot");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* result)
|
||||
{
|
||||
const char* ffDetectBios(FFBiosResult* result) {
|
||||
ffSettingsGetFreeBSDKenv("smbios.bios.reldate", &result->date);
|
||||
ffCleanUpSmbiosValue(&result->date);
|
||||
ffSettingsGetFreeBSDKenv("smbios.bios.revision", &result->release);
|
||||
@@ -17,16 +16,15 @@ const char* ffDetectBios(FFBiosResult* result)
|
||||
ffCleanUpSmbiosValue(&result->version);
|
||||
ffSysctlGetString("machdep.bootmethod", &result->type);
|
||||
|
||||
if (result->type.length == 0)
|
||||
{
|
||||
if (ffSettingsGetFreeBSDKenv("loader.efi", &result->type))
|
||||
if (result->type.length == 0) {
|
||||
if (ffSettingsGetFreeBSDKenv("loader.efi", &result->type)) {
|
||||
ffStrbufSetStatic(&result->type, ffStrbufEqualS(&result->type, "1") ? "UEFI" : "BIOS");
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufSetStatic(&result->type,
|
||||
ffPathExists("/dev/efi" /*efidev*/, FF_PATHTYPE_FILE) ||
|
||||
ffPathExists("/boot/efi/efi/" /*efi partition. Note /boot/efi exists on BIOS system*/, FF_PATHTYPE_DIRECTORY)
|
||||
? "UEFI" : "BIOS");
|
||||
ffPathExists("/boot/efi/efi/" /*efi partition. Note /boot/efi exists on BIOS system*/, FF_PATHTYPE_DIRECTORY)
|
||||
? "UEFI"
|
||||
: "BIOS");
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -2,23 +2,20 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date))
|
||||
{
|
||||
const char* ffDetectBios(FFBiosResult* bios) {
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date)) {
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
|
||||
}
|
||||
else if (ffReadFileBuffer("/proc/device-tree/chosen/u-boot,version", &bios->version))
|
||||
{
|
||||
} else if (ffReadFileBuffer("/proc/device-tree/chosen/u-boot,version", &bios->version)) {
|
||||
ffStrbufTrimRight(&bios->version, '\0');
|
||||
ffStrbufSetStatic(&bios->vendor, "U-Boot");
|
||||
}
|
||||
|
||||
if (ffPathExists("/sys/firmware/efi/", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE))
|
||||
if (ffPathExists("/sys/firmware/efi/", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE)) {
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
#include "common/sysctl.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
if (ffSysctlGetString("machdep.dmi.bios-date", &bios->date) == NULL)
|
||||
const char* ffDetectBios(FFBiosResult* bios) {
|
||||
if (ffSysctlGetString("machdep.dmi.bios-date", &bios->date) == NULL) {
|
||||
ffCleanUpSmbiosValue(&bios->date);
|
||||
if (ffSysctlGetString("machdep.dmi.bios-version", &bios->version) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.bios-version", &bios->version) == NULL) {
|
||||
ffCleanUpSmbiosValue(&bios->version);
|
||||
if (ffSysctlGetString("machdep.dmi.bios-vendor", &bios->vendor) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.bios-vendor", &bios->vendor) == NULL) {
|
||||
ffCleanUpSmbiosValue(&bios->vendor);
|
||||
}
|
||||
ffSysctlGetString("machdep.bootmethod", &bios->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "bios.h"
|
||||
|
||||
const char* ffDetectBios(FF_MAYBE_UNUSED FFBiosResult* bios)
|
||||
{
|
||||
const char* ffDetectBios(FF_MAYBE_UNUSED FFBiosResult* bios) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -2,38 +2,37 @@
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/windows/registry.h"
|
||||
# include "common/windows/registry.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include "common/windows/nt.h"
|
||||
# include <ntstatus.h>
|
||||
# include "common/windows/nt.h"
|
||||
#elif __OpenBSD__
|
||||
#include "common/io.h"
|
||||
# include "common/io.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
#elif __sun
|
||||
#include <libdevinfo.h>
|
||||
#include <sys/sunddi.h>
|
||||
# include <libdevinfo.h>
|
||||
# include <sys/sunddi.h>
|
||||
#elif __APPLE__
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include <IOKit/IOKitLib.h>
|
||||
# include "common/apple/cf_helpers.h"
|
||||
# include <IOKit/IOKitLib.h>
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
{
|
||||
typedef struct FFSmbiosBios {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Vendor; // string
|
||||
uint8_t BiosVersion; // string
|
||||
uint8_t Vendor; // string
|
||||
uint8_t BiosVersion; // string
|
||||
uint16_t BiosStartingAddressSegment; // varies
|
||||
uint8_t BiosReleaseDate; // string
|
||||
uint8_t BiosRomSize; // string
|
||||
uint64_t BiosCharacteristics; // bit field
|
||||
uint8_t BiosReleaseDate; // string
|
||||
uint8_t BiosRomSize; // string
|
||||
uint64_t BiosCharacteristics; // bit field
|
||||
|
||||
// 2.4+
|
||||
uint8_t BiosCharacteristicsExtensionBytes[2]; // bit field
|
||||
uint8_t SystemBiosMajorRelease; // varies
|
||||
uint8_t SystemBiosMinorRelease; // varies
|
||||
uint8_t BiosCharacteristicsExtensionBytes[2]; // bit field
|
||||
uint8_t SystemBiosMajorRelease; // varies
|
||||
uint8_t SystemBiosMinorRelease; // varies
|
||||
uint8_t EmbeddedControllerFirmwareMajorRelease; // varies
|
||||
uint8_t EmbeddedControllerFirmwareMinorRelease; // varies
|
||||
|
||||
@@ -44,16 +43,16 @@ typedef struct FFSmbiosBios
|
||||
static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18,
|
||||
"FFSmbiosBios: Wrong struct alignment");
|
||||
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
const char* ffDetectBios(FFBiosResult* bios) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosBios* data = (const FFSmbiosBios*) (*smbiosTable)[FF_SMBIOS_TYPE_BIOS];
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "BIOS section is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
@@ -64,41 +63,45 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
ffStrbufSetStatic(&bios->date, ffSmbiosLocateString(strings, data->BiosReleaseDate));
|
||||
ffCleanUpSmbiosValue(&bios->date);
|
||||
|
||||
if (data->Header.Length > offsetof(FFSmbiosBios, SystemBiosMajorRelease))
|
||||
if (data->Header.Length > offsetof(FFSmbiosBios, SystemBiosMajorRelease)) {
|
||||
ffStrbufSetF(&bios->release, "%u.%u", data->SystemBiosMajorRelease, data->SystemBiosMinorRelease);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
// Same as GetFirmwareType, but support (?) Windows 7
|
||||
// https://ntdoc.m417z.com/system_information_class
|
||||
SYSTEM_BOOT_ENVIRONMENT_INFORMATION sbei;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBootEnvironmentInformation, &sbei, sizeof(sbei), NULL)))
|
||||
{
|
||||
switch (sbei.FirmwareType)
|
||||
{
|
||||
case FirmwareTypeBios: ffStrbufSetStatic(&bios->type, "BIOS"); break;
|
||||
case FirmwareTypeUefi: ffStrbufSetStatic(&bios->type, "UEFI"); break;
|
||||
default: break;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBootEnvironmentInformation, &sbei, sizeof(sbei), NULL))) {
|
||||
switch (sbei.FirmwareType) {
|
||||
case FirmwareTypeBios:
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
break;
|
||||
case FirmwareTypeUefi:
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif __sun
|
||||
#elif __sun
|
||||
di_node_t rootNode = di_init("/", DINFOPROP);
|
||||
if (rootNode != DI_NODE_NIL)
|
||||
{
|
||||
if (rootNode != DI_NODE_NIL) {
|
||||
char* efiVersion = NULL;
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0)
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0) {
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
}
|
||||
}
|
||||
di_fini(rootNode);
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
// Currently SMBIOS detection is supported in legacy BIOS only
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
#elif __APPLE__
|
||||
#elif __APPLE__
|
||||
// Intel Macs use UEFI from day one
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceEfi = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/efi");
|
||||
ffStrbufSetStatic(&bios->type, deviceEfi ? "UEFI" : "BIOS");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetooth/option.h"
|
||||
|
||||
typedef struct FFBluetoothResult
|
||||
{
|
||||
typedef struct FFBluetoothResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf address;
|
||||
FFstrbuf type;
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
#define L2CAP_SOCKET_CHECKED
|
||||
#include <bluetooth.h>
|
||||
|
||||
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices)
|
||||
{
|
||||
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices) {
|
||||
FFBluetoothResult* device = ffListAdd(devices);
|
||||
ffStrbufInitS(&device->name,
|
||||
#if __FreeBSD__
|
||||
#if __FreeBSD__
|
||||
bt_devremote_name_gen(dev->devname, &dev->bdaddr)
|
||||
#else
|
||||
#else
|
||||
dev->devname
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
ffStrbufInitS(&device->address, bt_ntoa(&dev->bdaddr, NULL));
|
||||
ffStrbufUpperCase(&device->address);
|
||||
@@ -21,11 +20,11 @@ static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFl
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) {
|
||||
// struct hostent* ent = bt_gethostent();
|
||||
if (bt_devenum((void*) enumDev, devices) < 0)
|
||||
if (bt_devenum((void*) enumDev, devices) < 0) {
|
||||
return "bt_devenum() failed";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ extern "C" {
|
||||
|
||||
#include <bluetooth/LocalDevice.h>
|
||||
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) {
|
||||
using namespace Bluetooth;
|
||||
FF_SUPPRESS_IO();
|
||||
|
||||
LocalDevice* dev = LocalDevice::GetLocalDevice();
|
||||
if (!dev) return NULL;
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BString devClass;
|
||||
dev->GetDeviceClass().DumpDeviceClass(devClass);
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
#include "common/io.h"
|
||||
# include "common/dbus.h"
|
||||
# include "common/io.h"
|
||||
|
||||
/* Example dbus reply, striped to only the relevant parts:
|
||||
array [ //root
|
||||
@@ -45,103 +45,108 @@ array [ //root
|
||||
]
|
||||
*/
|
||||
|
||||
static bool detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
static bool detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device) {
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DBusMessageIter dictIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* deviceProperty;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(ffStrEquals(deviceProperty, "Address"))
|
||||
if (ffStrEquals(deviceProperty, "Address")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->address);
|
||||
else if(ffStrEquals(deviceProperty, "Name"))
|
||||
} else if (ffStrEquals(deviceProperty, "Name")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->name);
|
||||
else if(ffStrEquals(deviceProperty, "Icon"))
|
||||
} else if (ffStrEquals(deviceProperty, "Icon")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->type);
|
||||
else if(ffStrEquals(deviceProperty, "Percentage"))
|
||||
{
|
||||
} else if (ffStrEquals(deviceProperty, "Percentage")) {
|
||||
uint32_t percentage;
|
||||
if (ffDBusGetUint(dbus, &dictIter, &percentage))
|
||||
if (ffDBusGetUint(dbus, &dictIter, &percentage)) {
|
||||
device->battery = (uint8_t) percentage;
|
||||
}
|
||||
else if(ffStrEquals(deviceProperty, "Connected"))
|
||||
}
|
||||
} else if (ffStrEquals(deviceProperty, "Connected")) {
|
||||
ffDBusGetBool(dbus, &dictIter, &device->connected);
|
||||
else if(ffStrEquals(deviceProperty, "Paired"))
|
||||
{
|
||||
} else if (ffStrEquals(deviceProperty, "Paired")) {
|
||||
bool paired = true;
|
||||
ffDBusGetBool(dbus, &dictIter, &paired);
|
||||
if (!paired) return false;
|
||||
if (!paired) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device) {
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBusMessageIter dictIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* propertyType;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType);
|
||||
|
||||
if(!ffStrContains(propertyType, ".Device") && !ffStrContains(propertyType, ".Battery"))
|
||||
if (!ffStrContains(propertyType, ".Device") && !ffStrContains(propertyType, ".Battery")) {
|
||||
return; // We don't care about other properties
|
||||
}
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
bool shouldContinue = detectBluetoothValue(dbus, &arrayIter, device);
|
||||
if (!shouldContinue)
|
||||
{
|
||||
if (!shouldContinue) {
|
||||
ffStrbufClear(&device->name);
|
||||
break;
|
||||
}
|
||||
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
|
||||
}
|
||||
|
||||
static FFBluetoothResult* detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
static FFBluetoothResult* detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) {
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBusMessageIter dictIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* objectPath;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath);
|
||||
|
||||
// We don't want adapter objects
|
||||
if(!ffStrContains(objectPath, "/dev_"))
|
||||
if (!ffStrContains(objectPath, "/dev_")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
|
||||
@@ -153,56 +158,53 @@ static FFBluetoothResult* detectBluetoothObject(FFlist* devices, FFDBusData* dbu
|
||||
device->battery = 0;
|
||||
device->connected = false;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
detectBluetoothProperty(dbus, &arrayIter, device);
|
||||
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter, int32_t connectedCount)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
|
||||
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter, int32_t connectedCount) {
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter);
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
FFBluetoothResult* device = detectBluetoothObject(devices, dbus, &arrayIter);
|
||||
|
||||
if (device)
|
||||
{
|
||||
if(device->name.length == 0 || (connectedCount > 0 && !device->connected))
|
||||
{
|
||||
if (device) {
|
||||
if (device->name.length == 0 || (connectedCount > 0 && !device->connected)) {
|
||||
ffStrbufDestroy(&device->name);
|
||||
ffStrbufDestroy(&device->address);
|
||||
ffStrbufDestroy(&device->type);
|
||||
--devices->length;
|
||||
}
|
||||
|
||||
if (device->connected && --connectedCount == 0)
|
||||
if (device->connected && --connectedCount == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
|
||||
}
|
||||
|
||||
static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
|
||||
{
|
||||
static const char* detectBluetooth(FFlist* devices, int32_t connectedCount) {
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
|
||||
if(error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL, NULL);
|
||||
if(!managedObjects)
|
||||
if (!managedObjects) {
|
||||
return "Failed to call GetManagedObjects";
|
||||
}
|
||||
|
||||
DBusMessageIter rootIter;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter))
|
||||
{
|
||||
if (!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter)) {
|
||||
dbus.lib->ffdbus_message_unref(managedObjects);
|
||||
return "Failed to get root iterator of GetManagedObjects";
|
||||
}
|
||||
@@ -213,18 +215,18 @@ static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t connectedDevices(void)
|
||||
{
|
||||
static uint32_t connectedDevices(void) {
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth");
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t result = 0;
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (strchr(entry->d_name, ':') != NULL)
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (strchr(entry->d_name, ':') != NULL) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -232,19 +234,18 @@ static uint32_t connectedDevices(void)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
int32_t connectedCount = -1;
|
||||
if (!options->showDisconnected)
|
||||
{
|
||||
connectedCount = (int32_t) connectedDevices();
|
||||
if (connectedCount == 0)
|
||||
return NULL;
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) {
|
||||
#ifdef FF_HAVE_DBUS
|
||||
int32_t connectedCount = -1;
|
||||
if (!options->showDisconnected) {
|
||||
connectedCount = (int32_t) connectedDevices();
|
||||
if (connectedCount == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return detectBluetooth(devices, connectedCount);
|
||||
#else
|
||||
return "Fastfetch was compiled without DBus support";
|
||||
#endif
|
||||
return detectBluetooth(devices, connectedCount);
|
||||
#else
|
||||
return "Fastfetch was compiled without DBus support";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "bluetooth.h"
|
||||
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -7,73 +7,74 @@
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wpointer-sign"
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextDevice)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindDeviceClose)
|
||||
|
||||
BLUETOOTH_DEVICE_INFO btdi = {
|
||||
.dwSize = sizeof(btdi)
|
||||
};
|
||||
.dwSize = sizeof(btdi)};
|
||||
HBLUETOOTH_DEVICE_FIND hFind = ffBluetoothFindFirstDevice(&(BLUETOOTH_DEVICE_SEARCH_PARAMS) {
|
||||
.fReturnConnected = TRUE,
|
||||
.fReturnRemembered = options->showDisconnected,
|
||||
.fReturnAuthenticated = options->showDisconnected,
|
||||
.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS)
|
||||
}, &btdi);
|
||||
if(!hFind)
|
||||
{
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
||||
.fReturnConnected = TRUE,
|
||||
.fReturnRemembered = options->showDisconnected,
|
||||
.fReturnAuthenticated = options->showDisconnected,
|
||||
.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS)},
|
||||
&btdi);
|
||||
if (!hFind) {
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
|
||||
return NULL;
|
||||
}
|
||||
return "BluetoothFindFirstDevice() failed";
|
||||
}
|
||||
|
||||
do {
|
||||
FFBluetoothResult* device = ffListAdd(devices);
|
||||
ffStrbufInitWS(&device->name, btdi.szName);
|
||||
ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
btdi.Address.rgBytes[5],
|
||||
btdi.Address.rgBytes[4],
|
||||
btdi.Address.rgBytes[3],
|
||||
btdi.Address.rgBytes[2],
|
||||
btdi.Address.rgBytes[1],
|
||||
btdi.Address.rgBytes[0]);
|
||||
ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X", btdi.Address.rgBytes[5], btdi.Address.rgBytes[4], btdi.Address.rgBytes[3], btdi.Address.rgBytes[2], btdi.Address.rgBytes[1], btdi.Address.rgBytes[0]);
|
||||
ffStrbufInit(&device->type);
|
||||
device->battery = 0;
|
||||
device->connected = !!btdi.fConnected;
|
||||
|
||||
//https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Assigned%20Numbers.pdf
|
||||
// https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Assigned%20Numbers.pdf
|
||||
|
||||
if(BitTest(&btdi.ulClassofDevice, 13))
|
||||
if (BitTest(&btdi.ulClassofDevice, 13)) {
|
||||
ffStrbufAppendS(&device->type, "Limited Discoverable Mode, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 14))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 14)) {
|
||||
ffStrbufAppendS(&device->type, "LE audio, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 15))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 15)) {
|
||||
ffStrbufAppendS(&device->type, "Reserved for future use, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 16))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 16)) {
|
||||
ffStrbufAppendS(&device->type, "Positioning, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 17))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 17)) {
|
||||
ffStrbufAppendS(&device->type, "Networking, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 18))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 18)) {
|
||||
ffStrbufAppendS(&device->type, "Rendering, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 19))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 19)) {
|
||||
ffStrbufAppendS(&device->type, "Capturing, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 20))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 20)) {
|
||||
ffStrbufAppendS(&device->type, "Object Transfer, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 21))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 21)) {
|
||||
ffStrbufAppendS(&device->type, "Audio, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 22))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 22)) {
|
||||
ffStrbufAppendS(&device->type, "Telephony, ");
|
||||
if(BitTest(&btdi.ulClassofDevice, 23))
|
||||
}
|
||||
if (BitTest(&btdi.ulClassofDevice, 23)) {
|
||||
ffStrbufAppendS(&device->type, "Information, ");
|
||||
}
|
||||
|
||||
if(device->type.length == 0)
|
||||
{
|
||||
if (device->type.length == 0) {
|
||||
uint32_t majorDeviceClasses = (btdi.ulClassofDevice >> 8) & ~(UINT32_MAX << 5);
|
||||
switch(majorDeviceClasses)
|
||||
{
|
||||
switch (majorDeviceClasses) {
|
||||
case 0b00000:
|
||||
ffStrbufAppendS(&device->type, "Miscellaneous");
|
||||
break;
|
||||
@@ -111,9 +112,7 @@ const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FF
|
||||
ffStrbufAppendS(&device->type, "Unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufTrimRight(&device->type, ' ');
|
||||
ffStrbufTrimRight(&device->type, ',');
|
||||
}
|
||||
@@ -121,7 +120,7 @@ const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FF
|
||||
|
||||
ffBluetoothFindDeviceClose(hFind);
|
||||
|
||||
const char* ffBluetoothDetectBattery(FFlist* result);
|
||||
const char* ffBluetoothDetectBattery(FFlist * result);
|
||||
ffBluetoothDetectBattery(devices);
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -1,84 +1,88 @@
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "bluetooth.h"
|
||||
}
|
||||
#include "common/windows/wmi.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
#include "common/windows/util.hpp"
|
||||
|
||||
extern "C"
|
||||
const char* ffBluetoothDetectBattery(FFlist* devices)
|
||||
{
|
||||
extern "C" const char* ffBluetoothDetectBattery(FFlist* devices) {
|
||||
FFWmiQuery query(L"SELECT __PATH FROM Win32_PnPEntity WHERE Service = 'BthHFEnum'", nullptr, FFWmiNamespace::CIMV2);
|
||||
if(!query)
|
||||
if (!query) {
|
||||
return "Query WMI service failed";
|
||||
}
|
||||
|
||||
IWbemClassObject* pInParams = nullptr;
|
||||
on_scope_exit releaseInParams([&] { pInParams && pInParams->Release(); });
|
||||
{
|
||||
IWbemClassObject* pnpEntityClass = nullptr;
|
||||
|
||||
if (FAILED(query.pService->GetObjectW(bstr_t(L"Win32_PnPEntity"), 0, nullptr, &pnpEntityClass, nullptr)))
|
||||
if (FAILED(query.pService->GetObjectW(bstr_t(L"Win32_PnPEntity"), 0, nullptr, &pnpEntityClass, nullptr))) {
|
||||
return "Failed to get PnP entity class";
|
||||
}
|
||||
on_scope_exit releasePnpEntityClass([&] { pnpEntityClass && pnpEntityClass->Release(); });
|
||||
|
||||
if (FAILED(pnpEntityClass->GetMethod(bstr_t(L"GetDeviceProperties"), 0, &pInParams, NULL)))
|
||||
if (FAILED(pnpEntityClass->GetMethod(bstr_t(L"GetDeviceProperties"), 0, &pInParams, NULL))) {
|
||||
return "Failed to get GetDeviceProperties method";
|
||||
}
|
||||
|
||||
FFWmiVariant devicePropertyKeys({ L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" });
|
||||
if (FAILED(pInParams->Put(L"devicePropertyKeys", 0, &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING)))
|
||||
FFWmiVariant devicePropertyKeys({L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress"});
|
||||
if (FAILED(pInParams->Put(L"devicePropertyKeys", 0, &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING))) {
|
||||
return "Failed to put devicePropertyKeys";
|
||||
}
|
||||
}
|
||||
|
||||
while (FFWmiRecord record = query.next())
|
||||
{
|
||||
while (FFWmiRecord record = query.next()) {
|
||||
IWbemCallResult* pCallResult = nullptr;
|
||||
|
||||
if (FAILED(query.pService->ExecMethod(record.get(L"__PATH").bstrVal, bstr_t(L"GetDeviceProperties"), 0, nullptr, pInParams, nullptr, &pCallResult)))
|
||||
if (FAILED(query.pService->ExecMethod(record.get(L"__PATH").bstrVal, bstr_t(L"GetDeviceProperties"), 0, nullptr, pInParams, nullptr, &pCallResult))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releaseCallResult([&] { pCallResult && pCallResult->Release(); });
|
||||
|
||||
IWbemClassObject* pResultObject = nullptr;
|
||||
if (FAILED(pCallResult->GetResultObject((LONG) WBEM_INFINITE, &pResultObject)))
|
||||
if (FAILED(pCallResult->GetResultObject((LONG) WBEM_INFINITE, &pResultObject))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releaseResultObject([&] { pResultObject && pResultObject->Release(); });
|
||||
|
||||
VARIANT propArray;
|
||||
if (FAILED(pResultObject->Get(L"deviceProperties", 0, &propArray, nullptr, nullptr)))
|
||||
if (FAILED(pResultObject->Get(L"deviceProperties", 0, &propArray, nullptr, nullptr))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releasePropArray([&] { VariantClear(&propArray); });
|
||||
|
||||
if (propArray.vt != (VT_ARRAY | VT_UNKNOWN) ||
|
||||
(propArray.parray->fFeatures & FADF_UNKNOWN) == 0 ||
|
||||
propArray.parray->cDims != 1 ||
|
||||
propArray.parray->rgsabound[0].cElements != 2
|
||||
)
|
||||
propArray.parray->rgsabound[0].cElements != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t batt = 0;
|
||||
for (LONG i = 0; i < 2; i++)
|
||||
{
|
||||
for (LONG i = 0; i < 2; i++) {
|
||||
IWbemClassObject* object = nullptr;
|
||||
if (FAILED(SafeArrayGetElement(propArray.parray, &i, &object)))
|
||||
if (FAILED(SafeArrayGetElement(propArray.parray, &i, &object))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFWmiRecord rec(object);
|
||||
auto data = rec.get(L"Data");
|
||||
if (data.vt == VT_EMPTY)
|
||||
if (data.vt == VT_EMPTY) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
if (i == 0) {
|
||||
batt = data.get<uint8_t>();
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_STRBUF_AUTO_DESTROY addr = ffStrbufCreateWSV(data.get<std::wstring_view>()); // MAC address without colon
|
||||
if (__builtin_expect(addr.length != 12, 0))
|
||||
if (__builtin_expect(addr.length != 12, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFBluetoothResult, bt, *devices)
|
||||
{
|
||||
if (bt->address.length != 12 + 5)
|
||||
FF_LIST_FOR_EACH (FFBluetoothResult, bt, *devices) {
|
||||
if (bt->address.length != 12 + 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr.chars[0] == bt->address.chars[0] &&
|
||||
addr.chars[1] == bt->address.chars[1] &&
|
||||
@@ -91,8 +95,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices)
|
||||
addr.chars[8] == bt->address.chars[12] &&
|
||||
addr.chars[9] == bt->address.chars[13] &&
|
||||
addr.chars[10] == bt->address.chars[15] &&
|
||||
addr.chars[11] == bt->address.chars[16])
|
||||
{
|
||||
addr.chars[11] == bt->address.chars[16]) {
|
||||
bt->battery = batt;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -53,60 +53,109 @@
|
||||
#define BTH_MFG_ARUBA_NETWORKS 283
|
||||
#define BTH_MFG_INTERNAL_USE 65535
|
||||
|
||||
const char* ffBluetoothRadioGetVendor(uint32_t manufacturerId)
|
||||
{
|
||||
switch (manufacturerId)
|
||||
{
|
||||
case BTH_MFG_ERICSSON: return "Ericsson";
|
||||
case BTH_MFG_NOKIA: return "Nokia";
|
||||
case BTH_MFG_INTEL: return "Intel";
|
||||
case BTH_MFG_IBM: return "IBM";
|
||||
case BTH_MFG_TOSHIBA: return "Toshiba";
|
||||
case BTH_MFG_3COM: return "3Com";
|
||||
case BTH_MFG_MICROSOFT: return "Microsoft";
|
||||
case BTH_MFG_LUCENT: return "Lucent";
|
||||
case BTH_MFG_MOTOROLA: return "Motorola";
|
||||
case BTH_MFG_INFINEON: return "Infineon";
|
||||
case BTH_MFG_CSR: return "CSR";
|
||||
case BTH_MFG_SILICONWAVE: return "Silicon-Wave";
|
||||
case BTH_MFG_DIGIANSWER: return "Digi-Answer";
|
||||
case BTH_MFG_TI: return "Ti";
|
||||
case BTH_MFG_PARTHUS: return "Parthus";
|
||||
case BTH_MFG_BROADCOM: return "Broadcom";
|
||||
case BTH_MFG_MITEL: return "Mitel";
|
||||
case BTH_MFG_WIDCOMM: return "Widcomm";
|
||||
case BTH_MFG_ZEEVO: return "Zeevo";
|
||||
case BTH_MFG_ATMEL: return "Atmel";
|
||||
case BTH_MFG_MITSIBUSHI: return "Mitsubishi";
|
||||
case BTH_MFG_RTX_TELECOM: return "RTX Telecom";
|
||||
case BTH_MFG_KC_TECHNOLOGY: return "KC Technology";
|
||||
case BTH_MFG_NEWLOGIC: return "Newlogic";
|
||||
case BTH_MFG_TRANSILICA: return "Transilica";
|
||||
case BTH_MFG_ROHDE_SCHWARZ: return "Rohde-Schwarz";
|
||||
case BTH_MFG_TTPCOM: return "TTPCom";
|
||||
case BTH_MFG_SIGNIA: return "Signia";
|
||||
case BTH_MFG_CONEXANT: return "Conexant";
|
||||
case BTH_MFG_QUALCOMM: return "Qualcomm";
|
||||
case BTH_MFG_INVENTEL: return "Inventel";
|
||||
case BTH_MFG_AVM_BERLIN: return "AVM Berlin";
|
||||
case BTH_MFG_BANDSPEED: return "Bandspeed";
|
||||
case BTH_MFG_MANSELLA: return "Mansella";
|
||||
case BTH_MFG_NEC: return "NEC";
|
||||
case BTH_MFG_WAVEPLUS_TECHNOLOGY_CO: return "Waveplus";
|
||||
case BTH_MFG_ALCATEL: return "Alcatel";
|
||||
case BTH_MFG_PHILIPS_SEMICONDUCTOR: return "Philips Semiconductors";
|
||||
case BTH_MFG_C_TECHNOLOGIES: return "C Technologies";
|
||||
case BTH_MFG_OPEN_INTERFACE: return "Open Interface";
|
||||
case BTH_MFG_RF_MICRO_DEVICES: return "RF Micro Devices";
|
||||
case BTH_MFG_HITACHI: return "Hitachi";
|
||||
case BTH_MFG_SYMBOL_TECHNOLOGIES: return "Symbol Technologies";
|
||||
case BTH_MFG_TENOVIS: return "Tenovis";
|
||||
case BTH_MFG_MACRONIX_INTERNATIONAL: return "Macronix International";
|
||||
case BTH_MFG_MARVELL: return "Marvell";
|
||||
case BTH_MFG_APPLE: return "Apple";
|
||||
case BTH_MFG_NORDIC_SEMICONDUCTORS_ASA: return "Nordic Semiconductor ASA";
|
||||
case BTH_MFG_ARUBA_NETWORKS: return "Aruba Networks";
|
||||
case BTH_MFG_INTERNAL_USE: return "Internal Use";
|
||||
default: return "Unknown";
|
||||
const char* ffBluetoothRadioGetVendor(uint32_t manufacturerId) {
|
||||
switch (manufacturerId) {
|
||||
case BTH_MFG_ERICSSON:
|
||||
return "Ericsson";
|
||||
case BTH_MFG_NOKIA:
|
||||
return "Nokia";
|
||||
case BTH_MFG_INTEL:
|
||||
return "Intel";
|
||||
case BTH_MFG_IBM:
|
||||
return "IBM";
|
||||
case BTH_MFG_TOSHIBA:
|
||||
return "Toshiba";
|
||||
case BTH_MFG_3COM:
|
||||
return "3Com";
|
||||
case BTH_MFG_MICROSOFT:
|
||||
return "Microsoft";
|
||||
case BTH_MFG_LUCENT:
|
||||
return "Lucent";
|
||||
case BTH_MFG_MOTOROLA:
|
||||
return "Motorola";
|
||||
case BTH_MFG_INFINEON:
|
||||
return "Infineon";
|
||||
case BTH_MFG_CSR:
|
||||
return "CSR";
|
||||
case BTH_MFG_SILICONWAVE:
|
||||
return "Silicon-Wave";
|
||||
case BTH_MFG_DIGIANSWER:
|
||||
return "Digi-Answer";
|
||||
case BTH_MFG_TI:
|
||||
return "Ti";
|
||||
case BTH_MFG_PARTHUS:
|
||||
return "Parthus";
|
||||
case BTH_MFG_BROADCOM:
|
||||
return "Broadcom";
|
||||
case BTH_MFG_MITEL:
|
||||
return "Mitel";
|
||||
case BTH_MFG_WIDCOMM:
|
||||
return "Widcomm";
|
||||
case BTH_MFG_ZEEVO:
|
||||
return "Zeevo";
|
||||
case BTH_MFG_ATMEL:
|
||||
return "Atmel";
|
||||
case BTH_MFG_MITSIBUSHI:
|
||||
return "Mitsubishi";
|
||||
case BTH_MFG_RTX_TELECOM:
|
||||
return "RTX Telecom";
|
||||
case BTH_MFG_KC_TECHNOLOGY:
|
||||
return "KC Technology";
|
||||
case BTH_MFG_NEWLOGIC:
|
||||
return "Newlogic";
|
||||
case BTH_MFG_TRANSILICA:
|
||||
return "Transilica";
|
||||
case BTH_MFG_ROHDE_SCHWARZ:
|
||||
return "Rohde-Schwarz";
|
||||
case BTH_MFG_TTPCOM:
|
||||
return "TTPCom";
|
||||
case BTH_MFG_SIGNIA:
|
||||
return "Signia";
|
||||
case BTH_MFG_CONEXANT:
|
||||
return "Conexant";
|
||||
case BTH_MFG_QUALCOMM:
|
||||
return "Qualcomm";
|
||||
case BTH_MFG_INVENTEL:
|
||||
return "Inventel";
|
||||
case BTH_MFG_AVM_BERLIN:
|
||||
return "AVM Berlin";
|
||||
case BTH_MFG_BANDSPEED:
|
||||
return "Bandspeed";
|
||||
case BTH_MFG_MANSELLA:
|
||||
return "Mansella";
|
||||
case BTH_MFG_NEC:
|
||||
return "NEC";
|
||||
case BTH_MFG_WAVEPLUS_TECHNOLOGY_CO:
|
||||
return "Waveplus";
|
||||
case BTH_MFG_ALCATEL:
|
||||
return "Alcatel";
|
||||
case BTH_MFG_PHILIPS_SEMICONDUCTOR:
|
||||
return "Philips Semiconductors";
|
||||
case BTH_MFG_C_TECHNOLOGIES:
|
||||
return "C Technologies";
|
||||
case BTH_MFG_OPEN_INTERFACE:
|
||||
return "Open Interface";
|
||||
case BTH_MFG_RF_MICRO_DEVICES:
|
||||
return "RF Micro Devices";
|
||||
case BTH_MFG_HITACHI:
|
||||
return "Hitachi";
|
||||
case BTH_MFG_SYMBOL_TECHNOLOGIES:
|
||||
return "Symbol Technologies";
|
||||
case BTH_MFG_TENOVIS:
|
||||
return "Tenovis";
|
||||
case BTH_MFG_MACRONIX_INTERNATIONAL:
|
||||
return "Macronix International";
|
||||
case BTH_MFG_MARVELL:
|
||||
return "Marvell";
|
||||
case BTH_MFG_APPLE:
|
||||
return "Apple";
|
||||
case BTH_MFG_NORDIC_SEMICONDUCTORS_ASA:
|
||||
return "Nordic Semiconductor ASA";
|
||||
case BTH_MFG_ARUBA_NETWORKS:
|
||||
return "Aruba Networks";
|
||||
case BTH_MFG_INTERNAL_USE:
|
||||
return "Internal Use";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetoothradio/option.h"
|
||||
|
||||
typedef struct FFBluetoothRadioResult
|
||||
{
|
||||
typedef struct FFBluetoothRadioResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf address;
|
||||
FFstrbuf vendor;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
#include "common/io.h"
|
||||
# include "common/dbus.h"
|
||||
# include "common/io.h"
|
||||
|
||||
/* Example dbus reply:
|
||||
array [
|
||||
@@ -34,62 +34,61 @@ array [
|
||||
]
|
||||
*/
|
||||
|
||||
static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBusData* dbus, DBusMessageIter* iter)
|
||||
{
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
|
||||
static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBusData* dbus, DBusMessageIter* iter) {
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
|
||||
return "Expected dict entry";
|
||||
}
|
||||
|
||||
DBusMessageIter dictIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) {
|
||||
return "Expected dict entry key to be a string";
|
||||
}
|
||||
|
||||
const char* deviceProperty;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
|
||||
|
||||
dbus->lib->ffdbus_message_iter_next(&dictIter);
|
||||
|
||||
if(ffStrEquals(deviceProperty, "Address"))
|
||||
if (ffStrEquals(deviceProperty, "Address")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->address);
|
||||
else if(ffStrEquals(deviceProperty, "Alias"))
|
||||
} else if (ffStrEquals(deviceProperty, "Alias")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->name);
|
||||
else if(ffStrEquals(deviceProperty, "Manufacturer"))
|
||||
{
|
||||
} else if (ffStrEquals(deviceProperty, "Manufacturer")) {
|
||||
uint32_t vendorId;
|
||||
if (ffDBusGetUint(dbus, &dictIter, &vendorId))
|
||||
if (ffDBusGetUint(dbus, &dictIter, &vendorId)) {
|
||||
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor(vendorId));
|
||||
}
|
||||
else if(ffStrEquals(deviceProperty, "Version"))
|
||||
}
|
||||
} else if (ffStrEquals(deviceProperty, "Version")) {
|
||||
ffDBusGetUint(dbus, &dictIter, (uint32_t*) &device->lmpVersion);
|
||||
else if(ffStrEquals(deviceProperty, "Powered"))
|
||||
} else if (ffStrEquals(deviceProperty, "Powered")) {
|
||||
ffDBusGetBool(dbus, &dictIter, &device->enabled);
|
||||
else if(ffStrEquals(deviceProperty, "Discoverable"))
|
||||
} else if (ffStrEquals(deviceProperty, "Discoverable")) {
|
||||
ffDBusGetBool(dbus, &dictIter, &device->discoverable);
|
||||
else if(ffStrEquals(deviceProperty, "Pairable"))
|
||||
} else if (ffStrEquals(deviceProperty, "Pairable")) {
|
||||
ffDBusGetBool(dbus, &dictIter, &device->connectable);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const char* hciName, FFDBusData* dbus)
|
||||
{
|
||||
static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const char* hciName, FFDBusData* dbus) {
|
||||
char objPath[300];
|
||||
snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName);
|
||||
|
||||
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1", NULL);
|
||||
if(!properties)
|
||||
if (!properties) {
|
||||
return "Failed to call org.freedesktop.DBus.Properties.GetAll";
|
||||
}
|
||||
|
||||
DBusMessageIter rootIter;
|
||||
if(!dbus->lib->ffdbus_message_iter_init(properties, &rootIter))
|
||||
{
|
||||
if (!dbus->lib->ffdbus_message_iter_init(properties, &rootIter)) {
|
||||
dbus->lib->ffdbus_message_unref(properties);
|
||||
return "Failed to get root iterator of org.freedesktop.DBus.Properties.GetAll";
|
||||
}
|
||||
|
||||
if(dbus->lib->ffdbus_message_iter_get_arg_type(&rootIter) != DBUS_TYPE_ARRAY)
|
||||
{
|
||||
if (dbus->lib->ffdbus_message_iter_get_arg_type(&rootIter) != DBUS_TYPE_ARRAY) {
|
||||
dbus->lib->ffdbus_message_unref(properties);
|
||||
return "Expected array";
|
||||
}
|
||||
@@ -97,8 +96,7 @@ static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const cha
|
||||
DBusMessageIter arrayIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(&rootIter, &arrayIter);
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
detectBluetoothProperty(device, dbus, &arrayIter);
|
||||
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
|
||||
|
||||
@@ -106,25 +104,27 @@ static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const cha
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectBluetooth(FFlist* devices)
|
||||
{
|
||||
static const char* detectBluetooth(FFlist* devices) {
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth");
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return "Failed to open /sys/class/bluetooth";
|
||||
}
|
||||
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
|
||||
if(error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr(entry->d_name, ':') != NULL) // ignore connected devices
|
||||
if (strchr(entry->d_name, ':') != NULL) { // ignore connected devices
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBluetoothRadioResult* device = ffListAdd(devices);
|
||||
ffStrbufInit(&device->name);
|
||||
@@ -140,12 +140,11 @@ static const char* detectBluetooth(FFlist* devices)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
return detectBluetooth(devices);
|
||||
#else
|
||||
FF_UNUSED(devices)
|
||||
return "Fastfetch was compiled without DBus support";
|
||||
#endif
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */) {
|
||||
#ifdef FF_HAVE_DBUS
|
||||
return detectBluetooth(devices);
|
||||
#else
|
||||
FF_UNUSED(devices)
|
||||
return "Fastfetch was compiled without DBus support";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "bluetoothradio.h"
|
||||
|
||||
const char* ffDetectBluetoothRadio(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothRadioResult */)
|
||||
{
|
||||
const char* ffDetectBluetoothRadio(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothRadioResult */) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
|
||||
// #include <bthioctl.h>
|
||||
|
||||
#define BTH_IOCTL_BASE 0
|
||||
#define BTH_CTL(id) CTL_CODE(FILE_DEVICE_BLUETOOTH, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_BTH_GET_LOCAL_INFO BTH_CTL(BTH_IOCTL_BASE+0x00)
|
||||
#define LMP_LE_SUPPORTED(x) ((x >> 38) & 1)
|
||||
#define BTH_IOCTL_BASE 0
|
||||
#define BTH_CTL(id) CTL_CODE(FILE_DEVICE_BLUETOOTH, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_BTH_GET_LOCAL_INFO BTH_CTL(BTH_IOCTL_BASE + 0x00)
|
||||
#define LMP_LE_SUPPORTED(x) ((x >> 38) & 1)
|
||||
|
||||
typedef struct _BTH_RADIO_INFO
|
||||
{
|
||||
typedef struct _BTH_RADIO_INFO {
|
||||
// Supported LMP features of the radio. Use LMP_XXX() to extract
|
||||
// the desired bits.
|
||||
ULONGLONG lmpSupportedFeatures;
|
||||
@@ -30,10 +29,9 @@ typedef struct _BTH_RADIO_INFO
|
||||
UCHAR lmpVersion;
|
||||
} __attribute__((__packed__)) BTH_RADIO_INFO;
|
||||
|
||||
typedef struct _BTH_LOCAL_RADIO_INFO
|
||||
{
|
||||
typedef struct _BTH_LOCAL_RADIO_INFO {
|
||||
// Local BTH_ADDR, class of device, and radio name
|
||||
BTH_DEVICE_INFO localInfo;
|
||||
BTH_DEVICE_INFO localInfo;
|
||||
|
||||
// Combo of LOCAL_RADIO_XXX values
|
||||
ULONG flags;
|
||||
@@ -51,8 +49,7 @@ static_assert(sizeof(BTH_LOCAL_RADIO_INFO) == 292, "BTH_LOCAL_RADIO_INFO should
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wpointer-sign"
|
||||
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
{
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */) {
|
||||
// Actually bluetoothapis.dll, but it's missing on Windows 7
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstRadio)
|
||||
@@ -63,33 +60,28 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
|
||||
HANDLE hRadio = NULL;
|
||||
HBLUETOOTH_DEVICE_FIND hFind = ffBluetoothFindFirstRadio(&(BLUETOOTH_FIND_RADIO_PARAMS) {
|
||||
.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS)
|
||||
}, &hRadio);
|
||||
if(!hFind)
|
||||
{
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
||||
.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS)},
|
||||
&hRadio);
|
||||
if (!hFind) {
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
|
||||
return "No Bluetooth radios found or service disabled";
|
||||
else
|
||||
} else {
|
||||
return "BluetoothFindFirstRadio() failed";
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
BTH_LOCAL_RADIO_INFO blri;
|
||||
DWORD returned;
|
||||
if (!DeviceIoControl(hRadio, IOCTL_BTH_GET_LOCAL_INFO, NULL, 0, &blri, sizeof(blri), &returned, NULL))
|
||||
if (!DeviceIoControl(hRadio, IOCTL_BTH_GET_LOCAL_INFO, NULL, 0, &blri, sizeof(blri), &returned, NULL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBluetoothRadioResult* device = ffListAdd(devices);
|
||||
ffStrbufInitS(&device->name, blri.localInfo.name);
|
||||
|
||||
BLUETOOTH_ADDRESS_STRUCT addr = { .ullLong = blri.localInfo.address };
|
||||
ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
addr.rgBytes[5],
|
||||
addr.rgBytes[4],
|
||||
addr.rgBytes[3],
|
||||
addr.rgBytes[2],
|
||||
addr.rgBytes[1],
|
||||
addr.rgBytes[0]);
|
||||
BLUETOOTH_ADDRESS_STRUCT addr = {.ullLong = blri.localInfo.address};
|
||||
ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X", addr.rgBytes[5], addr.rgBytes[4], addr.rgBytes[3], addr.rgBytes[2], addr.rgBytes[1], addr.rgBytes[0]);
|
||||
|
||||
device->lmpVersion = blri.radioInfo.lmpVersion;
|
||||
device->lmpSubversion = blri.radioInfo.lmpSubversion;
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/board/option.h"
|
||||
|
||||
typedef struct FFBoardResult
|
||||
{
|
||||
typedef struct FFBoardResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf vendor;
|
||||
FFstrbuf version;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "board.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
if (!ffSettingsGetAndroidProperty("ro.product.board", &board->name))
|
||||
const char* ffDetectBoard(FFBoardResult* board) {
|
||||
if (!ffSettingsGetAndroidProperty("ro.product.board", &board->name)) {
|
||||
ffSettingsGetAndroidProperty("ro.board.platform", &board->name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,29 +2,31 @@
|
||||
|
||||
#include "common/apple/cf_helpers.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* result)
|
||||
{
|
||||
const char* ffDetectBoard(FFBoardResult* result) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t service = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!service)
|
||||
if (!service) {
|
||||
return "No IOPlatformExpertDevice found";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef boardId = IORegistryEntryCreateCFProperty(service, CFSTR("board-id"), kCFAllocatorDefault, kNilOptions);
|
||||
if (boardId)
|
||||
if (boardId) {
|
||||
ffCfStrGetString(boardId, &result->name);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
io_name_t name;
|
||||
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
|
||||
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess) {
|
||||
ffStrbufSetS(&result->name, name);
|
||||
}
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(service, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (version)
|
||||
if (version) {
|
||||
ffCfStrGetString(version, &result->version);
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
if (manufacturer)
|
||||
if (manufacturer) {
|
||||
ffCfStrGetString(manufacturer, &result->vendor);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "common/settings.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* result)
|
||||
{
|
||||
const char* ffDetectBoard(FFBoardResult* result) {
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.product", &result->name);
|
||||
ffCleanUpSmbiosValue(&result->name);
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.serial", &result->serial);
|
||||
|
||||
@@ -2,29 +2,21 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name))
|
||||
{
|
||||
const char* ffDetectBoard(FFBoardResult* board) {
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name)) {
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_serial", "/sys/class/dmi/id/board_serial", &board->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
|
||||
}
|
||||
else if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/product", &board->name))
|
||||
{
|
||||
} else if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/product", &board->name)) {
|
||||
ffStrbufTrimRight(&board->name, '\0');
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/manufacturer", &board->vendor))
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/baseboard/manufacturer", &board->vendor)) {
|
||||
ffStrbufTrimRight(&board->vendor, '\0');
|
||||
}
|
||||
else if (ffReadFileBuffer("/sys/firmware/devicetree/base/board", &board->name))
|
||||
{
|
||||
}
|
||||
} else if (ffReadFileBuffer("/sys/firmware/devicetree/base/board", &board->name)) {
|
||||
ffStrbufTrimRightSpace(&board->name);
|
||||
}
|
||||
else if (ffReadFileBuffer("/sys/firmware/devicetree/base/compatible", &board->vendor))
|
||||
{
|
||||
} else if (ffReadFileBuffer("/sys/firmware/devicetree/base/compatible", &board->vendor)) {
|
||||
uint32_t comma = ffStrbufFirstIndexC(&board->vendor, ',');
|
||||
if (comma < board->vendor.length)
|
||||
{
|
||||
if (comma < board->vendor.length) {
|
||||
ffStrbufSetS(&board->name, board->vendor.chars + comma + 1);
|
||||
ffStrbufTrimRightSpace(&board->name);
|
||||
ffStrbufSubstrBefore(&board->vendor, comma);
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
#include "common/sysctl.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
if (ffSysctlGetString("machdep.dmi.board-product", &board->name) == NULL)
|
||||
const char* ffDetectBoard(FFBoardResult* board) {
|
||||
if (ffSysctlGetString("machdep.dmi.board-product", &board->name) == NULL) {
|
||||
ffCleanUpSmbiosValue(&board->name);
|
||||
if (ffSysctlGetString("machdep.dmi.board-version", &board->version) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.board-version", &board->version) == NULL) {
|
||||
ffCleanUpSmbiosValue(&board->version);
|
||||
if (ffSysctlGetString("machdep.dmi.board-vendor", &board->vendor) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.board-vendor", &board->vendor) == NULL) {
|
||||
ffCleanUpSmbiosValue(&board->vendor);
|
||||
if (ffSysctlGetString("machdep.dmi.board-serial", &board->serial) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.board-serial", &board->serial) == NULL) {
|
||||
ffCleanUpSmbiosValue(&board->serial);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "board.h"
|
||||
|
||||
const char* ffDetectBoard(FF_MAYBE_UNUSED FFBoardResult* board)
|
||||
{
|
||||
const char* ffDetectBoard(FF_MAYBE_UNUSED FFBoardResult* board) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
#include "board.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
typedef struct FFSmbiosBaseboard
|
||||
{
|
||||
typedef struct FFSmbiosBaseboard {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Product; // string
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTag; // string
|
||||
uint8_t FeatureFlags; // bit field
|
||||
uint8_t LocationInChassis; // string
|
||||
uint16_t ChassisHandle; // varies
|
||||
uint8_t BoardType; // enum
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Product; // string
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTag; // string
|
||||
uint8_t FeatureFlags; // bit field
|
||||
uint8_t LocationInChassis; // string
|
||||
uint16_t ChassisHandle; // varies
|
||||
uint8_t BoardType; // enum
|
||||
uint8_t NumberOfContainedObjectHandles; // varies
|
||||
uint16_t ContainedObjectHandles[]; // varies
|
||||
uint16_t ContainedObjectHandles[]; // varies
|
||||
} __attribute__((__packed__)) FFSmbiosBaseboard;
|
||||
|
||||
static_assert(offsetof(FFSmbiosBaseboard, ContainedObjectHandles) == 0x0F,
|
||||
"FFSmbiosBaseboard: Wrong struct alignment");
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
const char* ffDetectBoard(FFBoardResult* board) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosBaseboard* data = (const FFSmbiosBaseboard*) (*smbiosTable)[FF_SMBIOS_TYPE_BASEBOARD_INFO];
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "Baseboard information section is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
#include "efi_helper.h"
|
||||
|
||||
static inline uint8_t evBits(uint16_t val, uint8_t mask, uint8_t shift)
|
||||
{
|
||||
static inline uint8_t evBits(uint16_t val, uint8_t mask, uint8_t shift) {
|
||||
return (uint8_t) ((val & (mask << shift)) >> shift);
|
||||
}
|
||||
|
||||
static void ffEfiUcs2ToUtf8(const uint16_t *const chars, FFstrbuf* result)
|
||||
{
|
||||
for (uint32_t i = 0; chars[i]; i++)
|
||||
{
|
||||
if (chars[i] <= 0x007f)
|
||||
static void ffEfiUcs2ToUtf8(const uint16_t* const chars, FFstrbuf* result) {
|
||||
for (uint32_t i = 0; chars[i]; i++) {
|
||||
if (chars[i] <= 0x007f) {
|
||||
ffStrbufAppendC(result, (char) chars[i]);
|
||||
else if (chars[i] > 0x007f && chars[i] <= 0x07ff)
|
||||
{
|
||||
} else if (chars[i] > 0x007f && chars[i] <= 0x07ff) {
|
||||
ffStrbufAppendC(result, (char) (0xc0 | evBits(chars[i], 0x1f, 6)));
|
||||
ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppendC(result, (char) (0xe0 | evBits(chars[i], 0xf, 12)));
|
||||
ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 6)));
|
||||
ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 0)));
|
||||
@@ -25,21 +19,21 @@ static void ffEfiUcs2ToUtf8(const uint16_t *const chars, FFstrbuf* result)
|
||||
}
|
||||
}
|
||||
|
||||
bool ffEfiFillLoadOption(const FFEfiLoadOption* efiOption, FFBootmgrResult* result)
|
||||
{
|
||||
bool ffEfiFillLoadOption(const FFEfiLoadOption* efiOption, FFBootmgrResult* result) {
|
||||
uint32_t descLen = 0;
|
||||
while (efiOption->Description[descLen]) ++descLen;
|
||||
while (efiOption->Description[descLen]) {
|
||||
++descLen;
|
||||
}
|
||||
|
||||
if (descLen)
|
||||
if (descLen) {
|
||||
ffEfiUcs2ToUtf8(efiOption->Description, &result->name);
|
||||
}
|
||||
|
||||
for (
|
||||
ffEfiDevicePathProtocol* filePathList = (ffEfiDevicePathProtocol*) &efiOption->Description[descLen + 1];
|
||||
filePathList->Type != 0x7F; // End of Hardware Device Path
|
||||
filePathList = (ffEfiDevicePathProtocol*) ((uint8_t*) filePathList + filePathList->Length))
|
||||
{
|
||||
if (filePathList->Type == 4 && filePathList->SubType == 4)
|
||||
{
|
||||
filePathList = (ffEfiDevicePathProtocol*) ((uint8_t*) filePathList + filePathList->Length)) {
|
||||
if (filePathList->Type == 4 && filePathList->SubType == 4) {
|
||||
// https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#file-path-media-device-path
|
||||
ffEfiUcs2ToUtf8((uint16_t*) filePathList->SpecificDevicePathData, &result->firmware);
|
||||
return true;
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bootmgr/option.h"
|
||||
|
||||
typedef struct FFBootmgrResult
|
||||
{
|
||||
typedef struct FFBootmgrResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf firmware;
|
||||
uint16_t order;
|
||||
|
||||
@@ -4,43 +4,48 @@
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
static const char* detectSecureBoot(bool* result)
|
||||
{
|
||||
#if __aarch64__
|
||||
static const char* detectSecureBoot(bool* result) {
|
||||
#if __aarch64__
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (!entryDevice)
|
||||
if (!entryDevice) {
|
||||
return "IORegistryEntryFromPath() failed";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("secure-boot"), kCFAllocatorDefault, 0);
|
||||
if (!prop)
|
||||
if (!prop) {
|
||||
return "IORegistryEntryCreateCFProperty() failed";
|
||||
}
|
||||
|
||||
if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0)
|
||||
if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0) {
|
||||
return "Invalid secure-boot property";
|
||||
}
|
||||
|
||||
*result = (bool) *CFDataGetBytePtr((CFDataRef) prop);
|
||||
#else
|
||||
#else
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/options");
|
||||
if (!entryDevice)
|
||||
if (!entryDevice) {
|
||||
return "IORegistryEntryFromPath() failed";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("94b73556-2197-4702-82a8-3e1337dafbfb:AppleSecureBootPolicy"), kCFAllocatorDefault, 0);
|
||||
if (!prop)
|
||||
if (!prop) {
|
||||
return "IORegistryEntryCreateCFProperty() failed";
|
||||
}
|
||||
|
||||
if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0)
|
||||
if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0) {
|
||||
return "Invalid secure-boot property";
|
||||
}
|
||||
|
||||
*result = *CFDataGetBytePtr((CFDataRef) prop) != 0x02 /* Permissive Security */;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
if (ffPathExists("/System/Library/CoreServices/boot.efi", FF_PATHTYPE_FILE))
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
if (ffPathExists("/System/Library/CoreServices/boot.efi", FF_PATHTYPE_FILE)) {
|
||||
ffStrbufSetStatic(&result->firmware, "/System/Library/CoreServices/boot.efi");
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&result->name, "iBoot");
|
||||
|
||||
|
||||
@@ -3,26 +3,27 @@
|
||||
#include "common/io.h"
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#include <dev/efi/efiio.h>
|
||||
# include <dev/efi/efiio.h>
|
||||
#else
|
||||
#include <sys/efiio.h>
|
||||
# include <sys/efiio.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
typedef uint16_t efi_char;
|
||||
typedef uint16_t efi_char;
|
||||
#endif
|
||||
|
||||
#ifndef EFI_GLOBAL_VARIABLE
|
||||
#define EFI_GLOBAL_VARIABLE { 0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, { 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c } }
|
||||
# define EFI_GLOBAL_VARIABLE {0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, {0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c}}
|
||||
#endif
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
|
||||
if (efifd < 0) return "open(/dev/efi) failed";
|
||||
if (efifd < 0) {
|
||||
return "open(/dev/efi) failed";
|
||||
}
|
||||
|
||||
alignas(uint16_t) uint8_t buffer[2048];
|
||||
struct efi_var_ioc ioc = {
|
||||
@@ -31,28 +32,31 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
};
|
||||
|
||||
ioc.datasize = sizeof(buffer);
|
||||
ioc.name = (efi_char[]){ 'B', 'o', 'o', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', '\0' };
|
||||
ioc.name = (efi_char[]) {'B', 'o', 'o', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', '\0'};
|
||||
ioc.namesize = sizeof("BootCurrent") * 2;
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize != 2)
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize != 2) {
|
||||
return "ioctl(EFIIOC_VAR_GET, BootCurrent) failed";
|
||||
}
|
||||
|
||||
result->order = *(uint16_t*)buffer;
|
||||
result->order = *(uint16_t*) buffer;
|
||||
|
||||
unsigned char hex[5];
|
||||
snprintf((char*) hex, sizeof(hex), "%04X", result->order);
|
||||
ioc.datasize = sizeof(buffer);
|
||||
ioc.name = (efi_char[]){ 'B', 'o', 'o', 't', hex[0], hex[1], hex[2], hex[3], '\0' };
|
||||
ioc.name = (efi_char[]) {'B', 'o', 'o', 't', hex[0], hex[1], hex[2], hex[3], '\0'};
|
||||
ioc.namesize = sizeof("Boot####") * 2;
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize == sizeof(buffer))
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize == sizeof(buffer)) {
|
||||
return "ioctl(EFIIOC_VAR_GET, Boot####) failed";
|
||||
}
|
||||
|
||||
ffEfiFillLoadOption((FFEfiLoadOption *)buffer, result);
|
||||
ffEfiFillLoadOption((FFEfiLoadOption*) buffer, result);
|
||||
|
||||
ioc.name = (efi_char[]){ 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', '\0' };
|
||||
ioc.name = (efi_char[]) {'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', '\0'};
|
||||
ioc.namesize = sizeof("SecureBoot") * 2;
|
||||
ioc.datasize = sizeof(buffer);
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) == 0 && ioc.datasize == 1)
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) == 0 && ioc.datasize == 1) {
|
||||
result->secureBoot = !!buffer[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -6,26 +6,27 @@
|
||||
|
||||
#define FF_EFIVARS_PATH_PREFIX "/sys/firmware/efi/efivars/"
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
alignas(uint16_t) uint8_t buffer[2048];
|
||||
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6)
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6) {
|
||||
return "Failed to read efivar: BootCurrent";
|
||||
}
|
||||
|
||||
|
||||
result->order = *(uint16_t *)&buffer[4];
|
||||
result->order = *(uint16_t*) &buffer[4];
|
||||
|
||||
snprintf((char*) buffer, sizeof(buffer), FF_EFIVARS_PATH_PREFIX "Boot%04X-" FF_EFI_GLOBAL_GUID, result->order);
|
||||
|
||||
ssize_t size = ffReadFileData((const char*) buffer, sizeof(buffer), buffer);
|
||||
if (size < 5 + (int) sizeof(FFEfiLoadOption) || size == (ssize_t) sizeof(buffer))
|
||||
if (size < 5 + (int) sizeof(FFEfiLoadOption) || size == (ssize_t) sizeof(buffer)) {
|
||||
return "Failed to read efivar: Boot####";
|
||||
}
|
||||
|
||||
ffEfiFillLoadOption((FFEfiLoadOption *)&buffer[4], result);
|
||||
ffEfiFillLoadOption((FFEfiLoadOption*) &buffer[4], result);
|
||||
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "SecureBoot-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) >= 5)
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "SecureBoot-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) >= 5) {
|
||||
result->secureBoot = buffer[4] == 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "bootmgr.h"
|
||||
|
||||
const char* ffDetectBootmgr(FF_MAYBE_UNUSED FFBootmgrResult* result)
|
||||
{
|
||||
const char* ffDetectBootmgr(FF_MAYBE_UNUSED FFBootmgrResult* result) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -6,61 +6,69 @@
|
||||
#include <ntstatus.h>
|
||||
#include <windows.h>
|
||||
|
||||
const char* enablePrivilege(const wchar_t* privilege)
|
||||
{
|
||||
const char* enablePrivilege(const wchar_t* privilege) {
|
||||
FF_AUTO_CLOSE_FD HANDLE token = NULL;
|
||||
if (!NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)))
|
||||
if (!NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))) {
|
||||
return "NtOpenProcessToken() failed";
|
||||
}
|
||||
|
||||
TOKEN_PRIVILEGES tp = {
|
||||
.PrivilegeCount = 1,
|
||||
.Privileges = {
|
||||
(LUID_AND_ATTRIBUTES) { .Attributes = SE_PRIVILEGE_ENABLED }
|
||||
},
|
||||
(LUID_AND_ATTRIBUTES) {.Attributes = SE_PRIVILEGE_ENABLED}},
|
||||
};
|
||||
if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid))
|
||||
if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid)) {
|
||||
return "LookupPrivilegeValue() failed";
|
||||
}
|
||||
|
||||
NTSTATUS status = NtAdjustPrivilegesToken(token, false, &tp, sizeof(tp), NULL, NULL);
|
||||
if (!NT_SUCCESS(status))
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return "NtAdjustPrivilegesToken() failed";
|
||||
}
|
||||
|
||||
if (status == STATUS_NOT_ALL_ASSIGNED)
|
||||
if (status == STATUS_NOT_ALL_ASSIGNED) {
|
||||
return "The token does not have the specified privilege; try sudo please";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
const char* err = enablePrivilege(L"SeSystemEnvironmentPrivilege");
|
||||
if (err != NULL)
|
||||
if (err != NULL) {
|
||||
return err;
|
||||
}
|
||||
|
||||
GUID efiGlobalGuid;
|
||||
if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid)))
|
||||
if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid))) {
|
||||
return "RtlGUIDFromString() failed";
|
||||
}
|
||||
|
||||
ULONG size = sizeof(result->order);
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"BootCurrent"), &efiGlobalGuid, &result->order, &size, NULL)))
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"BootCurrent"), &efiGlobalGuid, &result->order, &size, NULL))) {
|
||||
return "NtQuerySystemEnvironmentValueEx(BootCurrent) failed";
|
||||
if (size != sizeof(result->order))
|
||||
}
|
||||
if (size != sizeof(result->order)) {
|
||||
return "NtQuerySystemEnvironmentValueEx(BootCurrent) returned unexpected size";
|
||||
}
|
||||
|
||||
uint8_t buffer[2048];
|
||||
wchar_t key[9];
|
||||
swprintf(key, ARRAY_SIZE(key), L"Boot%04X", result->order);
|
||||
size = sizeof(buffer);
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(key), &efiGlobalGuid, buffer, &size, NULL)))
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(key), &efiGlobalGuid, buffer, &size, NULL))) {
|
||||
return "NtQuerySystemEnvironmentValueEx(Boot####) failed";
|
||||
if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer))
|
||||
}
|
||||
if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer)) {
|
||||
return "NtQuerySystemEnvironmentValueEx(Boot####) returned unexpected size";
|
||||
}
|
||||
|
||||
ffEfiFillLoadOption((FFEfiLoadOption *)buffer, result);
|
||||
ffEfiFillLoadOption((FFEfiLoadOption*) buffer, result);
|
||||
|
||||
SYSTEM_SECUREBOOT_INFORMATION ssi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemSecureBootInformation, &ssi, sizeof(ssi), NULL)))
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemSecureBootInformation, &ssi, sizeof(ssi), NULL))) {
|
||||
result->secureBoot = ssi.SecureBootEnabled;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "bootmgr.h"
|
||||
|
||||
// https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#generic-device-path-structures
|
||||
typedef struct ffEfiDevicePathProtocol
|
||||
{
|
||||
typedef struct ffEfiDevicePathProtocol {
|
||||
uint8_t Type;
|
||||
uint8_t SubType;
|
||||
uint16_t Length;
|
||||
@@ -10,8 +9,7 @@ typedef struct ffEfiDevicePathProtocol
|
||||
} ffEfiDevicePathProtocol;
|
||||
|
||||
// https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html#load-options
|
||||
typedef struct FFEfiLoadOption
|
||||
{
|
||||
typedef struct FFEfiLoadOption {
|
||||
uint32_t Attributes;
|
||||
uint16_t FilePathListLength;
|
||||
uint16_t Description[];
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/brightness/option.h"
|
||||
|
||||
typedef struct FFBrightnessResult
|
||||
{
|
||||
typedef struct FFBrightnessResult {
|
||||
FFstrbuf name;
|
||||
double min, max, current;
|
||||
bool builtin;
|
||||
|
||||
@@ -15,28 +15,25 @@ extern IOReturn IOAVServiceReadI2C(IOAVServiceRef service, uint32_t chipAddress,
|
||||
extern IOReturn IOAVServiceWriteI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t dataAddress, void* inputBuffer, uint32_t inputBufferSize) __attribute__((weak_import));
|
||||
#else
|
||||
// DDC/CI (Intel)
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <IOKit/i2c/IOI2CInterface.h>
|
||||
# include <IOKit/IOKitLib.h>
|
||||
# include <IOKit/graphics/IOGraphicsLib.h>
|
||||
# include <IOKit/i2c/IOI2CInterface.h>
|
||||
extern void CGSServiceForDisplayNumber(CGDirectDisplayID display, io_service_t* service) __attribute__((weak_import));
|
||||
#endif
|
||||
|
||||
// ACPI
|
||||
extern int DisplayServicesGetBrightness(CGDirectDisplayID display, float *brightness) __attribute__((weak_import));
|
||||
extern int DisplayServicesGetBrightness(CGDirectDisplayID display, float* brightness) __attribute__((weak_import));
|
||||
|
||||
// Works for internal display
|
||||
static const char* detectWithDisplayServices(const FFDisplayServerResult* displayServer, FFlist* result)
|
||||
{
|
||||
if(DisplayServicesGetBrightness == NULL)
|
||||
static const char* detectWithDisplayServices(const FFDisplayServerResult* displayServer, FFlist* result) {
|
||||
if (DisplayServicesGetBrightness == NULL) {
|
||||
return "DisplayServices function DisplayServicesGetBrightness is not available";
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN)
|
||||
{
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN) {
|
||||
float value;
|
||||
if(DisplayServicesGetBrightness((CGDirectDisplayID) display->id, &value) == kCGErrorSuccess)
|
||||
{
|
||||
if (DisplayServicesGetBrightness((CGDirectDisplayID) display->id, &value) == kCGErrorSuccess) {
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
brightness->current = value;
|
||||
brightness->max = 1;
|
||||
@@ -53,56 +50,55 @@ static const char* detectWithDisplayServices(const FFDisplayServerResult* displa
|
||||
#ifdef __aarch64__
|
||||
// https://github.com/waydabber/m1ddc
|
||||
// Works for Apple Silicon and USB-C adapter connection ( but not HTMI )
|
||||
static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
if (!IOAVServiceCreate || !IOAVServiceReadI2C || !IOAVServiceWriteI2C)
|
||||
static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result) {
|
||||
if (!IOAVServiceCreate || !IOAVServiceReadI2C || !IOAVServiceWriteI2C) {
|
||||
return "IOAVService is not available";
|
||||
}
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess)
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) {
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
}
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
|
||||
FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = NULL;
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryAv = registryEntry;
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(entryAv, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions);
|
||||
if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported))
|
||||
{
|
||||
if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported)) {
|
||||
// IOAVServiceCreateWithService won't work
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(entryAv, CFSTR("Location"), kCFAllocatorDefault, kNilOptions);
|
||||
if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0)
|
||||
{
|
||||
if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0) {
|
||||
// Builtin display should be handled by DisplayServices
|
||||
continue;
|
||||
}
|
||||
|
||||
service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry);
|
||||
if (!service) continue;
|
||||
if (!service) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t i2cIn[4] = { 0x82, 0x01, 0x10 /* luminance */ };
|
||||
uint8_t i2cIn[4] = {0x82, 0x01, 0x10 /* luminance */};
|
||||
i2cIn[3] = 0x6e ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2];
|
||||
|
||||
for (uint32_t i = 0; i < 2; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
IOAVServiceWriteI2C(service, 0x37, 0x51, i2cIn, ARRAY_SIZE(i2cIn));
|
||||
usleep(options->ddcciSleep * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
if (IOAVServiceReadI2C(service, 0x37, 0x51, i2cOut, ARRAY_SIZE(i2cOut)) == KERN_SUCCESS)
|
||||
{
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00)
|
||||
if (IOAVServiceReadI2C(service, 0x37, 0x51, i2cOut, ARRAY_SIZE(i2cOut)) == KERN_SUCCESS) {
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
|
||||
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
|
||||
@@ -115,37 +111,38 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult*
|
||||
brightness->builtin = false;
|
||||
|
||||
uint8_t edid[128] = {};
|
||||
if (IOAVServiceReadI2C(service, 0x50, 0x00, edid, ARRAY_SIZE(edid)) == KERN_SUCCESS)
|
||||
if (IOAVServiceReadI2C(service, 0x50, 0x00, edid, ARRAY_SIZE(edid)) == KERN_SUCCESS) {
|
||||
ffEdidGetName(edid, &brightness->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static IOOptionBits getSupportedTransactionType(void)
|
||||
{
|
||||
static IOOptionBits getSupportedTransactionType(void) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("IOFramebufferI2CInterface"), &iterator) != KERN_SUCCESS)
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("IOFramebufferI2CInterface"), &iterator) != KERN_SUCCESS) {
|
||||
return kIOI2CNoTransactionType;
|
||||
}
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != MACH_PORT_NULL)
|
||||
{
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != MACH_PORT_NULL) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t io_service = registryEntry;
|
||||
FF_CFTYPE_AUTO_RELEASE CFNumberRef IOI2CTransactionTypes = IORegistryEntryCreateCFProperty(io_service, CFSTR(kIOI2CTransactionTypesKey), kCFAllocatorDefault, kNilOptions);
|
||||
|
||||
if (IOI2CTransactionTypes)
|
||||
{
|
||||
if (IOI2CTransactionTypes) {
|
||||
int64_t types = 0;
|
||||
ffCfNumGetInt64(IOI2CTransactionTypes, &types);
|
||||
|
||||
if (types) {
|
||||
if ((1 << kIOI2CDDCciReplyTransactionType) & (uint64_t) types)
|
||||
if ((1 << kIOI2CDDCciReplyTransactionType) & (uint64_t) types) {
|
||||
return kIOI2CDDCciReplyTransactionType;
|
||||
if ((1 << kIOI2CSimpleTransactionType) & (uint64_t) types)
|
||||
}
|
||||
if ((1 << kIOI2CSimpleTransactionType) & (uint64_t) types) {
|
||||
return kIOI2CSimpleTransactionType;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -154,36 +151,41 @@ static IOOptionBits getSupportedTransactionType(void)
|
||||
return kIOI2CNoTransactionType;
|
||||
}
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
if (!CGSServiceForDisplayNumber) return "CGSServiceForDisplayNumber is not available";
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result) {
|
||||
if (!CGSServiceForDisplayNumber) {
|
||||
return "CGSServiceForDisplayNumber is not available";
|
||||
}
|
||||
IOOptionBits transactionType = getSupportedTransactionType();
|
||||
if (transactionType == kIOI2CNoTransactionType)
|
||||
if (transactionType == kIOI2CNoTransactionType) {
|
||||
return "No supported IOI2C transaction type found";
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
if (display->type == FF_DISPLAY_TYPE_EXTERNAL)
|
||||
{
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_EXTERNAL) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t framebuffer = IO_OBJECT_NULL;
|
||||
CGSServiceForDisplayNumber((CGDirectDisplayID)display->id, &framebuffer);
|
||||
if (framebuffer == IO_OBJECT_NULL) continue;
|
||||
CGSServiceForDisplayNumber((CGDirectDisplayID) display->id, &framebuffer);
|
||||
if (framebuffer == IO_OBJECT_NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IOItemCount count;
|
||||
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0)
|
||||
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (IOItemCount bus = 0; bus < count; ++bus)
|
||||
{
|
||||
for (IOItemCount bus = 0; bus < count; ++bus) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t interface = IO_OBJECT_NULL;
|
||||
if (IOFBCopyI2CInterfaceForBus(framebuffer, bus, &interface) != KERN_SUCCESS) continue;
|
||||
if (IOFBCopyI2CInterfaceForBus(framebuffer, bus, &interface) != KERN_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
IOI2CConnectRef connect = NULL;
|
||||
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS)
|
||||
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
|
||||
uint8_t i2cIn[] = {0x51, 0x82, 0x01, 0x10 /* luminance */, 0};
|
||||
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
|
||||
IOI2CRequest request = {
|
||||
@@ -202,8 +204,12 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
IOReturn ret = IOI2CSendRequest(connect, kNilOptions, &request);
|
||||
IOI2CInterfaceClose(connect, kNilOptions);
|
||||
|
||||
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess || request.replyBytes < 10) continue;
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) continue;
|
||||
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess || request.replyBytes < 10) {
|
||||
continue;
|
||||
}
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
|
||||
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
|
||||
@@ -224,14 +230,14 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffDetectBrightness(FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FFBrightnessOptions* options, FFlist* result) {
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
|
||||
detectWithDisplayServices(displayServer, result);
|
||||
|
||||
if (displayServer->displays.length > result->length)
|
||||
if (displayServer->displays.length > result->length) {
|
||||
detectWithDdcci(displayServer, options, result);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,29 +2,29 @@
|
||||
|
||||
#if __has_include(<sys/backlight.h>)
|
||||
|
||||
#include "common/io.h"
|
||||
# include "common/io.h"
|
||||
|
||||
#include <sys/backlight.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
# include <sys/backlight.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/fcntl.h>
|
||||
# include <unistd.h>
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
// https://man.freebsd.org/cgi/man.cgi?query=backlight&sektion=9
|
||||
char path[] = "/dev/backlight/backlight0";
|
||||
|
||||
for (char i = '0'; i <= '9'; ++i)
|
||||
{
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
path[ARRAY_SIZE(path) - 2] = i;
|
||||
|
||||
FF_AUTO_CLOSE_FD int blfd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (blfd < 0)
|
||||
if (blfd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct backlight_props status;
|
||||
if(ioctl(blfd, BACKLIGHTGETSTATUS, &status) < 0)
|
||||
if (ioctl(blfd, BACKLIGHTGETSTATUS, &status) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufInit(&brightness->name);
|
||||
@@ -35,18 +35,18 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
brightness->builtin = true;
|
||||
|
||||
struct backlight_info info;
|
||||
if(ioctl(blfd, BACKLIGHTGETINFO, &info) == 0)
|
||||
if (ioctl(blfd, BACKLIGHTGETINFO, &info) == 0) {
|
||||
ffStrbufAppendS(&brightness->name, info.name);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/"));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FF_MAYBE_UNUSED FFlist* result) {
|
||||
return "Backlight is supported only on FreeBSD 13 and newer";
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
static const char* detectWithBacklight(FFlist* result)
|
||||
{
|
||||
//https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
|
||||
static const char* detectWithBacklight(FFlist* result) {
|
||||
// https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
|
||||
const char* backlightDirPath = "/sys/class/backlight/";
|
||||
|
||||
DIR* dirp = opendir(backlightDirPath);
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return "Failed to open `/sys/class/backlight/`";
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY backlightDir = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&backlightDir, backlightDirPath);
|
||||
@@ -23,54 +23,46 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&backlightDir, entry->d_name);
|
||||
ffStrbufAppendS(&backlightDir, "/brightness");
|
||||
if(ffReadFileBuffer(backlightDir.chars, &buffer))
|
||||
{
|
||||
if (ffReadFileBuffer(backlightDir.chars, &buffer)) {
|
||||
double actualBrightness = ffStrbufToDouble(&buffer, 0);
|
||||
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
|
||||
ffStrbufAppendS(&backlightDir, entry->d_name);
|
||||
ffStrbufAppendS(&backlightDir, "/max_brightness");
|
||||
if(ffReadFileBuffer(backlightDir.chars, &buffer))
|
||||
{
|
||||
if (ffReadFileBuffer(backlightDir.chars, &buffer)) {
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufSubstrBeforeLastC(&backlightDir, '/');
|
||||
ffStrbufAppendS(&backlightDir, "/device");
|
||||
ffStrbufInitA(&brightness->name, PATH_MAX);
|
||||
if(realpath(backlightDir.chars, brightness->name.chars))
|
||||
{
|
||||
if (realpath(backlightDir.chars, brightness->name.chars)) {
|
||||
ffStrbufRecalculateLength(&brightness->name);
|
||||
// if we managed to get edid, use it
|
||||
ffStrbufAppendS(&brightness->name, "/edid");
|
||||
uint8_t edidData[128];
|
||||
if(ffReadFileData(brightness->name.chars, ARRAY_SIZE(edidData), edidData) == ARRAY_SIZE(edidData))
|
||||
{
|
||||
if (ffReadFileData(brightness->name.chars, ARRAY_SIZE(edidData), edidData) == ARRAY_SIZE(edidData)) {
|
||||
ffStrbufClear(&brightness->name);
|
||||
ffEdidGetName(edidData, &brightness->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufSubstrBeforeLastC(&brightness->name, '/'); // remove "/edid"
|
||||
ffStrbufSubstrAfterLastC(&brightness->name, '/'); // try getting DRM connector name
|
||||
if(ffCharIsDigit(brightness->name.chars[0]))
|
||||
{
|
||||
ffStrbufSubstrAfterLastC(&brightness->name, '/'); // try getting DRM connector name
|
||||
if (ffCharIsDigit(brightness->name.chars[0])) {
|
||||
// PCI address or some unknown path, give up
|
||||
ffStrbufSetS(&brightness->name, entry->d_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ffStrbufStartsWithS(&brightness->name, "card") && ffCharIsDigit(brightness->name.chars[4]))
|
||||
} else {
|
||||
if (ffStrbufStartsWithS(&brightness->name, "card") && ffCharIsDigit(brightness->name.chars[4])) {
|
||||
ffStrbufSubstrAfterFirstC(&brightness->name, '-');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ffStrbufInitS(&brightness->name, entry->d_name);
|
||||
}
|
||||
brightness->max = ffStrbufToDouble(&buffer, 0);
|
||||
brightness->min = 0;
|
||||
brightness->current = actualBrightness;
|
||||
@@ -86,22 +78,21 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_DDCUTIL
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "common/library.h"
|
||||
#include "common/mallocHelper.h"
|
||||
# include "detection/displayserver/displayserver.h"
|
||||
# include "common/library.h"
|
||||
# include "common/mallocHelper.h"
|
||||
|
||||
#include <ddcutil_macros.h>
|
||||
#include <ddcutil_c_api.h>
|
||||
# include <ddcutil_macros.h>
|
||||
# include <ddcutil_c_api.h>
|
||||
|
||||
// Try to be compatible with ddcutil 2.0
|
||||
#if DDCUTIL_VMAJOR >= 2
|
||||
# if DDCUTIL_VMAJOR >= 2
|
||||
double ddca_set_default_sleep_multiplier(double multiplier); // ddcutil 1.4
|
||||
#else
|
||||
DDCA_Status ddca_init(const char *libopts, int syslog_level, int opts);
|
||||
#endif
|
||||
# else
|
||||
DDCA_Status ddca_init(const char* libopts, int syslog_level, int opts);
|
||||
# endif
|
||||
|
||||
static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(libddcutil, "libddcutil" FF_LIBRARY_EXTENSION, 5);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_get_display_info_list2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_open_display2)
|
||||
@@ -109,49 +100,48 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options,
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_free_any_vcp_value)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_close_display)
|
||||
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
# ifndef FF_DISABLE_DLOPEN
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_init)
|
||||
if (ffddca_init)
|
||||
{
|
||||
if (ffddca_init) {
|
||||
FF_SUPPRESS_IO();
|
||||
// Ref: https://github.com/rockowitz/ddcutil/issues/344
|
||||
if (ffddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
|
||||
if (ffddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0) {
|
||||
return "ddca_init() failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_set_default_sleep_multiplier);
|
||||
if (ffddca_set_default_sleep_multiplier)
|
||||
if (ffddca_set_default_sleep_multiplier) {
|
||||
ffddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
|
||||
}
|
||||
|
||||
libddcutil = NULL; // Don't dlclose libddcutil. See https://github.com/rockowitz/ddcutil/issues/330
|
||||
}
|
||||
#else
|
||||
#if DDCUTIL_VMAJOR >= 2
|
||||
if (ddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
|
||||
return "ddca_init() failed";
|
||||
#else
|
||||
ddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
|
||||
#endif
|
||||
#endif
|
||||
# else
|
||||
# if DDCUTIL_VMAJOR >= 2
|
||||
if (ddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0) {
|
||||
return "ddca_init() failed";
|
||||
}
|
||||
# else
|
||||
ddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
FF_AUTO_FREE DDCA_Display_Info_List* infoList = NULL;
|
||||
if (ffddca_get_display_info_list2(false, &infoList) < 0)
|
||||
if (ffddca_get_display_info_list2(false, &infoList) < 0) {
|
||||
return "ddca_get_display_info_list2(false, &infoList) failed";
|
||||
}
|
||||
|
||||
if (infoList->ct == 0)
|
||||
if (infoList->ct == 0) {
|
||||
return "No DDC/CI compatible displays found";
|
||||
}
|
||||
|
||||
for (int index = 0; index < infoList->ct; ++index)
|
||||
{
|
||||
for (int index = 0; index < infoList->ct; ++index) {
|
||||
const DDCA_Display_Info* display = &infoList->info[index];
|
||||
|
||||
DDCA_Display_Handle handle;
|
||||
if (ffddca_open_display2(display->dref, false, &handle) >= 0)
|
||||
{
|
||||
if (ffddca_open_display2(display->dref, false, &handle) >= 0) {
|
||||
DDCA_Any_Vcp_Value* vcpValue = NULL;
|
||||
if (ffddca_get_any_vcp_value_using_explicit_type(handle, 0x10 /*brightness*/, DDCA_NON_TABLE_VCP_VALUE, &vcpValue) >= 0)
|
||||
{
|
||||
if (ffddca_get_any_vcp_value_using_explicit_type(handle, 0x10 /*brightness*/, DDCA_NON_TABLE_VCP_VALUE, &vcpValue) >= 0) {
|
||||
assert(vcpValue->value_type == DDCA_NON_TABLE_VCP_VALUE);
|
||||
int current = VALREC_CUR_VAL(vcpValue), max = VALREC_MAX_VAL(vcpValue);
|
||||
ffddca_free_any_vcp_value(vcpValue);
|
||||
@@ -170,15 +160,15 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options,
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
detectWithBacklight(result);
|
||||
|
||||
#ifdef FF_HAVE_DDCUTIL
|
||||
#ifdef FF_HAVE_DDCUTIL
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
if (result->length < displayServer->displays.length)
|
||||
if (result->length < displayServer->displays.length) {
|
||||
detectWithDdcci(options, result);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
#include "common/sysctl.h"
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
// https://man.netbsd.org/NetBSD-10.1/acpiout.4#DESCRIPTION
|
||||
char key[] = "hw.acpi.acpiout0.brightness";
|
||||
char* pn = key + strlen("hw.acpi.acpiout");
|
||||
|
||||
for (uint32_t i = 0; i <= 9; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i <= 9; ++i) {
|
||||
*pn = (char) ('0' + i);
|
||||
int value = ffSysctlGetInt(key, -1);
|
||||
if (value == -1) continue;
|
||||
if (value == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&brightness->name, "acpiout%d", i);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "brightness.h"
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FF_MAYBE_UNUSED FFlist* result) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
char path[] = "/dev/ttyCX";
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
path[strlen("/dev/ttyC")] = i;
|
||||
@@ -15,10 +14,12 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES && i == '0')
|
||||
if (errno == EACCES && i == '0') {
|
||||
return "Permission denied when opening tty device";
|
||||
if (errno == ENOENT)
|
||||
}
|
||||
if (errno == ENOENT) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -26,8 +27,9 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
.param = WSDISPLAYIO_PARAM_BRIGHTNESS,
|
||||
};
|
||||
|
||||
if (ioctl(devfd, WSDISPLAYIO_GETPARAM, ¶m) < 0)
|
||||
if (ioctl(devfd, WSDISPLAYIO_GETPARAM, ¶m) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&brightness->name, "ttyC%c", i);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "brightness.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "common/library.h"
|
||||
@@ -10,45 +9,40 @@ extern "C"
|
||||
#include <winternl.h>
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
|
||||
_In_ UNICODE_STRING *pstrDeviceName,
|
||||
_In_ DWORD dwPhysicalMonitorArraySize,
|
||||
_Out_ DWORD *pdwNumPhysicalMonitorHandlesInArray,
|
||||
_Out_ HANDLE *phPhysicalMonitorArray
|
||||
);
|
||||
_In_ UNICODE_STRING* pstrDeviceName,
|
||||
_In_ DWORD dwPhysicalMonitorArraySize,
|
||||
_Out_ DWORD* pdwNumPhysicalMonitorHandlesInArray,
|
||||
_Out_ HANDLE* phPhysicalMonitorArray);
|
||||
|
||||
typedef enum _MC_VCP_CODE_TYPE {
|
||||
MC_MOMENTARY,
|
||||
MC_SET_PARAMETER
|
||||
} MC_VCP_CODE_TYPE, *LPMC_VCP_CODE_TYPE;
|
||||
MC_MOMENTARY,
|
||||
MC_SET_PARAMETER
|
||||
} MC_VCP_CODE_TYPE,
|
||||
*LPMC_VCP_CODE_TYPE;
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwVCPCode,
|
||||
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
|
||||
_Out_ DWORD *pdwCurrentValue,
|
||||
_Out_opt_ DWORD *pdwMaximumValue
|
||||
);
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwVCPCode,
|
||||
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
|
||||
_Out_ DWORD* pdwCurrentValue,
|
||||
_Out_opt_ DWORD* pdwMaximumValue);
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
|
||||
_In_ HANDLE hMonitor
|
||||
);
|
||||
_In_ HANDLE hMonitor);
|
||||
|
||||
NTSTATUS WINAPI GetPhysicalMonitorDescription(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
|
||||
_Out_ LPWSTR szPhysicalMonitorDescription
|
||||
);
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
|
||||
_Out_ LPWSTR szPhysicalMonitorDescription);
|
||||
|
||||
static const char* detectWithWmi(FFlist* result)
|
||||
{
|
||||
static const char* detectWithWmi(FFlist* result) {
|
||||
FFWmiQuery query(L"SELECT CurrentBrightness, InstanceName FROM WmiMonitorBrightness WHERE Active = true", nullptr, FFWmiNamespace::WMI);
|
||||
if(!query)
|
||||
if (!query) {
|
||||
return "Query WMI service failed";
|
||||
}
|
||||
|
||||
while(FFWmiRecord record = query.next())
|
||||
{
|
||||
if(FFWmiVariant vtValue = record.get(L"CurrentBrightness"))
|
||||
{
|
||||
while (FFWmiRecord record = query.next()) {
|
||||
if (FFWmiVariant vtValue = record.get(L"CurrentBrightness")) {
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
brightness->max = 100;
|
||||
brightness->min = 0;
|
||||
@@ -56,8 +50,7 @@ static const char* detectWithWmi(FFlist* result)
|
||||
brightness->builtin = true;
|
||||
|
||||
ffStrbufInit(&brightness->name);
|
||||
if (FFWmiVariant vtName = record.get(L"InstanceName"))
|
||||
{
|
||||
if (FFWmiVariant vtName = record.get(L"InstanceName")) {
|
||||
ffStrbufSetWSV(&brightness->name, vtName.get<std::wstring_view>());
|
||||
ffStrbufSubstrAfterFirstC(&brightness->name, '\\');
|
||||
ffStrbufSubstrBeforeFirstC(&brightness->name, '\\');
|
||||
@@ -67,22 +60,25 @@ static const char* detectWithWmi(FFlist* result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result)
|
||||
{
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result) {
|
||||
void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
|
||||
if (!gdi32) return "ffLibraryGetModule(gdi32.dll) failed";
|
||||
if (!gdi32) {
|
||||
return "ffLibraryGetModule(gdi32.dll) failed";
|
||||
}
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN) continue;
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MONITORINFOEXW mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (!GetMonitorInfoW((HMONITOR)(uintptr_t) display->id, (LPMONITORINFO) &mi))
|
||||
if (!GetMonitorInfoW((HMONITOR) (uintptr_t) display->id, (LPMONITORINFO) &mi)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UNICODE_STRING deviceName = {
|
||||
.Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
|
||||
@@ -91,25 +87,23 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
};
|
||||
HANDLE physicalMonitor;
|
||||
DWORD monitorCount = 0;
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor)) && monitorCount >= 1)
|
||||
{
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor)) && monitorCount >= 1) {
|
||||
DWORD curr = 0, max = 0;
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max)))
|
||||
{
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max))) {
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
if (display->name.length > 0)
|
||||
if (display->name.length > 0) {
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
|
||||
if (ffGetPhysicalMonitorDescription)
|
||||
{
|
||||
if (ffGetPhysicalMonitorDescription) {
|
||||
wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description)))
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description))) {
|
||||
ffStrbufInitWS(&brightness->name, description);
|
||||
}
|
||||
}
|
||||
if (brightness->name.length == 0)
|
||||
if (brightness->name.length == 0) {
|
||||
ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
|
||||
}
|
||||
}
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
@@ -123,25 +117,24 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hasBuiltinDisplay(const FFDisplayServerResult* displayServer)
|
||||
{
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN)
|
||||
static bool hasBuiltinDisplay(const FFDisplayServerResult* displayServer) {
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
extern "C" const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
|
||||
if (hasBuiltinDisplay(displayServer))
|
||||
if (hasBuiltinDisplay(displayServer)) {
|
||||
detectWithWmi(result);
|
||||
}
|
||||
|
||||
if (result->length < displayServer->displays.length)
|
||||
if (result->length < displayServer->displays.length) {
|
||||
detectWithDdcci(displayServer, result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/btrfs/option.h"
|
||||
|
||||
typedef struct FFBtrfsDiskUsage
|
||||
{
|
||||
typedef struct FFBtrfsDiskUsage {
|
||||
uint64_t total;
|
||||
uint64_t used;
|
||||
const char* type;
|
||||
@@ -12,8 +11,7 @@ typedef struct FFBtrfsDiskUsage
|
||||
uint8_t copies;
|
||||
} FFBtrfsDiskUsage;
|
||||
|
||||
typedef struct FFBtrfsResult
|
||||
{
|
||||
typedef struct FFBtrfsResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf uuid;
|
||||
FFstrbuf devices;
|
||||
|
||||
@@ -5,132 +5,141 @@
|
||||
|
||||
enum { uuidLen = (uint32_t) __builtin_strlen("00000000-0000-0000-0000-000000000000") };
|
||||
|
||||
static const char* enumerateDevices(FFBtrfsResult* item, int dfd, FFstrbuf* buffer)
|
||||
{
|
||||
static const char* enumerateDevices(FFBtrfsResult* item, int dfd, FFstrbuf* buffer) {
|
||||
int subfd = openat(dfd, "devices", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
|
||||
if (subfd < 0) return "openat(\"/sys/fs/btrfs/UUID/devices\") == -1";
|
||||
if (subfd < 0) {
|
||||
return "openat(\"/sys/fs/btrfs/UUID/devices\") == -1";
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = fdopendir(subfd);
|
||||
if(dirp == NULL)
|
||||
{
|
||||
if (dirp == NULL) {
|
||||
close(subfd);
|
||||
return "fdopendir(\"/sys/fs/btrfs/UUID/devices\") == NULL";
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->devices.length)
|
||||
if (item->devices.length) {
|
||||
ffStrbufAppendC(&item->devices, ',');
|
||||
}
|
||||
ffStrbufAppendS(&item->devices, entry->d_name);
|
||||
|
||||
char path[sizeof(entry->d_name) + sizeof("/size") + 1];
|
||||
snprintf(path, ARRAY_SIZE(path), "%s/size", entry->d_name);
|
||||
|
||||
if (ffReadFileBufferRelative(subfd, path, buffer))
|
||||
if (ffReadFileBufferRelative(subfd, path, buffer)) {
|
||||
item->totalSize += ffStrbufToUInt(buffer, 0) * 512;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* enumerateFeatures(FFBtrfsResult* item, int dfd)
|
||||
{
|
||||
static const char* enumerateFeatures(FFBtrfsResult* item, int dfd) {
|
||||
int subfd = openat(dfd, "features", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
|
||||
if (subfd < 0) return "openat(\"/sys/fs/btrfs/UUID/features\") == -1";
|
||||
if (subfd < 0) {
|
||||
return "openat(\"/sys/fs/btrfs/UUID/features\") == -1";
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = fdopendir(subfd);
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return "fdopendir(\"/sys/fs/btrfs/UUID/features\") == NULL";
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
if (item->features.length)
|
||||
}
|
||||
if (item->features.length) {
|
||||
ffStrbufAppendC(&item->features, ',');
|
||||
}
|
||||
ffStrbufAppendS(&item->features, entry->d_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectAllocation(FFBtrfsResult* item, int dfd, FFstrbuf* buffer)
|
||||
{
|
||||
static const char* detectAllocation(FFBtrfsResult* item, int dfd, FFstrbuf* buffer) {
|
||||
FF_AUTO_CLOSE_FD int subfd = openat(dfd, "allocation", O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
|
||||
if (subfd < 0) return "openat(\"/sys/fs/btrfs/UUID/allocation\") == -1";
|
||||
if (subfd < 0) {
|
||||
return "openat(\"/sys/fs/btrfs/UUID/allocation\") == -1";
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(subfd, "global_rsv_size", buffer))
|
||||
if (ffReadFileBufferRelative(subfd, "global_rsv_size", buffer)) {
|
||||
item->globalReservationTotal = ffStrbufToUInt(buffer, 0);
|
||||
else
|
||||
} else {
|
||||
return "ffReadFileBuffer(\"/sys/fs/btrfs/UUID/allocation/global_rsv_size\") == NULL";
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(subfd, "global_rsv_reserved", buffer))
|
||||
if (ffReadFileBufferRelative(subfd, "global_rsv_reserved", buffer)) {
|
||||
item->globalReservationUsed = ffStrbufToUInt(buffer, 0);
|
||||
}
|
||||
item->globalReservationUsed = item->globalReservationTotal - item->globalReservationUsed;
|
||||
|
||||
#define FF_BTRFS_DETECT_PROFILE(_index, _type, _profile, _copies) \
|
||||
else if (faccessat(subfd, _type "/" _profile "/", F_OK, 0) == 0) { \
|
||||
item->allocation[_index].profile = _profile; \
|
||||
item->allocation[_index].copies = _copies; \
|
||||
}
|
||||
#define FF_BTRFS_DETECT_PROFILE(_index, _type, _profile, _copies) \
|
||||
else if (faccessat(subfd, _type "/" _profile "/", F_OK, 0) == 0) { \
|
||||
item->allocation[_index].profile = _profile; \
|
||||
item->allocation[_index].copies = _copies; \
|
||||
}
|
||||
|
||||
#define FF_BTRFS_DETECT_TYPE(_index, _type) \
|
||||
do { \
|
||||
item->allocation[_index].type = _type; \
|
||||
#define FF_BTRFS_DETECT_TYPE(_index, _type) \
|
||||
do { \
|
||||
item->allocation[_index].type = _type; \
|
||||
if (ffReadFileBufferRelative(subfd, _type "/total_bytes", buffer)) \
|
||||
item->allocation[_index].total = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (ffReadFileBufferRelative(subfd, _type "/bytes_used", buffer)) \
|
||||
item->allocation[_index].used = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (false) {} \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "single", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "dup", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid0", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid10", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c3", 3) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c4", 4) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid5", 1) /* (n-1)/n */ \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid6", 1) /* (n-2)/n */ \
|
||||
else { \
|
||||
item->allocation[_index].profile = "unknown"; \
|
||||
item->allocation[_index].copies = 1; \
|
||||
} \
|
||||
item->allocation[_index].total = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (ffReadFileBufferRelative(subfd, _type "/bytes_used", buffer)) \
|
||||
item->allocation[_index].used = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (false) {} \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "single", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "dup", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid0", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid10", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c3", 3) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c4", 4) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid5", 1) /* (n-1)/n */ \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid6", 1) /* (n-2)/n */ \
|
||||
else { \
|
||||
item->allocation[_index].profile = "unknown"; \
|
||||
item->allocation[_index].copies = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
FF_BTRFS_DETECT_TYPE(0, "data");
|
||||
FF_BTRFS_DETECT_TYPE(1, "metadata");
|
||||
FF_BTRFS_DETECT_TYPE(2, "system");
|
||||
|
||||
#undef FF_BTRFS_DETECT_TYPE
|
||||
#undef FF_BTRFS_DETECT_TYPE
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBtrfs(FFlist* result)
|
||||
{
|
||||
const char* ffDetectBtrfs(FFlist* result) {
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/fs/btrfs/");
|
||||
if(dirp == NULL)
|
||||
if (dirp == NULL) {
|
||||
return "opendir(\"/sys/fs/btrfs\") == NULL";
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.')
|
||||
while ((entry = readdir(dirp)) != NULL) {
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
if (strlen(entry->d_name) != uuidLen)
|
||||
}
|
||||
if (strlen(entry->d_name) != uuidLen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBtrfsResult* item = ffListAdd(result);
|
||||
(*item) = (FFBtrfsResult){
|
||||
(*item) = (FFBtrfsResult) {
|
||||
.uuid = ffStrbufCreateNS(uuidLen, entry->d_name),
|
||||
.name = ffStrbufCreate(),
|
||||
.devices = ffStrbufCreate(),
|
||||
@@ -138,23 +147,29 @@ const char* ffDetectBtrfs(FFlist* result)
|
||||
};
|
||||
|
||||
FF_AUTO_CLOSE_FD int dfd = openat(dirfd(dirp), entry->d_name, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
|
||||
if (dfd < 0) continue;
|
||||
if (dfd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ffAppendFileBufferRelative(dfd, "label", &item->name))
|
||||
if (ffAppendFileBufferRelative(dfd, "label", &item->name)) {
|
||||
ffStrbufTrimRightSpace(&item->name);
|
||||
}
|
||||
|
||||
enumerateDevices(item, dfd, &buffer);
|
||||
|
||||
enumerateFeatures(item, dfd);
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "generation", &buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "generation", &buffer)) {
|
||||
item->generation = (uint32_t) ffStrbufToUInt(&buffer, 0);
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "nodesize", &buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "nodesize", &buffer)) {
|
||||
item->nodeSize = (uint32_t) ffStrbufToUInt(&buffer, 0);
|
||||
}
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "sectorsize", &buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "sectorsize", &buffer)) {
|
||||
item->sectorSize = (uint32_t) ffStrbufToUInt(&buffer, 0);
|
||||
}
|
||||
|
||||
detectAllocation(item, dfd, &buffer);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "btrfs.h"
|
||||
|
||||
const char* ffDetectBtrfs(FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
const char* ffDetectBtrfs(FF_MAYBE_UNUSED FFlist* result) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/camera/option.h"
|
||||
|
||||
typedef struct FFCameraResult
|
||||
{
|
||||
typedef struct FFCameraResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf vendor;
|
||||
FFstrbuf id;
|
||||
|
||||
@@ -6,54 +6,51 @@
|
||||
#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api"
|
||||
#define FF_TERMUX_API_PARAM "CameraInfo"
|
||||
|
||||
static inline void wrapYyjsonFree(yyjson_doc** doc)
|
||||
{
|
||||
static inline void wrapYyjsonFree(yyjson_doc** doc) {
|
||||
assert(doc);
|
||||
if (*doc)
|
||||
if (*doc) {
|
||||
yyjson_doc_free(*doc);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
if(ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
FF_TERMUX_API_PATH,
|
||||
FF_TERMUX_API_PARAM,
|
||||
NULL
|
||||
}))
|
||||
if (ffProcessAppendStdOut(&buffer, (char* const[]) {FF_TERMUX_API_PATH, FF_TERMUX_API_PARAM, NULL})) {
|
||||
return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed";
|
||||
}
|
||||
|
||||
yyjson_doc* __attribute__((__cleanup__(wrapYyjsonFree))) doc = yyjson_read_opts(buffer.chars, buffer.length, 0, NULL, NULL);
|
||||
if (!doc)
|
||||
if (!doc) {
|
||||
return "Failed to parse camera info";
|
||||
}
|
||||
|
||||
yyjson_val* root = yyjson_doc_get_root(doc);
|
||||
if (!yyjson_is_arr(root))
|
||||
if (!yyjson_is_arr(root)) {
|
||||
return "Camera info result is not a JSON array";
|
||||
}
|
||||
|
||||
yyjson_val* device;
|
||||
size_t idx, max;
|
||||
yyjson_arr_foreach(root, idx, max, device)
|
||||
{
|
||||
yyjson_arr_foreach (root, idx, max, device) {
|
||||
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
|
||||
{
|
||||
const char* facing = yyjson_get_str(yyjson_obj_get(device, "facing"));
|
||||
if (facing)
|
||||
if (facing) {
|
||||
ffStrbufInitF(&camera->name, "builtin-%s", facing);
|
||||
else
|
||||
} else {
|
||||
ffStrbufInitStatic(&camera->name, "Unknown");
|
||||
}
|
||||
}
|
||||
ffStrbufInit(&camera->vendor);
|
||||
ffStrbufInitJsonVal(&camera->id, yyjson_obj_get(device, "id"));
|
||||
yyjson_val* sizes = yyjson_arr_get_first(yyjson_obj_get(device, "jpeg_output_sizes"));
|
||||
if (yyjson_is_obj(sizes))
|
||||
{
|
||||
if (yyjson_is_obj(sizes)) {
|
||||
camera->width = (uint32_t) yyjson_get_uint(yyjson_obj_get(sizes, "width"));
|
||||
camera->height = (uint32_t) yyjson_get_uint(yyjson_obj_get(sizes, "height"));
|
||||
}
|
||||
else
|
||||
} else {
|
||||
camera->width = camera->height = 0;
|
||||
}
|
||||
ffStrbufInit(&camera->colorspace);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,57 +6,81 @@
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
#include <linux/videodev2.h>
|
||||
# include <linux/videodev2.h>
|
||||
#elif __has_include(<sys/videoio.h>) // OpenBSD
|
||||
#include <sys/videoio.h>
|
||||
#define FF_HAVE_LINUX_VIDEODEV2 1
|
||||
# include <sys/videoio.h>
|
||||
# define FF_HAVE_LINUX_VIDEODEV2 1
|
||||
#endif
|
||||
|
||||
const char* ffDetectCamera(FFlist* result)
|
||||
{
|
||||
const char* ffDetectCamera(FFlist* result) {
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
char path[] = "/dev/videoN";
|
||||
|
||||
for (uint32_t i = 0; i <= 9; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i <= 9; ++i) {
|
||||
path[ARRAY_SIZE(path) - 2] = (char) (i + '0');
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT) {
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
}
|
||||
if (errno == ENXIO) {
|
||||
continue;
|
||||
}
|
||||
return "Failed to open /dev/videoN";
|
||||
}
|
||||
|
||||
struct v4l2_capability cap = {};
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
|
||||
if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
|
||||
struct v4l2_format fmt = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
|
||||
if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
|
||||
ffStrbufInitS(&camera->name, (const char*) cap.card);
|
||||
ffStrbufInit(&camera->vendor);
|
||||
ffStrbufInitS(&camera->id, (const char*) cap.bus_info);
|
||||
switch (fmt.fmt.pix.colorspace)
|
||||
{
|
||||
case V4L2_COLORSPACE_SMPTE170M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 170M"); break;
|
||||
case V4L2_COLORSPACE_SMPTE240M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 240M"); break;
|
||||
case V4L2_COLORSPACE_BT878: ffStrbufInitStatic(&camera->colorspace, "BT.878"); break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_M: ffStrbufInitStatic(&camera->colorspace, "NTSC"); break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_BG: ffStrbufInitStatic(&camera->colorspace, "EBU 3213"); break;
|
||||
case V4L2_COLORSPACE_JPEG: ffStrbufInitStatic(&camera->colorspace, "JPEG"); break;
|
||||
case V4L2_COLORSPACE_REC709:
|
||||
case V4L2_COLORSPACE_SRGB: ffStrbufInitStatic(&camera->colorspace, "sRGB"); break;
|
||||
case 9 /* V4L2_COLORSPACE_OPRGB */: ffStrbufInitStatic(&camera->colorspace, "Adobe RGB"); break;
|
||||
case 10 /* V4L2_COLORSPACE_BT2020 */: ffStrbufInitStatic(&camera->colorspace, "BT.2020"); break;
|
||||
case 11 /* V4L2_COLORSPACE_RAW */: ffStrbufInitStatic(&camera->colorspace, "RAW"); break;
|
||||
case 12 /* V4L2_COLORSPACE_DCI_P3 */: ffStrbufInitStatic(&camera->colorspace, "DCI-P3"); break;
|
||||
default: ffStrbufInit(&camera->colorspace); break;
|
||||
switch (fmt.fmt.pix.colorspace) {
|
||||
case V4L2_COLORSPACE_SMPTE170M:
|
||||
ffStrbufInitStatic(&camera->colorspace, "SMPTE 170M");
|
||||
break;
|
||||
case V4L2_COLORSPACE_SMPTE240M:
|
||||
ffStrbufInitStatic(&camera->colorspace, "SMPTE 240M");
|
||||
break;
|
||||
case V4L2_COLORSPACE_BT878:
|
||||
ffStrbufInitStatic(&camera->colorspace, "BT.878");
|
||||
break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_M:
|
||||
ffStrbufInitStatic(&camera->colorspace, "NTSC");
|
||||
break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_BG:
|
||||
ffStrbufInitStatic(&camera->colorspace, "EBU 3213");
|
||||
break;
|
||||
case V4L2_COLORSPACE_JPEG:
|
||||
ffStrbufInitStatic(&camera->colorspace, "JPEG");
|
||||
break;
|
||||
case V4L2_COLORSPACE_REC709:
|
||||
case V4L2_COLORSPACE_SRGB:
|
||||
ffStrbufInitStatic(&camera->colorspace, "sRGB");
|
||||
break;
|
||||
case 9 /* V4L2_COLORSPACE_OPRGB */:
|
||||
ffStrbufInitStatic(&camera->colorspace, "Adobe RGB");
|
||||
break;
|
||||
case 10 /* V4L2_COLORSPACE_BT2020 */:
|
||||
ffStrbufInitStatic(&camera->colorspace, "BT.2020");
|
||||
break;
|
||||
case 11 /* V4L2_COLORSPACE_RAW */:
|
||||
ffStrbufInitStatic(&camera->colorspace, "RAW");
|
||||
break;
|
||||
case 12 /* V4L2_COLORSPACE_DCI_P3 */:
|
||||
ffStrbufInitStatic(&camera->colorspace, "DCI-P3");
|
||||
break;
|
||||
default:
|
||||
ffStrbufInit(&camera->colorspace);
|
||||
break;
|
||||
}
|
||||
camera->width = fmt.fmt.pix.width;
|
||||
camera->height = fmt.fmt.pix.height;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "camera.h"
|
||||
|
||||
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result) {
|
||||
return "Not support on this platform";
|
||||
}
|
||||
|
||||
@@ -10,42 +10,43 @@ extern "C" {
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
|
||||
extern "C"
|
||||
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
{
|
||||
extern "C" const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(mfplat, "mfplat" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes)
|
||||
FF_LIBRARY_LOAD_MESSAGE(mf, "mf" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mf, MFEnumDeviceSources)
|
||||
|
||||
const char* error = ffInitCom();
|
||||
if (error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
IMFAttributes* FF_AUTO_RELEASE_COM_OBJECT attrs = nullptr;
|
||||
if (FAILED(ffMFCreateAttributes(&attrs, 1)))
|
||||
if (FAILED(ffMFCreateAttributes(&attrs, 1))) {
|
||||
return "MFCreateAttributes() failed";
|
||||
}
|
||||
|
||||
if (FAILED(attrs->SetGUID(
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
|
||||
)))
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID))) {
|
||||
return "SetGUID(MF_*) failed";
|
||||
}
|
||||
|
||||
IMFActivate** devices = NULL;
|
||||
uint32_t count;
|
||||
|
||||
if (FAILED(ffMFEnumDeviceSources(attrs, &devices, &count)))
|
||||
if (FAILED(ffMFEnumDeviceSources(attrs, &devices, &count))) {
|
||||
return "MFEnumDeviceSources() failed";
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
IMFActivate* FF_AUTO_RELEASE_COM_OBJECT device = devices[i];
|
||||
|
||||
wchar_t buffer[256];
|
||||
uint32_t length = 0;
|
||||
if (FAILED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buffer, ARRAY_SIZE(buffer), &length)) || length == 0)
|
||||
if (FAILED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buffer, ARRAY_SIZE(buffer), &length)) || length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
|
||||
ffStrbufInitNWS(&camera->name, length, buffer);
|
||||
@@ -55,60 +56,85 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
camera->width = 0;
|
||||
camera->height = 0;
|
||||
|
||||
if (SUCCEEDED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buffer, ARRAY_SIZE(buffer), &length)) && length > 0)
|
||||
if (SUCCEEDED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buffer, ARRAY_SIZE(buffer), &length)) && length > 0) {
|
||||
ffStrbufSetNWS(&camera->id, length, buffer);
|
||||
}
|
||||
|
||||
IMFMediaSource* FF_AUTO_RELEASE_COM_OBJECT source = nullptr;
|
||||
if (FAILED(device->ActivateObject(IID_PPV_ARGS(&source))))
|
||||
if (FAILED(device->ActivateObject(IID_PPV_ARGS(&source)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
on_scope_exit destroySource([&] { source->Shutdown(); });
|
||||
|
||||
IMFPresentationDescriptor* FF_AUTO_RELEASE_COM_OBJECT pd = nullptr;
|
||||
if (FAILED(source->CreatePresentationDescriptor(&pd)))
|
||||
if (FAILED(source->CreatePresentationDescriptor(&pd))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IMFStreamDescriptor* FF_AUTO_RELEASE_COM_OBJECT sd = NULL;
|
||||
BOOL selected;
|
||||
if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd)))
|
||||
if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IMFMediaTypeHandler* FF_AUTO_RELEASE_COM_OBJECT handler = NULL;
|
||||
if (FAILED(sd->GetMediaTypeHandler(&handler)))
|
||||
if (FAILED(sd->GetMediaTypeHandler(&handler))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD mediaTypeCount;
|
||||
if (FAILED(handler->GetMediaTypeCount(&mediaTypeCount)))
|
||||
if (FAILED(handler->GetMediaTypeCount(&mediaTypeCount))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assume first type is the maximum resolution
|
||||
IMFMediaType* type = NULL;
|
||||
for (DWORD idx = 0; SUCCEEDED(handler->GetMediaTypeByIndex(idx, &type)); ++idx)
|
||||
{
|
||||
for (DWORD idx = 0; SUCCEEDED(handler->GetMediaTypeByIndex(idx, &type)); ++idx) {
|
||||
on_scope_exit destroyType([=] { type->Release(); });
|
||||
|
||||
GUID majorType;
|
||||
if (FAILED(type->GetMajorType(&majorType)) || majorType != MFMediaType_Video)
|
||||
if (FAILED(type->GetMajorType(&majorType)) || majorType != MFMediaType_Video) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MFVideoPrimaries primaries;
|
||||
static_assert(sizeof(primaries) == sizeof(uint32_t), "");
|
||||
if (SUCCEEDED(type->GetUINT32(MF_MT_VIDEO_PRIMARIES, (uint32_t*) &primaries)))
|
||||
{
|
||||
switch (primaries)
|
||||
{
|
||||
case MFVideoPrimaries_BT709: ffStrbufSetStatic(&camera->colorspace, "sRGB"); break;
|
||||
case MFVideoPrimaries_BT470_2_SysM:
|
||||
case MFVideoPrimaries_BT470_2_SysBG: ffStrbufSetStatic(&camera->colorspace, "NTSC"); break;
|
||||
case MFVideoPrimaries_SMPTE170M: ffStrbufSetStatic(&camera->colorspace, "SMPTE 170M"); break;
|
||||
case MFVideoPrimaries_SMPTE240M: ffStrbufSetStatic(&camera->colorspace, "SMPTE 240M"); break;
|
||||
case MFVideoPrimaries_EBU3213: ffStrbufSetStatic(&camera->colorspace, "EBU 3213"); break;
|
||||
case MFVideoPrimaries_SMPTE_C: ffStrbufSetStatic(&camera->colorspace, "SMPTE C"); break;
|
||||
case MFVideoPrimaries_BT2020: ffStrbufSetStatic(&camera->colorspace, "BT.2020"); break;
|
||||
case MFVideoPrimaries_XYZ: ffStrbufSetStatic(&camera->colorspace, "XYZ"); break;
|
||||
case MFVideoPrimaries_DCI_P3: ffStrbufSetStatic(&camera->colorspace, "DCI-P3"); break;
|
||||
case MFVideoPrimaries_ACES: ffStrbufSetStatic(&camera->colorspace, "ACES"); break;
|
||||
default: break;
|
||||
if (SUCCEEDED(type->GetUINT32(MF_MT_VIDEO_PRIMARIES, (uint32_t*) &primaries))) {
|
||||
switch (primaries) {
|
||||
case MFVideoPrimaries_BT709:
|
||||
ffStrbufSetStatic(&camera->colorspace, "sRGB");
|
||||
break;
|
||||
case MFVideoPrimaries_BT470_2_SysM:
|
||||
case MFVideoPrimaries_BT470_2_SysBG:
|
||||
ffStrbufSetStatic(&camera->colorspace, "NTSC");
|
||||
break;
|
||||
case MFVideoPrimaries_SMPTE170M:
|
||||
ffStrbufSetStatic(&camera->colorspace, "SMPTE 170M");
|
||||
break;
|
||||
case MFVideoPrimaries_SMPTE240M:
|
||||
ffStrbufSetStatic(&camera->colorspace, "SMPTE 240M");
|
||||
break;
|
||||
case MFVideoPrimaries_EBU3213:
|
||||
ffStrbufSetStatic(&camera->colorspace, "EBU 3213");
|
||||
break;
|
||||
case MFVideoPrimaries_SMPTE_C:
|
||||
ffStrbufSetStatic(&camera->colorspace, "SMPTE C");
|
||||
break;
|
||||
case MFVideoPrimaries_BT2020:
|
||||
ffStrbufSetStatic(&camera->colorspace, "BT.2020");
|
||||
break;
|
||||
case MFVideoPrimaries_XYZ:
|
||||
ffStrbufSetStatic(&camera->colorspace, "XYZ");
|
||||
break;
|
||||
case MFVideoPrimaries_DCI_P3:
|
||||
ffStrbufSetStatic(&camera->colorspace, "DCI-P3");
|
||||
break;
|
||||
case MFVideoPrimaries_ACES:
|
||||
ffStrbufSetStatic(&camera->colorspace, "ACES");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +143,9 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
}
|
||||
}
|
||||
|
||||
if (devices) CoTaskMemFree(devices);
|
||||
if (devices) {
|
||||
CoTaskMemFree(devices);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1,47 +1,82 @@
|
||||
#include "chassis.h"
|
||||
|
||||
const char* ffChassisTypeToString(uint32_t type)
|
||||
{
|
||||
const char* ffChassisTypeToString(uint32_t type) {
|
||||
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf
|
||||
// 7.4.1 System Enclosure or Chassis Types
|
||||
switch (type & 0b01111111)
|
||||
{
|
||||
case 0x01: return "Other";
|
||||
case 0x02: return "Unknown";
|
||||
case 0x03: return "Desktop";
|
||||
case 0x04: return "Low Profile Desktop";
|
||||
case 0x05: return "Pizza Box";
|
||||
case 0x06: return "Mini Tower";
|
||||
case 0x07: return "Tower";
|
||||
case 0x08: return "Portable";
|
||||
case 0x09: return "Laptop";
|
||||
case 0x0A: return "Notebook";
|
||||
case 0x0B: return "Hand Held";
|
||||
case 0x0C: return "Docking Station";
|
||||
case 0x0D: return "All in One";
|
||||
case 0x0E: return "Sub Notebook";
|
||||
case 0x0F: return "Space-saving";
|
||||
case 0x10: return "Lunch Box";
|
||||
case 0x11: return "Main Server Chassis";
|
||||
case 0x12: return "Expansion Chassis";
|
||||
case 0x13: return "SubChassis";
|
||||
case 0x14: return "Bus Expansion Chassis";
|
||||
case 0x15: return "Peripheral Chassis";
|
||||
case 0x16: return "RAID Chassis";
|
||||
case 0x17: return "Rack Mount Chassis";
|
||||
case 0x18: return "Sealed-case PC";
|
||||
case 0x19: return "Multi-system chassis";
|
||||
case 0x1A: return "Compact PCI";
|
||||
case 0x1B: return "Advanced TCA";
|
||||
case 0x1C: return "Blade";
|
||||
case 0x1D: return "Mobile Workstation";
|
||||
case 0x1E: return "Tablet";
|
||||
case 0x1F: return "Convertible";
|
||||
case 0x20: return "Detachable";
|
||||
case 0x21: return "IoT Gateway";
|
||||
case 0x22: return "Embedded PC";
|
||||
case 0x23: return "Mini PC";
|
||||
case 0x24: return "Stick PC";
|
||||
default: return NULL;
|
||||
switch (type & 0b01111111) {
|
||||
case 0x01:
|
||||
return "Other";
|
||||
case 0x02:
|
||||
return "Unknown";
|
||||
case 0x03:
|
||||
return "Desktop";
|
||||
case 0x04:
|
||||
return "Low Profile Desktop";
|
||||
case 0x05:
|
||||
return "Pizza Box";
|
||||
case 0x06:
|
||||
return "Mini Tower";
|
||||
case 0x07:
|
||||
return "Tower";
|
||||
case 0x08:
|
||||
return "Portable";
|
||||
case 0x09:
|
||||
return "Laptop";
|
||||
case 0x0A:
|
||||
return "Notebook";
|
||||
case 0x0B:
|
||||
return "Hand Held";
|
||||
case 0x0C:
|
||||
return "Docking Station";
|
||||
case 0x0D:
|
||||
return "All in One";
|
||||
case 0x0E:
|
||||
return "Sub Notebook";
|
||||
case 0x0F:
|
||||
return "Space-saving";
|
||||
case 0x10:
|
||||
return "Lunch Box";
|
||||
case 0x11:
|
||||
return "Main Server Chassis";
|
||||
case 0x12:
|
||||
return "Expansion Chassis";
|
||||
case 0x13:
|
||||
return "SubChassis";
|
||||
case 0x14:
|
||||
return "Bus Expansion Chassis";
|
||||
case 0x15:
|
||||
return "Peripheral Chassis";
|
||||
case 0x16:
|
||||
return "RAID Chassis";
|
||||
case 0x17:
|
||||
return "Rack Mount Chassis";
|
||||
case 0x18:
|
||||
return "Sealed-case PC";
|
||||
case 0x19:
|
||||
return "Multi-system chassis";
|
||||
case 0x1A:
|
||||
return "Compact PCI";
|
||||
case 0x1B:
|
||||
return "Advanced TCA";
|
||||
case 0x1C:
|
||||
return "Blade";
|
||||
case 0x1D:
|
||||
return "Mobile Workstation";
|
||||
case 0x1E:
|
||||
return "Tablet";
|
||||
case 0x1F:
|
||||
return "Convertible";
|
||||
case 0x20:
|
||||
return "Detachable";
|
||||
case 0x21:
|
||||
return "IoT Gateway";
|
||||
case 0x22:
|
||||
return "Embedded PC";
|
||||
case 0x23:
|
||||
return "Mini PC";
|
||||
case 0x24:
|
||||
return "Stick PC";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/chassis/option.h"
|
||||
|
||||
typedef struct FFChassisResult
|
||||
{
|
||||
typedef struct FFChassisResult {
|
||||
FFstrbuf type;
|
||||
FFstrbuf serial;
|
||||
FFstrbuf vendor;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "chassis.h"
|
||||
#include "detection/host/host.h"
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
const char* ffDetectChassis(FFChassisResult* result) {
|
||||
FFHostResult host = {
|
||||
.family = ffStrbufCreate(),
|
||||
.name = ffStrbufCreate(),
|
||||
@@ -12,18 +11,20 @@ const char* ffDetectChassis(FFChassisResult* result)
|
||||
.uuid = ffStrbufCreate(),
|
||||
.vendor = ffStrbufCreate(),
|
||||
};
|
||||
if (ffDetectHost(&host) != NULL)
|
||||
if (ffDetectHost(&host) != NULL) {
|
||||
return "Failed to detect host";
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithS(&host.name, "MacBook "))
|
||||
if (ffStrbufStartsWithS(&host.name, "MacBook ")) {
|
||||
ffStrbufSetStatic(&result->type, "Laptop");
|
||||
else if (ffStrbufStartsWithS(&host.name, "Mac mini ") ||
|
||||
ffStrbufStartsWithS(&host.name, "Mac Studio "))
|
||||
} else if (ffStrbufStartsWithS(&host.name, "Mac mini ") ||
|
||||
ffStrbufStartsWithS(&host.name, "Mac Studio ")) {
|
||||
ffStrbufSetStatic(&result->type, "Mini PC");
|
||||
else if (ffStrbufStartsWithS(&host.name, "iMac "))
|
||||
} else if (ffStrbufStartsWithS(&host.name, "iMac ")) {
|
||||
ffStrbufSetStatic(&result->type, "All in One");
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetStatic(&result->type, "Desktop");
|
||||
}
|
||||
|
||||
ffStrbufSet(&result->vendor, &host.vendor);
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "common/settings.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
const char* ffDetectChassis(FFChassisResult* result) {
|
||||
// Unlike other platforms, `smbios.chassis.type` return display string directly on my machine
|
||||
ffSettingsGetFreeBSDKenv("smbios.chassis.type", &result->type);
|
||||
ffCleanUpSmbiosValue(&result->type);
|
||||
|
||||
@@ -4,37 +4,33 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type))
|
||||
{
|
||||
const char* ffDetectChassis(FFChassisResult* result) {
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type)) {
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_serial", "/sys/class/dmi/id/chassis_serial", &result->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
|
||||
|
||||
if(result->type.length)
|
||||
{
|
||||
if (result->type.length) {
|
||||
const char* typeStr = ffChassisTypeToString((uint32_t) ffStrbufToUInt(&result->type, 9999));
|
||||
if(typeStr)
|
||||
if (typeStr) {
|
||||
ffStrbufSetStatic(&result->type, typeStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Available on Asahi Linux
|
||||
uint32_t chassisType = 0;
|
||||
if (ffReadFileData("/sys/firmware/devicetree/base/smbios/smbios/chassis/chassis-type", sizeof(chassisType), &chassisType)) // big endian
|
||||
{
|
||||
chassisType = __builtin_bswap32(chassisType);
|
||||
const char* typeStr = ffChassisTypeToString(chassisType);
|
||||
if(typeStr)
|
||||
if (typeStr) {
|
||||
ffStrbufSetStatic(&result->type, typeStr);
|
||||
}
|
||||
|
||||
if(ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/chassis/manufacturer", &result->vendor) && result->vendor.length > 0)
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/smbios/smbios/chassis/manufacturer", &result->vendor) && result->vendor.length > 0) {
|
||||
ffStrbufTrimRight(&result->vendor, '\0');
|
||||
}
|
||||
else if(ffReadFileBuffer("/sys/firmware/devicetree/base/chassis-type", &result->type) && result->type.length > 0)
|
||||
{
|
||||
}
|
||||
} else if (ffReadFileBuffer("/sys/firmware/devicetree/base/chassis-type", &result->type) && result->type.length > 0) {
|
||||
ffStrbufTrimRight(&result->type, '\0');
|
||||
result->type.chars[0] = (char) toupper(result->type.chars[0]);
|
||||
}
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
#include "common/sysctl.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* chassis)
|
||||
{
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-type", &chassis->type) == NULL)
|
||||
const char* ffDetectChassis(FFChassisResult* chassis) {
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-type", &chassis->type) == NULL) {
|
||||
ffCleanUpSmbiosValue(&chassis->type);
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-version", &chassis->version) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-version", &chassis->version) == NULL) {
|
||||
ffCleanUpSmbiosValue(&chassis->version);
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-vendor", &chassis->vendor) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-vendor", &chassis->vendor) == NULL) {
|
||||
ffCleanUpSmbiosValue(&chassis->vendor);
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-serial", &chassis->serial) == NULL)
|
||||
}
|
||||
if (ffSysctlGetString("machdep.dmi.chassis-serial", &chassis->serial) == NULL) {
|
||||
ffCleanUpSmbiosValue(&chassis->serial);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "chassis.h"
|
||||
|
||||
const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result)
|
||||
{
|
||||
const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -2,43 +2,43 @@
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
// 7.4
|
||||
typedef struct FFSmbiosSystemEnclosure
|
||||
{
|
||||
typedef struct FFSmbiosSystemEnclosure {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Type; // varies
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Type; // varies
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTagNumber; // string
|
||||
|
||||
// 2.1+
|
||||
uint8_t BootupState; // enum
|
||||
uint8_t BootupState; // enum
|
||||
uint8_t PowerSupplyState; // enum
|
||||
uint8_t ThermalState; // enum
|
||||
uint8_t SecurityStatus; // enum
|
||||
uint8_t ThermalState; // enum
|
||||
uint8_t SecurityStatus; // enum
|
||||
|
||||
// 2.3+
|
||||
uint32_t OEMDefined; // varies
|
||||
uint8_t Height; // varies
|
||||
uint8_t NumberOfPowerCords; // varies
|
||||
uint32_t OEMDefined; // varies
|
||||
uint8_t Height; // varies
|
||||
uint8_t NumberOfPowerCords; // varies
|
||||
uint8_t ContainedElementCount; // varies
|
||||
uint8_t ContainedRecordLength; // varies
|
||||
uint8_t ContainedElements[]; // varies
|
||||
uint8_t ContainedElements[]; // varies
|
||||
} __attribute__((__packed__)) FFSmbiosSystemEnclosure;
|
||||
|
||||
static_assert(offsetof(FFSmbiosSystemEnclosure, ContainedElements) == 0x15,
|
||||
"FFSmbiosSystemEnclosure: Wrong struct alignment");
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
const char* ffDetectChassis(FFChassisResult* result) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) (*smbiosTable)[FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE];
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "System enclosure is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "common/processing.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
typedef struct FFCommandResultBundle
|
||||
{
|
||||
typedef struct FFCommandResultBundle {
|
||||
FFProcessHandle handle;
|
||||
const char* error;
|
||||
} FFCommandResultBundle;
|
||||
@@ -13,26 +12,25 @@ static FFlist commandQueue = {
|
||||
.elementSize = sizeof(FFCommandResultBundle),
|
||||
};
|
||||
|
||||
static const char* spawnProcess(FFCommandOptions* options, FFProcessHandle* handle)
|
||||
{
|
||||
if (options->text.length == 0)
|
||||
static const char* spawnProcess(FFCommandOptions* options, FFProcessHandle* handle) {
|
||||
if (options->text.length == 0) {
|
||||
return "No command text specified";
|
||||
}
|
||||
|
||||
return ffProcessSpawn(options->param.length ? (char* const[]){
|
||||
options->shell.chars,
|
||||
options->param.chars,
|
||||
options->text.chars,
|
||||
NULL
|
||||
} : (char* const[]){
|
||||
options->shell.chars,
|
||||
options->text.chars,
|
||||
NULL
|
||||
}, options->useStdErr, handle);
|
||||
return ffProcessSpawn(options->param.length ? (char* const[]) {
|
||||
options->shell.chars,
|
||||
options->param.chars,
|
||||
options->text.chars,
|
||||
NULL}
|
||||
: (char* const[]) {options->shell.chars, options->text.chars, NULL},
|
||||
options->useStdErr,
|
||||
handle);
|
||||
}
|
||||
|
||||
bool ffPrepareCommand(FFCommandOptions* options)
|
||||
{
|
||||
if (!options->parallel) return false;
|
||||
bool ffPrepareCommand(FFCommandOptions* options) {
|
||||
if (!options->parallel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FFCommandResultBundle* bundle = ffListAdd(&commandQueue);
|
||||
bundle->error = spawnProcess(options, &bundle->handle);
|
||||
@@ -40,20 +38,22 @@ bool ffPrepareCommand(FFCommandOptions* options)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result)
|
||||
{
|
||||
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result) {
|
||||
FFCommandResultBundle bundle = {};
|
||||
if (!options->parallel)
|
||||
if (!options->parallel) {
|
||||
bundle.error = spawnProcess(options, &bundle.handle);
|
||||
else if (!ffListShift(&commandQueue, &bundle))
|
||||
} else if (!ffListShift(&commandQueue, &bundle)) {
|
||||
return "[BUG] command queue is empty";
|
||||
}
|
||||
|
||||
if (bundle.error)
|
||||
if (bundle.error) {
|
||||
return bundle.error;
|
||||
}
|
||||
|
||||
bundle.error = ffProcessReadOutput(&bundle.handle, result);
|
||||
if (bundle.error)
|
||||
if (bundle.error) {
|
||||
return bundle.error;
|
||||
}
|
||||
|
||||
ffStrbufTrimRightSpace(result);
|
||||
return NULL;
|
||||
|
||||
+201
-188
@@ -2,111 +2,126 @@
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu);
|
||||
|
||||
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
const char* error = ffDetectCPUImpl(options, cpu);
|
||||
if (error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const char* removeStrings[] = {
|
||||
" CPU", " FPU", " APU", " Processor",
|
||||
" Dual-Core", " Quad-Core", " Six-Core", " Eight-Core", " Ten-Core",
|
||||
" 2-Core", " 4-Core", " 6-Core", " 8-Core", " 10-Core", " 12-Core", " 14-Core", " 16-Core"
|
||||
};
|
||||
" CPU", " FPU", " APU", " Processor", " Dual-Core", " Quad-Core", " Six-Core", " Eight-Core", " Ten-Core", " 2-Core", " 4-Core", " 6-Core", " 8-Core", " 10-Core", " 12-Core", " 14-Core", " 16-Core"};
|
||||
ffStrbufRemoveStrings(&cpu->name, ARRAY_SIZE(removeStrings), removeStrings);
|
||||
uint32_t radeonGraphics = ffStrbufFirstIndexS(&cpu->name, " w/ Radeon "); // w/ Radeon 780M Graphics
|
||||
if (radeonGraphics >= cpu->name.length)
|
||||
if (radeonGraphics >= cpu->name.length) {
|
||||
radeonGraphics = ffStrbufFirstIndexS(&cpu->name, " with Radeon ");
|
||||
if (radeonGraphics < cpu->name.length)
|
||||
}
|
||||
if (radeonGraphics < cpu->name.length) {
|
||||
ffStrbufSubstrBefore(&cpu->name, radeonGraphics);
|
||||
ffStrbufSubstrBeforeFirstC(&cpu->name, '@'); //Cut the speed output in the name as we append our own
|
||||
ffStrbufTrimRight(&cpu->name, ' '); //If we removed the @ in previous step there was most likely a space before it
|
||||
}
|
||||
ffStrbufSubstrBeforeFirstC(&cpu->name, '@'); // Cut the speed output in the name as we append our own
|
||||
ffStrbufTrimRight(&cpu->name, ' '); // If we removed the @ in previous step there was most likely a space before it
|
||||
ffStrbufRemoveDupWhitespaces(&cpu->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCPUAppleCodeToName(uint32_t code)
|
||||
{
|
||||
const char* ffCPUAppleCodeToName(uint32_t code) {
|
||||
// https://github.com/AsahiLinux/docs/wiki/Codenames
|
||||
switch (code)
|
||||
{
|
||||
case 8103: return "Apple M1";
|
||||
case 6000: return "Apple M1 Pro";
|
||||
case 6001: return "Apple M1 Max";
|
||||
case 6002: return "Apple M1 Ultra";
|
||||
case 8112: return "Apple M2";
|
||||
case 6020: return "Apple M2 Pro";
|
||||
case 6021: return "Apple M2 Max";
|
||||
case 6022: return "Apple M2 Ultra";
|
||||
case 8122: return "Apple M3";
|
||||
case 6030: return "Apple M3 Pro";
|
||||
switch (code) {
|
||||
case 8103:
|
||||
return "Apple M1";
|
||||
case 6000:
|
||||
return "Apple M1 Pro";
|
||||
case 6001:
|
||||
return "Apple M1 Max";
|
||||
case 6002:
|
||||
return "Apple M1 Ultra";
|
||||
case 8112:
|
||||
return "Apple M2";
|
||||
case 6020:
|
||||
return "Apple M2 Pro";
|
||||
case 6021:
|
||||
return "Apple M2 Max";
|
||||
case 6022:
|
||||
return "Apple M2 Ultra";
|
||||
case 8122:
|
||||
return "Apple M3";
|
||||
case 6030:
|
||||
return "Apple M3 Pro";
|
||||
case 6031:
|
||||
case 6034: return "Apple M3 Max";
|
||||
case 8132: return "Apple M4";
|
||||
case 6040: return "Apple M4 Pro";
|
||||
case 6041: return "Apple M4 Max";
|
||||
default: return NULL;
|
||||
case 6034:
|
||||
return "Apple M3 Max";
|
||||
case 8132:
|
||||
return "Apple M4";
|
||||
case 6040:
|
||||
return "Apple M4 Pro";
|
||||
case 6041:
|
||||
return "Apple M4 Max";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffCPUQualcommCodeToName(uint32_t code)
|
||||
{
|
||||
const char* ffCPUQualcommCodeToName(uint32_t code) {
|
||||
// https://github.com/AsahiLinux/docs/wiki/Codenames
|
||||
switch (code)
|
||||
{
|
||||
case 7180: return "Qualcomm Snapdragon 7c";
|
||||
case 7280: return "Qualcomm Snapdragon 7c+ Gen 3";
|
||||
case 8180: return "Qualcomm Snapdragon 8cx Gen 2 5G";
|
||||
case 8280: return "Qualcomm Snapdragon 8cx Gen 3";
|
||||
default: return NULL;
|
||||
switch (code) {
|
||||
case 7180:
|
||||
return "Qualcomm Snapdragon 7c";
|
||||
case 7280:
|
||||
return "Qualcomm Snapdragon 7c+ Gen 3";
|
||||
case 8180:
|
||||
return "Qualcomm Snapdragon 8cx Gen 2 5G";
|
||||
case 8280:
|
||||
return "Qualcomm Snapdragon 8cx Gen 3";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
|
||||
#include <cpuid.h>
|
||||
# include <cpuid.h>
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu) {
|
||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
if (__get_cpuid(0x16, &eax, &ebx, &ecx, &edx))
|
||||
{
|
||||
if (__get_cpuid(0x16, &eax, &ebx, &ecx, &edx)) {
|
||||
// WARNING: CPUID may report frequencies of efficient cores
|
||||
// cpuid returns 0 MHz when hypervisor is enabled
|
||||
if (eax) cpu->frequencyBase = eax;
|
||||
if (ebx) cpu->frequencyMax = ebx;
|
||||
if (eax) {
|
||||
cpu->frequencyBase = eax;
|
||||
}
|
||||
if (ebx) {
|
||||
cpu->frequencyMax = ebx;
|
||||
}
|
||||
}
|
||||
|
||||
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx))
|
||||
{
|
||||
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
||||
// Feature tests (leaf1.ecx, leaf7.ebx)
|
||||
bool sse2 = (ecx & bit_SSE2) != 0;
|
||||
bool sse4_2 = (ecx & bit_SSE4_2) != 0;
|
||||
bool pclmul = (ecx & bit_PCLMUL) != 0;
|
||||
bool popcnt = (ecx & bit_POPCNT) != 0;
|
||||
bool fma = (ecx & bit_FMA) != 0;
|
||||
bool osxsave = (ecx & bit_OSXSAVE) != 0;
|
||||
bool sse2 = (ecx & bit_SSE2) != 0;
|
||||
bool sse4_2 = (ecx & bit_SSE4_2) != 0;
|
||||
bool pclmul = (ecx & bit_PCLMUL) != 0;
|
||||
bool popcnt = (ecx & bit_POPCNT) != 0;
|
||||
bool fma = (ecx & bit_FMA) != 0;
|
||||
bool osxsave = (ecx & bit_OSXSAVE) != 0;
|
||||
|
||||
unsigned int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0;
|
||||
__get_cpuid_count(7, 0, &eax7, &ebx7, &ecx7, &edx7);
|
||||
|
||||
bool avx2 = (ebx7 & bit_AVX2) != 0;
|
||||
bool bmi2 = (ebx7 & bit_BMI2) != 0;
|
||||
bool avx512f = (ebx7 & bit_AVX512F) != 0;
|
||||
bool avx2 = (ebx7 & bit_AVX2) != 0;
|
||||
bool bmi2 = (ebx7 & bit_BMI2) != 0;
|
||||
bool avx512f = (ebx7 & bit_AVX512F) != 0;
|
||||
bool avx512bw = (ebx7 & bit_AVX512BW) != 0;
|
||||
bool avx512dq = (ebx7 & bit_AVX512DQ) != 0;
|
||||
|
||||
// OS support for AVX/AVX512: check XGETBV (requires OSXSAVE)
|
||||
bool avx_os = false;
|
||||
bool avx_os = false;
|
||||
bool avx512_os = false;
|
||||
if (osxsave)
|
||||
{
|
||||
if (osxsave) {
|
||||
__asm__ __volatile__(
|
||||
"xgetbv"
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: "c"(0)
|
||||
:
|
||||
);
|
||||
uint64_t xcr0 = ((uint64_t)edx << 32) | eax;
|
||||
:);
|
||||
uint64_t xcr0 = ((uint64_t) edx << 32) | eax;
|
||||
|
||||
// AVX requires XCR0[1:2] == 11b (XMM and YMM state)
|
||||
avx_os = (xcr0 & 0x6ULL) == 0x6ULL;
|
||||
@@ -115,10 +130,15 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
}
|
||||
|
||||
cpu->march = "unknown";
|
||||
if (avx512f && avx512bw && avx512dq && avx512_os) cpu->march = "x86_64-v4";
|
||||
else if (avx2 && fma && bmi2 && avx_os) cpu->march = "x86_64-v3";
|
||||
else if (sse4_2 && popcnt && pclmul) cpu->march = "x86_64-v2";
|
||||
else if (sse2) cpu->march = "x86_64-v1";
|
||||
if (avx512f && avx512bw && avx512dq && avx512_os) {
|
||||
cpu->march = "x86_64-v4";
|
||||
} else if (avx2 && fma && bmi2 && avx_os) {
|
||||
cpu->march = "x86_64-v3";
|
||||
} else if (sse4_2 && popcnt && pclmul) {
|
||||
cpu->march = "x86_64-v2";
|
||||
} else if (sse2) {
|
||||
cpu->march = "x86_64-v1";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,33 +149,32 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
// https://en.wikipedia.org/wiki/AArch64#ARM-A_(application_architecture)
|
||||
// Worth noting: Apple M1 is marked as ARMv8.5-A on Wikipedia, but it lacks BTI (mandatory in v8.5)
|
||||
|
||||
#ifdef __linux__
|
||||
#include "common/io.h"
|
||||
#include <elf.h>
|
||||
# ifdef __linux__
|
||||
# include "common/io.h"
|
||||
# include <elf.h>
|
||||
// #include <asm/hwcap.h>
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu) {
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData("/proc/self/auxv", ARRAY_SIZE(buf), buf);
|
||||
|
||||
if (nRead < (ssize_t) sizeof(Elf64_auxv_t)) return;
|
||||
if (nRead < (ssize_t) sizeof(Elf64_auxv_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t hwcap = 0, hwcap2 = 0;
|
||||
|
||||
for (Elf64_auxv_t* auxv = (Elf64_auxv_t*)buf; (char*)auxv < buf + nRead; ++auxv)
|
||||
{
|
||||
if (auxv->a_type == AT_HWCAP)
|
||||
{
|
||||
for (Elf64_auxv_t* auxv = (Elf64_auxv_t*) buf; (char*) auxv < buf + nRead; ++auxv) {
|
||||
if (auxv->a_type == AT_HWCAP) {
|
||||
hwcap = auxv->a_un.a_val;
|
||||
}
|
||||
else if (auxv->a_type == AT_HWCAP2)
|
||||
{
|
||||
} else if (auxv->a_type == AT_HWCAP2) {
|
||||
hwcap2 = auxv->a_un.a_val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hwcap) return;
|
||||
if (!hwcap) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpu->march = "unknown";
|
||||
|
||||
@@ -164,31 +183,31 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
bool has_asimd = (hwcap & (1 << 1) /* HWCAP_ASIMD */) != 0;
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_atomics = (hwcap & (1 << 8) /* HWCAP_ATOMICS */) != 0; // optional from v8.0
|
||||
bool has_crc32 = (hwcap & (1 << 7) /* HWCAP_CRC32 */) != 0; // optional from v8.0
|
||||
bool has_atomics = (hwcap & (1 << 8) /* HWCAP_ATOMICS */) != 0; // optional from v8.0
|
||||
bool has_crc32 = (hwcap & (1 << 7) /* HWCAP_CRC32 */) != 0; // optional from v8.0
|
||||
bool has_asimdrdm = (hwcap & (1 << 12) /* HWCAP_ASIMDRDM */) != 0; // optional from v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fphp = (hwcap & (1 << 9) /* HWCAP_FPHP */) != 0; // optional
|
||||
bool has_fphp = (hwcap & (1 << 9) /* HWCAP_FPHP */) != 0; // optional
|
||||
bool has_dcpop = (hwcap & (1 << 16) /* HWCAP_DCPOP */) != 0; // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_paca = (hwcap & (1 << 30) /* HWCAP_PACA */) != 0; // optional from v8.2
|
||||
bool has_paca = (hwcap & (1 << 30) /* HWCAP_PACA */) != 0; // optional from v8.2
|
||||
bool has_lrcpc = (hwcap & (1 << 15) /* HWCAP_LRCPC */) != 0; // optional from v8.2
|
||||
bool has_fcma = (hwcap & (1 << 14) /* HWCAP_FCMA */) != 0; // optional from v8.2
|
||||
bool has_fcma = (hwcap & (1 << 14) /* HWCAP_FCMA */) != 0; // optional from v8.2
|
||||
bool has_jscvt = (hwcap & (1 << 13) /* HWCAP_JSCVT */) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_dit = (hwcap & (1 << 24) /* HWCAP_DIT */) != 0; // optional from v8.3
|
||||
bool has_flagm = (hwcap & (1 << 27) /* HWCAP_FLAGM */) != 0; // optional from v8.1
|
||||
bool has_dit = (hwcap & (1 << 24) /* HWCAP_DIT */) != 0; // optional from v8.3
|
||||
bool has_flagm = (hwcap & (1 << 27) /* HWCAP_FLAGM */) != 0; // optional from v8.1
|
||||
bool has_ilrcpc = (hwcap & (1 << 26) /* HWCAP_ILRCPC */) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = (hwcap2 & (1 << 17) /* HWCAP2_BTI */) != 0; // optional from v8.4
|
||||
bool has_sb = (hwcap & (1 << 29) /* HWCAP_SB */) != 0; // optional from v8.0
|
||||
bool has_bti = (hwcap2 & (1 << 17) /* HWCAP2_BTI */) != 0; // optional from v8.4
|
||||
bool has_sb = (hwcap & (1 << 29) /* HWCAP_SB */) != 0; // optional from v8.0
|
||||
bool has_dcpodp = (hwcap2 & (1 << 0) /* HWCAP2_DCPODP */) != 0; // optional from v8.1
|
||||
bool has_flagm2 = (hwcap2 & (1 << 7) /* HWCAP2_FLAGM2 */) != 0; // optional from v8.4
|
||||
bool has_frint = (hwcap2 & (1 << 8) /* HWCAP2_FRINT */) != 0; // optional from v8.4
|
||||
bool has_frint = (hwcap2 & (1 << 8) /* HWCAP2_FRINT */) != 0; // optional from v8.4
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = (hwcap2 & (1 << 1) /* HWCAP2_SVE2 */) != 0;
|
||||
@@ -221,7 +240,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
bool has_f8e5m2 = (hwcap2 & (1UL << 56) /* HWCAP2_F8E5M2 */) != 0; // optional from v9.2
|
||||
|
||||
// ARMv9.6-A
|
||||
bool has_cmpbr = (hwcap & (1UL << 33) /* HWCAP_CMPBR */) != 0; // optional from v9.5
|
||||
bool has_cmpbr = (hwcap & (1UL << 33) /* HWCAP_CMPBR */) != 0; // optional from v9.5
|
||||
bool has_fprcvt = (hwcap & (1UL << 34) /* HWCAP_FPRCVT */) != 0; // optional from v9.5
|
||||
|
||||
if (has_sve2 || has_sme) {
|
||||
@@ -266,77 +285,78 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif __APPLE__
|
||||
#include <sys/sysctl.h>
|
||||
# elif __APPLE__
|
||||
# include <sys/sysctl.h>
|
||||
// #include <arm/cpu_capabilities_public.h> // Not available in macOS 14-
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu) {
|
||||
uint64_t caps[2] = {0}; // 80-bit capability mask, split into two 64-bit values
|
||||
size_t size = sizeof(caps);
|
||||
|
||||
if (sysctlbyname("hw.optional.arm.caps", caps, &size, NULL, 0) != 0) return;
|
||||
if (sysctlbyname("hw.optional.arm.caps", caps, &size, NULL, 0) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper macro to test bit in 80-bit capability mask
|
||||
#define FF_HAS_CAP(bit) \
|
||||
(((bit) < 64) ? ((caps[0] >> (bit)) & 1ULL) : ((caps[1] >> ((bit) - 64U)) & 1ULL))
|
||||
// Helper macro to test bit in 80-bit capability mask
|
||||
# define FF_HAS_CAP(bit) \
|
||||
(((bit) < 64) ? ((caps[0] >> (bit)) & 1ULL) : ((caps[1] >> ((bit) - 64U)) & 1ULL))
|
||||
|
||||
cpu->march = "unknown";
|
||||
|
||||
// ARMv8-A
|
||||
bool has_fp = FF_HAS_CAP(50); /* CAP_BIT_AdvSIMD_HPFPCvt */ // Full FP16 support (implies FP/ASIMD)
|
||||
bool has_asimd = FF_HAS_CAP(49); /* CAP_BIT_AdvSIMD */ // Advanced SIMD (NEON)
|
||||
bool has_fp = FF_HAS_CAP(50); /* CAP_BIT_AdvSIMD_HPFPCvt */ // Full FP16 support (implies FP/ASIMD)
|
||||
bool has_asimd = FF_HAS_CAP(49); /* CAP_BIT_AdvSIMD */ // Advanced SIMD (NEON)
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_lse = FF_HAS_CAP(6); /* CAP_BIT_FEAT_LSE */ // Large System Extensions, optional in v8.0
|
||||
bool has_crc32 = FF_HAS_CAP(51); /* CAP_BIT_FEAT_CRC32 */ // CRC32 instructions, optional in v8.0
|
||||
bool has_rdm = FF_HAS_CAP(5); /* CAP_BIT_FEAT_RDM */ // AdvSIMD rounding double multiply accumulate, optional in v8.0
|
||||
bool has_lse = FF_HAS_CAP(6); /* CAP_BIT_FEAT_LSE */ // Large System Extensions, optional in v8.0
|
||||
bool has_crc32 = FF_HAS_CAP(51); /* CAP_BIT_FEAT_CRC32 */ // CRC32 instructions, optional in v8.0
|
||||
bool has_rdm = FF_HAS_CAP(5); /* CAP_BIT_FEAT_RDM */ // AdvSIMD rounding double multiply accumulate, optional in v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fp16 = FF_HAS_CAP(34); /* CAP_BIT_FEAT_FP16 */ // Half-precision FP support, optional
|
||||
bool has_dpb = FF_HAS_CAP(22); /* CAP_BIT_FEAT_DPB */ // DC CVAP, optional from v8.1
|
||||
bool has_fp16 = FF_HAS_CAP(34); /* CAP_BIT_FEAT_FP16 */ // Half-precision FP support, optional
|
||||
bool has_dpb = FF_HAS_CAP(22); /* CAP_BIT_FEAT_DPB */ // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_pauth = FF_HAS_CAP(19); /* CAP_BIT_FEAT_PAuth */ // Pointer Authentication (PAC), optional from v8.2
|
||||
bool has_lrcpc = FF_HAS_CAP(15); /* CAP_BIT_FEAT_LRCPC */ // LDAPR/LR with RCPC semantics, optional from v8.2
|
||||
bool has_fcma = FF_HAS_CAP(17); /* CAP_BIT_FEAT_FCMA */ // Complex number multiply-add, optional from v8.2
|
||||
bool has_jscvt = FF_HAS_CAP(18); /* CAP_BIT_FEAT_JSCVT */ // JavaScript-style conversion (FJCVTZS), optional from v8.2
|
||||
bool has_pauth = FF_HAS_CAP(19); /* CAP_BIT_FEAT_PAuth */ // Pointer Authentication (PAC), optional from v8.2
|
||||
bool has_lrcpc = FF_HAS_CAP(15); /* CAP_BIT_FEAT_LRCPC */ // LDAPR/LR with RCPC semantics, optional from v8.2
|
||||
bool has_fcma = FF_HAS_CAP(17); /* CAP_BIT_FEAT_FCMA */ // Complex number multiply-add, optional from v8.2
|
||||
bool has_jscvt = FF_HAS_CAP(18); /* CAP_BIT_FEAT_JSCVT */ // JavaScript-style conversion (FJCVTZS), optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_lse2 = FF_HAS_CAP(30); /* CAP_BIT_FEAT_LSE2 */ // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dit = FF_HAS_CAP(33); /* CAP_BIT_FEAT_DIT */ // Data Independent Timing, optional from v8.3
|
||||
bool has_flagm = FF_HAS_CAP(0); /* CAP_BIT_FEAT_FlagM */ // Flag manipulation (FMOV/FCVT), optional from v8.1
|
||||
bool has_lrcpc2 = FF_HAS_CAP(16); /* CAP_BIT_FEAT_LRCPC2 */ // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
|
||||
bool has_lse2 = FF_HAS_CAP(30); /* CAP_BIT_FEAT_LSE2 */ // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dit = FF_HAS_CAP(33); /* CAP_BIT_FEAT_DIT */ // Data Independent Timing, optional from v8.3
|
||||
bool has_flagm = FF_HAS_CAP(0); /* CAP_BIT_FEAT_FlagM */ // Flag manipulation (FMOV/FCVT), optional from v8.1
|
||||
bool has_lrcpc2 = FF_HAS_CAP(16); /* CAP_BIT_FEAT_LRCPC2 */ // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = FF_HAS_CAP(36); /* CAP_BIT_FEAT_BTI */ // Branch Target Identification, optional from v8.4
|
||||
bool has_sb = FF_HAS_CAP(13); /* CAP_BIT_FEAT_SB */ // Speculative Barrier, optional from v8.0
|
||||
bool has_dpb2 = FF_HAS_CAP(23); /* CAP_BIT_FEAT_DPB2 */ // DC CVADP (DPB2), optional from v8.1
|
||||
bool has_flagm2 = FF_HAS_CAP(1); /* CAP_BIT_FEAT_FlagM2 */ // Enhanced FlagM, optional from v8.4
|
||||
bool has_frintts = FF_HAS_CAP(14); /* CAP_BIT_FEAT_FRINTTS */ // Floating-point to integer instructions, optional from v8.4
|
||||
bool has_bti = FF_HAS_CAP(36); /* CAP_BIT_FEAT_BTI */ // Branch Target Identification, optional from v8.4
|
||||
bool has_sb = FF_HAS_CAP(13); /* CAP_BIT_FEAT_SB */ // Speculative Barrier, optional from v8.0
|
||||
bool has_dpb2 = FF_HAS_CAP(23); /* CAP_BIT_FEAT_DPB2 */ // DC CVADP (DPB2), optional from v8.1
|
||||
bool has_flagm2 = FF_HAS_CAP(1); /* CAP_BIT_FEAT_FlagM2 */ // Enhanced FlagM, optional from v8.4
|
||||
bool has_frintts = FF_HAS_CAP(14); /* CAP_BIT_FEAT_FRINTTS */ // Floating-point to integer instructions, optional from v8.4
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = false; // Not exposed and not supported by Apple M4
|
||||
bool has_sve2 = false; // Not exposed and not supported by Apple M4
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = FF_HAS_CAP(24); /* CAP_BIT_FEAT_BF16 */ // Brain float16, optional from v8.2
|
||||
bool has_i8mm = FF_HAS_CAP(25); /* CAP_BIT_FEAT_I8MM */ // Int8 Matrix Multiply, optional from v8.1
|
||||
bool has_bf16 = FF_HAS_CAP(24); /* CAP_BIT_FEAT_BF16 */ // Brain float16, optional from v8.2
|
||||
bool has_i8mm = FF_HAS_CAP(25); /* CAP_BIT_FEAT_I8MM */ // Int8 Matrix Multiply, optional from v8.1
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_afp = FF_HAS_CAP(29); /* CAP_BIT_FEAT_AFP */ // Alternate FP16 (FEXPA), optional from v8.6
|
||||
bool has_afp = FF_HAS_CAP(29); /* CAP_BIT_FEAT_AFP */ // Alternate FP16 (FEXPA), optional from v8.6
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = FF_HAS_CAP(40); /* CAP_BIT_FEAT_SME */ // Scalable Matrix Extension, optional from v9.2
|
||||
bool has_sme = FF_HAS_CAP(40); /* CAP_BIT_FEAT_SME */ // Scalable Matrix Extension, optional from v9.2
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = FF_HAS_CAP(41); /* CAP_BIT_FEAT_SME2 */ // SME2, optional from v9.2
|
||||
bool has_sme2 = FF_HAS_CAP(41); /* CAP_BIT_FEAT_SME2 */ // SME2, optional from v9.2
|
||||
|
||||
// ARMv8.8-A
|
||||
bool has_hbc = FF_HAS_CAP(64); /* CAP_BIT_FEAT_HBC */ // Hinted conditional branches, optional from v8.7
|
||||
bool has_hbc = FF_HAS_CAP(64); /* CAP_BIT_FEAT_HBC */ // Hinted conditional branches, optional from v8.7
|
||||
|
||||
// ARMv8.9-A
|
||||
bool has_cssc = FF_HAS_CAP(67); /* CAP_BIT_FEAT_CSSC */ // Common Short String Compare, optional from v8.7
|
||||
bool has_cssc = FF_HAS_CAP(67); /* CAP_BIT_FEAT_CSSC */ // Common Short String Compare, optional from v8.7
|
||||
|
||||
// ARMv9.4-A+ are not exposed yet
|
||||
|
||||
@@ -376,85 +396,82 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
}
|
||||
}
|
||||
|
||||
#undef HAS_CAP
|
||||
# undef HAS_CAP
|
||||
}
|
||||
#elif _WIN32
|
||||
#include <processthreadsapi.h>
|
||||
# elif _WIN32
|
||||
# include <processthreadsapi.h>
|
||||
|
||||
// Missing from winnt.h of MinGW-w64
|
||||
#define PF_ARM_LSE2_AVAILABLE 62
|
||||
#define PF_RESERVED_FEATURE 63
|
||||
#define PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE 64
|
||||
#define PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE 65
|
||||
#define PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE 66
|
||||
#define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67
|
||||
#define PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE 68
|
||||
#define PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE 69
|
||||
#define PF_ARM_SME_INSTRUCTIONS_AVAILABLE 70
|
||||
#define PF_ARM_SME2_INSTRUCTIONS_AVAILABLE 71
|
||||
#define PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE 72
|
||||
#define PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE 73
|
||||
#define PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE 74
|
||||
#define PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE 75
|
||||
#define PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE 76
|
||||
#define PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE 77
|
||||
#define PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE 78
|
||||
#define PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE 79
|
||||
#define PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE 80
|
||||
#define PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE 81
|
||||
#define PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE 82
|
||||
#define PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE 83
|
||||
#define PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE 84
|
||||
#define PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE 85
|
||||
#define PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE 86
|
||||
#define PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE 87
|
||||
#define PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE 88
|
||||
# define PF_ARM_LSE2_AVAILABLE 62
|
||||
# define PF_RESERVED_FEATURE 63
|
||||
# define PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE 64
|
||||
# define PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE 65
|
||||
# define PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE 66
|
||||
# define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67
|
||||
# define PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE 68
|
||||
# define PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE 69
|
||||
# define PF_ARM_SME_INSTRUCTIONS_AVAILABLE 70
|
||||
# define PF_ARM_SME2_INSTRUCTIONS_AVAILABLE 71
|
||||
# define PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE 72
|
||||
# define PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE 73
|
||||
# define PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE 74
|
||||
# define PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE 75
|
||||
# define PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE 76
|
||||
# define PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE 77
|
||||
# define PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE 78
|
||||
# define PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE 79
|
||||
# define PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE 80
|
||||
# define PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE 81
|
||||
# define PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE 82
|
||||
# define PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE 83
|
||||
# define PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE 84
|
||||
# define PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE 85
|
||||
# define PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE 86
|
||||
# define PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE 87
|
||||
# define PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE 88
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu) {
|
||||
// ARMv8-A
|
||||
bool has_vfp = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); // Implies basic FP support
|
||||
bool has_neon = IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); // NEON (ASIMD)
|
||||
bool has_vfp = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); // Implies basic FP support
|
||||
bool has_neon = IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); // NEON (ASIMD)
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_atomics = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); // LSE atomics
|
||||
bool has_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); // CRC32
|
||||
bool has_atomics = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); // LSE atomics
|
||||
bool has_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); // CRC32
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fp16 = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE); // Half-precision FP
|
||||
bool has_fp16 = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE); // Half-precision FP
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_lrcpc = IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE); // LDAPR/LR with RCPC semantics
|
||||
bool has_jscvt = IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); // FJCVTZS
|
||||
bool has_lrcpc = IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE); // LDAPR/LR with RCPC semantics
|
||||
bool has_jscvt = IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); // FJCVTZS
|
||||
|
||||
// ARMv8.4-A
|
||||
// My CPU (Apple M1 Pro in VM) does support LSE2, but Windows doesn't detect it for some reason
|
||||
bool has_lse2 = IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE); // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dp = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); // DotProd, optional from v8.1 (*)
|
||||
bool has_lse2 = IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE); // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dp = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); // DotProd, optional from v8.1 (*)
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE); // SVE2
|
||||
bool has_sve2 = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE); // SVE2
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE); // BF16, optional from v8.2
|
||||
bool has_i8mm = IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE); // Int8 matrix multiply, optional from v8.2
|
||||
bool has_bf16 = IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE); // BF16, optional from v8.2
|
||||
bool has_i8mm = IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE); // Int8 matrix multiply, optional from v8.2
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_ebf16 = IsProcessorFeaturePresent(PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE); // Extended BFloat16 behaviors, optional from v8.2
|
||||
bool has_ebf16 = IsProcessorFeaturePresent(PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE); // Extended BFloat16 behaviors, optional from v8.2
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE); // SME
|
||||
bool has_sme = IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE); // SME
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE); // SME2
|
||||
bool has_sme2 = IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE); // SME2
|
||||
|
||||
// ARMv9.4-A
|
||||
bool has_sme2p1 = IsProcessorFeaturePresent(PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE); // SME2.1
|
||||
bool has_sme2p1 = IsProcessorFeaturePresent(PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE); // SME2.1
|
||||
|
||||
|
||||
if (has_sve2 || has_sme)
|
||||
{
|
||||
if (has_sve2 || has_sme) {
|
||||
// ARMv9 family
|
||||
if (has_sme2p1) {
|
||||
cpu->march = "ARMv9.4-A";
|
||||
@@ -467,9 +484,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
} else {
|
||||
cpu->march = "ARMv9.0-A";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// ARMv8 family
|
||||
if (has_ebf16) {
|
||||
cpu->march = "ARMv8.7-A";
|
||||
@@ -488,17 +503,15 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
# else
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu) {
|
||||
// Unsupported system
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu) {
|
||||
// Unsupported architecture
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
|
||||
#define FF_CPU_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFCPUCore
|
||||
{
|
||||
typedef struct FFCPUCore {
|
||||
uint32_t freq;
|
||||
uint32_t count;
|
||||
} FFCPUCore;
|
||||
|
||||
typedef struct FFCPUResult
|
||||
{
|
||||
typedef struct FFCPUResult {
|
||||
FFstrbuf name;
|
||||
FFstrbuf vendor;
|
||||
const char* march; // Microarchitecture
|
||||
@@ -24,7 +22,7 @@ typedef struct FFCPUResult
|
||||
uint16_t numaNodes;
|
||||
|
||||
uint32_t frequencyBase; // GHz
|
||||
uint32_t frequencyMax; // GHz
|
||||
uint32_t frequencyMax; // GHz
|
||||
|
||||
FFCPUCore coreTypes[16]; // number of P cores, E cores, etc.
|
||||
|
||||
|
||||
@@ -3,106 +3,114 @@
|
||||
#include "common/apple/smc_temps.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
static double detectCpuTemp(const FFCPUOptions* options, const FFstrbuf* cpuName)
|
||||
{
|
||||
static double detectCpuTemp(const FFCPUOptions* options, const FFstrbuf* cpuName) {
|
||||
double result = 0;
|
||||
|
||||
const char* error = NULL;
|
||||
|
||||
if (options->tempSensor.length)
|
||||
{
|
||||
if (options->tempSensor.length) {
|
||||
error = ffDetectSmcSpecificTemp(options->tempSensor.chars, &result);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ffStrbufStartsWithS(cpuName, "Apple M"))
|
||||
{
|
||||
switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10))
|
||||
{
|
||||
case 1: error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result); break;
|
||||
case 2: error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result); break;
|
||||
case 3: error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result); break;
|
||||
case 4: error = ffDetectSmcTemps(FF_TEMP_CPU_M4X, &result); break;
|
||||
default: error = "Unsupported Apple Silicon CPU";
|
||||
} else {
|
||||
if (ffStrbufStartsWithS(cpuName, "Apple M")) {
|
||||
switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10)) {
|
||||
case 1:
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result);
|
||||
break;
|
||||
case 2:
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result);
|
||||
break;
|
||||
case 3:
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result);
|
||||
break;
|
||||
case 4:
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_M4X, &result);
|
||||
break;
|
||||
default:
|
||||
error = "Unsupported Apple Silicon CPU";
|
||||
}
|
||||
}
|
||||
else // PPC?
|
||||
} else { // PPC?
|
||||
error = ffDetectSmcTemps(FF_TEMP_CPU_X64, &result);
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include "common/apple/cf_helpers.h"
|
||||
# include "common/apple/cf_helpers.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
# include <IOKit/IOKitLib.h>
|
||||
|
||||
static const char* detectFrequency(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectFrequency(FFCPUResult* cpu) {
|
||||
// https://github.com/giampaolo/psutil/pull/2222/files
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
|
||||
if (!entryDevice)
|
||||
if (!entryDevice) {
|
||||
return "IOServiceGetMatchingService() failed";
|
||||
}
|
||||
|
||||
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice"))
|
||||
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice")) {
|
||||
return "\"pmgr\" should conform to \"AppleARMIODevice\"";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFDataRef freqProperty = (CFDataRef) IORegistryEntryCreateCFProperty(entryDevice, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, kNilOptions);
|
||||
if (!freqProperty || CFGetTypeID(freqProperty) != CFDataGetTypeID())
|
||||
if (!freqProperty || CFGetTypeID(freqProperty) != CFDataGetTypeID()) {
|
||||
return "\"voltage-states5-sram\" in \"pmgr\" is not found";
|
||||
}
|
||||
|
||||
// voltage-states5-sram stores supported <frequency / voltage> pairs of pcores from the lowest to the highest
|
||||
// voltage-states1-sram stores ecores'
|
||||
CFIndex propLength = CFDataGetLength(freqProperty);
|
||||
if (propLength == 0 || propLength % (CFIndex) sizeof(uint32_t) * 2 != 0)
|
||||
if (propLength == 0 || propLength % (CFIndex) sizeof(uint32_t) * 2 != 0) {
|
||||
return "Invalid \"voltage-states5-sram\" length";
|
||||
}
|
||||
|
||||
uint32_t* pStart = (uint32_t*) CFDataGetBytePtr(freqProperty);
|
||||
uint32_t pMax = *pStart;
|
||||
for (CFIndex i = 2; i < propLength / (CFIndex) sizeof(uint32_t) && pStart[i] > 0; i += 2 /* skip voltage */)
|
||||
for (CFIndex i = 2; i < propLength / (CFIndex) sizeof(uint32_t) && pStart[i] > 0; i += 2 /* skip voltage */) {
|
||||
pMax = pMax > pStart[i] ? pMax : pStart[i];
|
||||
}
|
||||
|
||||
if (pMax > 0)
|
||||
{
|
||||
if (pMax > 100000000) // Assume that pMax is in Hz, M1~M3
|
||||
if (pMax > 0) {
|
||||
if (pMax > 100000000) { // Assume that pMax is in Hz, M1~M3
|
||||
cpu->frequencyMax = pMax / 1000 / 1000;
|
||||
else // Assume that pMax is in kHz, M4 and later (#1394)
|
||||
} else { // Assume that pMax is in kHz, M4 and later (#1394)
|
||||
cpu->frequencyMax = pMax / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static const char* detectFrequency(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectFrequency(FFCPUResult* cpu) {
|
||||
cpu->frequencyBase = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency", 0) / 1000 / 1000);
|
||||
cpu->frequencyMax = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000 / 1000);
|
||||
if(cpu->frequencyBase == 0)
|
||||
{
|
||||
if (cpu->frequencyBase == 0) {
|
||||
unsigned current = 0;
|
||||
size_t size = sizeof(current);
|
||||
if (sysctl((int[]){ CTL_HW, HW_CPU_FREQ }, 2, ¤t, &size, NULL, 0) == 0)
|
||||
if (sysctl((int[]) {CTL_HW, HW_CPU_FREQ}, 2, ¤t, &size, NULL, 0) == 0) {
|
||||
cpu->frequencyBase = (uint32_t) (current / 1000 / 1000);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* detectCoreCount(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectCoreCount(FFCPUResult* cpu) {
|
||||
uint32_t nPerfLevels = (uint32_t) ffSysctlGetInt("hw.nperflevels", 0);
|
||||
if (nPerfLevels <= 0) return "sysctl(hw.nperflevels) failed";
|
||||
if (nPerfLevels <= 0) {
|
||||
return "sysctl(hw.nperflevels) failed";
|
||||
}
|
||||
|
||||
char sysctlKey[] = "hw.perflevelN.logicalcpu";
|
||||
if (nPerfLevels > ARRAY_SIZE(cpu->coreTypes))
|
||||
if (nPerfLevels > ARRAY_SIZE(cpu->coreTypes)) {
|
||||
nPerfLevels = ARRAY_SIZE(cpu->coreTypes);
|
||||
for (uint32_t i = 0; i < nPerfLevels; ++i)
|
||||
{
|
||||
}
|
||||
for (uint32_t i = 0; i < nPerfLevels; ++i) {
|
||||
sysctlKey[strlen("hw.perflevel")] = (char) ('0' + i);
|
||||
cpu->coreTypes[i] = (FFCPUCore) {
|
||||
.freq = nPerfLevels - i,
|
||||
@@ -112,31 +120,37 @@ static const char* detectCoreCount(FFCPUResult* cpu)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString("machdep.cpu.brand_string", &cpu->name) != NULL)
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
if (ffSysctlGetString("machdep.cpu.brand_string", &cpu->name) != NULL) {
|
||||
return "sysctlbyname(machdep.cpu.brand_string) failed";
|
||||
}
|
||||
|
||||
ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor);
|
||||
cpu->packages = (uint16_t) ffSysctlGetInt("hw.packages", 1);
|
||||
if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple "))
|
||||
if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple ")) {
|
||||
ffStrbufAppendS(&cpu->vendor, "Apple");
|
||||
}
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu_max", 1);
|
||||
if(cpu->coresPhysical == 1)
|
||||
if (cpu->coresPhysical == 1) {
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu", 1);
|
||||
}
|
||||
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.logicalcpu_max", 1);
|
||||
if(cpu->coresLogical == 1)
|
||||
if (cpu->coresLogical == 1) {
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
}
|
||||
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.logicalcpu", 1);
|
||||
if(cpu->coresOnline == 1)
|
||||
if (cpu->coresOnline == 1) {
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1);
|
||||
}
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
detectFrequency(cpu);
|
||||
if (options->showPeCoreCount) detectCoreCount(cpu);
|
||||
if (options->showPeCoreCount) {
|
||||
detectCoreCount(cpu);
|
||||
}
|
||||
|
||||
cpu->temperature = options->temp ? detectCpuTemp(options, &cpu->name) : FF_CPU_TEMP_UNSET;
|
||||
|
||||
|
||||
+528
-318
@@ -5,374 +5,584 @@
|
||||
// https://github.com/util-linux/util-linux/blob/master/sys-utils/lscpu-arm.c
|
||||
// We use the util-linux's data but not its code. Call me if it violates util-linux's GPL license.
|
||||
|
||||
static const char* hwImplId2Vendor(uint32_t implId)
|
||||
{
|
||||
switch (implId)
|
||||
{
|
||||
case 0x41: return "ARM";
|
||||
case 0x42: return "Broadcom";
|
||||
case 0x43: return "Cavium";
|
||||
case 0x44: return "DEC";
|
||||
case 0x46: return "FUJITSU";
|
||||
case 0x48: return "HiSilicon";
|
||||
case 0x49: return "Infineon";
|
||||
case 0x4d: return "Motorola";
|
||||
case 0x4e: return "NVIDIA";
|
||||
case 0x50: return "APM";
|
||||
case 0x51: return "Qualcomm";
|
||||
case 0x53: return "Samsung";
|
||||
case 0x56: return "Marvell";
|
||||
case 0x61: return "Apple";
|
||||
case 0x66: return "Faraday";
|
||||
case 0x69: return "Intel";
|
||||
case 0x6D: return "Microsoft";
|
||||
case 0x70: return "Phytium";
|
||||
case 0xc0: return "Ampere";
|
||||
default: return "Unknown";
|
||||
static const char* hwImplId2Vendor(uint32_t implId) {
|
||||
switch (implId) {
|
||||
case 0x41:
|
||||
return "ARM";
|
||||
case 0x42:
|
||||
return "Broadcom";
|
||||
case 0x43:
|
||||
return "Cavium";
|
||||
case 0x44:
|
||||
return "DEC";
|
||||
case 0x46:
|
||||
return "FUJITSU";
|
||||
case 0x48:
|
||||
return "HiSilicon";
|
||||
case 0x49:
|
||||
return "Infineon";
|
||||
case 0x4d:
|
||||
return "Motorola";
|
||||
case 0x4e:
|
||||
return "NVIDIA";
|
||||
case 0x50:
|
||||
return "APM";
|
||||
case 0x51:
|
||||
return "Qualcomm";
|
||||
case 0x53:
|
||||
return "Samsung";
|
||||
case 0x56:
|
||||
return "Marvell";
|
||||
case 0x61:
|
||||
return "Apple";
|
||||
case 0x66:
|
||||
return "Faraday";
|
||||
case 0x69:
|
||||
return "Intel";
|
||||
case 0x6D:
|
||||
return "Microsoft";
|
||||
case 0x70:
|
||||
return "Phytium";
|
||||
case 0xc0:
|
||||
return "Ampere";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* armPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x810: return "ARM810";
|
||||
case 0x920: return "ARM920";
|
||||
case 0x922: return "ARM922";
|
||||
case 0x926: return "ARM926";
|
||||
case 0x940: return "ARM940";
|
||||
case 0x946: return "ARM946";
|
||||
case 0x966: return "ARM966";
|
||||
case 0xa20: return "ARM1020";
|
||||
case 0xa22: return "ARM1022";
|
||||
case 0xa26: return "ARM1026";
|
||||
case 0xb02: return "ARM11-MPCore";
|
||||
case 0xb36: return "ARM1136";
|
||||
case 0xb56: return "ARM1156";
|
||||
case 0xb76: return "ARM1176";
|
||||
case 0xc05: return "Cortex-A5";
|
||||
case 0xc07: return "Cortex-A7";
|
||||
case 0xc08: return "Cortex-A8";
|
||||
case 0xc09: return "Cortex-A9";
|
||||
case 0xc0d: return "Cortex-A17"; /* Originally A12 */
|
||||
case 0xc0f: return "Cortex-A15";
|
||||
case 0xc0e: return "Cortex-A17";
|
||||
case 0xc14: return "Cortex-R4";
|
||||
case 0xc15: return "Cortex-R5";
|
||||
case 0xc17: return "Cortex-R7";
|
||||
case 0xc18: return "Cortex-R8";
|
||||
case 0xc20: return "Cortex-M0";
|
||||
case 0xc21: return "Cortex-M1";
|
||||
case 0xc23: return "Cortex-M3";
|
||||
case 0xc24: return "Cortex-M4";
|
||||
case 0xc27: return "Cortex-M7";
|
||||
case 0xc60: return "Cortex-M0+";
|
||||
case 0xd01: return "Cortex-A32";
|
||||
case 0xd02: return "Cortex-A34";
|
||||
case 0xd03: return "Cortex-A53";
|
||||
case 0xd04: return "Cortex-A35";
|
||||
case 0xd05: return "Cortex-A55";
|
||||
case 0xd06: return "Cortex-A65";
|
||||
case 0xd07: return "Cortex-A57";
|
||||
case 0xd08: return "Cortex-A72";
|
||||
case 0xd09: return "Cortex-A73";
|
||||
case 0xd0a: return "Cortex-A75";
|
||||
case 0xd0b: return "Cortex-A76";
|
||||
case 0xd0c: return "Neoverse-N1";
|
||||
case 0xd0d: return "Cortex-A77";
|
||||
case 0xd0e: return "Cortex-A76AE";
|
||||
case 0xd13: return "Cortex-R52";
|
||||
case 0xd14: return "Cortex-R82AE";
|
||||
case 0xd15: return "Cortex-R82";
|
||||
case 0xd16: return "Cortex-R52+";
|
||||
case 0xd20: return "Cortex-M23";
|
||||
case 0xd21: return "Cortex-M33";
|
||||
case 0xd24: return "Cortex-M52";
|
||||
case 0xd22: return "Cortex-M55";
|
||||
case 0xd23: return "Cortex-M85";
|
||||
case 0xd40: return "Neoverse-V1";
|
||||
case 0xd41: return "Cortex-A78";
|
||||
case 0xd42: return "Cortex-A78AE";
|
||||
case 0xd43: return "Cortex-A65AE";
|
||||
case 0xd44: return "Cortex-X1";
|
||||
case 0xd46: return "Cortex-A510";
|
||||
case 0xd47: return "Cortex-A710";
|
||||
case 0xd48: return "Cortex-X2";
|
||||
case 0xd49: return "Neoverse-N2";
|
||||
case 0xd4a: return "Neoverse-E1";
|
||||
case 0xd4b: return "Cortex-A78C";
|
||||
case 0xd4c: return "Cortex-X1C";
|
||||
case 0xd4d: return "Cortex-A715";
|
||||
case 0xd4e: return "Cortex-X3";
|
||||
case 0xd4f: return "Neoverse-V2";
|
||||
case 0xd80: return "Cortex-A520";
|
||||
case 0xd81: return "Cortex-A720";
|
||||
case 0xd82: return "Cortex-X4";
|
||||
case 0xd83: return "Neoverse-V3AE";
|
||||
case 0xd84: return "Neoverse-V3";
|
||||
case 0xd85: return "Cortex-X925";
|
||||
case 0xd87: return "Cortex-A725";
|
||||
case 0xd88: return "Cortex-A520AE";
|
||||
case 0xd89: return "Cortex-A720AE";
|
||||
case 0xd8a: return "C1-Nano";
|
||||
case 0xd8b: return "C1-Pro";
|
||||
case 0xd8c: return "C1-Ultra";
|
||||
case 0xd8e: return "Neoverse-N3";
|
||||
case 0xd8f: return "Cortex-A320";
|
||||
case 0xd90: return "C1-Premium";
|
||||
default: return NULL;
|
||||
static const char* armPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x810:
|
||||
return "ARM810";
|
||||
case 0x920:
|
||||
return "ARM920";
|
||||
case 0x922:
|
||||
return "ARM922";
|
||||
case 0x926:
|
||||
return "ARM926";
|
||||
case 0x940:
|
||||
return "ARM940";
|
||||
case 0x946:
|
||||
return "ARM946";
|
||||
case 0x966:
|
||||
return "ARM966";
|
||||
case 0xa20:
|
||||
return "ARM1020";
|
||||
case 0xa22:
|
||||
return "ARM1022";
|
||||
case 0xa26:
|
||||
return "ARM1026";
|
||||
case 0xb02:
|
||||
return "ARM11-MPCore";
|
||||
case 0xb36:
|
||||
return "ARM1136";
|
||||
case 0xb56:
|
||||
return "ARM1156";
|
||||
case 0xb76:
|
||||
return "ARM1176";
|
||||
case 0xc05:
|
||||
return "Cortex-A5";
|
||||
case 0xc07:
|
||||
return "Cortex-A7";
|
||||
case 0xc08:
|
||||
return "Cortex-A8";
|
||||
case 0xc09:
|
||||
return "Cortex-A9";
|
||||
case 0xc0d:
|
||||
return "Cortex-A17"; /* Originally A12 */
|
||||
case 0xc0f:
|
||||
return "Cortex-A15";
|
||||
case 0xc0e:
|
||||
return "Cortex-A17";
|
||||
case 0xc14:
|
||||
return "Cortex-R4";
|
||||
case 0xc15:
|
||||
return "Cortex-R5";
|
||||
case 0xc17:
|
||||
return "Cortex-R7";
|
||||
case 0xc18:
|
||||
return "Cortex-R8";
|
||||
case 0xc20:
|
||||
return "Cortex-M0";
|
||||
case 0xc21:
|
||||
return "Cortex-M1";
|
||||
case 0xc23:
|
||||
return "Cortex-M3";
|
||||
case 0xc24:
|
||||
return "Cortex-M4";
|
||||
case 0xc27:
|
||||
return "Cortex-M7";
|
||||
case 0xc60:
|
||||
return "Cortex-M0+";
|
||||
case 0xd01:
|
||||
return "Cortex-A32";
|
||||
case 0xd02:
|
||||
return "Cortex-A34";
|
||||
case 0xd03:
|
||||
return "Cortex-A53";
|
||||
case 0xd04:
|
||||
return "Cortex-A35";
|
||||
case 0xd05:
|
||||
return "Cortex-A55";
|
||||
case 0xd06:
|
||||
return "Cortex-A65";
|
||||
case 0xd07:
|
||||
return "Cortex-A57";
|
||||
case 0xd08:
|
||||
return "Cortex-A72";
|
||||
case 0xd09:
|
||||
return "Cortex-A73";
|
||||
case 0xd0a:
|
||||
return "Cortex-A75";
|
||||
case 0xd0b:
|
||||
return "Cortex-A76";
|
||||
case 0xd0c:
|
||||
return "Neoverse-N1";
|
||||
case 0xd0d:
|
||||
return "Cortex-A77";
|
||||
case 0xd0e:
|
||||
return "Cortex-A76AE";
|
||||
case 0xd13:
|
||||
return "Cortex-R52";
|
||||
case 0xd14:
|
||||
return "Cortex-R82AE";
|
||||
case 0xd15:
|
||||
return "Cortex-R82";
|
||||
case 0xd16:
|
||||
return "Cortex-R52+";
|
||||
case 0xd20:
|
||||
return "Cortex-M23";
|
||||
case 0xd21:
|
||||
return "Cortex-M33";
|
||||
case 0xd24:
|
||||
return "Cortex-M52";
|
||||
case 0xd22:
|
||||
return "Cortex-M55";
|
||||
case 0xd23:
|
||||
return "Cortex-M85";
|
||||
case 0xd40:
|
||||
return "Neoverse-V1";
|
||||
case 0xd41:
|
||||
return "Cortex-A78";
|
||||
case 0xd42:
|
||||
return "Cortex-A78AE";
|
||||
case 0xd43:
|
||||
return "Cortex-A65AE";
|
||||
case 0xd44:
|
||||
return "Cortex-X1";
|
||||
case 0xd46:
|
||||
return "Cortex-A510";
|
||||
case 0xd47:
|
||||
return "Cortex-A710";
|
||||
case 0xd48:
|
||||
return "Cortex-X2";
|
||||
case 0xd49:
|
||||
return "Neoverse-N2";
|
||||
case 0xd4a:
|
||||
return "Neoverse-E1";
|
||||
case 0xd4b:
|
||||
return "Cortex-A78C";
|
||||
case 0xd4c:
|
||||
return "Cortex-X1C";
|
||||
case 0xd4d:
|
||||
return "Cortex-A715";
|
||||
case 0xd4e:
|
||||
return "Cortex-X3";
|
||||
case 0xd4f:
|
||||
return "Neoverse-V2";
|
||||
case 0xd80:
|
||||
return "Cortex-A520";
|
||||
case 0xd81:
|
||||
return "Cortex-A720";
|
||||
case 0xd82:
|
||||
return "Cortex-X4";
|
||||
case 0xd83:
|
||||
return "Neoverse-V3AE";
|
||||
case 0xd84:
|
||||
return "Neoverse-V3";
|
||||
case 0xd85:
|
||||
return "Cortex-X925";
|
||||
case 0xd87:
|
||||
return "Cortex-A725";
|
||||
case 0xd88:
|
||||
return "Cortex-A520AE";
|
||||
case 0xd89:
|
||||
return "Cortex-A720AE";
|
||||
case 0xd8a:
|
||||
return "C1-Nano";
|
||||
case 0xd8b:
|
||||
return "C1-Pro";
|
||||
case 0xd8c:
|
||||
return "C1-Ultra";
|
||||
case 0xd8e:
|
||||
return "Neoverse-N3";
|
||||
case 0xd8f:
|
||||
return "Cortex-A320";
|
||||
case 0xd90:
|
||||
return "C1-Premium";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* brcmPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x0f: return "Brahma-B15";
|
||||
case 0x100: return "Brahma-B53";
|
||||
case 0x516: return "ThunderX2";
|
||||
default: return NULL;
|
||||
static const char* brcmPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x0f:
|
||||
return "Brahma-B15";
|
||||
case 0x100:
|
||||
return "Brahma-B53";
|
||||
case 0x516:
|
||||
return "ThunderX2";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* decPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0xa10: return "SA110";
|
||||
case 0xa11: return "SA1100";
|
||||
default: return NULL;
|
||||
static const char* decPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0xa10:
|
||||
return "SA110";
|
||||
case 0xa11:
|
||||
return "SA1100";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* caviumPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x0a0: return "ThunderX";
|
||||
case 0x0a1: return "ThunderX-88XX";
|
||||
case 0x0a2: return "ThunderX-81XX";
|
||||
case 0x0a3: return "ThunderX-83XX";
|
||||
case 0x0af: return "ThunderX2-99xx";
|
||||
case 0x0b0: return "OcteonTX2";
|
||||
case 0x0b1: return "OcteonTX2-98XX";
|
||||
case 0x0b2: return "OcteonTX2-96XX";
|
||||
case 0x0b3: return "OcteonTX2-95XX";
|
||||
case 0x0b4: return "OcteonTX2-95XXN";
|
||||
case 0x0b5: return "OcteonTX2-95XXMM";
|
||||
case 0x0b6: return "OcteonTX2-95XXO";
|
||||
case 0x0b8: return "ThunderX3-T110";
|
||||
default: return NULL;
|
||||
static const char* caviumPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x0a0:
|
||||
return "ThunderX";
|
||||
case 0x0a1:
|
||||
return "ThunderX-88XX";
|
||||
case 0x0a2:
|
||||
return "ThunderX-81XX";
|
||||
case 0x0a3:
|
||||
return "ThunderX-83XX";
|
||||
case 0x0af:
|
||||
return "ThunderX2-99xx";
|
||||
case 0x0b0:
|
||||
return "OcteonTX2";
|
||||
case 0x0b1:
|
||||
return "OcteonTX2-98XX";
|
||||
case 0x0b2:
|
||||
return "OcteonTX2-96XX";
|
||||
case 0x0b3:
|
||||
return "OcteonTX2-95XX";
|
||||
case 0x0b4:
|
||||
return "OcteonTX2-95XXN";
|
||||
case 0x0b5:
|
||||
return "OcteonTX2-95XXMM";
|
||||
case 0x0b6:
|
||||
return "OcteonTX2-95XXO";
|
||||
case 0x0b8:
|
||||
return "ThunderX3-T110";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* apmPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x000: return "X-Gene";
|
||||
default: return NULL;
|
||||
static const char* apmPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x000:
|
||||
return "X-Gene";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* qcomPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x001: return "Oryon 1";
|
||||
case 0x002: return "Oryon 2";
|
||||
case 0x00f: return "Scorpion";
|
||||
case 0x02d: return "Scorpion";
|
||||
case 0x04d: return "Krait";
|
||||
case 0x06f: return "Krait";
|
||||
case 0x201: return "Kryo";
|
||||
case 0x205: return "Kryo";
|
||||
case 0x211: return "Kryo";
|
||||
case 0x800: return "Falkor-V1/Kryo";
|
||||
case 0x801: return "Kryo-V2";
|
||||
case 0x802: return "Kryo-3XX-Gold";
|
||||
case 0x803: return "Kryo-3XX-Silver";
|
||||
case 0x804: return "Kryo-4XX-Gold";
|
||||
case 0x805: return "Kryo-4XX-Silver";
|
||||
case 0xc00: return "Falkor";
|
||||
case 0xc01: return "Saphira";
|
||||
default: return NULL;
|
||||
static const char* qcomPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x001:
|
||||
return "Oryon 1";
|
||||
case 0x002:
|
||||
return "Oryon 2";
|
||||
case 0x00f:
|
||||
return "Scorpion";
|
||||
case 0x02d:
|
||||
return "Scorpion";
|
||||
case 0x04d:
|
||||
return "Krait";
|
||||
case 0x06f:
|
||||
return "Krait";
|
||||
case 0x201:
|
||||
return "Kryo";
|
||||
case 0x205:
|
||||
return "Kryo";
|
||||
case 0x211:
|
||||
return "Kryo";
|
||||
case 0x800:
|
||||
return "Falkor-V1/Kryo";
|
||||
case 0x801:
|
||||
return "Kryo-V2";
|
||||
case 0x802:
|
||||
return "Kryo-3XX-Gold";
|
||||
case 0x803:
|
||||
return "Kryo-3XX-Silver";
|
||||
case 0x804:
|
||||
return "Kryo-4XX-Gold";
|
||||
case 0x805:
|
||||
return "Kryo-4XX-Silver";
|
||||
case 0xc00:
|
||||
return "Falkor";
|
||||
case 0xc01:
|
||||
return "Saphira";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* samsungPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x001: return "Exynos-M1";
|
||||
case 0x002: return "Exynos-M3";
|
||||
case 0x003: return "Exynos-M4";
|
||||
case 0x004: return "Exynos-M5";
|
||||
default: return NULL;
|
||||
static const char* samsungPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x001:
|
||||
return "Exynos-M1";
|
||||
case 0x002:
|
||||
return "Exynos-M3";
|
||||
case 0x003:
|
||||
return "Exynos-M4";
|
||||
case 0x004:
|
||||
return "Exynos-M5";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* nvidiaPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x000: return "Denver";
|
||||
case 0x003: return "Denver-2";
|
||||
case 0x004: return "Carmel";
|
||||
case 0x010: return "Olympus";
|
||||
default: return NULL;
|
||||
static const char* nvidiaPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x000:
|
||||
return "Denver";
|
||||
case 0x003:
|
||||
return "Denver-2";
|
||||
case 0x004:
|
||||
return "Carmel";
|
||||
case 0x010:
|
||||
return "Olympus";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* marvellPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x131: return "Feroceon-88FR131";
|
||||
case 0x581: return "PJ4/PJ4b";
|
||||
case 0x584: return "PJ4B-MP";
|
||||
default: return NULL;
|
||||
static const char* marvellPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x131:
|
||||
return "Feroceon-88FR131";
|
||||
case 0x581:
|
||||
return "PJ4/PJ4b";
|
||||
case 0x584:
|
||||
return "PJ4B-MP";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* applePartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x000: return "Swift";
|
||||
case 0x001: return "Cyclone";
|
||||
case 0x002: return "Typhoon";
|
||||
case 0x003: return "Typhoon/Capri";
|
||||
case 0x004: return "Twister";
|
||||
case 0x005: return "Twister/Elba/Malta";
|
||||
case 0x006: return "Hurricane";
|
||||
case 0x007: return "Hurricane/Myst";
|
||||
case 0x008: return "Monsoon";
|
||||
case 0x009: return "Mistral";
|
||||
case 0x00b: return "Vortex";
|
||||
case 0x00c: return "Tempest";
|
||||
case 0x00f: return "Tempest-M9";
|
||||
case 0x010: return "Vortex/Aruba";
|
||||
case 0x011: return "Tempest/Aruba";
|
||||
case 0x012: return "Lightning";
|
||||
case 0x013: return "Thunder";
|
||||
case 0x020: return "Icestorm-A14";
|
||||
case 0x021: return "Firestorm-A14";
|
||||
case 0x022: return "Icestorm-M1";
|
||||
case 0x023: return "Firestorm-M1";
|
||||
case 0x024: return "Icestorm-M1-Pro";
|
||||
case 0x025: return "Firestorm-M1-Pro";
|
||||
case 0x026: return "Thunder-M10";
|
||||
case 0x028: return "Icestorm-M1-Max";
|
||||
case 0x029: return "Firestorm-M1-Max";
|
||||
case 0x030: return "Blizzard-A15";
|
||||
case 0x031: return "Avalanche-A15";
|
||||
case 0x032: return "Blizzard-M2";
|
||||
case 0x033: return "Avalanche-M2";
|
||||
case 0x034: return "Blizzard-M2-Pro";
|
||||
case 0x035: return "Avalanche-M2-Pro";
|
||||
case 0x036: return "Sawtooth-A16";
|
||||
case 0x037: return "Everest-A16";
|
||||
case 0x038: return "Blizzard-M2-Max";
|
||||
case 0x039: return "Avalanche-M2-Max";
|
||||
case 0x046: return "Sawtooth-M11";
|
||||
case 0x048: return "Sawtooth-M3-Max";
|
||||
case 0x049: return "Everest-M3-Max";
|
||||
default: return NULL;
|
||||
static const char* applePartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x000:
|
||||
return "Swift";
|
||||
case 0x001:
|
||||
return "Cyclone";
|
||||
case 0x002:
|
||||
return "Typhoon";
|
||||
case 0x003:
|
||||
return "Typhoon/Capri";
|
||||
case 0x004:
|
||||
return "Twister";
|
||||
case 0x005:
|
||||
return "Twister/Elba/Malta";
|
||||
case 0x006:
|
||||
return "Hurricane";
|
||||
case 0x007:
|
||||
return "Hurricane/Myst";
|
||||
case 0x008:
|
||||
return "Monsoon";
|
||||
case 0x009:
|
||||
return "Mistral";
|
||||
case 0x00b:
|
||||
return "Vortex";
|
||||
case 0x00c:
|
||||
return "Tempest";
|
||||
case 0x00f:
|
||||
return "Tempest-M9";
|
||||
case 0x010:
|
||||
return "Vortex/Aruba";
|
||||
case 0x011:
|
||||
return "Tempest/Aruba";
|
||||
case 0x012:
|
||||
return "Lightning";
|
||||
case 0x013:
|
||||
return "Thunder";
|
||||
case 0x020:
|
||||
return "Icestorm-A14";
|
||||
case 0x021:
|
||||
return "Firestorm-A14";
|
||||
case 0x022:
|
||||
return "Icestorm-M1";
|
||||
case 0x023:
|
||||
return "Firestorm-M1";
|
||||
case 0x024:
|
||||
return "Icestorm-M1-Pro";
|
||||
case 0x025:
|
||||
return "Firestorm-M1-Pro";
|
||||
case 0x026:
|
||||
return "Thunder-M10";
|
||||
case 0x028:
|
||||
return "Icestorm-M1-Max";
|
||||
case 0x029:
|
||||
return "Firestorm-M1-Max";
|
||||
case 0x030:
|
||||
return "Blizzard-A15";
|
||||
case 0x031:
|
||||
return "Avalanche-A15";
|
||||
case 0x032:
|
||||
return "Blizzard-M2";
|
||||
case 0x033:
|
||||
return "Avalanche-M2";
|
||||
case 0x034:
|
||||
return "Blizzard-M2-Pro";
|
||||
case 0x035:
|
||||
return "Avalanche-M2-Pro";
|
||||
case 0x036:
|
||||
return "Sawtooth-A16";
|
||||
case 0x037:
|
||||
return "Everest-A16";
|
||||
case 0x038:
|
||||
return "Blizzard-M2-Max";
|
||||
case 0x039:
|
||||
return "Avalanche-M2-Max";
|
||||
case 0x046:
|
||||
return "Sawtooth-M11";
|
||||
case 0x048:
|
||||
return "Sawtooth-M3-Max";
|
||||
case 0x049:
|
||||
return "Everest-M3-Max";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* faradayPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x526: return "FA526";
|
||||
case 0x626: return "FA626";
|
||||
default: return NULL;
|
||||
static const char* faradayPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x526:
|
||||
return "FA526";
|
||||
case 0x626:
|
||||
return "FA626";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* intelPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x200: return "i80200";
|
||||
case 0x210: return "PXA250A";
|
||||
case 0x212: return "PXA210A";
|
||||
case 0x242: return "i80321-400";
|
||||
case 0x243: return "i80321-600";
|
||||
case 0x290: return "PXA250B/PXA26x";
|
||||
case 0x292: return "PXA210B";
|
||||
case 0x2c2: return "i80321-400-B0";
|
||||
case 0x2c3: return "i80321-600-B0";
|
||||
case 0x2d0: return "PXA250C/PXA255/PXA26x";
|
||||
case 0x2d2: return "PXA210C";
|
||||
case 0x411: return "PXA27x";
|
||||
case 0x41c: return "IPX425-533";
|
||||
case 0x41d: return "IPX425-400";
|
||||
case 0x41f: return "IPX425-266";
|
||||
case 0x682: return "PXA32x";
|
||||
case 0x683: return "PXA930/PXA935";
|
||||
case 0x688: return "PXA30x";
|
||||
case 0x689: return "PXA31x";
|
||||
case 0xb11: return "SA1110";
|
||||
case 0xc12: return "IPX1200";
|
||||
default: return NULL;
|
||||
static const char* intelPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x200:
|
||||
return "i80200";
|
||||
case 0x210:
|
||||
return "PXA250A";
|
||||
case 0x212:
|
||||
return "PXA210A";
|
||||
case 0x242:
|
||||
return "i80321-400";
|
||||
case 0x243:
|
||||
return "i80321-600";
|
||||
case 0x290:
|
||||
return "PXA250B/PXA26x";
|
||||
case 0x292:
|
||||
return "PXA210B";
|
||||
case 0x2c2:
|
||||
return "i80321-400-B0";
|
||||
case 0x2c3:
|
||||
return "i80321-600-B0";
|
||||
case 0x2d0:
|
||||
return "PXA250C/PXA255/PXA26x";
|
||||
case 0x2d2:
|
||||
return "PXA210C";
|
||||
case 0x411:
|
||||
return "PXA27x";
|
||||
case 0x41c:
|
||||
return "IPX425-533";
|
||||
case 0x41d:
|
||||
return "IPX425-400";
|
||||
case 0x41f:
|
||||
return "IPX425-266";
|
||||
case 0x682:
|
||||
return "PXA32x";
|
||||
case 0x683:
|
||||
return "PXA930/PXA935";
|
||||
case 0x688:
|
||||
return "PXA30x";
|
||||
case 0x689:
|
||||
return "PXA31x";
|
||||
case 0xb11:
|
||||
return "SA1110";
|
||||
case 0xc12:
|
||||
return "IPX1200";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* fujitsuPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x001: return "A64FX";
|
||||
case 0x003: return "MONAKA";
|
||||
default: return NULL;
|
||||
static const char* fujitsuPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x001:
|
||||
return "A64FX";
|
||||
case 0x003:
|
||||
return "MONAKA";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* hisiPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0xd01: return "TaiShan-v110"; /* used in Kunpeng-920 SoC */
|
||||
case 0xd02: return "TaiShan-v120"; /* used in Kirin 990A and 9000S SoCs */
|
||||
case 0xd40: return "Cortex-A76"; /* HiSilicon uses this ID though advertises A76 */
|
||||
case 0xd41: return "Cortex-A77"; /* HiSilicon uses this ID though advertises A77 */
|
||||
default: return NULL;
|
||||
static const char* hisiPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0xd01:
|
||||
return "TaiShan-v110"; /* used in Kunpeng-920 SoC */
|
||||
case 0xd02:
|
||||
return "TaiShan-v120"; /* used in Kirin 990A and 9000S SoCs */
|
||||
case 0xd40:
|
||||
return "Cortex-A76"; /* HiSilicon uses this ID though advertises A76 */
|
||||
case 0xd41:
|
||||
return "Cortex-A77"; /* HiSilicon uses this ID though advertises A77 */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* amperePartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0xac3: return "Ampere-1";
|
||||
case 0xac4: return "Ampere-1a";
|
||||
default: return NULL;
|
||||
static const char* amperePartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0xac3:
|
||||
return "Ampere-1";
|
||||
case 0xac4:
|
||||
return "Ampere-1a";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* ftPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0x303: return "FTC310";
|
||||
case 0x660: return "FTC660";
|
||||
case 0x661: return "FTC661";
|
||||
case 0x662: return "FTC662";
|
||||
case 0x663: return "FTC663";
|
||||
case 0x664: return "FTC664";
|
||||
case 0x862: return "FTC862";
|
||||
default: return NULL;
|
||||
static const char* ftPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0x303:
|
||||
return "FTC310";
|
||||
case 0x660:
|
||||
return "FTC660";
|
||||
case 0x661:
|
||||
return "FTC661";
|
||||
case 0x662:
|
||||
return "FTC662";
|
||||
case 0x663:
|
||||
return "FTC663";
|
||||
case 0x664:
|
||||
return "FTC664";
|
||||
case 0x862:
|
||||
return "FTC862";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* msPartId2name(uint32_t partId)
|
||||
{
|
||||
switch (partId)
|
||||
{
|
||||
case 0xd49: return "Azure-Cobalt-100";
|
||||
default: return NULL;
|
||||
static const char* msPartId2name(uint32_t partId) {
|
||||
switch (partId) {
|
||||
case 0xd49:
|
||||
return "Azure-Cobalt-100";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+32
-29
@@ -4,28 +4,25 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#if __has_include(<sys/cpuset.h>)
|
||||
#include <sys/cpuset.h>
|
||||
#define FF_HAVE_CPUSET 1
|
||||
# include <sys/cpuset.h>
|
||||
# define FF_HAVE_CPUSET 1
|
||||
#endif
|
||||
|
||||
static const char* detectCpuTemp(const FFCPUOptions* options, double* current)
|
||||
{
|
||||
static const char* detectCpuTemp(const FFCPUOptions* options, double* current) {
|
||||
int temp;
|
||||
if (options->tempSensor.length > 0)
|
||||
{
|
||||
if (options->tempSensor.length > 0) {
|
||||
temp = ffSysctlGetInt(options->tempSensor.chars, -999999);
|
||||
if (temp == -999999)
|
||||
if (temp == -999999) {
|
||||
return "ffSysctlGetInt(options->tempSensor) failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999);
|
||||
if (temp == -999999)
|
||||
{
|
||||
if (temp == -999999) {
|
||||
// Thermal zone temperature
|
||||
temp = ffSysctlGetInt("hw.acpi.thermal.tz0.temperature", -999999);
|
||||
if (temp == -999999)
|
||||
if (temp == -999999) {
|
||||
return "ffSysctlGetInt(\"dev.cpu.0.temperature\" or \"hw.acpi.thermal.tz0.temperature\") failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,18 +31,17 @@ static const char* detectCpuTemp(const FFCPUOptions* options, double* current)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString("hw.model", &cpu->name) != NULL)
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
if (ffSysctlGetString("hw.model", &cpu->name) != NULL) {
|
||||
return "sysctlbyname(hw.model) failed";
|
||||
}
|
||||
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0)
|
||||
{
|
||||
if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0) {
|
||||
// <groups>
|
||||
// <group level="1" cache-level="3">
|
||||
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
|
||||
@@ -61,8 +57,9 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
// </children>
|
||||
// </group>
|
||||
// </groups>
|
||||
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
|
||||
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p) {
|
||||
cpu->packages++;
|
||||
}
|
||||
}
|
||||
|
||||
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
|
||||
@@ -77,28 +74,34 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
|
||||
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
|
||||
if (clockrate > cpu->frequencyBase) {
|
||||
cpu->frequencyBase = clockrate;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < cpu->coresLogical; ++i)
|
||||
{
|
||||
for (uint16_t i = 0; i < cpu->coresLogical; ++i) {
|
||||
ffStrbufClear(&buffer);
|
||||
char key[32];
|
||||
snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
|
||||
if (ffSysctlGetString(key, &buffer) == NULL)
|
||||
{
|
||||
if (buffer.length == 0) continue;
|
||||
if (ffSysctlGetString(key, &buffer) == NULL) {
|
||||
if (buffer.length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
|
||||
uint32_t fmax = (uint32_t) strtoul(buffer.chars, NULL, 10);
|
||||
if (cpu->frequencyMax < fmax) cpu->frequencyMax = fmax;
|
||||
}
|
||||
else
|
||||
if (cpu->frequencyMax < fmax) {
|
||||
cpu->frequencyMax = fmax;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
if (options->temp) detectCpuTemp(options, &cpu->temperature);
|
||||
if (options->temp) {
|
||||
detectCpuTemp(options, &cpu->temperature);
|
||||
}
|
||||
|
||||
cpu->numaNodes = (uint16_t) ffSysctlGetInt("vm.ndomains", 0);
|
||||
|
||||
|
||||
@@ -4,28 +4,29 @@
|
||||
#include <OS.h>
|
||||
#include <private/shared/cpu_type.h>
|
||||
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
system_info sysInfo;
|
||||
if (get_system_info(&sysInfo) != B_OK)
|
||||
if (get_system_info(&sysInfo) != B_OK) {
|
||||
return "get_system_info() failed";
|
||||
}
|
||||
|
||||
uint32 topoNodeCount = 0;
|
||||
get_cpu_topology_info(NULL, &topoNodeCount);
|
||||
if (topoNodeCount == 0)
|
||||
if (topoNodeCount == 0) {
|
||||
return "get_cpu_topology_info(NULL) failed";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE cpu_topology_node_info* topology = malloc(sizeof(*topology) * topoNodeCount);
|
||||
if (get_cpu_topology_info(topology, &topoNodeCount) != B_OK)
|
||||
if (get_cpu_topology_info(topology, &topoNodeCount) != B_OK) {
|
||||
return "get_cpu_topology_info(topology) failed";
|
||||
}
|
||||
|
||||
enum cpu_platform platform = B_CPU_UNKNOWN;
|
||||
enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
|
||||
uint32 cpuModel = 0, frequency = 0;
|
||||
uint16_t packages = 0, cores = 0;
|
||||
|
||||
for (uint32 i = 0; i < topoNodeCount; i++)
|
||||
{
|
||||
for (uint32 i = 0; i < topoNodeCount; i++) {
|
||||
switch (topology[i].type) {
|
||||
case B_TOPOLOGY_ROOT:
|
||||
platform = topology[i].data.root.platform;
|
||||
@@ -48,15 +49,18 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
}
|
||||
}
|
||||
|
||||
const char *model = get_cpu_model_string(platform, cpuVendor, cpuModel);
|
||||
if (model)
|
||||
const char* model = get_cpu_model_string(platform, cpuVendor, cpuModel);
|
||||
if (model) {
|
||||
ffStrbufSetS(&cpu->name, model);
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetF(&cpu->name, "(Unknown %" B_PRIx32 ")", cpuModel);
|
||||
}
|
||||
ffStrbufSetS(&cpu->vendor, get_cpu_vendor_string(cpuVendor));
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
if (cpu->frequencyBase < frequency) cpu->frequencyBase = frequency;
|
||||
if (cpu->frequencyBase < frequency) {
|
||||
cpu->frequencyBase = frequency;
|
||||
}
|
||||
cpu->packages = packages;
|
||||
cpu->coresPhysical = cores;
|
||||
cpu->coresOnline = cpu->coresLogical = (uint16_t) sysInfo.cpu_count;
|
||||
|
||||
+517
-379
File diff suppressed because it is too large
Load Diff
@@ -9,66 +9,78 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static void freePropDict(prop_dictionary_t* pdict)
|
||||
{
|
||||
static void freePropDict(prop_dictionary_t* pdict) {
|
||||
assert(pdict != NULL);
|
||||
if (*pdict == NULL) return;
|
||||
if (*pdict == NULL) {
|
||||
return;
|
||||
}
|
||||
prop_object_release(*pdict);
|
||||
}
|
||||
|
||||
static const char* detectCpuTemp(const FFCPUOptions* options, double* current)
|
||||
{
|
||||
static const char* detectCpuTemp(const FFCPUOptions* options, double* current) {
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
if (fd < 0) {
|
||||
return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
}
|
||||
|
||||
__attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL;
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) {
|
||||
return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
|
||||
}
|
||||
|
||||
prop_array_t array;
|
||||
|
||||
if (options->tempSensor.length > 0)
|
||||
{
|
||||
if (options->tempSensor.length > 0) {
|
||||
array = prop_dictionary_get(root, options->tempSensor.chars);
|
||||
if (!array) return "No temp data found in specified sensor";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array) {
|
||||
return "No temp data found in specified sensor";
|
||||
}
|
||||
} else {
|
||||
array = prop_dictionary_get(root, "coretemp0");
|
||||
if (!array) array = prop_dictionary_get(root, "amdzentemp0");
|
||||
if (!array) array = prop_dictionary_get(root, "viac7temp0");
|
||||
if (!array) array = prop_dictionary_get(root, "acpitz0"); // Thermal Zones
|
||||
if (!array) return "No temp data found in root dictionary";
|
||||
if (!array) {
|
||||
array = prop_dictionary_get(root, "amdzentemp0");
|
||||
}
|
||||
if (!array) {
|
||||
array = prop_dictionary_get(root, "viac7temp0");
|
||||
}
|
||||
if (!array) {
|
||||
array = prop_dictionary_get(root, "acpitz0"); // Thermal Zones
|
||||
}
|
||||
if (!array) {
|
||||
return "No temp data found in root dictionary";
|
||||
}
|
||||
}
|
||||
|
||||
if (prop_array_count(array) != 2)
|
||||
if (prop_array_count(array) != 2) {
|
||||
return "Unexpected `xtemp0` data";
|
||||
}
|
||||
|
||||
prop_dictionary_t dict = prop_array_get(array, 0);
|
||||
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY)
|
||||
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) {
|
||||
return "Unexpected `xtemp0[0]`";
|
||||
}
|
||||
|
||||
int temp = 0; // in µK
|
||||
if (!prop_dictionary_get_int(dict, "cur-value", &temp))
|
||||
if (!prop_dictionary_get_int(dict, "cur-value", &temp)) {
|
||||
return "Failed to get temperature";
|
||||
}
|
||||
|
||||
*current = temp / 1e6 - 273.15;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("hw.model", &cpu->name) != NULL)
|
||||
{
|
||||
ffSysctlGetString("hw.model", &cpu->name) != NULL) {
|
||||
ffStrbufSetS(&cpu->name, "Unknown CPU");
|
||||
}
|
||||
|
||||
if (ffSysctlGetString("machdep.dmi.processor-vendor", &cpu->vendor) == NULL)
|
||||
if (ffSysctlGetString("machdep.dmi.processor-vendor", &cpu->vendor) == NULL) {
|
||||
ffStrbufTrimRightSpace(&cpu->vendor);
|
||||
}
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
@@ -77,13 +89,21 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
|
||||
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
|
||||
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
|
||||
if (freq == 0) {
|
||||
freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
}
|
||||
if (freq == 0) {
|
||||
freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
|
||||
}
|
||||
if (freq > cpu->frequencyBase) {
|
||||
cpu->frequencyBase = freq;
|
||||
}
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
if (options->temp) detectCpuTemp(options, &cpu->temperature);
|
||||
if (options->temp) {
|
||||
detectCpuTemp(options, &cpu->temperature);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "cpu.h"
|
||||
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FF_MAYBE_UNUSED FFCPUResult* cpu) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -6,48 +6,46 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/sensors.h>
|
||||
|
||||
static const char* detectCPUTemp(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectCPUTemp(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
|
||||
|
||||
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
|
||||
{
|
||||
for (mib[2] = 0; mib[2] < 1024; mib[2]++) {
|
||||
struct sensordev sensordev;
|
||||
size_t sdlen = sizeof(struct sensordev);
|
||||
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0) {
|
||||
if (errno == ENOENT) {
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
}
|
||||
if (errno == ENXIO) {
|
||||
continue;
|
||||
}
|
||||
return "sysctl(sensordev) failed";
|
||||
}
|
||||
|
||||
if (options->tempSensor.length > 0)
|
||||
{
|
||||
if (!ffStrbufEqualS(&options->tempSensor, sensordev.xname))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ffStrStartsWith(sensordev.xname, "cpu"))
|
||||
continue;
|
||||
}
|
||||
|
||||
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
|
||||
{
|
||||
struct sensor sensor;
|
||||
size_t slen = sizeof(struct sensor);
|
||||
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return "sysctl(sensor) failed";
|
||||
if (options->tempSensor.length > 0) {
|
||||
if (!ffStrbufEqualS(&options->tempSensor, sensordev.xname)) {
|
||||
continue;
|
||||
}
|
||||
if (sensor.flags & SENSOR_FINVALID)
|
||||
} else {
|
||||
if (!ffStrStartsWith(sensordev.xname, "cpu")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
|
||||
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++) {
|
||||
struct sensor sensor;
|
||||
size_t slen = sizeof(struct sensor);
|
||||
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0) {
|
||||
if (errno != ENOENT) {
|
||||
return "sysctl(sensor) failed";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sensor.flags & SENSOR_FINVALID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu->temperature = (double) (sensor.value - 273150000) / 1E6;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -55,10 +53,10 @@ static const char* detectCPUTemp(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
return "No sensor for CPU temp found";
|
||||
}
|
||||
|
||||
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name)) {
|
||||
return "sysctl(hw.model) failed";
|
||||
}
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt(CTL_HW, HW_NCPU, 1);
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
@@ -67,10 +65,14 @@ const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t cpuspeed = (uint32_t) ffSysctlGetInt(CTL_HW, HW_CPUSPEED, 0);
|
||||
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
|
||||
if (cpuspeed > cpu->frequencyBase) {
|
||||
cpu->frequencyBase = cpuspeed;
|
||||
}
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
if (options->temp) detectCPUTemp(options, cpu);
|
||||
if (options->temp) {
|
||||
detectCPUTemp(options, cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "common/stringUtils.h"
|
||||
#include <kstat.h>
|
||||
|
||||
static const char* detectCPUTempByKstat(const FFCPUOptions* options, kstat_ctl_t* kc, FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectCPUTempByKstat(const FFCPUOptions* options, kstat_ctl_t* kc, FFCPUResult* cpu) {
|
||||
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
|
||||
|
||||
if (options->tempSensor.length > 0) {
|
||||
@@ -19,10 +18,10 @@ static const char* detectCPUTempByKstat(const FFCPUOptions* options, kstat_ctl_t
|
||||
if (kn) {
|
||||
switch (kn->data_type) {
|
||||
case KSTAT_DATA_INT32:
|
||||
cpu->temperature = (float)kn->value.i32;
|
||||
cpu->temperature = (float) kn->value.i32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_UINT32:
|
||||
cpu->temperature = (float)kn->value.ui32;
|
||||
cpu->temperature = (float) kn->value.ui32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_FLOAT:
|
||||
cpu->temperature = kn->value.f;
|
||||
@@ -35,61 +34,53 @@ static const char* detectCPUTempByKstat(const FFCPUOptions* options, kstat_ctl_t
|
||||
return "Failed to find CPU temperature using kstat";
|
||||
}
|
||||
|
||||
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
"ipmitool",
|
||||
"-c",
|
||||
"sdr",
|
||||
"list",
|
||||
NULL
|
||||
});
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {"ipmitool", "-c", "sdr", "list", NULL});
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
|
||||
while (ffStrbufGetline(&line, &len, &buffer)) {
|
||||
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "ipmitool sdr list failed to find CPU temperature";
|
||||
}
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc) {
|
||||
assert(pkc);
|
||||
if (*pkc)
|
||||
if (*pkc) {
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
|
||||
{
|
||||
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type) {
|
||||
uint64_t low = 0, high = 0;
|
||||
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
|
||||
{
|
||||
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
|
||||
{
|
||||
if (kstat_read(kc, ksp, NULL) < 0)
|
||||
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
|
||||
if (ffStrStartsWith(ksp->ks_module, "cpu_info")) {
|
||||
if (kstat_read(kc, ksp, NULL) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kstat_named_t* stat = kstat_data_lookup(ksp, type);
|
||||
if (!stat)
|
||||
if (!stat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t id = 0;
|
||||
switch (stat->data_type)
|
||||
{
|
||||
#ifdef _INT64_TYPE
|
||||
switch (stat->data_type) {
|
||||
#ifdef _INT64_TYPE
|
||||
case KSTAT_DATA_INT64:
|
||||
case KSTAT_DATA_UINT64:
|
||||
id = (uint32_t) stat->value.ui64;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case KSTAT_DATA_INT32:
|
||||
case KSTAT_DATA_UINT32:
|
||||
id = stat->value.ui32;
|
||||
@@ -97,57 +88,66 @@ static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (__builtin_expect(id > 64, false))
|
||||
if (__builtin_expect(id > 64, false)) {
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
} else {
|
||||
low |= 1ULL << id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc)
|
||||
if (!kc) {
|
||||
return "kstat_open() failed";
|
||||
}
|
||||
|
||||
kstat_t* ks = kstat_lookup(kc, "cpu_info", -1, NULL);
|
||||
if (!ks)
|
||||
if (!ks) {
|
||||
return "kstat_lookup() failed";
|
||||
}
|
||||
|
||||
if (kstat_read(kc, ks, NULL) < 0)
|
||||
if (kstat_read(kc, ks, NULL) < 0) {
|
||||
return "kstat_read() failed";
|
||||
}
|
||||
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "brand");
|
||||
if (kn) ffStrbufSetNS(&cpu->name, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
if (kn) {
|
||||
ffStrbufSetNS(&cpu->name, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
}
|
||||
}
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "vendor_id");
|
||||
if (kn) ffStrbufSetNS(&cpu->vendor, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
if (kn) {
|
||||
ffStrbufSetNS(&cpu->vendor, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
}
|
||||
}
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "clock_MHz");
|
||||
if (kn && kn->value.ui32 > cpu->frequencyBase)
|
||||
if (kn && kn->value.ui32 > cpu->frequencyBase) {
|
||||
cpu->frequencyBase = kn->value.ui32;
|
||||
}
|
||||
}
|
||||
|
||||
ks = kstat_lookup(kc, "unix", -1, "system_misc");
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0) {
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
|
||||
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
if (kn) {
|
||||
cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
}
|
||||
}
|
||||
|
||||
cpu->packages = countTypeId(kc, "chip_id");
|
||||
cpu->coresPhysical = countTypeId(kc, "core_id");
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (detectCPUTempByKstat(options, kc, cpu) != NULL)
|
||||
if (options->temp) {
|
||||
if (detectCPUTempByKstat(options, kc, cpu) != NULL) {
|
||||
detectCPUTempByIpmiTool(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
+135
-123
@@ -9,26 +9,22 @@
|
||||
#include "common/windows/nt.h"
|
||||
#include <wchar.h>
|
||||
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
|
||||
{
|
||||
if (*phQuery != NULL)
|
||||
{
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery) {
|
||||
if (*phQuery != NULL) {
|
||||
PerfCloseQueryHandle(*phQuery);
|
||||
*phQuery = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* detectThermalTemp(const FFCPUOptions* options, double* result)
|
||||
{
|
||||
struct FFPerfQuerySpec
|
||||
{
|
||||
const char* detectThermalTemp(const FFCPUOptions* options, double* result) {
|
||||
struct FFPerfQuerySpec {
|
||||
PERF_COUNTER_IDENTIFIER Identifier;
|
||||
WCHAR Name[16];
|
||||
} querySpec = {
|
||||
.Identifier = {
|
||||
// Thermal Zone Information
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{52bc5412-dac2-449c-8bc2-96443888fe6b}
|
||||
.CounterSetGuid = { 0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b} },
|
||||
.CounterSetGuid = {0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b}},
|
||||
.Size = sizeof(querySpec),
|
||||
.CounterId = PERF_WILDCARD_COUNTER,
|
||||
.InstanceId = PERF_WILDCARD_COUNTER,
|
||||
@@ -36,43 +32,47 @@ const char* detectThermalTemp(const FFCPUOptions* options, double* result)
|
||||
.Name = L"\\_TZ.CPUZ", // The standard(?) instance name for CPU temperature in the thermal provider
|
||||
};
|
||||
|
||||
if (options->tempSensor.length > 0)
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(querySpec.Name, (ULONG) sizeof(querySpec.Name), NULL, options->tempSensor.chars, (ULONG)options->tempSensor.length + 1)))
|
||||
if (options->tempSensor.length > 0) {
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(querySpec.Name, (ULONG) sizeof(querySpec.Name), NULL, options->tempSensor.chars, (ULONG) options->tempSensor.length + 1))) {
|
||||
return "Invalid temp sensor string";
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dataSize = 0;
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY) {
|
||||
return "PerfEnumerateCounterSetInstances() failed";
|
||||
}
|
||||
|
||||
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
|
||||
if (dataSize <= sizeof(PERF_INSTANCE_HEADER)) {
|
||||
return "No `Thermal Zone Information` instances found";
|
||||
}
|
||||
|
||||
{
|
||||
FF_AUTO_FREE PERF_INSTANCE_HEADER* const pHead = malloc(dataSize);
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS) {
|
||||
return "PerfEnumerateCounterSetInstances() failed to get instance headers";
|
||||
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = pHead;
|
||||
while (1)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
if (wcscmp(instanceName, querySpec.Name) == 0)
|
||||
break;
|
||||
|
||||
dataSize -= pInstanceHeader->Size;
|
||||
if (dataSize == 0)
|
||||
break;
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
}
|
||||
|
||||
if (dataSize == 0)
|
||||
{
|
||||
if (options->tempSensor.length > 0)
|
||||
return "Unable to find CPU sensor";
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = pHead;
|
||||
while (1) {
|
||||
const wchar_t* instanceName = (const wchar_t*) ((BYTE*) pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
if (wcscmp(instanceName, querySpec.Name) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pHead + sizeof(*pHead));
|
||||
dataSize -= pInstanceHeader->Size;
|
||||
if (dataSize == 0) {
|
||||
break;
|
||||
}
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*) ((BYTE*) pInstanceHeader + pInstanceHeader->Size);
|
||||
}
|
||||
|
||||
if (dataSize == 0) {
|
||||
if (options->tempSensor.length > 0) {
|
||||
return "Unable to find CPU sensor";
|
||||
}
|
||||
|
||||
const wchar_t* instanceName = (const wchar_t*) ((BYTE*) pHead + sizeof(*pHead));
|
||||
wcscpy(querySpec.Name, instanceName); // Use the first instance name if the specific one is not found
|
||||
}
|
||||
}
|
||||
@@ -80,75 +80,80 @@ const char* detectThermalTemp(const FFCPUOptions* options, double* result)
|
||||
__attribute__((__cleanup__(ffPerfCloseQueryHandle)))
|
||||
HANDLE hQuery = NULL;
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS) {
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
}
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS) {
|
||||
return "PerfAddCounters() failed";
|
||||
}
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS) {
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
}
|
||||
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY) {
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
}
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) { // PERF_ERROR_RETURN, should not happen
|
||||
return "instance doesn't exist";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = malloc(dataSize);
|
||||
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS) {
|
||||
return "PerfQueryCounterData(pDataHeader) failed";
|
||||
}
|
||||
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS)
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*) (pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS) {
|
||||
return "Invalid counter type";
|
||||
}
|
||||
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*) (pCounterHeader + 1);
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*) ((BYTE*) pMultiCounters + pMultiCounters->dwSize);
|
||||
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
|
||||
{
|
||||
if (pCounterData->dwDataSize == sizeof(int32_t))
|
||||
{
|
||||
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
|
||||
int32_t value = *(int32_t*)(pCounterData + 1);
|
||||
if (value == 0)
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++) {
|
||||
if (pCounterData->dwDataSize == sizeof(int32_t)) {
|
||||
DWORD* pCounterIds = (DWORD*) (pMultiCounters + 1);
|
||||
int32_t value = *(int32_t*) (pCounterData + 1);
|
||||
if (value == 0) {
|
||||
return "Temperature data is zero";
|
||||
}
|
||||
|
||||
switch (pCounterIds[iCounter]) {
|
||||
case 0: // Temperature
|
||||
*result = value - 273;
|
||||
break;
|
||||
case 3: // High Precision Temperature
|
||||
*result = value / 10.0 - 273;
|
||||
break;
|
||||
case 0: // Temperature
|
||||
*result = value - 273;
|
||||
break;
|
||||
case 3: // High Precision Temperature
|
||||
*result = value / 10.0 - 273;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
|
||||
pCounterData = (PERF_COUNTER_DATA*) ((BYTE*) pCounterData + pCounterData->dwSize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 7.5
|
||||
typedef struct FFSmbiosProcessorInfo
|
||||
{
|
||||
typedef struct FFSmbiosProcessorInfo {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t SocketDesignation; // string
|
||||
uint8_t ProcessorType; // enum
|
||||
uint8_t ProcessorFamily; // enum
|
||||
uint8_t SocketDesignation; // string
|
||||
uint8_t ProcessorType; // enum
|
||||
uint8_t ProcessorFamily; // enum
|
||||
uint8_t ProcessorManufacturer; // string
|
||||
uint64_t ProcessorID; // varies
|
||||
uint8_t ProcessorVersion; // string
|
||||
uint8_t Voltage; // varies
|
||||
uint16_t ExternalClock; // varies
|
||||
uint16_t MaxSpeed; // varies
|
||||
uint16_t CurrentSpeed; // varies
|
||||
uint8_t Status; // varies
|
||||
uint8_t ProcessorUpgrade; // enum
|
||||
uint64_t ProcessorID; // varies
|
||||
uint8_t ProcessorVersion; // string
|
||||
uint8_t Voltage; // varies
|
||||
uint16_t ExternalClock; // varies
|
||||
uint16_t MaxSpeed; // varies
|
||||
uint16_t CurrentSpeed; // varies
|
||||
uint8_t Status; // varies
|
||||
uint8_t ProcessorUpgrade; // enum
|
||||
|
||||
// 2.1+
|
||||
uint16_t L1CacheHandle; // varies
|
||||
@@ -157,20 +162,20 @@ typedef struct FFSmbiosProcessorInfo
|
||||
|
||||
// 2.3+
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssertTag; // string
|
||||
uint8_t PartNumber; // string
|
||||
uint8_t AssertTag; // string
|
||||
uint8_t PartNumber; // string
|
||||
|
||||
// 2.5+
|
||||
uint8_t CoreCount; // varies
|
||||
uint8_t CoreEnabled; // varies
|
||||
uint8_t ThreadCount; // varies
|
||||
uint8_t CoreCount; // varies
|
||||
uint8_t CoreEnabled; // varies
|
||||
uint8_t ThreadCount; // varies
|
||||
uint16_t ProcessorCharacteristics; // bit field
|
||||
|
||||
// 2.6+
|
||||
uint16_t ProcessorFamily2; // enum
|
||||
|
||||
// 3.0+
|
||||
uint16_t CoreCount2; // varies
|
||||
uint16_t CoreCount2; // varies
|
||||
uint16_t CoreEnabled2; // varies
|
||||
uint16_t ThreadCount2; // varies
|
||||
|
||||
@@ -181,128 +186,135 @@ typedef struct FFSmbiosProcessorInfo
|
||||
static_assert(offsetof(FFSmbiosProcessorInfo, ThreadEnabled) == 0x30,
|
||||
"FFSmbiosProcessorInfo: Wrong struct alignment");
|
||||
|
||||
static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_PROCESSOR_INFO];
|
||||
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "Processor information is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
while (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/)
|
||||
{
|
||||
while (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/) {
|
||||
data = (const FFSmbiosProcessorInfo*) ffSmbiosNextEntry(&data->Header);
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_PROCESSOR_INFO)
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_PROCESSOR_INFO) {
|
||||
return "No active CPU is found in SMBIOS data";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t speed = data->MaxSpeed;
|
||||
// Sometimes SMBIOS reports invalid value. We assume that max speed is small than 2x of base
|
||||
if (speed < cpu->frequencyBase || speed > cpu->frequencyBase * 2)
|
||||
if (speed < cpu->frequencyBase || speed > cpu->frequencyBase * 2) {
|
||||
return "Possible invalid CPU max speed in SMBIOS data. See #800";
|
||||
}
|
||||
|
||||
cpu->frequencyMax = speed;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectNCores(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectNCores(FFCPUResult* cpu) {
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationAll;
|
||||
ULONG length = 0;
|
||||
NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length);
|
||||
if (length == 0)
|
||||
if (length == 0) {
|
||||
return "GetLogicalProcessorInformationEx(RelationAll, NULL, &length) failed";
|
||||
}
|
||||
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length);
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) malloc(length);
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length)))
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length))) {
|
||||
return "GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length) failed";
|
||||
}
|
||||
|
||||
for(
|
||||
for (
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo;
|
||||
(uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length;
|
||||
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size)
|
||||
)
|
||||
{
|
||||
if (ptr->Relationship == RelationGroup)
|
||||
{
|
||||
for (uint32_t index = 0; index < ptr->Group.ActiveGroupCount; ++index)
|
||||
{
|
||||
(uint8_t*) ptr < ((uint8_t*) pProcessorInfo) + length;
|
||||
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) (((uint8_t*) ptr) + ptr->Size)) {
|
||||
if (ptr->Relationship == RelationGroup) {
|
||||
for (uint32_t index = 0; index < ptr->Group.ActiveGroupCount; ++index) {
|
||||
cpu->coresOnline += ptr->Group.GroupInfo[index].ActiveProcessorCount;
|
||||
cpu->coresLogical += ptr->Group.GroupInfo[index].MaximumProcessorCount;
|
||||
}
|
||||
}
|
||||
else if (ptr->Relationship == RelationProcessorCore)
|
||||
} else if (ptr->Relationship == RelationProcessorCore) {
|
||||
++cpu->coresPhysical;
|
||||
else if (ptr->Relationship == RelationProcessorPackage)
|
||||
} else if (ptr->Relationship == RelationProcessorPackage) {
|
||||
++cpu->packages;
|
||||
else if (ptr->Relationship == RelationNumaNode)
|
||||
} else if (ptr->Relationship == RelationNumaNode) {
|
||||
++cpu->numaNodes;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectByRegistry(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectByRegistry(FFCPUResult* cpu) {
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL))
|
||||
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL)) {
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
|
||||
}
|
||||
|
||||
if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) {
|
||||
FF_ARG(cpu->name, L"ProcessorNameString"),
|
||||
FF_ARG(cpu->vendor, L"VendorIdentifier"),
|
||||
FF_ARG(cpu->frequencyBase, L"~MHz"),
|
||||
}, NULL))
|
||||
FF_ARG(cpu->name, L"ProcessorNameString"),
|
||||
FF_ARG(cpu->vendor, L"VendorIdentifier"),
|
||||
FF_ARG(cpu->frequencyBase, L"~MHz"),
|
||||
},
|
||||
NULL)) {
|
||||
ffStrbufTrimRightSpace(&cpu->vendor);
|
||||
else
|
||||
} else {
|
||||
return "ffRegReadValues() failed for CPU registry key";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectCoreTypes(FFCPUResult* cpu)
|
||||
{
|
||||
static const char* detectCoreTypes(FFCPUResult* cpu) {
|
||||
FF_AUTO_FREE PROCESSOR_POWER_INFORMATION* pinfo = calloc(cpu->coresLogical, sizeof(PROCESSOR_POWER_INFORMATION));
|
||||
if (!NT_SUCCESS(NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, (ULONG) sizeof(PROCESSOR_POWER_INFORMATION) * cpu->coresLogical)))
|
||||
if (!NT_SUCCESS(NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, (ULONG) sizeof(PROCESSOR_POWER_INFORMATION) * cpu->coresLogical))) {
|
||||
return "NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, size) failed";
|
||||
}
|
||||
|
||||
for (uint32_t icore = 0; icore < cpu->coresLogical && pinfo[icore].MhzLimit; ++icore)
|
||||
{
|
||||
for (uint32_t icore = 0; icore < cpu->coresLogical && pinfo[icore].MhzLimit; ++icore) {
|
||||
uint32_t ifreq = 0;
|
||||
while (cpu->coreTypes[ifreq].freq != pinfo[icore].MhzLimit && cpu->coreTypes[ifreq].freq > 0)
|
||||
while (cpu->coreTypes[ifreq].freq != pinfo[icore].MhzLimit && cpu->coreTypes[ifreq].freq > 0) {
|
||||
++ifreq;
|
||||
if (cpu->coreTypes[ifreq].freq == 0)
|
||||
}
|
||||
if (cpu->coreTypes[ifreq].freq == 0) {
|
||||
cpu->coreTypes[ifreq].freq = pinfo[icore].MhzLimit;
|
||||
}
|
||||
++cpu->coreTypes[ifreq].count;
|
||||
}
|
||||
|
||||
if (cpu->frequencyBase == 0)
|
||||
if (cpu->frequencyBase == 0) {
|
||||
cpu->frequencyBase = pinfo->MaxMhz;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
|
||||
detectNCores(cpu);
|
||||
|
||||
const char* error = detectByRegistry(cpu);
|
||||
if (error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
if (options->showPeCoreCount) detectCoreTypes(cpu);
|
||||
if (options->showPeCoreCount) {
|
||||
detectCoreTypes(cpu);
|
||||
}
|
||||
|
||||
if (cpu->frequencyMax == 0)
|
||||
if (cpu->frequencyMax == 0) {
|
||||
detectMaxSpeedBySmbios(cpu);
|
||||
}
|
||||
|
||||
if(options->temp)
|
||||
if (options->temp) {
|
||||
detectThermalTemp(options, &cpu->temperature);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,43 +3,37 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpucache/option.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFCPUCacheType
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFCPUCacheType {
|
||||
FF_CPU_CACHE_TYPE_UNIFIED = 0,
|
||||
FF_CPU_CACHE_TYPE_INSTRUCTION = 1,
|
||||
FF_CPU_CACHE_TYPE_DATA = 2,
|
||||
FF_CPU_CACHE_TYPE_TRACE = 3,
|
||||
} FFCPUCacheType;
|
||||
|
||||
typedef struct FFCPUCache
|
||||
{
|
||||
typedef struct FFCPUCache {
|
||||
uint32_t size;
|
||||
uint32_t num;
|
||||
uint32_t lineSize;
|
||||
FFCPUCacheType type;
|
||||
} FFCPUCache;
|
||||
|
||||
typedef struct FFCPUCacheResult
|
||||
{
|
||||
typedef struct FFCPUCacheResult {
|
||||
FFlist caches[4]; // L1, L2, L3, L4(?)
|
||||
} FFCPUCacheResult;
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result);
|
||||
|
||||
static inline FFCPUCache* ffCPUCacheAddItem(FFCPUCacheResult* result, uint32_t level, uint32_t size, uint32_t lineSize, FFCPUCacheType type)
|
||||
{
|
||||
static inline FFCPUCache* ffCPUCacheAddItem(FFCPUCacheResult* result, uint32_t level, uint32_t size, uint32_t lineSize, FFCPUCacheType type) {
|
||||
FFlist* cacheLevel = &result->caches[level - 1];
|
||||
|
||||
FF_LIST_FOR_EACH(FFCPUCache, item, *cacheLevel)
|
||||
{
|
||||
if (item->type == type && item->size == size && item->lineSize == lineSize)
|
||||
{
|
||||
FF_LIST_FOR_EACH (FFCPUCache, item, *cacheLevel) {
|
||||
if (item->type == type && item->size == size && item->lineSize == lineSize) {
|
||||
item->num++;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
FFCPUCache* item = (FFCPUCache*)ffListAdd(cacheLevel);
|
||||
FFCPUCache* item = (FFCPUCache*) ffListAdd(cacheLevel);
|
||||
*item = (FFCPUCache) {
|
||||
.size = size,
|
||||
.num = 1,
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
#include "common/sysctl.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
{
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result) {
|
||||
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_system_capabilities#3901385
|
||||
uint32_t nPerfLevels = (uint32_t) ffSysctlGetInt("hw.nperflevels", 0);
|
||||
if (nPerfLevels <= 0) return "sysctl(hw.nperflevels) failed";
|
||||
if (nPerfLevels <= 0) {
|
||||
return "sysctl(hw.nperflevels) failed";
|
||||
}
|
||||
|
||||
// macOS provides the global system cache line size
|
||||
uint32_t lineSize = (uint32_t) ffSysctlGetInt64("hw.cachelinesize", 0);
|
||||
@@ -16,42 +17,45 @@ const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
char* pSubkey = sysctlKey + strlen("hw.perflevelN.");
|
||||
const size_t lenLeft = ARRAY_SIZE(sysctlKey) - strlen("hw.perflevelN.");
|
||||
|
||||
for (uint32_t i = 0; i < nPerfLevels; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < nPerfLevels; ++i) {
|
||||
*pNum = (char) ('0' + i);
|
||||
|
||||
ffStrCopy(pSubkey, "physicalcpu", lenLeft);
|
||||
uint32_t ncpu = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (ncpu <= 0) continue;
|
||||
if (ncpu <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrCopy(pSubkey, "l1icachesize", lenLeft);
|
||||
uint32_t size = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (size)
|
||||
if (size) {
|
||||
ffCPUCacheAddItem(result, 1, size, lineSize, FF_CPU_CACHE_TYPE_INSTRUCTION)->num = ncpu;
|
||||
}
|
||||
|
||||
ffStrCopy(pSubkey, "l1dcachesize", lenLeft);
|
||||
size = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (size)
|
||||
if (size) {
|
||||
ffCPUCacheAddItem(result, 1, size, lineSize, FF_CPU_CACHE_TYPE_DATA)->num = ncpu;
|
||||
}
|
||||
|
||||
ffStrCopy(pSubkey, "l2cachesize", lenLeft);
|
||||
size = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (size)
|
||||
{
|
||||
if (size) {
|
||||
ffStrCopy(pSubkey, "cpusperl2", lenLeft);
|
||||
uint32_t cpuSper = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (cpuSper)
|
||||
if (cpuSper) {
|
||||
ffCPUCacheAddItem(result, 2, size, lineSize, FF_CPU_CACHE_TYPE_UNIFIED)->num = ncpu / cpuSper;
|
||||
}
|
||||
}
|
||||
|
||||
ffStrCopy(pSubkey, "l3cachesize", lenLeft);
|
||||
size = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (size)
|
||||
{
|
||||
if (size) {
|
||||
ffStrCopy(pSubkey, "cpusperl3", lenLeft);
|
||||
uint32_t cpuSper = (uint32_t) ffSysctlGetInt(sysctlKey, 0);
|
||||
if (cpuSper)
|
||||
if (cpuSper) {
|
||||
ffCPUCacheAddItem(result, 3, size, lineSize, FF_CPU_CACHE_TYPE_UNIFIED)->num = ncpu / cpuSper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,107 +2,130 @@
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added)
|
||||
{
|
||||
static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) {
|
||||
uint32_t baseLen = path->length;
|
||||
ffStrbufAppendS(path, "/level");
|
||||
if (!ffReadFileBuffer(path->chars, buffer))
|
||||
if (!ffReadFileBuffer(path->chars, buffer)) {
|
||||
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/level\") == NULL";
|
||||
}
|
||||
|
||||
uint32_t level = (uint32_t) ffStrbufToUInt(buffer, 0);
|
||||
if (level < 1 || level > 4) return "level < 1 || level > 4";
|
||||
if (level < 1 || level > 4) {
|
||||
return "level < 1 || level > 4";
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "/size");
|
||||
if (!ffReadFileBuffer(path->chars, buffer))
|
||||
if (!ffReadFileBuffer(path->chars, buffer)) {
|
||||
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/size\") == NULL";
|
||||
}
|
||||
|
||||
uint32_t sizeKb = (uint32_t) ffStrbufToUInt(buffer, 0);
|
||||
if (sizeKb == 0) return "size == 0";
|
||||
if (sizeKb == 0) {
|
||||
return "size == 0";
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "/type");
|
||||
if (!ffReadFileBuffer(path->chars, buffer))
|
||||
if (!ffReadFileBuffer(path->chars, buffer)) {
|
||||
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/type\") == NULL";
|
||||
}
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
|
||||
FFCPUCacheType cacheType = 0;
|
||||
switch (buffer->chars[0])
|
||||
{
|
||||
case 'I': cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION; break;
|
||||
case 'D': cacheType = FF_CPU_CACHE_TYPE_DATA; break;
|
||||
case 'U': cacheType = FF_CPU_CACHE_TYPE_UNIFIED; break;
|
||||
case 'T': cacheType = FF_CPU_CACHE_TYPE_TRACE; break;
|
||||
default: return "unknown cache type";
|
||||
switch (buffer->chars[0]) {
|
||||
case 'I':
|
||||
cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION;
|
||||
break;
|
||||
case 'D':
|
||||
cacheType = FF_CPU_CACHE_TYPE_DATA;
|
||||
break;
|
||||
case 'U':
|
||||
cacheType = FF_CPU_CACHE_TYPE_UNIFIED;
|
||||
break;
|
||||
case 'T':
|
||||
cacheType = FF_CPU_CACHE_TYPE_TRACE;
|
||||
break;
|
||||
default:
|
||||
return "unknown cache type";
|
||||
}
|
||||
|
||||
uint32_t lineSize = 0;
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "/coherency_line_size");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBuffer(path->chars, buffer)) {
|
||||
lineSize = (uint32_t) ffStrbufToUInt(buffer, 0);
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "/shared_cpu_list");
|
||||
ffStrbufClear(buffer);
|
||||
ffStrbufAppendC(buffer, '[');
|
||||
if (!ffAppendFileBuffer(path->chars, buffer))
|
||||
if (!ffAppendFileBuffer(path->chars, buffer)) {
|
||||
return "ffAppendFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
|
||||
}
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
|
||||
// deduplicate shared caches
|
||||
ffStrbufAppendF(buffer, "_%u_%u_%u_%u]", level, sizeKb, lineSize, cacheType);
|
||||
|
||||
if (ffStrbufContain(added, buffer)) return NULL;
|
||||
if (ffStrbufContain(added, buffer)) {
|
||||
return NULL;
|
||||
}
|
||||
ffStrbufAppend(added, buffer);
|
||||
ffCPUCacheAddItem(result, level, sizeKb * 1024, lineSize, cacheType);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* parseCpuCache(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added)
|
||||
{
|
||||
static const char* parseCpuCache(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) {
|
||||
ffStrbufAppendS(path, "/cache/");
|
||||
uint32_t baseLen = path->length;
|
||||
FF_AUTO_CLOSE_DIR DIR* pathCacheDir = opendir(path->chars);
|
||||
if (!pathCacheDir)
|
||||
if (!pathCacheDir) {
|
||||
return "opendir(\"/sys/devices/system/cpu/cpuX/cache/\") == NULL";
|
||||
}
|
||||
|
||||
struct dirent* pathCacheEntry;
|
||||
while ((pathCacheEntry = readdir(pathCacheDir)) != NULL)
|
||||
{
|
||||
if (!ffStrStartsWith(pathCacheEntry->d_name, "index")
|
||||
|| !ffCharIsDigit(pathCacheEntry->d_name[strlen("index")])) continue;
|
||||
while ((pathCacheEntry = readdir(pathCacheDir)) != NULL) {
|
||||
if (!ffStrStartsWith(pathCacheEntry->d_name, "index") || !ffCharIsDigit(pathCacheEntry->d_name[strlen("index")])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(path, pathCacheEntry->d_name);
|
||||
const char* error = parseCpuCacheIndex(path, result, buffer, added);
|
||||
if (error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
{
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result) {
|
||||
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/");
|
||||
uint32_t baseLen = path.length;
|
||||
FF_AUTO_CLOSE_DIR DIR* pathCpuDir = opendir(path.chars);
|
||||
if (!pathCpuDir)
|
||||
if (!pathCpuDir) {
|
||||
return "opendir(\"/sys/devices/system/cpu/\") == NULL";
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY added = ffStrbufCreate();
|
||||
|
||||
struct dirent* pathCpuEntry;
|
||||
while ((pathCpuEntry = readdir(pathCpuDir)) != NULL)
|
||||
{
|
||||
while ((pathCpuEntry = readdir(pathCpuDir)) != NULL) {
|
||||
if (!ffStrStartsWith(pathCpuEntry->d_name, "cpu") ||
|
||||
!ffCharIsDigit(pathCpuEntry->d_name[strlen("cpu")])) continue;
|
||||
!ffCharIsDigit(pathCpuEntry->d_name[strlen("cpu")])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&path, pathCpuEntry->d_name);
|
||||
const char* error = parseCpuCache(&path, result, &buffer, &added);
|
||||
if (error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
ffStrbufSubstrBefore(&path, baseLen);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "cpucache.h"
|
||||
|
||||
const char* ffDetectCPUCache(FF_MAYBE_UNUSED FFCPUCacheResult* result)
|
||||
{
|
||||
const char* ffDetectCPUCache(FF_MAYBE_UNUSED FFCPUCacheResult* result) {
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -2,61 +2,60 @@
|
||||
#include "common/smbiosHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
typedef struct FFSmbiosCacheInfo
|
||||
{
|
||||
typedef struct FFSmbiosCacheInfo {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t SocketDesignation; // string
|
||||
uint8_t SocketDesignation; // string
|
||||
uint16_t CacheConfiguration; // varies
|
||||
uint16_t MaximumCacheSize; // varies
|
||||
uint16_t InstalledSize; // varies
|
||||
uint16_t SupportedSramType; // bit field
|
||||
uint16_t CurrentSramType; // bit field
|
||||
uint16_t MaximumCacheSize; // varies
|
||||
uint16_t InstalledSize; // varies
|
||||
uint16_t SupportedSramType; // bit field
|
||||
uint16_t CurrentSramType; // bit field
|
||||
|
||||
// 2.1+
|
||||
uint8_t CacheSpeed; // varies
|
||||
uint8_t CacheSpeed; // varies
|
||||
uint8_t ErrorCorrectionType; // enum
|
||||
uint8_t SystemCacheType; // enum
|
||||
uint8_t Associativity; // enum
|
||||
uint8_t SystemCacheType; // enum
|
||||
uint8_t Associativity; // enum
|
||||
|
||||
// 3.1+
|
||||
uint32_t MaximumCacheSize2; // bit field
|
||||
uint32_t MaximumCacheSize2; // bit field
|
||||
uint32_t InstalledCacheSize2; // bit field
|
||||
} __attribute__((__packed__)) FFSmbiosCacheInfo;
|
||||
|
||||
static_assert(offsetof(FFSmbiosCacheInfo, InstalledCacheSize2) == 0x17,
|
||||
"FFSmbiosCacheInfo: Wrong struct alignment");
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
{
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable)
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosCacheInfo* data = (const FFSmbiosCacheInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_CACHE_INFO];
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return "Cache information is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosCacheInfo* endOfTable = (const FFSmbiosCacheInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
|
||||
for (; data != endOfTable; data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header))
|
||||
{
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_CACHE_INFO)
|
||||
for (; data != endOfTable; data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header)) {
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_CACHE_INFO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool enabled = !!(data->CacheConfiguration & (1 << 7));
|
||||
if (!enabled)
|
||||
if (!enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t size = data->InstalledSize;
|
||||
if (size == 0)
|
||||
if (size == 0) {
|
||||
continue;
|
||||
|
||||
if (data->InstalledSize != 0xFFFF)
|
||||
{
|
||||
size *= (size >> 15 ? 64 : 1) * 1024u;
|
||||
}
|
||||
else if (data->Header.Length > offsetof(FFSmbiosCacheInfo, InstalledCacheSize2))
|
||||
{
|
||||
|
||||
if (data->InstalledSize != 0xFFFF) {
|
||||
size *= (size >> 15 ? 64 : 1) * 1024u;
|
||||
} else if (data->Header.Length > offsetof(FFSmbiosCacheInfo, InstalledCacheSize2)) {
|
||||
size = data->InstalledCacheSize2;
|
||||
size *= (size >> 31 ? 64 : 1) * 1024u;
|
||||
}
|
||||
@@ -64,11 +63,16 @@ const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
uint32_t level = (data->CacheConfiguration & 0b111u) + 1;
|
||||
|
||||
FFCPUCacheType type;
|
||||
switch (data->SystemCacheType)
|
||||
{
|
||||
case 3: type = FF_CPU_CACHE_TYPE_INSTRUCTION; break;
|
||||
case 4: type = FF_CPU_CACHE_TYPE_DATA; break;
|
||||
default: type = FF_CPU_CACHE_TYPE_UNIFIED; break;
|
||||
switch (data->SystemCacheType) {
|
||||
case 3:
|
||||
type = FF_CPU_CACHE_TYPE_INSTRUCTION;
|
||||
break;
|
||||
case 4:
|
||||
type = FF_CPU_CACHE_TYPE_DATA;
|
||||
break;
|
||||
default:
|
||||
type = FF_CPU_CACHE_TYPE_UNIFIED;
|
||||
break;
|
||||
}
|
||||
|
||||
ffCPUCacheAddItem(result, level, size, 0, type);
|
||||
|
||||
@@ -2,36 +2,42 @@
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
{
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result) {
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationCache;
|
||||
DWORD length = 0;
|
||||
NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length);
|
||||
if (length == 0)
|
||||
if (length == 0) {
|
||||
return "GetLogicalProcessorInformationEx(RelationCache, NULL, &length) failed";
|
||||
}
|
||||
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length);
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) malloc(length);
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length)))
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length))) {
|
||||
return "GetLogicalProcessorInformationEx(RelationCache, pProcessorInfo, &length) failed";
|
||||
}
|
||||
|
||||
for(
|
||||
for (
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo;
|
||||
(uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length;
|
||||
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size)
|
||||
)
|
||||
{
|
||||
if(__builtin_expect(ptr->Relationship == RelationCache && ptr->Cache.Level > 0 && ptr->Cache.Level <= 4, true))
|
||||
{
|
||||
(uint8_t*) ptr < ((uint8_t*) pProcessorInfo) + length;
|
||||
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) (((uint8_t*) ptr) + ptr->Size)) {
|
||||
if (__builtin_expect(ptr->Relationship == RelationCache && ptr->Cache.Level > 0 && ptr->Cache.Level <= 4, true)) {
|
||||
FFCPUCacheType cacheType = 0;
|
||||
switch (ptr->Cache.Type)
|
||||
{
|
||||
case CacheUnified: cacheType = FF_CPU_CACHE_TYPE_UNIFIED; break;
|
||||
case CacheInstruction: cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION; break;
|
||||
case CacheData: cacheType = FF_CPU_CACHE_TYPE_DATA; break;
|
||||
case CacheTrace: cacheType = FF_CPU_CACHE_TYPE_TRACE; break;
|
||||
default: break;
|
||||
switch (ptr->Cache.Type) {
|
||||
case CacheUnified:
|
||||
cacheType = FF_CPU_CACHE_TYPE_UNIFIED;
|
||||
break;
|
||||
case CacheInstruction:
|
||||
cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION;
|
||||
break;
|
||||
case CacheData:
|
||||
cacheType = FF_CPU_CACHE_TYPE_DATA;
|
||||
break;
|
||||
case CacheTrace:
|
||||
cacheType = FF_CPU_CACHE_TYPE_TRACE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ffCPUCacheAddItem(result, ptr->Cache.Level, ptr->Cache.CacheSize, ptr->Cache.LineSize, cacheType);
|
||||
}
|
||||
|
||||
@@ -7,50 +7,53 @@
|
||||
static FFlist cpuTimes1;
|
||||
static uint64_t startTime;
|
||||
|
||||
void ffPrepareCPUUsage(void)
|
||||
{
|
||||
if (cpuTimes1.elementSize != 0) return; // Already prepared
|
||||
void ffPrepareCPUUsage(void) {
|
||||
if (cpuTimes1.elementSize != 0) {
|
||||
return; // Already prepared
|
||||
}
|
||||
|
||||
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
|
||||
ffGetCpuUsageInfo(&cpuTimes1);
|
||||
startTime = ffTimeGetNow();
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
|
||||
{
|
||||
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result) {
|
||||
const char* error = NULL;
|
||||
if(cpuTimes1.elementSize == 0)
|
||||
{
|
||||
if (cpuTimes1.elementSize == 0) {
|
||||
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
|
||||
error = ffGetCpuUsageInfo(&cpuTimes1);
|
||||
if(error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
ffTimeSleep(options->waitTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint64_t elapsedTime = ffTimeGetNow() - startTime;
|
||||
if (elapsedTime < options->waitTime)
|
||||
ffTimeSleep(options->waitTime - (uint32_t)elapsedTime);
|
||||
if (elapsedTime < options->waitTime) {
|
||||
ffTimeSleep(options->waitTime - (uint32_t) elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
if(cpuTimes1.length == 0) return "No CPU cores found";
|
||||
if (cpuTimes1.length == 0) {
|
||||
return "No CPU cores found";
|
||||
}
|
||||
|
||||
FF_LIST_AUTO_DESTROY cpuTimes2 = ffListCreate(sizeof(FFCpuUsageInfo));
|
||||
uint32_t retryCount = 0;
|
||||
|
||||
retry:
|
||||
error = ffGetCpuUsageInfo(&cpuTimes2);
|
||||
if(error) return error;
|
||||
if(cpuTimes1.length != cpuTimes2.length) return "Unexpected CPU usage result";
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (cpuTimes1.length != cpuTimes2.length) {
|
||||
return "Unexpected CPU usage result";
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < cpuTimes1.length; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < cpuTimes1.length; ++i) {
|
||||
FFCpuUsageInfo* cpuTime1 = FF_LIST_GET(FFCpuUsageInfo, cpuTimes1, i);
|
||||
FFCpuUsageInfo* cpuTime2 = FF_LIST_GET(FFCpuUsageInfo, cpuTimes2, i);
|
||||
if (cpuTime2->totalAll <= cpuTime1->totalAll)
|
||||
{
|
||||
if (++retryCount <= 3)
|
||||
{
|
||||
if (cpuTime2->totalAll <= cpuTime1->totalAll) {
|
||||
if (++retryCount <= 3) {
|
||||
ffListClear(&cpuTimes2);
|
||||
ffTimeSleep(options->waitTime);
|
||||
goto retry;
|
||||
@@ -59,11 +62,10 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < cpuTimes1.length; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < cpuTimes1.length; ++i) {
|
||||
FFCpuUsageInfo* cpuTime1 = FF_LIST_GET(FFCpuUsageInfo, cpuTimes1, i);
|
||||
FFCpuUsageInfo* cpuTime2 = FF_LIST_GET(FFCpuUsageInfo, cpuTimes2, i);
|
||||
*(double*) ffListAdd(result) = (double)(cpuTime2->inUseAll - cpuTime1->inUseAll) / (double)(cpuTime2->totalAll - cpuTime1->totalAll) * 100;
|
||||
*(double*) ffListAdd(result) = (double) (cpuTime2->inUseAll - cpuTime1->inUseAll) / (double) (cpuTime2->totalAll - cpuTime1->totalAll) * 100;
|
||||
cpuTime1->inUseAll = cpuTime2->inUseAll;
|
||||
cpuTime1->totalAll = cpuTime2->totalAll;
|
||||
}
|
||||
|
||||
@@ -5,28 +5,26 @@
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/vm_map.h>
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
natural_t numCPUs = 0U;
|
||||
processor_info_array_t cpuInfo;
|
||||
mach_msg_type_number_t numCpuInfo;
|
||||
|
||||
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUs, &cpuInfo, &numCpuInfo) != KERN_SUCCESS)
|
||||
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUs, &cpuInfo, &numCpuInfo) != KERN_SUCCESS) {
|
||||
return "host_processor_info() failed";
|
||||
if (numCPUs * CPU_STATE_MAX != numCpuInfo)
|
||||
}
|
||||
if (numCPUs * CPU_STATE_MAX != numCpuInfo) {
|
||||
return "Unexpected host_processor_info() result";
|
||||
}
|
||||
|
||||
for (natural_t i = 0U; i < numCPUs; ++i)
|
||||
{
|
||||
integer_t inUse = cpuInfo[CPU_STATE_MAX * i + CPU_STATE_USER]
|
||||
+ cpuInfo[CPU_STATE_MAX * i + CPU_STATE_SYSTEM]
|
||||
+ cpuInfo[CPU_STATE_MAX * i + CPU_STATE_NICE];
|
||||
for (natural_t i = 0U; i < numCPUs; ++i) {
|
||||
integer_t inUse = cpuInfo[CPU_STATE_MAX * i + CPU_STATE_USER] + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_SYSTEM] + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_NICE];
|
||||
integer_t total = inUse + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_IDLE];
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
.inUseAll = (uint64_t)inUse,
|
||||
.totalAll = (uint64_t)total,
|
||||
.inUseAll = (uint64_t) inUse,
|
||||
.totalAll = (uint64_t) total,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,23 +7,24 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if __OpenBSD__ || __NetBSD__
|
||||
#include <sys/sched.h>
|
||||
# include <sys/sched.h>
|
||||
#endif
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
size_t neededLength = 0;
|
||||
#if __OpenBSD__|| __NetBSD__
|
||||
#ifdef KERN_CPTIME
|
||||
int ctls[] = {CTL_KERN, KERN_CPTIME};
|
||||
#else
|
||||
int ctls[] = {CTL_KERN, KERN_CP_TIME};
|
||||
#endif
|
||||
if (sysctl(ctls, 2, NULL, &neededLength, NULL, 0) != 0)
|
||||
#if __OpenBSD__ || __NetBSD__
|
||||
# ifdef KERN_CPTIME
|
||||
int ctls[] = {CTL_KERN, KERN_CPTIME};
|
||||
# else
|
||||
int ctls[] = {CTL_KERN, KERN_CP_TIME};
|
||||
# endif
|
||||
if (sysctl(ctls, 2, NULL, &neededLength, NULL, 0) != 0) {
|
||||
return "sysctl({CTL_KERN, KERN_CPTIME}, 2, NULL) failed";
|
||||
}
|
||||
#else
|
||||
if(sysctlbyname("kern.cp_times", NULL, &neededLength, NULL, 0) != 0)
|
||||
if (sysctlbyname("kern.cp_times", NULL, &neededLength, NULL, 0) != 0) {
|
||||
return "sysctlbyname(kern.cp_times, NULL) failed";
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t coreCount = (uint32_t) (neededLength / (CPUSTATES * sizeof(uint64_t)));
|
||||
@@ -32,15 +33,16 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
FF_AUTO_FREE uint64_t (*cpTimes)[CPUSTATES] = malloc(neededLength);
|
||||
|
||||
#if __OpenBSD__ || __NetBSD__
|
||||
if (sysctl(ctls, 2, cpTimes, &neededLength, NULL, 0) != 0)
|
||||
if (sysctl(ctls, 2, cpTimes, &neededLength, NULL, 0) != 0) {
|
||||
return "sysctl({CTL_KERN, KERN_CPTIME}, 2, NULL) failed";
|
||||
}
|
||||
#else
|
||||
if(sysctlbyname("kern.cp_times", cpTimes, &neededLength, NULL, 0) != 0)
|
||||
if (sysctlbyname("kern.cp_times", cpTimes, &neededLength, NULL, 0) != 0) {
|
||||
return "sysctlbyname(kern.cp_times, cpTime) failed";
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < coreCount; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < coreCount; ++i) {
|
||||
uint64_t* cpTime = cpTimes[i];
|
||||
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS] + cpTime[CP_INTR];
|
||||
uint64_t total = inUse + cpTime[CP_IDLE];
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
system_info sysInfo;
|
||||
if (get_system_info(&sysInfo) != B_OK)
|
||||
if (get_system_info(&sysInfo) != B_OK) {
|
||||
return "get_system_info() failed";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE cpu_info* cpuInfo = malloc(sizeof(*cpuInfo) * sysInfo.cpu_count);
|
||||
if (get_cpu_info(0, sysInfo.cpu_count, cpuInfo) != B_OK)
|
||||
if (get_cpu_info(0, sysInfo.cpu_count, cpuInfo) != B_OK) {
|
||||
return "get_cpu_info() failed";
|
||||
}
|
||||
|
||||
uint64_t uptime = (uint64_t) system_time();
|
||||
|
||||
for (uint32_t i = 0; i < sysInfo.cpu_count; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < sysInfo.cpu_count; ++i) {
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
info->inUseAll = (uint64_t) cpuInfo[i].active_time;
|
||||
info->totalAll = uptime;
|
||||
|
||||
@@ -5,32 +5,29 @@
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData("/proc/stat", ARRAY_SIZE(buf) - 1, buf);
|
||||
if(nRead < 0)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
if (nRead < 0) {
|
||||
#ifdef __ANDROID__
|
||||
return "Accessing \"/proc/stat\" is restricted on Android O+";
|
||||
#else
|
||||
#else
|
||||
return "ffReadFileData(\"/proc/stat\", ARRAY_SIZE(buf) - 1, buf) failed";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
buf[nRead] = '\0';
|
||||
|
||||
// Skip first line
|
||||
char *start = NULL;
|
||||
if((start = strchr(buf, '\n')) == NULL)
|
||||
char* start = NULL;
|
||||
if ((start = strchr(buf, '\n')) == NULL) {
|
||||
return "skip first line failed";
|
||||
}
|
||||
++start;
|
||||
|
||||
uint64_t user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0;
|
||||
char *token = NULL;
|
||||
while ((token = strchr(start, '\n')))
|
||||
{
|
||||
if(sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7)
|
||||
{
|
||||
char* token = NULL;
|
||||
while ((token = strchr(start, '\n'))) {
|
||||
if (sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7) {
|
||||
uint64_t inUse = user + nice + system + irq + softirq;
|
||||
uint64_t total = inUse + idle + iowait;
|
||||
|
||||
@@ -39,9 +36,9 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
.inUseAll = inUse,
|
||||
.totalAll = total,
|
||||
};
|
||||
}
|
||||
else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
start = token + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/cpuusage/cpuusage.h"
|
||||
|
||||
const char* ffGetCpuUsageInfo(FF_MAYBE_UNUSED FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FF_MAYBE_UNUSED FFlist* cpuTimes) {
|
||||
return "Not support on this platform";
|
||||
}
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
#include <kstat.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc) {
|
||||
assert(pkc);
|
||||
if (*pkc)
|
||||
if (*pkc) {
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc)
|
||||
if (!kc) {
|
||||
return "kstat_open() failed";
|
||||
}
|
||||
|
||||
for (int i = 0;; ++i)
|
||||
{
|
||||
for (int i = 0;; ++i) {
|
||||
kstat_t* ks = kstat_lookup(kc, "cpu_stat", i, NULL);
|
||||
|
||||
cpu_stat_t cs;
|
||||
if (!ks || kstat_read(kc, ks, &cs) < 0)
|
||||
if (!ks || kstat_read(kc, ks, &cs) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t inUse = cs.cpu_sysinfo.cpu[CPU_USER] + cs.cpu_sysinfo.cpu[CPU_KERNEL];
|
||||
uint64_t total = inUse + cs.cpu_sysinfo.cpu[CPU_IDLE] + cs.cpu_sysinfo.cpu[CPU_WAIT];
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
#include "common/windows/perflib_.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
static const char* getInfoByNqsi(FFlist* cpuTimes)
|
||||
{
|
||||
static const char* getInfoByNqsi(FFlist* cpuTimes) {
|
||||
ULONG size = 0;
|
||||
if(NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
|
||||
if (NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH) {
|
||||
return "NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL) failed";
|
||||
}
|
||||
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* FF_AUTO_FREE pinfo = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*)malloc(size);
|
||||
if(!NT_SUCCESS(NtQuerySystemInformation(SystemProcessorPerformanceInformation, pinfo, size, &size)))
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* FF_AUTO_FREE pinfo = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(size);
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemProcessorPerformanceInformation, pinfo, size, &size))) {
|
||||
return "NtQuerySystemInformation(SystemProcessorPerformanceInformation, size) failed";
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); ++i) {
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* coreInfo = pinfo + i;
|
||||
|
||||
// KernelTime includes IdleTime and DpcTime.
|
||||
coreInfo->KernelTime.QuadPart -= coreInfo->IdleTime.QuadPart;
|
||||
|
||||
uint64_t inUse = (uint64_t) (coreInfo->UserTime.QuadPart + coreInfo->KernelTime.QuadPart);
|
||||
uint64_t total = inUse + (uint64_t)coreInfo->IdleTime.QuadPart;
|
||||
uint64_t total = inUse + (uint64_t) coreInfo->IdleTime.QuadPart;
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
@@ -38,21 +38,18 @@ static const char* getInfoByNqsi(FFlist* cpuTimes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
{
|
||||
static const char* getInfoByPerflib(FFlist* cpuTimes) {
|
||||
static HANDLE hQuery = NULL;
|
||||
|
||||
if (hQuery == NULL)
|
||||
{
|
||||
struct FFPerfQuerySpec
|
||||
{
|
||||
if (hQuery == NULL) {
|
||||
struct FFPerfQuerySpec {
|
||||
PERF_COUNTER_IDENTIFIER Identifier;
|
||||
WCHAR Name[16];
|
||||
} querySpec = {
|
||||
.Identifier = {
|
||||
// Processor Information GUID
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{b4fc721a-0378-476f-89ba-a5a79f810b36}
|
||||
.CounterSetGuid = { 0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36} },
|
||||
.CounterSetGuid = {0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36}},
|
||||
.Size = sizeof(querySpec),
|
||||
.CounterId = PERF_WILDCARD_COUNTER, // https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
.InstanceId = PERF_WILDCARD_COUNTER,
|
||||
@@ -60,84 +57,86 @@ static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
.Name = PERF_WILDCARD_INSTANCE,
|
||||
};
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
{
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS) {
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
}
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
{
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS) {
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() failed";
|
||||
}
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
{
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS) {
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
}
|
||||
}
|
||||
|
||||
if (hQuery == INVALID_HANDLE_VALUE)
|
||||
if (hQuery == INVALID_HANDLE_VALUE) {
|
||||
return "Init hQuery failed";
|
||||
}
|
||||
|
||||
DWORD dataSize = 0;
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY) {
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
}
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER))
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) {
|
||||
return "instance doesn't exist";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*)malloc(dataSize);
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*) malloc(dataSize);
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS) {
|
||||
return "PerfQueryCounterData(pDataHeader) failed";
|
||||
}
|
||||
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_COUNTERSET)
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*) (pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_COUNTERSET) {
|
||||
return "Invalid counter type";
|
||||
}
|
||||
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
|
||||
if (pMultiCounters->dwCounters == 0)
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*) (pCounterHeader + 1);
|
||||
if (pMultiCounters->dwCounters == 0) {
|
||||
return "No CPU counters found";
|
||||
}
|
||||
|
||||
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
|
||||
if (pMultiInstances->dwInstances == 0)
|
||||
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*) ((BYTE*) pMultiCounters + pMultiCounters->dwSize);
|
||||
if (pMultiInstances->dwInstances == 0) {
|
||||
return "No CPU instances found";
|
||||
}
|
||||
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*)(pMultiInstances + 1);
|
||||
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*) (pMultiInstances + 1);
|
||||
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance) {
|
||||
const wchar_t* instanceName = (const wchar_t*) ((BYTE*) pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*) ((BYTE*) pInstanceHeader + pInstanceHeader->Size);
|
||||
|
||||
uint64_t processorUtility = UINT64_MAX, utilityBase = UINT64_MAX;
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
|
||||
{
|
||||
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++) {
|
||||
DWORD* pCounterIds = (DWORD*) (pMultiCounters + 1);
|
||||
// https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
switch (pCounterIds[iCounter]) {
|
||||
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint64_t));
|
||||
processorUtility = *(uint64_t*)(pCounterData + 1);
|
||||
break;
|
||||
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint32_t));
|
||||
utilityBase = *(uint32_t*)(pCounterData + 1) * 100LLU;
|
||||
break;
|
||||
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint64_t));
|
||||
processorUtility = *(uint64_t*) (pCounterData + 1);
|
||||
break;
|
||||
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint32_t));
|
||||
utilityBase = *(uint32_t*) (pCounterData + 1) * 100LLU;
|
||||
break;
|
||||
}
|
||||
|
||||
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
|
||||
pCounterData = (PERF_COUNTER_DATA*) ((BYTE*) pCounterData + pCounterData->dwSize);
|
||||
}
|
||||
|
||||
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */)
|
||||
{
|
||||
if (processorUtility == UINT64_MAX)
|
||||
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */) {
|
||||
if (processorUtility == UINT64_MAX) {
|
||||
return "Counter \"% Processor Utility\" are not supported";
|
||||
}
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
@@ -146,21 +145,21 @@ static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
};
|
||||
}
|
||||
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)pCounterData;
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*) pCounterData;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes) {
|
||||
const char* error = NULL;
|
||||
|
||||
if (ffIsWindows10OrGreater())
|
||||
{
|
||||
if (ffIsWindows10OrGreater()) {
|
||||
error = getInfoByPerflib(cpuTimes);
|
||||
FF_DEBUG("Get CPU usage info by Perflib: %s", error ?: "success");
|
||||
if (!error) return NULL;
|
||||
if (!error) {
|
||||
return NULL;
|
||||
}
|
||||
ffListClear(cpuTimes);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cursor/option.h"
|
||||
|
||||
typedef struct FFCursorResult
|
||||
{
|
||||
typedef struct FFCursorResult {
|
||||
FFstrbuf theme;
|
||||
FFstrbuf size;
|
||||
FFstrbuf error;
|
||||
|
||||
@@ -9,58 +9,54 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool detectCursorGTK(FFCursorResult* result)
|
||||
{
|
||||
static bool detectCursorGTK(FFCursorResult* result) {
|
||||
const FFGTKResult* gtk = ffDetectGTK4();
|
||||
|
||||
if(gtk->cursor.length == 0)
|
||||
if (gtk->cursor.length == 0) {
|
||||
gtk = ffDetectGTK3();
|
||||
}
|
||||
|
||||
if(gtk->cursor.length == 0)
|
||||
if (gtk->cursor.length == 0) {
|
||||
gtk = ffDetectGTK2();
|
||||
}
|
||||
|
||||
if(gtk->cursor.length == 0)
|
||||
if (gtk->cursor.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufAppend(&result->theme, >k->cursor);
|
||||
ffStrbufAppend(&result->size, >k->cursorSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void detectCursorFromConfigFile(const char* relativeFilePath, const char* themeStart, const char* themeDefault, const char* sizeStart, const char* sizeDefault, FFCursorResult* result)
|
||||
{
|
||||
if(ffParsePropFileConfigValues(relativeFilePath, 2, (FFpropquery[]) {
|
||||
{themeStart, &result->theme},
|
||||
{sizeStart, &result->size}
|
||||
})) {
|
||||
|
||||
if(result->theme.length == 0)
|
||||
static void detectCursorFromConfigFile(const char* relativeFilePath, const char* themeStart, const char* themeDefault, const char* sizeStart, const char* sizeDefault, FFCursorResult* result) {
|
||||
if (ffParsePropFileConfigValues(relativeFilePath, 2, (FFpropquery[]) {{themeStart, &result->theme}, {sizeStart, &result->size}})) {
|
||||
if (result->theme.length == 0) {
|
||||
ffStrbufAppendS(&result->theme, themeDefault);
|
||||
}
|
||||
|
||||
if(result->size.length == 0)
|
||||
if (result->size.length == 0) {
|
||||
ffStrbufAppendS(&result->size, sizeDefault);
|
||||
}
|
||||
}
|
||||
|
||||
if(result->theme.length == 0)
|
||||
if (result->theme.length == 0) {
|
||||
ffStrbufAppendF(&result->error, "Couldn't find cursor in %s", relativeFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
static bool detectCursorFromXResources(FFCursorResult* result)
|
||||
{
|
||||
ffParsePropFileHomeValues(".Xresources", 2, (FFpropquery[]) {
|
||||
{"Xcursor.theme :", &result->theme},
|
||||
{"Xcursor.size :", &result->size}
|
||||
});
|
||||
static bool detectCursorFromXResources(FFCursorResult* result) {
|
||||
ffParsePropFileHomeValues(".Xresources", 2, (FFpropquery[]) {{"Xcursor.theme :", &result->theme}, {"Xcursor.size :", &result->size}});
|
||||
|
||||
return result->theme.length > 0;
|
||||
}
|
||||
|
||||
static bool detectCursorFromEnv(FFCursorResult* result)
|
||||
{
|
||||
static bool detectCursorFromEnv(FFCursorResult* result) {
|
||||
const char* xcursor_theme = getenv("XCURSOR_THEME");
|
||||
|
||||
if(!ffStrSet(xcursor_theme))
|
||||
if (!ffStrSet(xcursor_theme)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&result->theme, xcursor_theme);
|
||||
ffStrbufAppendS(&result->size, getenv("XCURSOR_SIZE"));
|
||||
@@ -68,12 +64,12 @@ static bool detectCursorFromEnv(FFCursorResult* result)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool detectCursorHyprcursor(FFCursorResult* result)
|
||||
{
|
||||
static bool detectCursorHyprcursor(FFCursorResult* result) {
|
||||
const char* hyprcursor_theme = getenv("HYPRCURSOR_THEME");
|
||||
|
||||
if(!ffStrSet(hyprcursor_theme))
|
||||
if (!ffStrSet(hyprcursor_theme)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&result->theme, hyprcursor_theme);
|
||||
ffStrbufAppendS(&result->size, getenv("HYPRCURSOR_SIZE"));
|
||||
@@ -81,25 +77,25 @@ static bool detectCursorHyprcursor(FFCursorResult* result)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffDetectCursor(FFCursorResult* result)
|
||||
{
|
||||
void ffDetectCursor(FFCursorResult* result) {
|
||||
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
|
||||
|
||||
if(ffStrbufEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_WSLG))
|
||||
if (ffStrbufEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_WSLG)) {
|
||||
ffStrbufAppendS(&result->error, "WSLg uses native windows cursor");
|
||||
else if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY))
|
||||
} else if (ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY)) {
|
||||
ffStrbufAppendS(&result->error, "Cursor isn't supported in TTY");
|
||||
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA))
|
||||
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA)) {
|
||||
detectCursorFromConfigFile("kcminputrc", "cursorTheme =", "Breeze", "cursorSize =", "24", result);
|
||||
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT))
|
||||
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT)) {
|
||||
detectCursorFromConfigFile("lxqt/session.conf", "cursor_theme =", "Adwaita", "cursor_size =", "24", result);
|
||||
else if(ffStrbufIgnCaseEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_HYPRLAND) && detectCursorHyprcursor(result))
|
||||
} else if (ffStrbufIgnCaseEqualS(&wmde->wmPrettyName, FF_WM_PRETTY_HYPRLAND) && detectCursorHyprcursor(result)) {
|
||||
return;
|
||||
else if(
|
||||
} else if (
|
||||
!detectCursorGTK(result) &&
|
||||
!detectCursorFromEnv(result) &&
|
||||
!ffParsePropFileHome(".icons/default/index.theme", "Inherits =", &result->theme) &&
|
||||
!detectCursorFromXResources(result) &&
|
||||
!ffParsePropFileData("icons/default/index.theme", "Inherits =", &result->theme)
|
||||
) ffStrbufAppendS(&result->error, "Couldn't find cursor");
|
||||
!ffParsePropFileData("icons/default/index.theme", "Inherits =", &result->theme)) {
|
||||
ffStrbufAppendS(&result->error, "Couldn't find cursor");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "cursor.h"
|
||||
|
||||
void ffDetectCursor(FF_MAYBE_UNUSED FFCursorResult* result)
|
||||
{
|
||||
void ffDetectCursor(FF_MAYBE_UNUSED FFCursorResult* result) {
|
||||
ffStrbufInitS(&result->error, "Not supported on this platform");
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user