From a6a5792c5f5f349bea5c07ac8a537e0e5b541083 Mon Sep 17 00:00:00 2001 From: Stephen Horvath Date: Tue, 13 May 2025 02:33:05 +1000 Subject: [PATCH] Replace WinRing0 with PawnIO for SMBus and Super-IO access on Windows Commits squashed, files cleaned up, and rebased by Adam Honse --- OpenRGB.pro | 69 ++- README.md | 3 +- dependencies/PawnIO/PawnIOLib.dll | Bin 0 -> 4096 bytes dependencies/PawnIO/PawnIOLib.h | 75 +++ dependencies/PawnIO/PawnIOLib.lib | Bin 0 -> 2506 bytes dependencies/PawnIO/modules/LpcIO.bin | Bin 0 -> 27228 bytes dependencies/PawnIO/modules/SmbusI801.bin | Bin 0 -> 39836 bytes dependencies/PawnIO/modules/SmbusPIIX4.bin | Bin 0 -> 35036 bytes dependencies/winring0/Win32/WinRing0.dll | Bin 65536 -> 0 bytes dependencies/winring0/Win32/WinRing0.lib | Bin 14774 -> 0 bytes dependencies/winring0/Win32/WinRing0.sys | Bin 14416 -> 0 bytes dependencies/winring0/include/OlsApi.h | 580 ------------------- dependencies/winring0/x64/WinRing0x64.dll | Bin 62976 -> 0 bytes dependencies/winring0/x64/WinRing0x64.lib | Bin 15124 -> 0 bytes dependencies/winring0/x64/WinRing0x64.sys | Bin 14544 -> 0 bytes i2c_smbus/{ => Linux}/i2c_smbus_linux.cpp | 0 i2c_smbus/{ => Linux}/i2c_smbus_linux.h | 0 i2c_smbus/{ => MacOS}/i2c_smbus_i801.cpp | 146 +---- i2c_smbus/{ => MacOS}/i2c_smbus_i801.h | 14 +- i2c_smbus/{ => MacOS}/i2c_smbus_nct6775.cpp | 50 +- i2c_smbus/{ => MacOS}/i2c_smbus_nct6775.h | 13 +- i2c_smbus/{ => MacOS}/i2c_smbus_piix4.cpp | 146 +---- i2c_smbus/{ => MacOS}/i2c_smbus_piix4.h | 15 +- i2c_smbus/{ => Windows}/i2c_smbus_amdadl.cpp | 0 i2c_smbus/{ => Windows}/i2c_smbus_amdadl.h | 0 i2c_smbus/{ => Windows}/i2c_smbus_nvapi.cpp | 0 i2c_smbus/{ => Windows}/i2c_smbus_nvapi.h | 0 i2c_smbus/Windows/i2c_smbus_pawnio.cpp | 558 ++++++++++++++++++ i2c_smbus/Windows/i2c_smbus_pawnio.h | 42 ++ startup/main_Windows.cpp | 82 --- super_io/super_io.cpp | 12 +- super_io/super_io.h | 2 + super_io/super_io_pawnio.cpp | 120 ++++ super_io/super_io_pawnio.h | 18 + 34 files changed, 878 insertions(+), 1067 deletions(-) create mode 100644 dependencies/PawnIO/PawnIOLib.dll create mode 100644 dependencies/PawnIO/PawnIOLib.h create mode 100644 dependencies/PawnIO/PawnIOLib.lib create mode 100644 dependencies/PawnIO/modules/LpcIO.bin create mode 100644 dependencies/PawnIO/modules/SmbusI801.bin create mode 100644 dependencies/PawnIO/modules/SmbusPIIX4.bin delete mode 100644 dependencies/winring0/Win32/WinRing0.dll delete mode 100644 dependencies/winring0/Win32/WinRing0.lib delete mode 100644 dependencies/winring0/Win32/WinRing0.sys delete mode 100644 dependencies/winring0/include/OlsApi.h delete mode 100644 dependencies/winring0/x64/WinRing0x64.dll delete mode 100644 dependencies/winring0/x64/WinRing0x64.lib delete mode 100644 dependencies/winring0/x64/WinRing0x64.sys rename i2c_smbus/{ => Linux}/i2c_smbus_linux.cpp (100%) rename i2c_smbus/{ => Linux}/i2c_smbus_linux.h (100%) rename i2c_smbus/{ => MacOS}/i2c_smbus_i801.cpp (77%) rename i2c_smbus/{ => MacOS}/i2c_smbus_i801.h (93%) rename i2c_smbus/{ => MacOS}/i2c_smbus_nct6775.cpp (86%) rename i2c_smbus/{ => MacOS}/i2c_smbus_nct6775.h (88%) rename i2c_smbus/{ => MacOS}/i2c_smbus_piix4.cpp (67%) rename i2c_smbus/{ => MacOS}/i2c_smbus_piix4.h (86%) rename i2c_smbus/{ => Windows}/i2c_smbus_amdadl.cpp (100%) rename i2c_smbus/{ => Windows}/i2c_smbus_amdadl.h (100%) rename i2c_smbus/{ => Windows}/i2c_smbus_nvapi.cpp (100%) rename i2c_smbus/{ => Windows}/i2c_smbus_nvapi.h (100%) create mode 100644 i2c_smbus/Windows/i2c_smbus_pawnio.cpp create mode 100644 i2c_smbus/Windows/i2c_smbus_pawnio.h create mode 100644 super_io/super_io_pawnio.cpp create mode 100644 super_io/super_io_pawnio.h diff --git a/OpenRGB.pro b/OpenRGB.pro index 9a49651d3..f9a78837c 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -198,7 +198,6 @@ HEADERS += serial_port/find_usb_serial_port.h \ serial_port/serial_port.h \ StringUtils.h \ - super_io/super_io.h \ SuspendResume/SuspendResume.h \ AutoStart/AutoStart.h \ KeyboardLayoutManager/KeyboardLayoutManager.h \ @@ -265,7 +264,6 @@ SOURCES += net_port/net_port.cpp \ serial_port/serial_port.cpp \ StringUtils.cpp \ - super_io/super_io.cpp \ AutoStart/AutoStart.cpp \ KeyboardLayoutManager/KeyboardLayoutManager.cpp \ RGBController/RGBController.cpp \ @@ -329,10 +327,11 @@ win32:QMAKE_CXXFLAGS += /utf-8 win32:INCLUDEPATH += \ dependencies/display-library/include \ dependencies/hidapi-win/include \ - dependencies/winring0/include \ dependencies/libusb-1.0.27/include \ dependencies/mbedtls-3.2.1/include \ dependencies/NVFC \ + dependencies/PawnIO \ + i2c_smbus/Windows \ wmi/ \ win32:SOURCES += $$CONTROLLER_CPP_WINDOWS @@ -340,11 +339,10 @@ win32:SOURCES += $$CONTROLLER_CPP_WINDOWS win32:SOURCES += \ dependencies/hueplusplus-1.2.0/src/WinHttpHandler.cpp \ dependencies/NVFC/nvapi.cpp \ - i2c_smbus/i2c_smbus_amdadl.cpp \ - i2c_smbus/i2c_smbus_i801.cpp \ - i2c_smbus/i2c_smbus_nct6775.cpp \ - i2c_smbus/i2c_smbus_nvapi.cpp \ - i2c_smbus/i2c_smbus_piix4.cpp \ + i2c_smbus/Windows/i2c_smbus_amdadl.cpp \ + i2c_smbus/Windows/i2c_smbus_nvapi.cpp \ + i2c_smbus/Windows/i2c_smbus_pawnio.cpp \ + super_io/super_io_pawnio.cpp \ scsiapi/scsiapi_windows.c \ serial_port/find_usb_serial_port_win.cpp \ SuspendResume/SuspendResume_Windows.cpp \ @@ -358,12 +356,12 @@ win32:HEADERS += dependencies/display-library/include/adl_defines.h \ dependencies/display-library/include/adl_sdk.h \ dependencies/display-library/include/adl_structures.h \ - dependencies/winring0/include/OlsApi.h \ dependencies/NVFC/nvapi.h \ - i2c_smbus/i2c_smbus_i801.h \ - i2c_smbus/i2c_smbus_nct6775.h \ - i2c_smbus/i2c_smbus_nvapi.h \ - i2c_smbus/i2c_smbus_piix4.h \ + dependencies/PawnIO/PawnIOLib.h \ + i2c_smbus/Windows/i2c_smbus_amdadl.h \ + i2c_smbus/Windows/i2c_smbus_nvapi.h \ + i2c_smbus/Windows/i2c_smbus_pawnio.h \ + super_io/super_io_pawnio.h \ wmi/wmi.h \ AutoStart/AutoStart-Windows.h \ SuspendResume/SuspendResume_Windows.h \ @@ -372,17 +370,16 @@ win32:contains(QMAKE_TARGET.arch, x86_64) { LIBS += \ -lws2_32 \ -liphlpapi \ - -L"$$PWD/dependencies/winring0/x64/" -lWinRing0x64 \ -L"$$PWD/dependencies/libusb-1.0.27/VS2019/MS64/dll" -llibusb-1.0 \ -L"$$PWD/dependencies/hidapi-win/x64/" -lhidapi \ -L"$$PWD/dependencies/mbedtls-3.2.1/lib/x64/" -lmbedcrypto -lmbedtls -lmbedx509 \ + -L"$$PWD/dependencies/PawnIO/" -lPawnIOLib \ } win32:contains(QMAKE_TARGET.arch, x86) { LIBS += \ -lws2_32 \ -liphlpapi \ - -L"$$PWD/dependencies/winring0/Win32/" -lWinRing0 \ -L"$$PWD/dependencies/libusb-1.0.27/VS2019/MS32/dll" -llibusb-1.0 \ -L"$$PWD/dependencies/hidapi-win/x86/" -lhidapi \ -L"$$PWD/dependencies/mbedtls-3.2.1/lib/x86/" -lmbedcrypto -lmbedtls -lmbedx509 \ @@ -402,6 +399,11 @@ win32:DEFINES += win32:RC_ICONS += \ qt/OpenRGB.ico +win32:DISTFILES += \ + dependencies/PawnIO/modules/SmbusPIIX4.bin \ + dependencies/PawnIO/modules/SmbusI801.bin \ + dependencies/PawnIO/modules/LpcIO.bin + #-----------------------------------------------------------------------------------------------# # Windows GitLab CI Configuration # #-----------------------------------------------------------------------------------------------# @@ -423,10 +425,12 @@ win32:UI_DIR = _intermediate_$$DESTDIR/.ui #-----------------------------------------------------------------------------------------------# win32:contains(QMAKE_TARGET.arch, x86_64) { - copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/winring0/x64/WinRing0x64.dll )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) - copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/winring0/x64/WinRing0x64.sys )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/libusb-1.0.27/VS2019/MS64/dll/libusb-1.0.dll)\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/hidapi-win/x64/hidapi.dll )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) + copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/PawnIOLib.dll )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) + copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/SmbusPIIX4.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) + copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/SmbusI801.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) + copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/PawnIO/modules/LpcIO.bin )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) first.depends = $(first) copydata export(first.depends) export(copydata.commands) @@ -434,9 +438,6 @@ win32:contains(QMAKE_TARGET.arch, x86_64) { } win32:contains(QMAKE_TARGET.arch, x86) { - copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/winring0/Win32/WinRing0.dll )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) - copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/winring0/Win32/WinRing0.sys )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) - copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/winring0/x64/WinRing0x64.sys )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/libusb-1.0.27/VS2019/MS32/dll/libusb-1.0.dll)\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) copydata.commands += $(COPY_FILE) \"$$shell_path($$PWD/dependencies/hidapi-win/x86/hidapi.dll )\" \"$$shell_path($$DESTDIR)\" $$escape_expand(\n\t) @@ -461,14 +462,16 @@ contains(QMAKE_PLATFORM, linux) { HEADERS += \ dependencies/NVFC/nvapi.h \ - i2c_smbus/i2c_smbus_linux.h \ + i2c_smbus/Linux/i2c_smbus_linux.h \ AutoStart/AutoStart-Linux.h \ SPDAccessor/EE1004Accessor_Linux.h \ SPDAccessor/SPD5118Accessor_Linux.h \ SuspendResume/SuspendResume_Linux_FreeBSD.h \ + super_io/super_io.h \ INCLUDEPATH += \ dependencies/NVFC \ + i2c_smbus/Linux \ /usr/include/mbedtls/ \ LIBS += \ @@ -515,7 +518,7 @@ contains(QMAKE_PLATFORM, linux) { SOURCES += \ dependencies/hueplusplus-1.2.0/src/LinHttpHandler.cpp \ dependencies/NVFC/nvapi.cpp \ - i2c_smbus/i2c_smbus_linux.cpp \ + i2c_smbus/Linux/i2c_smbus_linux.cpp \ scsiapi/scsiapi_linux.c \ serial_port/find_usb_serial_port_linux.cpp \ AutoStart/AutoStart-Linux.cpp \ @@ -523,6 +526,7 @@ contains(QMAKE_PLATFORM, linux) { SPDAccessor/SPD5118Accessor_Linux.cpp \ SuspendResume/SuspendResume_Linux_FreeBSD.cpp \ startup/main_Linux_MacOS.cpp \ + super_io/super_io.cpp \ #-------------------------------------------------------------------------------------------# # Set up install paths # @@ -598,6 +602,7 @@ contains(QMAKE_PLATFORM, freebsd) { HEADERS += \ AutoStart/AutoStart-FreeBSD.h \ SuspendResume/SuspendResume_Linux_FreeBSD.h \ + super_io/super_io.h \ HEADERS -= \ Controllers/SeagateController/RGBController_Seagate.h \ @@ -646,6 +651,7 @@ contains(QMAKE_PLATFORM, freebsd) { serial_port/find_usb_serial_port_linux.cpp \ AutoStart/AutoStart-FreeBSD.cpp \ SuspendResume/SuspendResume_Linux_FreeBSD.cpp \ + super_io/super_io.cpp \ SOURCES -= \ Controllers/SeagateController/RGBController_Seagate.cpp \ @@ -748,6 +754,10 @@ macx:contains(QMAKE_HOST.arch, arm64) { SOURCES += \ scsiapi/scsiapi_macos.c \ + super_io/super_io.cpp \ + + HEADERS += \ + super_io/super_io.h \ LIBS += \ -L/opt/homebrew/lib \ @@ -759,20 +769,23 @@ macx:contains(QMAKE_HOST.arch, arm64) { macx:contains(QMAKE_HOST.arch, x86_64) { INCLUDEPATH += \ dependencies/macUSPCIO \ + i2c_smbus/MacOS \ /usr/local/include \ /usr/local/homebrew/include \ SOURCES += \ - i2c_smbus/i2c_smbus_i801.cpp \ - i2c_smbus/i2c_smbus_nct6775.cpp \ - i2c_smbus/i2c_smbus_piix4.cpp \ + i2c_smbus/MacOS/i2c_smbus_i801.cpp \ + i2c_smbus/MacOS/i2c_smbus_nct6775.cpp \ + i2c_smbus/MacOS/i2c_smbus_piix4.cpp \ scsiapi/scsiapi_macos.c \ + super_io/super_io.cpp \ HEADERS += \ dependencies/macUSPCIO/macUSPCIOAccess.h \ - i2c_smbus/i2c_smbus_i801.h \ - i2c_smbus/i2c_smbus_nct6775.h \ - i2c_smbus/i2c_smbus_piix4.h \ + i2c_smbus/MacOS/i2c_smbus_i801.h \ + i2c_smbus/MacOS/i2c_smbus_nct6775.h \ + i2c_smbus/MacOS/i2c_smbus_piix4.h \ + super_io/super_io.h \ LIBS += \ -L/usr/local/lib \ diff --git a/README.md b/README.md index 772c922ce..ec61606e9 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,7 @@ This project interacts directly with hardware using reverse engineered protocols ## Projects Used * OpenRGB directly relies upon these projects. - - * WinRing0: https://openlibsys.org/ + * PawnIO: https://pawnio.eu/ * libusb: https://github.com/libusb/libusb * hidapi: https://github.com/libusb/hidapi * libe131: https://github.com/hhromic/libe131 diff --git a/dependencies/PawnIO/PawnIOLib.dll b/dependencies/PawnIO/PawnIOLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..1e79e772f9189d6d4c628faa74fee1cc88e7004f GIT binary patch literal 4096 zcmeGfZERCj^z?)8bt@k;GnwITJnW)wE0)AbI%!=uUSszW*qD(id%V8UC$I0-_uk5e zC`ClA&%$D20?|Jj6BC08!4Ve1kLu9PxFrOQB0m)M2PGi}6_pT^dhYA%>;U19`h#%N zbI<2J_uO;uyZ5&Ji4kxBfDH2{aO&lFNW?Hm9&M+fqnKdPApDFRSE zOLGeW{rhj?(x3}NI@*unoXlM59ISa1yAcf0phh{J1GtxN22{+d5sDN7_-jZM{4o8( z1ZdncD*O!r>ZfWdk1BJnr~v9$j#vT#Gh~V44*S1XV2tj?@u?YL_gt*YrEsx~$((^? zZ}$25700qJfO#o)&&j$HSF;bB?qlY&X^C;OX`QL+4R!~6f*XUq7^gpCj51ja-;rUa z3DU6fbGvbcHO@wi3*ia#%gR?iTLI8+ob;V$jY-zXy`t%_jkQAl5zfqW{meWo9QI^%3WwRUS#OmRnePm^?lar%lb}-jp>TTA*L(i{DgX^ zLk!EJ*J0#Y6as7pjiGduX=2km8Sg}hsdLsGd7IiuE{%0D&g{(&m9a*Id7S;|f+L(R zj~Ej)(dm5U6z*l?^IQzwN=p>U^fCQmW0N;*Y-pM-;d68J@nDfZdN#n9yMp8N^E=z1?S?GGWd)eI=Q*@ff zH*BVI7*oXoeR($hFq?@mUK-7t`w$&y9y^&jS_v;LLU#o10h&{PgjNSteaF!cliJA) zv6(TzC;5EF|5P9csg0eA)VZy>&lco^{nB8_0j7nc*dxb1SdGa_zjh)NP9 zP!g5RyrgJCQ4od%eo&tgC54L?O-e$Li+oa0HBpiAIxeaG8RY8-)~iHUMb{K{H-i6q zA2@6sdW$)^L&$Yv`fZ{l0Q8^~5|Sb>gq0RW)>TC^4foAiuS*^J2A$IfwQeP(XsxQM zsPMWI^}H||2q8w{4c?xtv>+poDG?4 zz`u4VE)na9YWA#Z@Op?K*}DUhvfmqidK7zXuevrANJJn3|2*b*pgAB3eODUC_=PL6_a>~Z56Z`W2w2-JihT{ zjtEIXA`)$zJ)9Pnlgc(h^^id^$kWrO*)zaNn&2UgGjaTl|2&GnaaK?A0$KlhoB#j- literal 0 HcmV?d00001 diff --git a/dependencies/PawnIO/PawnIOLib.h b/dependencies/PawnIO/PawnIOLib.h new file mode 100644 index 000000000..b1f6b07fb --- /dev/null +++ b/dependencies/PawnIO/PawnIOLib.h @@ -0,0 +1,75 @@ +// PawnIOLib - Library and tooling source to be used with PawnIO. +// Copyright (C) 2023 namazso +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef PAWNIOLIB_LIBRARY_H +#define PAWNIOLIB_LIBRARY_H + +#ifdef PawnIOLib_EXPORTS +#define PAWNIO_EXPORT __declspec(dllexport) +#else +#define PAWNIO_EXPORT __declspec(dllimport) +#endif + +#define PAWNIOAPI EXTERN_C PAWNIO_EXPORT HRESULT STDAPICALLTYPE + +/// Get PawnIOLib version. +/// +/// @p version A pointer to a ULONG which receives the version. +/// @return A HRESULT. +PAWNIOAPI pawnio_version(PULONG version); + +/// Open a PawnIO executor. +/// +/// @p handle A handle to the executor, or NULL. +/// @return A HRESULT. +PAWNIOAPI pawnio_open(PHANDLE handle); + +/// Load a PawnIO blob. +/// +/// @p handle Handle from @c pawnio_open. +/// @p blob Blob to load. +/// @p size Size of blob. +/// @return A HRESULT. +PAWNIOAPI pawnio_load(HANDLE handle, const UCHAR* blob, SIZE_T size); + +/// Executes a function from the loaded blob. +/// +/// @p handle Handle from @c pawnio_open. +/// @p name Function name to execute. +/// @p in Input buffer. +/// @p in_size Input buffer count. +/// @p out Output buffer. +/// @p out_size Output buffer count. +/// @p return_size Entries written in out_size. +/// @return A HRESULT. +PAWNIOAPI pawnio_execute( + HANDLE handle, + PCSTR name, + const ULONG64* in, + SIZE_T in_size, + PULONG64 out, + SIZE_T out_size, + PSIZE_T return_size +); + +/// Close a PawnIO executor. +/// +/// @p handle Handle from @c pawnio_open. +/// @return A HRESULT. +PAWNIOAPI pawnio_close(HANDLE handle); + +#endif //PAWNIOLIB_LIBRARY_H diff --git a/dependencies/PawnIO/PawnIOLib.lib b/dependencies/PawnIO/PawnIOLib.lib new file mode 100644 index 0000000000000000000000000000000000000000..daa76a6f6d18a076dceb49607e2f66f0940a22c9 GIT binary patch literal 2506 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 literal 0 HcmV?d00001 diff --git a/dependencies/winring0/Win32/WinRing0.dll b/dependencies/winring0/Win32/WinRing0.dll deleted file mode 100644 index 1cd219a8bb49b76532dafb1ceb60d9bbfe3096ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/dependencies/winring0/Win32/WinRing0.lib b/dependencies/winring0/Win32/WinRing0.lib deleted file mode 100644 index e7adf350ac510faa09714608bd7ec89f89bb3cf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14774 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 BZ*Kqq diff --git a/dependencies/winring0/Win32/WinRing0.sys b/dependencies/winring0/Win32/WinRing0.sys deleted file mode 100644 index feaea414a8b4991a2de419dc0c81a9144256807b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14416 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 diff --git a/i2c_smbus/i2c_smbus_linux.cpp b/i2c_smbus/Linux/i2c_smbus_linux.cpp similarity index 100% rename from i2c_smbus/i2c_smbus_linux.cpp rename to i2c_smbus/Linux/i2c_smbus_linux.cpp diff --git a/i2c_smbus/i2c_smbus_linux.h b/i2c_smbus/Linux/i2c_smbus_linux.h similarity index 100% rename from i2c_smbus/i2c_smbus_linux.h rename to i2c_smbus/Linux/i2c_smbus_linux.h diff --git a/i2c_smbus/i2c_smbus_i801.cpp b/i2c_smbus/MacOS/i2c_smbus_i801.cpp similarity index 77% rename from i2c_smbus/i2c_smbus_i801.cpp rename to i2c_smbus/MacOS/i2c_smbus_i801.cpp index 8b3a18410..d5cd7ce47 100644 --- a/i2c_smbus/i2c_smbus_i801.cpp +++ b/i2c_smbus/MacOS/i2c_smbus_i801.cpp @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_i801.cpp | | | -| i801 SMBUS driver for Windows | +| i801 SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 29 Jan 2019 | | Portions based on Linux source code | @@ -10,47 +10,22 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include "macUSPCIOAccess.h" + #include "Detector.h" #include "i2c_smbus_i801.h" -#include "ResourceManager.h" - -#ifdef _WIN32 -#include "OlsApi.h" -#include "wmi.h" -#elif _MACOSX_X86_X64 -#include "macUSPCIOAccess.h" -#endif - #include "LogManager.h" +#include "ResourceManager.h" #include "SettingsManager.h" using namespace std::chrono_literals; i2c_smbus_i801::i2c_smbus_i801() { -#ifdef _WIN32 - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - - bool shared_smbus_access = true; - if(drivers_settings.contains("shared_smbus_access")) - { - shared_smbus_access = drivers_settings["shared_smbus_access"].get(); - } - if(shared_smbus_access) - { - global_smbus_access_handle = CreateMutexA(NULL, FALSE, GLOBAL_SMBUS_MUTEX_NAME); - } -#endif } i2c_smbus_i801::~i2c_smbus_i801() { -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - CloseHandle(global_smbus_access_handle); - } -#endif } /* Return negative errno on error. */ @@ -519,22 +494,8 @@ int i2c_smbus_i801::i801_wait_intr() s32 i2c_smbus_i801::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) { -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - WaitForSingleObject(global_smbus_access_handle, INFINITE); - } -#endif - s32 result = i801_access(addr, read_write, command, size, data); -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - ReleaseMutex(global_smbus_access_handle); - } -#endif - return result; } @@ -543,103 +504,6 @@ s32 i2c_smbus_i801::i2c_xfer(u8 /*addr*/, char /*read_write*/, int* /*size*/, u8 return -1; } -#ifdef _WIN32 - -bool i2c_smbus_i801_detect() -{ - if(!InitializeOls() || GetDllStatus()) - { - LOG_INFO("WinRing0 is not loaded, i801 I2C bus detection aborted"); - return(false); - } - - i2c_smbus_interface * bus; - HRESULT hres; - Wmi wmi; - - // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" - // These devices may be browsed under Device Manager -> System Devices - std::vector q_res_PnPSignedDriver; - hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'", q_res_PnPSignedDriver); - - if (hres) - { - LOG_INFO("WMI query failed, i801 I2C bus detection aborted"); - return(false); - } - - // For each detected SMBus adapter, try enumerating it as either AMD or Intel - for (QueryObj &i : q_res_PnPSignedDriver) - { - // Intel SMBus controllers do show I/O resources in Device Manager - // Analysis of many Intel boards has shown that Intel SMBus adapter I/O space varies between boards - // We can query Win32_PnPAllocatedResource entries and look up the PCI device ID to find the allocated I/O space - // Intel SMBus adapters use the i801 driver - if ((i["Manufacturer"].find("Intel") != std::string::npos) - || (i["Manufacturer"].find("INTEL") != std::string::npos)) - { - std::string rgx1 = ".+" + q_res_PnPSignedDriver[0]["DeviceID"].substr(4, 33) + ".+"; - - AdditionalFilters filters; - filters.emplace("Dependent", rgx1); - filters.emplace("Antecedent", ".*Port.*"); - - std::vector q_res_PNPAllocatedResource; - hres = wmi.query("SELECT * FROM Win32_PnPAllocatedResource", q_res_PNPAllocatedResource, &filters); - - std::regex rgx2(".*StartingAddress=\"(\\d+)\".*"); - std::smatch matches; - - // Query the StartingAddress for the matching device ID and use it to enumerate the bus - if (!q_res_PNPAllocatedResource.empty() && std::regex_search(q_res_PNPAllocatedResource[0]["Antecedent"], matches, rgx2)) - { - unsigned int IORangeStart = std::stoi(matches[1].str()); - - std::string pnp_str = i["DeviceID"]; - - std::size_t ven_loc = pnp_str.find("VEN_"); - std::size_t dev_loc = pnp_str.find("DEV_"); - std::size_t sub_loc = pnp_str.find("SUBSYS_"); - - std::string ven_str = pnp_str.substr(ven_loc + 4, 4); - std::string dev_str = pnp_str.substr(dev_loc + 4, 4); - std::string sbv_str = pnp_str.substr(sub_loc + 11, 4); - std::string sbd_str = pnp_str.substr(sub_loc + 7, 4); - - int ven_id = (int)std::stoul(ven_str, nullptr, 16); - int dev_id = (int)std::stoul(dev_str, nullptr, 16); - 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 = (uint8_t)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; - bus->pci_subsystem_vendor = sbv_id; - bus->pci_subsystem_device = sbd_id; - strcpy(bus->device_name, i["Description"].c_str()); - ((i2c_smbus_i801 *)bus)->i801_smba = IORangeStart; - ResourceManager::get()->RegisterI2CBus(bus); - } - } - } - - return(true); -} - -#elif _MACOSX_X86_X64 - bool i2c_smbus_i801_detect() { if(!GetMacUSPCIODriverStatus()) @@ -675,6 +539,4 @@ bool i2c_smbus_i801_detect() return(true); } -#endif - REGISTER_I2C_BUS_DETECTOR(i2c_smbus_i801_detect); diff --git a/i2c_smbus/i2c_smbus_i801.h b/i2c_smbus/MacOS/i2c_smbus_i801.h similarity index 93% rename from i2c_smbus/i2c_smbus_i801.h rename to i2c_smbus/MacOS/i2c_smbus_i801.h index 27bb18ce5..8c06b6177 100644 --- a/i2c_smbus/i2c_smbus_i801.h +++ b/i2c_smbus/MacOS/i2c_smbus_i801.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_i801.h | | | -| i801 SMBUS driver for Windows | +| i801 SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 29 Jan 2019 | | Portions based on Linux source code | @@ -14,10 +14,6 @@ #include "i2c_smbus.h" -#ifdef _WIN32 -#include -#endif - /* BIT shifting macro */ #define BIT(x) ( 1 << x ) @@ -87,10 +83,6 @@ #define SMBHSTCFG 0x040 #define SMBHSTCFG_HST_EN BIT(0) -#ifdef _WIN32 -#define GLOBAL_SMBUS_MUTEX_NAME "Global\\Access_SMBUS.HTP.Method" -#endif - class i2c_smbus_i801 : public i2c_smbus_interface { public: @@ -109,8 +101,4 @@ private: int i801_wait_intr(); s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data); s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data); - -#ifdef _WIN32 - HANDLE global_smbus_access_handle = NULL; -#endif }; diff --git a/i2c_smbus/i2c_smbus_nct6775.cpp b/i2c_smbus/MacOS/i2c_smbus_nct6775.cpp similarity index 86% rename from i2c_smbus/i2c_smbus_nct6775.cpp rename to i2c_smbus/MacOS/i2c_smbus_nct6775.cpp index d18674e60..020ca0fad 100644 --- a/i2c_smbus/i2c_smbus_nct6775.cpp +++ b/i2c_smbus/MacOS/i2c_smbus_nct6775.cpp @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_nct6775.cpp | | | -| Nuvoton NCT67xx SMBUS driver for Windows | +| Nuvoton NCT67xx SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 19 May 2019 | | | @@ -9,14 +9,11 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include "macUSPCIOAccess.h" + #include "Detector.h" #include "i2c_smbus_nct6775.h" #include "LogManager.h" -#ifdef _WIN32 -#include "OlsApi.h" -#elif _MACOSX_X86_X64 -#include "macUSPCIOAccess.h" -#endif #include "ResourceManager.h" #include "SettingsManager.h" #include "super_io.h" @@ -25,29 +22,10 @@ using namespace std::chrono_literals; i2c_smbus_nct6775::i2c_smbus_nct6775() { -#ifdef _WIN32 - json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); - - bool shared_smbus_access = true; - if(drivers_settings.contains("shared_smbus_access")) - { - shared_smbus_access = drivers_settings["shared_smbus_access"].get(); - } - if(shared_smbus_access) - { - global_smbus_access_handle = CreateMutexA(NULL, FALSE, GLOBAL_SMBUS_MUTEX_NAME); - } -#endif } i2c_smbus_nct6775::~i2c_smbus_nct6775() { -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - CloseHandle(global_smbus_access_handle); - } -#endif } s32 i2c_smbus_nct6775::nct6775_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data) @@ -223,22 +201,8 @@ s32 i2c_smbus_nct6775::nct6775_access(u16 addr, char read_write, u8 command, int s32 i2c_smbus_nct6775::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) { -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - WaitForSingleObject(global_smbus_access_handle, INFINITE); - } -#endif - s32 result = nct6775_access(addr, read_write, command, size, data); -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - ReleaseMutex(global_smbus_access_handle); - } -#endif - return result; } @@ -249,19 +213,11 @@ s32 i2c_smbus_nct6775::i2c_xfer(u8 /*addr*/, char /*read_write*/, int* /*size*/, bool i2c_smbus_nct6775_detect() { -#ifdef _WIN32 - if(!InitializeOls() || GetDllStatus()) - { - LOG_INFO("WinRing0 is not loaded, nct6775 I2C bus detection aborted"); - return(false); - } -#elif _MACOSX_X86_X64 if(!GetMacUSPCIODriverStatus()) { LOG_INFO("macUSPCIO is not loaded, nct6775 I2C bus detection aborted"); return(false); } -#endif i2c_smbus_interface* bus; int sioaddr = 0x2E; diff --git a/i2c_smbus/i2c_smbus_nct6775.h b/i2c_smbus/MacOS/i2c_smbus_nct6775.h similarity index 88% rename from i2c_smbus/i2c_smbus_nct6775.h rename to i2c_smbus/MacOS/i2c_smbus_nct6775.h index 651c413ca..127894c32 100644 --- a/i2c_smbus/i2c_smbus_nct6775.h +++ b/i2c_smbus/MacOS/i2c_smbus_nct6775.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_nct6775.h | | | -| Nuvoton NCT67xx SMBUS driver for Windows | +| Nuvoton NCT67xx SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 19 May 2019 | | | @@ -12,9 +12,6 @@ #pragma once #include "i2c_smbus.h" -#ifdef _WIN32 -#include -#endif #define SMBHSTDAT (0 + nct6775_smba) #define SMBBLKSZ (1 + nct6775_smba) @@ -50,10 +47,6 @@ /* Other settings */ #define NCT6775_MAX_RETRIES 400 -#ifdef _WIN32 -#define GLOBAL_SMBUS_MUTEX_NAME "Global\\Access_SMBUS.HTP.Method" -#endif - class i2c_smbus_nct6775: public i2c_smbus_interface { public: @@ -65,8 +58,4 @@ private: s32 nct6775_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data); s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data); s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data); - -#ifdef _WIN32 - HANDLE global_smbus_access_handle = NULL; -#endif }; diff --git a/i2c_smbus/i2c_smbus_piix4.cpp b/i2c_smbus/MacOS/i2c_smbus_piix4.cpp similarity index 67% rename from i2c_smbus/i2c_smbus_piix4.cpp rename to i2c_smbus/MacOS/i2c_smbus_piix4.cpp index cdd5ce301..ed0482ad1 100644 --- a/i2c_smbus/i2c_smbus_piix4.cpp +++ b/i2c_smbus/MacOS/i2c_smbus_piix4.cpp @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_piix4.cpp | | | -| PIIX4 SMBUS driver for Windows | +| PIIX4 SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 08 Aug 2018 | | Portions based on Linux source code | @@ -10,17 +10,13 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include +#include "macUSPCIOAccess.h" + #include "Detector.h" #include "i2c_smbus_piix4.h" #include "LogManager.h" -#ifdef _WIN32 -#include "OlsApi.h" -#include "wmi.h" -#elif _MACOSX_X86_X64 -#include -#include "macUSPCIOAccess.h" #include "pci_ids.h" -#endif #include "ResourceManager.h" #include "SettingsManager.h" @@ -33,43 +29,12 @@ i2c_smbus_piix4::i2c_smbus_piix4() { amd_smbus_reduce_cpu = drivers_settings["amd_smbus_reduce_cpu"].get(); } -#ifdef _WIN32 - if(amd_smbus_reduce_cpu) - { - delay_timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_MANUAL_RESET | CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); - if(delay_timer == NULL) // high resolution timer not supported - { - delay_timer = CreateWaitableTimer(NULL, TRUE, NULL); // create regular timer instead - } - } - bool shared_smbus_access = true; - if(drivers_settings.contains("shared_smbus_access")) - { - shared_smbus_access = drivers_settings["shared_smbus_access"].get(); - } - if(shared_smbus_access) - { - global_smbus_access_handle = CreateMutexA(NULL, FALSE, GLOBAL_SMBUS_MUTEX_NAME); - } -#else delay_timer = amd_smbus_reduce_cpu; -#endif } i2c_smbus_piix4::~i2c_smbus_piix4() { -#ifdef _WIN32 - if(delay_timer != NULL) - { - CloseHandle(delay_timer); - } - - if(global_smbus_access_handle != NULL) - { - CloseHandle(global_smbus_access_handle); - } -#endif } //Logic adapted from piix4_transaction() in i2c-piix4.c @@ -105,21 +70,8 @@ int i2c_smbus_piix4::piix4_transaction() | if this bit is set. Note that there may be moderate latency before the transaction begins and the Host Busy bit | | gets set. | \*---------------------------------------------------------------------------------------------------------------*/ -#ifdef _WIN32 - if(delay_timer != NULL) - { - LARGE_INTEGER retry_delay; - retry_delay.QuadPart = RETRY_DELAY_US * -10; + temp = 0; - do - { - SetWaitableTimer(delay_timer, &retry_delay, 0, NULL, NULL, FALSE); - WaitForSingleObject(delay_timer, INFINITE); - temp = ReadIoPortByte(SMBHSTSTS); - } - while((++timeout < MAX_TIMEOUT) && ((temp & 0x03) != 0x02)); - } -#else if(delay_timer) { do @@ -129,7 +81,6 @@ int i2c_smbus_piix4::piix4_transaction() } while((++timeout < MAX_TIMEOUT) && ((temp & 0x03) != 0x02)); } -#endif else { std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); @@ -282,22 +233,8 @@ s32 i2c_smbus_piix4::piix4_access(u16 addr, char read_write, u8 command, int siz s32 i2c_smbus_piix4::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) { -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - WaitForSingleObject(global_smbus_access_handle, INFINITE); - } -#endif - s32 result = piix4_access(addr, read_write, command, size, data); -#ifdef _WIN32 - if(global_smbus_access_handle != NULL) - { - ReleaseMutex(global_smbus_access_handle); - } -#endif - return result; } @@ -305,79 +242,7 @@ s32 i2c_smbus_piix4::i2c_xfer(u8 /*addr*/, char /*read_write*/, int* /*size*/, u { return -1; } -#ifdef _WIN32 -bool i2c_smbus_piix4_detect() -{ - if(!InitializeOls() || GetDllStatus()) - { - LOG_INFO("WinRing0 is not loaded, piix4 I2C bus detection aborted"); - return(false); - } - i2c_smbus_interface * bus; - HRESULT hres; - Wmi wmi; - - // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" - // These devices may be browsed under Device Manager -> System Devices - std::vector q_res_PnPSignedDriver; - hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'", q_res_PnPSignedDriver); - - if (hres) - { - LOG_INFO("WMI query failed, piix4 I2C bus detection aborted"); - return(false); - } - - // For each detected SMBus adapter, try enumerating it as either AMD or Intel - for (QueryObj &i : q_res_PnPSignedDriver) - { - // AMD SMBus controllers do not show any I/O resources allocated in Device Manager - // Analysis of many AMD boards has shown that AMD SMBus controllers have two adapters with fixed I/O spaces at 0x0B00 and 0x0B20 - // AMD SMBus adapters use the PIIX4 driver - if (i["Manufacturer"].find("Advanced Micro Devices, Inc") != std::string::npos) - { - std::string pnp_str = i["DeviceID"]; - - std::size_t ven_loc = pnp_str.find("VEN_"); - std::size_t dev_loc = pnp_str.find("DEV_"); - std::size_t sub_loc = pnp_str.find("SUBSYS_"); - - std::string ven_str = pnp_str.substr(ven_loc + 4, 4); - std::string dev_str = pnp_str.substr(dev_loc + 4, 4); - std::string sbv_str = pnp_str.substr(sub_loc + 11, 4); - std::string sbd_str = pnp_str.substr(sub_loc + 7, 4); - - int ven_id = (int)std::stoul(ven_str, nullptr, 16); - int dev_id = (int)std::stoul(dev_str, nullptr, 16); - int sbv_id = (int)std::stoul(sbv_str, nullptr, 16); - int sbd_id = (int)std::stoul(sbd_str, nullptr, 16); - - bus = new i2c_smbus_piix4(); - bus->pci_vendor = ven_id; - bus->pci_device = dev_id; - bus->pci_subsystem_vendor = sbv_id; - bus->pci_subsystem_device = sbd_id; - strcpy(bus->device_name, i["Description"].c_str()); - strcat(bus->device_name, " at 0x0B00"); - ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B00; - ResourceManager::get()->RegisterI2CBus(bus); - - bus = new i2c_smbus_piix4(); - bus->pci_vendor = ven_id; - bus->pci_device = dev_id; - bus->pci_subsystem_vendor = sbv_id; - bus->pci_subsystem_device = sbd_id; - ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B20; - strcpy(bus->device_name, i["Description"].c_str()); - strcat(bus->device_name, " at 0x0B20"); - ResourceManager::get()->RegisterI2CBus(bus); - } - } - - return(true); -} -#elif _MACOSX_X86_X64 bool i2c_smbus_piix4_detect() { if(!GetMacUSPCIODriverStatus()) @@ -419,6 +284,5 @@ bool i2c_smbus_piix4_detect() return(true); } -#endif REGISTER_I2C_BUS_DETECTOR(i2c_smbus_piix4_detect); diff --git a/i2c_smbus/i2c_smbus_piix4.h b/i2c_smbus/MacOS/i2c_smbus_piix4.h similarity index 86% rename from i2c_smbus/i2c_smbus_piix4.h rename to i2c_smbus/MacOS/i2c_smbus_piix4.h index bcb2dbdc5..abf5a2852 100644 --- a/i2c_smbus/i2c_smbus_piix4.h +++ b/i2c_smbus/MacOS/i2c_smbus_piix4.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------*\ | i2c_smbus_piix4.h | | | -| PIIX4 SMBUS driver for Windows | +| PIIX4 SMBUS driver for MacOS | | | | Adam Honse (CalcProgrammer1) 08 Aug 2018 | | Portions based on Linux source code | @@ -13,9 +13,6 @@ #pragma once #include "i2c_smbus.h" -#ifdef _WIN32 -#include "windows.h" -#endif // PIIX4 SMBus address offsets #define SMBHSTSTS (0 + piix4_smba) @@ -41,10 +38,6 @@ #define PIIX4_WORD_DATA 0x0C #define PIIX4_BLOCK_DATA 0x14 -#ifdef _WIN32 -#define GLOBAL_SMBUS_MUTEX_NAME "Global\\Access_SMBUS.HTP.Method" -#endif - class i2c_smbus_piix4 : public i2c_smbus_interface { public: @@ -57,10 +50,6 @@ private: s32 piix4_access(u16 addr, char read_write, u8 command, int size, i2c_smbus_data *data); s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data); s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data); -#ifdef _WIN32 - HANDLE delay_timer = NULL; - HANDLE global_smbus_access_handle = NULL; -#else + bool delay_timer; -#endif }; diff --git a/i2c_smbus/i2c_smbus_amdadl.cpp b/i2c_smbus/Windows/i2c_smbus_amdadl.cpp similarity index 100% rename from i2c_smbus/i2c_smbus_amdadl.cpp rename to i2c_smbus/Windows/i2c_smbus_amdadl.cpp diff --git a/i2c_smbus/i2c_smbus_amdadl.h b/i2c_smbus/Windows/i2c_smbus_amdadl.h similarity index 100% rename from i2c_smbus/i2c_smbus_amdadl.h rename to i2c_smbus/Windows/i2c_smbus_amdadl.h diff --git a/i2c_smbus/i2c_smbus_nvapi.cpp b/i2c_smbus/Windows/i2c_smbus_nvapi.cpp similarity index 100% rename from i2c_smbus/i2c_smbus_nvapi.cpp rename to i2c_smbus/Windows/i2c_smbus_nvapi.cpp diff --git a/i2c_smbus/i2c_smbus_nvapi.h b/i2c_smbus/Windows/i2c_smbus_nvapi.h similarity index 100% rename from i2c_smbus/i2c_smbus_nvapi.h rename to i2c_smbus/Windows/i2c_smbus_nvapi.h diff --git a/i2c_smbus/Windows/i2c_smbus_pawnio.cpp b/i2c_smbus/Windows/i2c_smbus_pawnio.cpp new file mode 100644 index 000000000..3a1200e09 --- /dev/null +++ b/i2c_smbus/Windows/i2c_smbus_pawnio.cpp @@ -0,0 +1,558 @@ +/*---------------------------------------------------------*\ +| i2c_smbus_pawnio.cpp | +| | +| PawnIO SMBUS driver for Windows | +| | +| Stephen Horvath (Steve-Tech) 04 May 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "Detector.h" +#include "i2c_smbus_pawnio.h" +#include "LogManager.h" +#include "PawnIOLib.h" +#include "ResourceManager.h" +#include "SettingsManager.h" +#include "wmi.h" + +std::unordered_map i2c_smbus_pawnio::using_handle; + +i2c_smbus_pawnio::i2c_smbus_pawnio(HANDLE handle, std::string name) +{ + /*-----------------------------------------------------*\ + | Get driver settings | + \*-----------------------------------------------------*/ + json drivers_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("Drivers"); + + /*-----------------------------------------------------*\ + | Get shared SMBus access setting | + \*-----------------------------------------------------*/ + bool shared_smbus_access = true; + + if(drivers_settings.contains("shared_smbus_access")) + { + shared_smbus_access = drivers_settings["shared_smbus_access"].get(); + } + + /*-----------------------------------------------------*\ + | Create global SMBus mutex if enabled | + \*-----------------------------------------------------*/ + if(shared_smbus_access) + { + global_smbus_access_handle = CreateMutexA(NULL, FALSE, GLOBAL_SMBUS_MUTEX_NAME); + } + + /*-----------------------------------------------------*\ + | Store bus information | + | TODO: Remove name field once all drivers use the same | + | ioctl names | + \*-----------------------------------------------------*/ + this->handle = handle; + this->name = name; + + using_handle[name]++; +} + +i2c_smbus_pawnio::~i2c_smbus_pawnio() +{ + /*-----------------------------------------------------*\ + | Close global SMBus mutex | + \*-----------------------------------------------------*/ + if(global_smbus_access_handle != NULL) + { + CloseHandle(global_smbus_access_handle); + } + + /*-----------------------------------------------------*\ + | TODO: find a way to do this without name field | + \*-----------------------------------------------------*/ + if(--using_handle[name] == 0 && pawnio_close(handle)) + { + LOG_ERROR("PawnIO failed to close"); + } +} + +s32 i2c_smbus_pawnio::pawnio_read(u8 addr, char /*read_write*/, u8 command, int size, i2c_smbus_data* data) +{ + SIZE_T return_size; + + switch(size) + { + case I2C_SMBUS_BYTE: + { + const SIZE_T in_size = 1; + ULONG64 in[in_size] = {addr}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + + /*---------------------------------------------*\ + | Execute PawnIO read_byte ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_read_byte").c_str(), in, in_size, out, out_size, &return_size); + data->byte = (u8)out[0]; + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_BYTE_DATA: + { + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {addr, command}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + + /*---------------------------------------------*\ + | Execute PawnIO read_byte_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_read_byte_data").c_str(), in, in_size, out, out_size, &return_size); + data->byte = (u8)out[0]; + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_WORD_DATA: + { + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {addr, command}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + + /*---------------------------------------------*\ + | Execute PawnIO read_word_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_read_word_data").c_str(), in, in_size, out, out_size, &return_size); + data->word = (u16)out[0]; + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_BLOCK_DATA: + { + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {addr, command}; + + /*---------------------------------------------*\ + | Calculate output data buffer size | + | Pawn only deals with 64-bit cells, divide by | + | 8 to convert bytes to qwords. | + | The first cell is also the length. | + \*---------------------------------------------*/ + const SIZE_T out_size = 1 + (I2C_SMBUS_BLOCK_MAX / 8); + ULONG64 out[out_size]; + + /*---------------------------------------------*\ + | Execute PawnIO read_block_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_read_block_data").c_str(), in, in_size, out, out_size, &return_size); + + if(status) + { + return(-EIO); + } + + if(out[0] == 0 || out[0] > I2C_SMBUS_BLOCK_MAX) + { + return(-EPROTO); + } + + /*---------------------------------------------*\ + | Unpack bytes from 64bit Pawn cells | + \*---------------------------------------------*/ + u8 *out_bytes = (u8*)(&out[1]); + memcpy(&data->block[1], out_bytes, out[0]); + + return(0); + } + + default: + return(-EOPNOTSUPP); + } +} + +s32 i2c_smbus_pawnio::pawnio_write(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) +{ + SIZE_T return_size; + + switch(size) + { + case I2C_SMBUS_QUICK: + { + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {addr, (u8)read_write}; + + /*---------------------------------------------*\ + | Execute PawnIO write_quick ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_write_quick").c_str(), in, in_size, NULL, 0, &return_size); + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_BYTE: + { + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {addr, data->byte}; + + /*---------------------------------------------*\ + | Execute PawnIO write_byte ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_write_byte").c_str(), in, in_size, NULL, 0, &return_size); + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_BYTE_DATA: + { + const SIZE_T in_size = 3; + ULONG64 in[in_size] = {addr, command, data->byte}; + + /*---------------------------------------------*\ + | Execute PawnIO write_byte_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_write_byte_data").c_str(), in, in_size, NULL, 0, &return_size); + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_WORD_DATA: + { + const SIZE_T in_size = 3; + ULONG64 in[in_size] = {addr, command, data->word}; + + /*---------------------------------------------*\ + | Execute PawnIO write_word_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_write_word_data").c_str(), in, in_size, NULL, 0, &return_size); + + return(status ? -EIO : 0); + } + + case I2C_SMBUS_BLOCK_DATA: + { + SIZE_T len = data->block[0]; + if(len == 0 || len > I2C_SMBUS_BLOCK_MAX) + { + return -EINVAL; + } + const SIZE_T in_size = 3 + (I2C_SMBUS_BLOCK_MAX/8); + ULONG64 in[3 + (I2C_SMBUS_BLOCK_MAX/8)] = {addr, command, len}; + + /*---------------------------------------------*\ + | Pack bytes into 64bit Pawn cells | + \*---------------------------------------------*/ + u8 *in_bytes = (u8*)&in[3]; + memcpy(in_bytes, &data->block[1], len); + + /*---------------------------------------------*\ + | Execute PawnIO write_block_data ioctl | + \*---------------------------------------------*/ + HRESULT status = pawnio_execute(handle, ("ioctl_" + name + "_write_block_data").c_str(), in, in_size, NULL, 0, &return_size); + + return(status ? -EIO : 0); + } + + default: + return(-EOPNOTSUPP); + } +} + +s32 i2c_smbus_pawnio::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data) +{ + if(global_smbus_access_handle != NULL) + { + WaitForSingleObject(global_smbus_access_handle, INFINITE); + } + + int status = -ENXIO; + + if(read_write && size != I2C_SMBUS_QUICK) { + status = pawnio_read(addr, read_write, command, size, data); + } + else + { + status = pawnio_write(addr, read_write, command, size, data); + } + + if(global_smbus_access_handle != NULL) + { + ReleaseMutex(global_smbus_access_handle); + } + + return(status); +} + +s32 i2c_smbus_pawnio::i2c_xfer(u8 /*addr*/, char /*read_write*/, int* /*size*/, u8* /*data*/) +{ + return(-1); +} + +// TODO: Find a better place for this function +HRESULT i2c_smbus_pawnio::start_pawnio(std::string filename, PHANDLE phandle) +{ + char exePath[MAX_PATH]; + HANDLE handle; + HRESULT status; + + /*-----------------------------------------------------*\ + | Open PawnIO driver | + \*-----------------------------------------------------*/ + status = pawnio_open(phandle); + + /*-----------------------------------------------------*\ + | Check result | + \*-----------------------------------------------------*/ + if(status) + { + if(status == E_ACCESSDENIED) + { + LOG_ERROR("Permission Denied, PawnIO initialization aborted"); + } + else + { + LOG_ERROR("Could not open PawnIO, PawnIO initialization aborted"); + } + + return(status); + } + + handle = *phandle; + + /*-----------------------------------------------------*\ + | Get the path of the executable | + \*-----------------------------------------------------*/ + if(!GetModuleFileNameA(NULL, exePath, MAX_PATH)) + { + LOG_ERROR("Failed to get executable path, PawnIO initialization aborted"); + return E_FAIL; + } + + /*-----------------------------------------------------*\ + | Construct the path to `filename` in the executable's | + | directory | + \*-----------------------------------------------------*/ + std::filesystem::path exeDir = std::filesystem::path(exePath).parent_path(); + std::filesystem::path filePath = exeDir / filename; + + /*-----------------------------------------------------*\ + | Check if the file exists | + \*-----------------------------------------------------*/ + if(!std::filesystem::exists(filePath)) + { + LOG_ERROR("Failed to find %s in the executable's directory, PawnIO initialization aborted", filename.c_str()); + return(E_FAIL); + } + + /*-----------------------------------------------------*\ + | Open the file | + \*-----------------------------------------------------*/ + std::ifstream file(filePath, std::ios::binary); + + if(!file.is_open()) + { + LOG_ERROR("Failed to open %s, PawnIO initialization aborted", filename.c_str()); + return(E_FAIL); + } + + /*-----------------------------------------------------*\ + | Read the contents of the file into a vector of bytes | + \*-----------------------------------------------------*/ + std::vector blob((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + /*-----------------------------------------------------*\ + | Close the file | + \*-----------------------------------------------------*/ + file.close(); + + /*-----------------------------------------------------*\ + | Load the file into PawnIO | + \*-----------------------------------------------------*/ + status = pawnio_load(handle, reinterpret_cast(blob.data()), blob.size()); + + /*-----------------------------------------------------*\ + | Check if the load was successful | + \*-----------------------------------------------------*/ + if(status) + { + LOG_ERROR("Failed to load %s, PawnIO initialization aborted", filename.c_str()); + return(status); + } + + /*-----------------------------------------------------*\ + | Log a message and return OK if PawnIO successfully | + | opened | + \*-----------------------------------------------------*/ + LOG_INFO("PawnIO initialized"); + return(S_OK); +} + +s32 piix4_port_sel(HANDLE pawnio_handle, s32 port) +{ + const SIZE_T in_size = 1; + ULONG64 in[in_size] = {(ULONG64)port}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + SIZE_T return_size; + HRESULT status; + + /*-----------------------------------------------------*\ + | Execute PIIX4 port_sel ioctl | + \*-----------------------------------------------------*/ + status = pawnio_execute(pawnio_handle, "ioctl_piix4_port_sel", in, in_size, out, 1, &return_size); + + return(status ? -EIO : 0); +} + +bool i2c_smbus_pawnio_detect() +{ + ULONG dll_version; + if(pawnio_version(&dll_version)) + { + LOG_INFO("PawnIO is not loaded, PawnIO I2C bus detection aborted"); + return(false); + } + + i2c_smbus_interface * bus; + HRESULT hres; + Wmi wmi; + HANDLE pawnio_handle; + + /*-----------------------------------------------------*\ + | Query WMI for Win32_PnPSignedDriver entries with | + | names matching "SMBUS" or "SM BUS". These devices | + | may be browsed under Device Manager -> System Devices | + \*-----------------------------------------------------*/ + std::vector q_res_PnPSignedDriver; + hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'", q_res_PnPSignedDriver); + + if(hres) + { + LOG_INFO("WMI query failed, I2C bus detection aborted"); + return(false); + } + + /*-----------------------------------------------------*\ + | For each detected SMBus adapter, try enumerating it | + | as either AMD (piix4) or Intel (i801) | + \*-----------------------------------------------------*/ + for(QueryObj &i : q_res_PnPSignedDriver) + { + /*-------------------------------------------------*\ + | Intel SMBus controllers do show I/O resources in | + | Device Manager. Analysis of many Intel boards | + | has shown that Intel SMBus adapter I/O space | + | varies between boards. We can query | + | Win32_PnPAllocatedResource entries and look up | + | the PCI device ID to find the allocated I/O space.| + | | + | Intel SMBus adapters use the i801 driver | + \*-------------------------------------------------*/ + if((i["Manufacturer"].find("Intel") != std::string::npos) + || (i["Manufacturer"].find("INTEL") != std::string::npos)) + { + std::string pnp_str = i["DeviceID"]; + + std::size_t ven_loc = pnp_str.find("VEN_"); + std::size_t dev_loc = pnp_str.find("DEV_"); + std::size_t sub_loc = pnp_str.find("SUBSYS_"); + + std::string ven_str = pnp_str.substr(ven_loc + 4, 4); + std::string dev_str = pnp_str.substr(dev_loc + 4, 4); + std::string sbv_str = pnp_str.substr(sub_loc + 11, 4); + std::string sbd_str = pnp_str.substr(sub_loc + 7, 4); + + int ven_id = (int)std::stoul(ven_str, nullptr, 16); + int dev_id = (int)std::stoul(dev_str, nullptr, 16); + int sbv_id = (int)std::stoul(sbv_str, nullptr, 16); + int sbd_id = (int)std::stoul(sbd_str, nullptr, 16); + + /*---------------------------------------------*\ + | Create bus | + \*---------------------------------------------*/ + if(i2c_smbus_pawnio::start_pawnio("SmbusI801.bin", &pawnio_handle) != S_OK) + { + return(false); + } + + bus = new i2c_smbus_pawnio(pawnio_handle, "i801"); + bus->pci_vendor = ven_id; + bus->pci_device = dev_id; + bus->pci_subsystem_vendor = sbv_id; + bus->pci_subsystem_device = sbd_id; + strncpy(bus->device_name, i["Description"].c_str(), sizeof bus->device_name); + ResourceManager::get()->RegisterI2CBus(bus); + } + + /*-------------------------------------------------*\ + | AMD SMBus adapters use the PIIX4 driver | + \*-------------------------------------------------*/ + else if(i["Manufacturer"].find("Advanced Micro Devices, Inc") != std::string::npos) + { + std::string pnp_str = i["DeviceID"]; + + std::size_t ven_loc = pnp_str.find("VEN_"); + std::size_t dev_loc = pnp_str.find("DEV_"); + std::size_t sub_loc = pnp_str.find("SUBSYS_"); + + std::string ven_str = pnp_str.substr(ven_loc + 4, 4); + std::string dev_str = pnp_str.substr(dev_loc + 4, 4); + std::string sbv_str = pnp_str.substr(sub_loc + 11, 4); + std::string sbd_str = pnp_str.substr(sub_loc + 7, 4); + + int ven_id = (int)std::stoul(ven_str, nullptr, 16); + int dev_id = (int)std::stoul(dev_str, nullptr, 16); + int sbv_id = (int)std::stoul(sbv_str, nullptr, 16); + int sbd_id = (int)std::stoul(sbd_str, nullptr, 16); + + /*---------------------------------------------*\ + | Create primary bus | + \*---------------------------------------------*/ + if(i2c_smbus_pawnio::start_pawnio("SmbusPIIX4.bin", &pawnio_handle) != S_OK) + { + return(false); + } + + /*---------------------------------------------*\ + | Select port 0 | + \*---------------------------------------------*/ + piix4_port_sel(pawnio_handle, 0); + + bus = new i2c_smbus_pawnio(pawnio_handle, "piix4"); + bus->pci_vendor = ven_id; + bus->pci_device = dev_id; + bus->pci_subsystem_vendor = sbv_id; + bus->pci_subsystem_device = sbd_id; + strncpy(bus->device_name, i["Description"].c_str(), sizeof bus->device_name); + strncat(bus->device_name, " port 0", sizeof bus->device_name); + ResourceManager::get()->RegisterI2CBus(bus); + + /*---------------------------------------------*\ + | Create secondary bus | + \*---------------------------------------------*/ + if(i2c_smbus_pawnio::start_pawnio("SmbusPIIX4.bin", &pawnio_handle) != S_OK) + { + return(false); + } + + /*---------------------------------------------*\ + | Select port 1 | + \*---------------------------------------------*/ + piix4_port_sel(pawnio_handle, 1); + + bus = new i2c_smbus_pawnio(pawnio_handle, "piix4"); + bus->pci_vendor = ven_id; + bus->pci_device = dev_id; + bus->pci_subsystem_vendor = sbv_id; + bus->pci_subsystem_device = sbd_id; + strncpy(bus->device_name, i["Description"].c_str(), sizeof bus->device_name); + strncat(bus->device_name, " port 1", sizeof bus->device_name); + ResourceManager::get()->RegisterI2CBus(bus); + } + } + + return(true); +} + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_pawnio_detect); diff --git a/i2c_smbus/Windows/i2c_smbus_pawnio.h b/i2c_smbus/Windows/i2c_smbus_pawnio.h new file mode 100644 index 000000000..1f56f5a1f --- /dev/null +++ b/i2c_smbus/Windows/i2c_smbus_pawnio.h @@ -0,0 +1,42 @@ +/*---------------------------------------------------------*\ +| i2c_smbus_piix4_pawnio.h | +| | +| PawnIO PIIX4 SMBUS driver for Windows | +| | +| Stephen Horvath (Steve-Tech) 21 Apr 2025 | +| Based on original OpenRGB PIIX4 source code | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include + +#include "windows.h" + +#include "i2c_smbus.h" + +#define GLOBAL_SMBUS_MUTEX_NAME "Global\\Access_SMBUS.HTP.Method" + +class i2c_smbus_pawnio : public i2c_smbus_interface +{ +public: + static std::unordered_map using_handle; + i2c_smbus_pawnio(HANDLE handle, std::string name); + ~i2c_smbus_pawnio(); + + static HRESULT start_pawnio(std::string filename, PHANDLE phandle); + +private: + s32 pawnio_read(u8 addr, char read_write, u8 command, int size, i2c_smbus_data *data); + s32 pawnio_write(u8 addr, char read_write, u8 command, int size, i2c_smbus_data *data); + s32 i2c_smbus_xfer(u8 addr, char read_write, u8 command, int size, i2c_smbus_data* data); + s32 i2c_xfer(u8 addr, char read_write, int* size, u8* data); + + HANDLE global_smbus_access_handle; + std::string name; + HANDLE handle; +}; diff --git a/startup/main_Windows.cpp b/startup/main_Windows.cpp index a812a6796..91c37ecc6 100644 --- a/startup/main_Windows.cpp +++ b/startup/main_Windows.cpp @@ -519,83 +519,6 @@ static void WaitWhileServerOnline(NetworkServer* srv) }; } -/*---------------------------------------------------------*\ -| InstallWinRing0 | -| | -| Install SMBus Driver WinRing0, If not already installed | -| (Win32) | -\*---------------------------------------------------------*/ -void InstallWinRing0() -{ - /*-----------------------------------------------------*\ - | Driver final location usually | - | C:\windows\system32\drivers\WinRing0x64.sys | - \*-----------------------------------------------------*/ - TCHAR winring0_install_location[MAX_PATH]; - uint system_path_length = GetSystemDirectory(winring0_install_location, MAX_PATH); - std::string winring0_filename = "WinRing0.sys"; - BOOL bIsWow64 = false; -#if _WIN64 - winring0_filename = "WinRing0x64.sys"; -#else - BOOL (*fnIsWow64Process)(HANDLE, PBOOL) = (BOOL (__cdecl *)(HANDLE, PBOOL))GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); - if (fnIsWow64Process) - { - fnIsWow64Process(GetCurrentProcess(),&bIsWow64); - } - if(bIsWow64) - { - winring0_filename = "WinRing0x64.sys"; - } -#endif - std::strncat(winring0_install_location, "\\drivers\\", MAX_PATH - system_path_length - 1); - std::strncat(winring0_install_location, winring0_filename.c_str(), MAX_PATH - system_path_length - 10); - - std::string driver_name = winring0_filename.substr(0, winring0_filename.size() - 4); // driver name: WinRing0 or WinRing0x64 - SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (manager) - { - PVOID wow64_fsredirection_OldValue = NULL; - if(bIsWow64) - { - Wow64DisableWow64FsRedirection(&wow64_fsredirection_OldValue); - } - if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(winring0_install_location) && GetLastError()==ERROR_FILE_NOT_FOUND) - { - char module_path_buffer[MAX_PATH]; - GetModuleFileNameA(NULL, module_path_buffer, MAX_PATH); - std::string::size_type exe_loc = std::string(module_path_buffer).find_last_of("\\/"); - std::string driver_source_path = std::string(module_path_buffer).substr(0, exe_loc + 1) + winring0_filename; - CopyFile(driver_source_path.c_str(), winring0_install_location, true); - } - if(bIsWow64) - { - Wow64RevertWow64FsRedirection(wow64_fsredirection_OldValue); - } - - SC_HANDLE service = OpenService(manager, driver_name.c_str(), SERVICE_ALL_ACCESS); - if(!service) - { - std::string service_sys_path = "System32\\Drivers\\" + winring0_filename; - service = CreateService(manager, - driver_name.c_str(), - driver_name.c_str(), - SERVICE_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, - SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, - service_sys_path.c_str(), - NULL, - NULL, - NULL, - NULL, - NULL); - } - CloseServiceHandle(service); - CloseServiceHandle(manager); - } -} - /*---------------------------------------------------------*\ | common_main | | | @@ -631,11 +554,6 @@ static int common_main(int argc, char* argv[]) InitializeTimerResolutionThread = new std::thread(InitializeTimerResolutionThreadFunction); InitializeTimerResolutionThread->detach(); - /*-----------------------------------------------------*\ - | Install SMBus Driver WinRing0 | - \*-----------------------------------------------------*/ - InstallWinRing0(); - /*-----------------------------------------------------*\ | Initialize ResourceManager | \*-----------------------------------------------------*/ diff --git a/super_io/super_io.cpp b/super_io/super_io.cpp index b97f389f4..65e6ae984 100644 --- a/super_io/super_io.cpp +++ b/super_io/super_io.cpp @@ -10,11 +10,9 @@ \*---------------------------------------------------------*/ #include "super_io.h" +#include "super_io_pawnio.h" -#ifdef _WIN32 -#include -#include "OlsApi.h" -#elif _MACOSX_X86_X64 +#if _MACOSX_X86_X64 #include "macUSPCIOAccess.h" #else #include @@ -34,7 +32,7 @@ int dev_port_fd; void superio_enter(int ioreg) { -#if defined(WIN32) || defined(_MACOSX_X86_X64) +#if defined(_MACOSX_X86_X64) WriteIoPortByte(ioreg, 0x87); WriteIoPortByte(ioreg, 0x87); #else @@ -71,7 +69,7 @@ void superio_enter(int ioreg) void superio_outb(int ioreg, int reg, int val) { -#if defined(WIN32) || defined(_MACOSX_X86_X64) +#if defined(_MACOSX_X86_X64) WriteIoPortByte(ioreg, reg); WriteIoPortByte(ioreg + 1, val); #else @@ -106,7 +104,7 @@ void superio_outb(int ioreg, int reg, int val) int superio_inb(int ioreg, int reg) { -#if defined(WIN32) || defined(_MACOSX_X86_X64) +#if defined(_MACOSX_X86_X64) WriteIoPortByte(ioreg, reg); return ReadIoPortByte(ioreg + 1); #else diff --git a/super_io/super_io.h b/super_io/super_io.h index 496735c50..b5581c931 100644 --- a/super_io/super_io.h +++ b/super_io/super_io.h @@ -9,6 +9,8 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#pragma once + /******************************************************************************************\ * * * Nuvoton Super IO constants * diff --git a/super_io/super_io_pawnio.cpp b/super_io/super_io_pawnio.cpp new file mode 100644 index 000000000..6d4f85ddd --- /dev/null +++ b/super_io/super_io_pawnio.cpp @@ -0,0 +1,120 @@ +/*---------------------------------------------------------*\ +| super_io_pawnio.cpp | +| | +| Functions for interfacing with Super-IO using PawnIO | +| | +| Stephen Horvath (Steve-Tech) 05 May 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "super_io_pawnio.h" + +#include +#include "PawnIOLib.h" +#include "i2c_smbus_pawnio.h" + + +static HANDLE pawnio_handle = NULL; + +static int pawnio_chip_type = 0; + +static int addr_to_pawnio(int addr) +{ + switch (addr) + { + case 0x2E: + return 0; + case 0x4E: + return 1; + default: + return -1; + } +} + +/******************************************************************************************\ +* * +* pawnio_superio_enter * +* * +* Put the Super IO chip into Extended Function Mode * +* * +\******************************************************************************************/ + +void superio_enter(int ioreg) +{ + HRESULT status; + SIZE_T return_size; + + if (pawnio_handle == NULL) + { + status = i2c_smbus_pawnio::start_pawnio("superio", &pawnio_handle); + if (status != S_OK) + { + // TODO: Figure out how to handle errors + return; + } + } + + if (pawnio_chip_type == 0) + { + int in_reg = addr_to_pawnio(ioreg); + if (in_reg == -1) { + return; + } + + const SIZE_T in_size = 1; + ULONG64 in[in_size] = {(ULONG64)in_reg}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + status = pawnio_execute(pawnio_handle, "ioctl_detect", in, in_size, out, out_size, &return_size); + if (status != S_OK || out[0] == 0) + { + return; + } + pawnio_chip_type = (int)out[0]; + } + + pawnio_execute(pawnio_handle, "ioctl_enter", NULL, 0, NULL, 0, &return_size); +} + + +/******************************************************************************************\ +* * +* pawnio_superio_outb * +* * +* Write a byte to the Super IO configuration register * +* * +\******************************************************************************************/ + +void superio_outb([[maybe_unused]] int ioreg, int reg, int val) +{ + const SIZE_T in_size = 2; + ULONG64 in[in_size] = {(ULONG64)reg, (ULONG64)val}; + SIZE_T return_size; + pawnio_execute(pawnio_handle, "ioctl_write", in, in_size, NULL, 0, &return_size); +} + + +/******************************************************************************************\ +* * +* pawnio_superio_inb * +* * +* Read a byte from the Super IO configuration register * +* * +\******************************************************************************************/ + +int superio_inb([[maybe_unused]] int ioreg, int reg) +{ + const SIZE_T in_size = 1; + ULONG64 in[in_size] = {(ULONG64)reg}; + const SIZE_T out_size = 1; + ULONG64 out[out_size]; + SIZE_T return_size; + HRESULT status = pawnio_execute(pawnio_handle, "ioctl_read", in, in_size, out, out_size, &return_size); + if (status != S_OK) + { + return -1; + } + return (int)out[0]; +} diff --git a/super_io/super_io_pawnio.h b/super_io/super_io_pawnio.h new file mode 100644 index 000000000..ac4b3b876 --- /dev/null +++ b/super_io/super_io_pawnio.h @@ -0,0 +1,18 @@ +/*---------------------------------------------------------*\ +| super_io_pawnio.h | +| | +| Functions for interfacing with Super-IO using PawnIO | +| | +| Stephen Horvath (Steve-Tech) 05 May 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +void superio_enter(int ioreg); + +void superio_outb(int ioreg, int reg, int val); + +int superio_inb(int ioreg, int reg);