Skip to content

Commit

Permalink
Added generic EC sensor type
Browse files Browse the repository at this point in the history
  • Loading branch information
vit9696 committed Apr 7, 2021
1 parent 1cb8fd1 commit 2a7455d
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 20 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Expand Up @@ -2,6 +2,7 @@ VirtualSMC Changelog
====================
#### v1.2.3
- Fixed Intel NUC EC sensors not showing proper values on some platforms
- Added `generic` EC sensor type

#### v1.2.2
- Improve manual fan control in SMCDellSensors (SMM access is enabled even if audio is played)
Expand Down
12 changes: 12 additions & 0 deletions Docs/EmbeddedControllers.md
Expand Up @@ -27,6 +27,18 @@ Debugger firstly tries to use MMIO mode and then falls back to PMIO mode on fail
The PMIO mode supports up to 256 bytes of memory. MMIO mode supports up to 64 KBs of memory with the (usually 256 bytes) EC region mapped somewhere in the area.
The `debug` driver dumps first 8 KBs of EC memory to the log to help to locate the mapped EC window in the MMIO mode.

#### Generic (`generic`)

This is another special type of EC driver available in SMCSuperIO to describe simple EC devices that report FANs via EC plainly. To use it in addition to `ec-device` property one must additionally
inject other properties describing the amount of fans, their addresses, value sizes, and encoding. Currently the following properties are supported (all 32-bit numbers):

- `fan-count` — amount of fans, defaults to `1`.
- `fan0-addr` — 0 fan address, defaults to `0`.
- `fan0-size` — 0 fan size, defaults to `1`, can be `1` or `2`.
- `fan0-big` — 0 fan endianness, defaults to `0` (little endian), can also be `1` (big endian).

Use `fan1-addr` for the second fan and so on.

## Supported devices with respective EC Identifiers

### Intel EC V1 (`Intel_EC_V1`)
Expand Down
7 changes: 6 additions & 1 deletion Sensors/SMCSuperIO/ECDevice.cpp
Expand Up @@ -7,6 +7,7 @@

#include "ECDevice.hpp"
#include "ECDeviceNUC.hpp"
#include "ECDeviceGeneric.hpp"
#include "ECDeviceDebug.hpp"
#include "SMCSuperIO.hpp"
#include "Devices.hpp"
Expand Down Expand Up @@ -152,7 +153,7 @@ namespace EC {
/**
* Device factory
*/
SuperIODevice* ECDevice::detect(SMCSuperIO* sio, const char *name) {
SuperIODevice* ECDevice::detect(SMCSuperIO* sio, const char *name, IORegistryEntry *lpc) {
if (name[0] == '\0') {
DBGLOG("ssio", "please inject ec-device property into LPC with the name");
return nullptr;
Expand All @@ -161,6 +162,10 @@ namespace EC {
DBGLOG("ssio", "ECDevice probing device %s", name);
ECDevice *detectedDevice = static_cast<ECDevice *>(createDeviceEC(name));

if (!detectedDevice) {
detectedDevice = ECDeviceGeneric::detect(sio, name, lpc);
}

#ifdef DEBUG
bool debug = false;
if (!detectedDevice) {
Expand Down
26 changes: 25 additions & 1 deletion Sensors/SMCSuperIO/ECDevice.hpp
Expand Up @@ -116,6 +116,30 @@ namespace EC {
uint16_t readLittleWordMMIO(uint32_t addr) {
return (mmioArea[addr + 1] << 8) | mmioArea[addr];
}
uint16_t readBigWordPMIO(uint8_t addr) {
return (readBytePMIO(addr) << 8) | readBytePMIO(addr + 1);
}
uint16_t readLittleWordPMIO(uint8_t addr) {
return (readBytePMIO(addr + 1) << 8) | readBytePMIO(addr);
}

uint16_t readValue(uint32_t addr, bool isWord, bool isBig) {
if (!isWord) {
if (mmioArea != nullptr)
return mmioArea[addr];
return readBytePMIO(addr);
}

if (mmioArea != nullptr) {
if (isBig)
return readBigWordMMIO(addr);
return readLittleWordMMIO(addr);
}

if (isBig)
return readBigWordPMIO(addr);
return readLittleWordPMIO(addr);
}

/**
* Overrides
Expand All @@ -138,7 +162,7 @@ namespace EC {
/**
* Device factory
*/
static SuperIODevice* detect(SMCSuperIO* sio, const char *name);
static SuperIODevice* detect(SMCSuperIO* sio, const char *name, IORegistryEntry *lpc);
};
}

Expand Down
77 changes: 77 additions & 0 deletions Sensors/SMCSuperIO/ECDeviceGeneric.cpp
@@ -0,0 +1,77 @@
//
// ECDeviceGeneric.cpp
// SMCSuperIO
//
// Copyright © 2021 vit9696. All rights reserved.
//

#include "ECDeviceGeneric.hpp"

namespace EC {
const char* ECDeviceGeneric::getModelName() {
return modelName;
}

uint8_t ECDeviceGeneric::getTachometerCount() {
return tachometerCount;
}

uint16_t ECDeviceGeneric::updateTachometer(uint8_t index) {
auto &t = tachometers[index];
return readValue(t.addr, t.size == sizeof(uint16_t), t.bigEndian);
}

const char *ECDeviceGeneric::getTachometerName(uint8_t index) {
return tachometers[index].name != nullptr ? tachometers[index].name : "FAN";
}

uint8_t ECDeviceGeneric::getVoltageCount() {
return 0;
}

float ECDeviceGeneric::updateVoltage(uint8_t index) {
return 0;
}

const char *ECDeviceGeneric::getVoltageName(uint8_t index) {
return "";
}

ECDeviceGeneric::ECDeviceGeneric(IORegistryEntry *lpc) {
device = lpc;

if (WIOKit::getOSDataValue(lpc, "fan-count", tachometerCount) && (tachometerCount == 0 || tachometerCount >= MaxTachometerCount)) {
tachometerCount = 1;
}

// TODO: Support MMIO
supportsPMIO = true;

for (uint32_t i = 0; i < tachometerCount; i++) {
char name[64];
snprintf(name, sizeof(name), "fan%u-addr", i);
WIOKit::getOSDataValue(lpc, name, tachometers[i].addr);
snprintf(name, sizeof(name), "fan%u-size", i);
uint32_t tmp = 1;
if (WIOKit::getOSDataValue(lpc, name, tmp) && (tmp == 0 || tmp > sizeof(uint16_t)))
tmp = 1;
tachometers[i].size = tmp;
tmp = 0;
snprintf(name, sizeof(name), "fan%u-big", i);
if (WIOKit::getOSDataValue(lpc, name, tmp) && (tmp != 0 && tmp != 1))
tmp = 0;
tachometers[i].bigEndian = tmp != 0;

DBGLOG("ssio", "added tach%u at 0x%04X (%d bytes, %s)", i, tachometers[i].addr, tachometers[i].size,
tachometers[i].bigEndian ? "big" : "little");
}
}

ECDevice* ECDeviceGeneric::detect(SMCSuperIO* sio, const char *name, IORegistryEntry *lpc) {
if (strcmp(name, "generic") != 0)
return nullptr;

DBGLOG("ssio", "initialising Generic EC");
return new ECDeviceGeneric(lpc);
}
}
57 changes: 57 additions & 0 deletions Sensors/SMCSuperIO/ECDeviceGeneric.hpp
@@ -0,0 +1,57 @@
//
// ECDeviceGeneric.hpp
// SMCSuperIO
//
// Copyright © 2021 vit9696. All rights reserved.
//

#ifndef ECDeviceGeneric_hpp
#define ECDeviceGeneric_hpp

#include "SuperIODevice.hpp"
#include "ECDevice.hpp"

namespace EC {

class ECDeviceGeneric : public ECDevice {
const char *modelName {"Generic EC"};
IORegistryEntry *device {nullptr};

uint32_t tachometerCount {1};

static constexpr uint32_t MaxTachometerCount {5};

struct Tachometer {
const char *name;
uint32_t addr;
uint8_t size;
bool bigEndian;
};

Tachometer tachometers[MaxTachometerCount] {};

protected:
const char* getModelName() override;

uint8_t getTachometerCount() override;
uint16_t updateTachometer(uint8_t index) override;
const char* getTachometerName(uint8_t index) override;

uint8_t getVoltageCount() override;
float updateVoltage(uint8_t index) override;
const char* getVoltageName(uint8_t index) override;

/**
* Ctor
*/
ECDeviceGeneric(IORegistryEntry *lpc);

public:
/**
* Device factory
*/
static ECDevice* detect(SMCSuperIO* sio, const char *name, IORegistryEntry *lpc);
};
}

#endif /* ECDeviceGeneric_hpp */
41 changes: 23 additions & 18 deletions Sensors/SMCSuperIO/SMCSuperIO.cpp
Expand Up @@ -141,27 +141,32 @@ IOReturn SMCSuperIO::setPowerState(unsigned long state, IOService *whatDevice) {
}

SuperIODevice* SMCSuperIO::detectDevice() {
if (PE_parse_boot_argn("ssioec", &deviceNameEC, sizeof(deviceNameEC))) {
DBGLOG("ssio", "found EC device %s", deviceNameEC);
} else {
auto name = getParentEntry(gIOServicePlane)->getProperty("ec-device");
auto nameStr = OSDynamicCast(OSString, name);
auto nameData = OSDynamicCast(OSData, name);
if (nameStr) {
strlcpy(deviceNameEC, nameStr->getCStringNoCopy(), sizeof(deviceNameEC));
DBGLOG("ssio", "found EC device %s from string", deviceNameEC);
} else if (nameData) {
auto s = nameData->getLength();
if (s > sizeof(deviceNameEC)) s = sizeof(deviceNameEC);
strlcpy(deviceNameEC, static_cast<const char *>(nameData->getBytesNoCopy()), s);
DBGLOG("ssio", "found EC device %s from data", deviceNameEC);
SuperIODevice* detectedDevice;

auto lpc = getParentEntry(gIOServicePlane);
if (lpc != nullptr) {
if (PE_parse_boot_argn("ssioec", &deviceNameEC, sizeof(deviceNameEC))) {
DBGLOG("ssio", "found EC device %s", deviceNameEC);
} else {
auto name = lpc->getProperty("ec-device");
auto nameStr = OSDynamicCast(OSString, name);
auto nameData = OSDynamicCast(OSData, name);
if (nameStr) {
strlcpy(deviceNameEC, nameStr->getCStringNoCopy(), sizeof(deviceNameEC));
DBGLOG("ssio", "found EC device %s from string", deviceNameEC);
} else if (nameData) {
auto s = nameData->getLength();
if (s > sizeof(deviceNameEC)) s = sizeof(deviceNameEC);
strlcpy(deviceNameEC, static_cast<const char *>(nameData->getBytesNoCopy()), s);
DBGLOG("ssio", "found EC device %s from data", deviceNameEC);
}
}
detectedDevice = EC::ECDevice::detect(this, deviceNameEC, lpc);
if (detectedDevice) {
return detectedDevice;
}
}

SuperIODevice* detectedDevice = EC::ECDevice::detect(this, deviceNameEC);
if (detectedDevice) {
return detectedDevice;
}
detectedDevice = WindbondFamilyDevice::detect(this);
if (detectedDevice) {
return detectedDevice;
Expand Down
8 changes: 8 additions & 0 deletions VirtualSMC.xcodeproj/project.pbxproj
Expand Up @@ -72,6 +72,8 @@
CE744A981F431FEC0077C377 /* kern_handler.S in Sources */ = {isa = PBXBuildFile; fileRef = CE744A961F431FEC0077C377 /* kern_handler.S */; };
CE744A991F431FEC0077C377 /* kern_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = CE744A971F431FEC0077C377 /* kern_handler.h */; };
CE775919211EBD910063EAE6 /* KeyImplementations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE775917211EBD910063EAE6 /* KeyImplementations.cpp */; };
CE853E4E261E629700B82635 /* ECDeviceGeneric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE853E4C261E629700B82635 /* ECDeviceGeneric.cpp */; };
CE853E4F261E629700B82635 /* ECDeviceGeneric.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CE853E4D261E629700B82635 /* ECDeviceGeneric.hpp */; };
CE8D9F7F2517B58C008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8D9F7E2517B58C008C44E8 /* libkmod.a */; };
CE8D9F802517B599008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8D9F7E2517B58C008C44E8 /* libkmod.a */; };
CE8D9F812517B59D008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8D9F7E2517B58C008C44E8 /* libkmod.a */; };
Expand Down Expand Up @@ -381,6 +383,8 @@
CE83AE401FFA825F00D9C958 /* SMCKeysMacPro.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = SMCKeysMacPro.html; path = Docs/SMCKeysMacPro.html; sourceTree = "<group>"; };
CE83AE411FFA825F00D9C958 /* SMCKeys.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = SMCKeys.txt; path = Docs/SMCKeys.txt; sourceTree = "<group>"; };
CE83AE421FFA826E00D9C958 /* SMCModels.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = SMCModels.txt; path = Docs/SMCModels.txt; sourceTree = "<group>"; };
CE853E4C261E629700B82635 /* ECDeviceGeneric.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ECDeviceGeneric.cpp; sourceTree = "<group>"; };
CE853E4D261E629700B82635 /* ECDeviceGeneric.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ECDeviceGeneric.hpp; sourceTree = "<group>"; };
CE8D9F7E2517B58C008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = ../Lilu/MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = "<group>"; };
CEA5AAB22129ACEB0001F426 /* SMCBasics.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = SMCBasics.txt; path = Docs/SMCBasics.txt; sourceTree = "<group>"; };
CEA5AAB72129AF3A0001F426 /* libaistat.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libaistat.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -673,6 +677,8 @@
CE462B5A260F770700B391DB /* ECDevice.hpp */,
CE462B78260F83F800B391DB /* ECDeviceNUC.cpp */,
CE462B6A260F81BF00B391DB /* ECDeviceNUC.hpp */,
CE853E4C261E629700B82635 /* ECDeviceGeneric.cpp */,
CE853E4D261E629700B82635 /* ECDeviceGeneric.hpp */,
CE462B9F260FC0BB00B391DB /* ECDeviceDebug.cpp */,
CE462BA0260FC0BB00B391DB /* ECDeviceDebug.hpp */,
AB8CD0C321693FD4002FB4D2 /* NuvotonDevice.cpp */,
Expand Down Expand Up @@ -912,6 +918,7 @@
files = (
AB8181E12380778C00244152 /* ITEDevice.hpp in Headers */,
AB8181DF2380445400244152 /* FintekDevice.hpp in Headers */,
CE853E4F261E629700B82635 /* ECDeviceGeneric.hpp in Headers */,
AB8181DD237F0E8F00244152 /* WinbondDevice.hpp in Headers */,
CE462B5C260F770700B391DB /* ECDevice.hpp in Headers */,
AB445549216A8EF80011E44E /* NuvotonDevice.hpp in Headers */,
Expand Down Expand Up @@ -1390,6 +1397,7 @@
CE462B79260F83F800B391DB /* ECDeviceNUC.cpp in Sources */,
AB8181DE237F0E9B00244152 /* WinbondDevice.cpp in Sources */,
AB4804E82172B97500683636 /* WinbondFamilyDevice.cpp in Sources */,
CE853E4E261E629700B82635 /* ECDeviceGeneric.cpp in Sources */,
AB3F62662169880300E4EFFD /* NuvotonDevice.cpp in Sources */,
CE462BA1260FC0BB00B391DB /* ECDeviceDebug.cpp in Sources */,
CE462B5D260F770700B391DB /* ECDevice.cpp in Sources */,
Expand Down

0 comments on commit 2a7455d

Please sign in to comment.