diff --git a/OpenRGB.pro b/OpenRGB.pro index 55d9a829..1b0a00c4 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -1616,12 +1616,23 @@ macx:contains(QMAKE_HOST.arch, arm64) { #-------------------------------------------------------------------------------------------# macx:contains(QMAKE_HOST.arch, x86_64) { INCLUDEPATH += \ + dependencies/macUSPCIO \ /usr/local/include \ /usr/local/homebrew/include \ + SOURCES += \ + i2c_smbus/i2c_smbus_i801.cpp \ + + HEADERS += \ + dependencies/macUSPCIO/macUSPCIOAccess.h \ + i2c_smbus/i2c_smbus_i801.h \ + LIBS += \ -L/usr/local/lib \ -L/usr/local/homebrew/lib \ + + DEFINES += \ + _MACOSX_X86_X64 \ } DISTFILES += \ diff --git a/README.md b/README.md index 25cb346a..2e7f5b5d 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ There have been two instances of hardware damage in OpenRGB's development and we ### SMBus Access - * SMBus/I2C devices are currently not supported on MacOS. + * For Intel devices using a controller in the I801 family you have to download and install the [macUSPCIO driver](https://github.com/ShadyNawara/macUSPCIO/releases) ### USB Access @@ -310,7 +310,8 @@ There have been two instances of hardware damage in OpenRGB's development and we * hueplusplus: https://github.com/enwi/hueplusplus * httplib: https://github.com/yhirose/cpp-httplib * mdns: https://github.com/mjansson/mdns - + * macUSPCIO: https://github.com/ShadyNawara/macUSPCIO + ## Projects Researched While no code from these projects directly made its way into OpenRGB, these projects have been invaluable resources for protocol information. diff --git a/dependencies/macUSPCIO/macUSPCIOAccess.h b/dependencies/macUSPCIO/macUSPCIOAccess.h new file mode 100644 index 00000000..06d99bfe --- /dev/null +++ b/dependencies/macUSPCIO/macUSPCIOAccess.h @@ -0,0 +1,110 @@ +// +// macUSPCIOAccess.h +// Access methods for macUSPCIO +// +// Created by Shady Nawara +// MacUSPCIO: https://github.com/ShadyNawara/macUSPCIO +// + +#ifndef macUSPCIOAccess_h +#define macUSPCIOAccess_h + +#include + +extern io_connect_t macUSPCIO_driver_connection; + +inline bool InitMacUSPCIODriver() +{ + if(macUSPCIO_driver_connection) + { + return true; + } + + io_service_t dev = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("macUSPCIO")); + if (dev) + { + kern_return_t ret = IOServiceOpen(dev, mach_task_self(), 0, &macUSPCIO_driver_connection); + IOObjectRelease(dev); + return ret == kIOReturnSuccess; + } + return false; +} + +inline bool GetMacUSPCIODriverStatus() { + if(macUSPCIO_driver_connection) + { + return true; + } + return false; +} + +inline void CloseMacUSPCIODriver() { + if(macUSPCIO_driver_connection) { + IOServiceClose(macUSPCIO_driver_connection); + macUSPCIO_driver_connection = 0; + } +} + +inline uint8_t ReadIoPortByte(uint16_t address) +{ + if(!macUSPCIO_driver_connection) + { + return 0; + } + + uint32_t outputCount = 1; + uint64_t output = 0; + uint64_t input[1] = {address}; + + IOConnectCallScalarMethod(macUSPCIO_driver_connection, 0, input, 1, &output, &outputCount); + + return (uint8_t)output; +} + +inline void WriteIoPortByte(uint16_t address, uint8_t value) +{ + if(!macUSPCIO_driver_connection) + { + return; + } + + uint32_t outputCount = 1; + uint64_t output = 0; + uint64_t input[2] = {address, value}; + + IOConnectCallScalarMethod(macUSPCIO_driver_connection, 1, input, 2, &output, &outputCount); +} + +inline uint8_t ReadConfigPortByte(uint16_t address) { + if(!macUSPCIO_driver_connection) + { + return 0; + } + + uint32_t outputCount = 1; + uint64_t output = 0; + uint64_t input[1] = {address}; + + IOConnectCallScalarMethod(macUSPCIO_driver_connection, 2, input, 1, &output, &outputCount); + + return (uint8_t)output; +} + +inline uint16_t ReadConfigPortWord(uint16_t address) +{ + if(!macUSPCIO_driver_connection) + { + return 0; + } + + uint32_t outputCount = 1; + uint64_t output = 0; + uint64_t input[1] = {address}; + + IOConnectCallScalarMethod(macUSPCIO_driver_connection, 3, input, 1, &output, &outputCount); + + return (uint16_t)output; +} + + +#endif /* macUSPCIOAccess_h */ diff --git a/i2c_smbus/i2c_smbus_i801.cpp b/i2c_smbus/i2c_smbus_i801.cpp index 05b702f5..09b011c7 100644 --- a/i2c_smbus/i2c_smbus_i801.cpp +++ b/i2c_smbus/i2c_smbus_i801.cpp @@ -9,8 +9,13 @@ \*-----------------------------------------*/ #include "i2c_smbus_i801.h" +#ifdef _WIN32 #include #include "OlsApi.h" +#elif _MACOSX_X86_X64 +#include "macUSPCIOAccess.h" +#endif + #include "LogManager.h" using namespace std::chrono_literals; @@ -490,6 +495,7 @@ s32 i2c_smbus_i801::i2c_xfer(u8 addr, char read_write, int* size, u8* data) } #include "Detector.h" +#ifdef _WIN32 #include "wmi.h" bool i2c_smbus_i801_detect() @@ -558,6 +564,18 @@ bool i2c_smbus_i801_detect() int sbv_id = (int)std::stoul(sbv_str, nullptr, 16); int sbd_id = (int)std::stoul(sbd_str, nullptr, 16); + DWORD pciAddress = FindPciDeviceById(ven_id, dev_id, 0); + if(pciAddress == 0xFFFFFFFF) + { + continue; + } + + uint8_t host_config = ReadPciConfigWord(pciAddress, SMBHSTCFG); + if ((host_config & SMBHSTCFG_HST_EN) == 0) + { + continue; + } + bus = new i2c_smbus_i801(); bus->pci_vendor = ven_id; bus->pci_device = dev_id; @@ -572,5 +590,41 @@ bool i2c_smbus_i801_detect() return(true); } +#elif _MACOSX_X86_X64 +bool i2c_smbus_i801_detect() +{ + if(!GetMacUSPCIODriverStatus()) + { + LOG_INFO("macUSPCIO is not loaded, i801 I2C bus detection aborted"); + return(false); + } + + uint8_t host_config = ReadConfigPortByte(SMBHSTCFG); + if ((host_config & SMBHSTCFG_HST_EN) == 0) + { + LOG_INFO("i801 SMBus Disabled"); + return(false); + } + + i2c_smbus_interface * bus; + bus = new i2c_smbus_i801(); + // addresses are referenced from: https://opensource.apple.com/source/IOPCIFamily/IOPCIFamily-146/IOKit/pci/IOPCIDevice.h.auto.html + bus->pci_vendor = ReadConfigPortWord(0x00); + bus->pci_device = ReadConfigPortWord(0x02); + bus->pci_subsystem_vendor = ReadConfigPortWord(0x2c); + bus->pci_subsystem_device = ReadConfigPortWord(0x2e); + + if(!bus->pci_vendor || !bus->pci_device || !bus->pci_subsystem_vendor || !bus->pci_subsystem_device) + { + return(false); + } + + sprintf(bus->device_name, "Intel(R) SMBus - %X", bus->pci_device); + ((i2c_smbus_i801 *)bus)->i801_smba = ReadConfigPortWord(0x20) & 0xFFFE; + ResourceManager::get()->RegisterI2CBus(bus); + + return(true); +} +#endif REGISTER_I2C_BUS_DETECTOR(i2c_smbus_i801_detect); diff --git a/i2c_smbus/i2c_smbus_i801.h b/i2c_smbus/i2c_smbus_i801.h index 5d59ddab..d6cfe9c1 100644 --- a/i2c_smbus/i2c_smbus_i801.h +++ b/i2c_smbus/i2c_smbus_i801.h @@ -77,6 +77,10 @@ #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR) #define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | STATUS_ERROR_FLAGS) +/* I801 Host Config */ +#define SMBHSTCFG 0x040 +#define SMBHSTCFG_HST_EN BIT(0) + class i2c_smbus_i801 : public i2c_smbus_interface { public: diff --git a/main.cpp b/main.cpp index a961cd56..af1cb847 100644 --- a/main.cpp +++ b/main.cpp @@ -20,6 +20,11 @@ #include #include +#ifdef _MACOSX_X86_X64 +#include "macUSPCIOAccess.h" +io_connect_t macUSPCIO_driver_connection; +#endif + #include "OpenRGBDialog2.h" #ifdef __APPLE__ @@ -262,6 +267,14 @@ int main(int argc, char* argv[]) \*---------------------------------------------------------*/ InstallWinRing0(); #endif + + /*---------------------------------------------------------*\ + | Mac x86/x64 only - Install SMBus Driver macUSPCIO | + \*---------------------------------------------------------*/ +#ifdef _MACOSX_X86_X64 + InitMacUSPCIODriver(); +#endif + /*---------------------------------------------------------*\ | Process command line arguments before detection | \*---------------------------------------------------------*/ @@ -400,15 +413,24 @@ int main(int argc, char* argv[]) { if(!ResourceManager::get()->GetServer()->GetOnline()) { +#ifdef _MACOSX_X86_X64 + CloseMacUSPCIODriver(); +#endif return 1; } else { WaitWhileServerOnline(ResourceManager::get()->GetServer()); +#ifdef _MACOSX_X86_X64 + CloseMacUSPCIODriver(); +#endif } } else { +#ifdef _MACOSX_X86_X64 + CloseMacUSPCIODriver(); +#endif return 0; } }