diff --git a/CommonHelpers/GlobalConfig.cs b/CommonHelpers/GlobalConfig.cs index e25fa0f..22cbf92 100644 --- a/CommonHelpers/GlobalConfig.cs +++ b/CommonHelpers/GlobalConfig.cs @@ -14,6 +14,12 @@ namespace CommonHelpers Max } + public enum KernelDriversLoaded : uint + { + Yes = 4363232, + No + } + public enum OverlayMode : uint { FPS = 10032, @@ -39,6 +45,7 @@ namespace CommonHelpers public struct FanModeSetting { public FanMode Current, Desired; + public KernelDriversLoaded KernelDriversLoaded; } [StructLayout(LayoutKind.Sequential)] @@ -46,6 +53,8 @@ namespace CommonHelpers { public OverlayMode Current, Desired; public OverlayEnabled CurrentEnabled, DesiredEnabled; + public KernelDriversLoaded KernelDriversLoaded; + public KernelDriversLoaded DesiredKernelDriversLoaded; } [StructLayout(LayoutKind.Sequential)] diff --git a/CommonHelpers/InpOut.cs b/CommonHelpers/InpOut.cs index 31771fc..d9a3a2b 100644 --- a/CommonHelpers/InpOut.cs +++ b/CommonHelpers/InpOut.cs @@ -7,29 +7,67 @@ using System.Threading.Tasks; namespace CommonHelpers { - public class InpOut + public class InpOut : IDisposable { - [DllImport("inpoutx64.dll", EntryPoint = "MapPhysToLin", CallingConvention = CallingConvention.StdCall)] - public static extern IntPtr MapPhysToLin(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); + public const String LibraryName = "inpoutx64.dll"; - [DllImport("inpoutx64.dll", EntryPoint = "UnmapPhysicalMemory", CallingConvention = CallingConvention.StdCall)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); + private IntPtr libraryHandle; + public MapPhysToLinDelegate MapPhysToLin; + public UnmapPhysicalMemoryDelegate UnmapPhysicalMemory; + public DlPortReadPortUcharDelegate DlPortReadPortUchar; + public DlPortWritePortUcharDelegate DlPortWritePortUchar; - [DllImport("inpoutx64.dll", EntryPoint = "DlPortReadPortUchar", CallingConvention = CallingConvention.StdCall)] - [return: MarshalAs(UnmanagedType.U1)] - public static extern byte DlPortReadPortUchar(ushort port); + public InpOut() + { + libraryHandle = LoadLibrary(LibraryName); + try + { + var addr = GetProcAddress(libraryHandle, "MapPhysToLin"); + if (addr == IntPtr.Zero) + throw new ArgumentException("Missing MapPhysToLin"); + MapPhysToLin = Marshal.GetDelegateForFunctionPointer(addr); - [DllImport("inpoutx64.dll", EntryPoint = "DlPortWritePortUchar", CallingConvention = CallingConvention.StdCall)] - public static extern byte DlPortWritePortUchar(ushort port, byte vlaue); + addr = GetProcAddress(libraryHandle, "UnmapPhysicalMemory"); + if (addr == IntPtr.Zero) + throw new ArgumentException("Missing UnmapPhysicalMemory"); + UnmapPhysicalMemory = Marshal.GetDelegateForFunctionPointer(addr); - [DllImport("inpoutx64.dll", CallingConvention = CallingConvention.StdCall)] - public static extern bool GetPhysLong(IntPtr pbPhysAddr, out uint physValue); + addr = GetProcAddress(libraryHandle, "UnmapPhysicalMemory"); + if (addr == IntPtr.Zero) + throw new ArgumentException("Missing UnmapPhysicalMemory"); + UnmapPhysicalMemory = Marshal.GetDelegateForFunctionPointer(addr); - [DllImport("inpoutx64.dll", CallingConvention = CallingConvention.StdCall)] - public static extern bool SetPhysLong(IntPtr pbPhysAddr, uint physValue); + addr = GetProcAddress(libraryHandle, "DlPortReadPortUchar"); + if (addr == IntPtr.Zero) + throw new ArgumentException("Missing DlPortReadPortUchar"); + DlPortReadPortUchar = Marshal.GetDelegateForFunctionPointer(addr); - public static byte[] ReadMemory(IntPtr baseAddress, uint size) + addr = GetProcAddress(libraryHandle, "DlPortWritePortUchar"); + if (addr == IntPtr.Zero) + throw new ArgumentException("Missing DlPortWritePortUchar"); + DlPortWritePortUchar = Marshal.GetDelegateForFunctionPointer(addr); + } + catch + { + FreeLibrary(libraryHandle); + libraryHandle = IntPtr.Zero; + throw; + } + } + + ~InpOut() + { + Dispose(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + FreeLibrary(libraryHandle); + libraryHandle = IntPtr.Zero; + } + + public byte[]? ReadMemory(IntPtr baseAddress, uint size) { IntPtr pdwLinAddr = MapPhysToLin(baseAddress, size, out IntPtr pPhysicalMemoryHandle); if (pdwLinAddr != IntPtr.Zero) @@ -37,25 +75,37 @@ namespace CommonHelpers byte[] bytes = new byte[size]; Marshal.Copy(pdwLinAddr, bytes, 0, bytes.Length); UnmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr); - return bytes; } - return null; } - public static bool WriteMemory(IntPtr baseAddress, byte[] data) + public bool WriteMemory(IntPtr baseAddress, byte[] data) { IntPtr pdwLinAddr = MapPhysToLin(baseAddress, (uint)data.Length, out IntPtr pPhysicalMemoryHandle); if (pdwLinAddr != IntPtr.Zero) { Marshal.Copy(data, 0, pdwLinAddr, data.Length); UnmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr); - return true; } return false; } + + public delegate IntPtr MapPhysToLinDelegate(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); + public delegate bool UnmapPhysicalMemoryDelegate(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); + public delegate byte DlPortReadPortUcharDelegate(ushort port); + public delegate byte DlPortWritePortUcharDelegate(ushort port, byte value); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", ExactSpelling = true)] + private static extern IntPtr GetProcAddress(IntPtr module, string methodName); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool FreeLibrary(IntPtr module); } } diff --git a/CommonHelpers/Instance.cs b/CommonHelpers/Instance.cs index 0e0afc8..18f5e2a 100644 --- a/CommonHelpers/Instance.cs +++ b/CommonHelpers/Instance.cs @@ -23,10 +23,32 @@ namespace CommonHelpers private static Mutex? runOnceMutex; private static Mutex? globalLockMutex; + private static bool useKernelDrivers; private const String GLOBAL_MUTEX_NAME = "Global\\SteamDeckToolsCommonHelpers"; private const int GLOBAL_DEFAULT_TIMEOUT = 5000; + public static bool UseKernelDrivers + { + get { return useKernelDrivers; } + set + { + if (useKernelDrivers == value) + return; + + useKernelDrivers = value; + + if (value) + Vlv0100.Open(); + else + Vlv0100.Close(); + + // CPU requires reading RyzenSMU + HardwareComputer.IsCpuEnabled = value; + HardwareComputer.Reset(); + } + } + public static Mutex? WaitGlobalMutex(int timeoutMs) { if (globalLockMutex == null) @@ -60,7 +82,7 @@ namespace CommonHelpers } } - public static void Open(String title, String? runOnce = null, int runOnceTimeout = 100) + public static void Open(String title, bool useKernelDrivers, String? runOnce = null, int runOnceTimeout = 100) { if (runOnce is not null) { @@ -72,17 +94,20 @@ namespace CommonHelpers if (mutex is null) { Fatal(title, "Failed to acquire global mutex."); + return; } try { - if (!Vlv0100.IsSupported()) + UseKernelDrivers = useKernelDrivers; + + if (Vlv0100.IsOpen && !Vlv0100.IsSupported) { String message = ""; message += "Current device is not supported.\n"; - message += "FirmwareVersion: " + Vlv0100.GetFirmwareVersion().ToString("X") + "\n"; - message += "BoardID: " + Vlv0100.GetBoardID().ToString("X") + "\n"; - message += "PDCS: " + Vlv0100.GetPDCS().ToString("X") + "\n"; + message += "FirmwareVersion: " + Vlv0100.FirmwareVersion.ToString("X") + "\n"; + message += "BoardID: " + Vlv0100.BoardID.ToString("X") + "\n"; + message += "PDCS: " + Vlv0100.PDCS.ToString("X") + "\n"; Fatal(title, message); } diff --git a/CommonHelpers/Vlv0100.cs b/CommonHelpers/Vlv0100.cs index 39ba423..9409b46 100644 --- a/CommonHelpers/Vlv0100.cs +++ b/CommonHelpers/Vlv0100.cs @@ -26,7 +26,7 @@ namespace CommonHelpers static ushort IO6C = 0x6C; public const ushort MAX_FAN_RPM = 0x1C84; - + public static readonly ushort[] SupportedFirmwares = { 0xB030 // 45104 }; @@ -39,51 +39,86 @@ namespace CommonHelpers 0x2B // 43 }; - public static bool IsSupported() - { - var firmwareVersion = GetFirmwareVersion(); - var boardID = GetBoardID(); - var pdcs = GetPDCS(); + private static InpOut? inpOut; - return SupportedFirmwares.Contains(firmwareVersion) && - SupportedBoardID.Contains(boardID); + public static bool IsOpen + { + get { return inpOut is not null; } } - public static ushort GetFirmwareVersion() + public static bool IsSupported { - byte[] data = InpOut.ReadMemory(PDFV, 2); - return BitConverter.ToUInt16(data); + get + { + return SupportedFirmwares.Contains(FirmwareVersion) && + SupportedBoardID.Contains(BoardID); + } } - public static byte GetBoardID() + public static ushort FirmwareVersion { get; private set; } + public static byte BoardID { get; private set; } + public static byte PDCS { get; private set; } + + public static bool Open() { - byte[] data = InpOut.ReadMemory(XBID, 1); - return data[0]; + if (inpOut != null) + return true; + + try + { + inpOut = new InpOut(); + + var data = inpOut?.ReadMemory(PDFV, 2); + if (data is not null) + FirmwareVersion = BitConverter.ToUInt16(data); + + data = inpOut?.ReadMemory(XBID, 1); + if (data is not null) + BoardID = data[0]; + + data = inpOut?.ReadMemory(PDCT, 1); + if (data is not null) + PDCS = data[0]; + + return true; + } + catch (Exception e) + { + Log.TraceLine("VLV0100: InpOut: {0}", e); + Close(); + return false; + } } - public static byte GetPDCS() + public static void Close() { - byte[] data = InpOut.ReadMemory(PDCT, 1); - return data[0]; + SetFanControl(false); + using (inpOut) { } + inpOut = null; } public static ushort GetFanDesiredRPM() { - byte[] data = InpOut.ReadMemory(FSLO_FSHI, 2); + var data = inpOut?.ReadMemory(FSLO_FSHI, 2); + if (data is null) + return 0; return BitConverter.ToUInt16(data); } - public static ushort GetFanRPM() + public static ushort? GetFanRPM() { - byte[] data = InpOut.ReadMemory(FNRL_FNRH, 2); + var data = inpOut?.ReadMemory(FNRL_FNRH, 2); + if (data is null) + return null; return BitConverter.ToUInt16(data); } + public static void SetFanControl(Boolean userControlled) { SetGain(10); SetRampRate(userControlled ? (byte)10 : (byte)20); - InpOut.DlPortWritePortUchar(IO6C, userControlled ? (byte)0xCC : (byte)0xCD); + inpOut?.DlPortWritePortUchar(IO6C, userControlled ? (byte)0xCC : (byte)0xCD); } public static void SetFanDesiredRPM(ushort rpm) @@ -92,18 +127,22 @@ namespace CommonHelpers rpm = MAX_FAN_RPM; byte[] data = BitConverter.GetBytes(rpm); - InpOut.WriteMemory(FSLO_FSHI, data); + inpOut?.WriteMemory(FSLO_FSHI, data); } public static bool GetFanCheck() { - byte[] data = InpOut.ReadMemory(FNCK, 1); + var data = inpOut?.ReadMemory(FNCK, 1); + if (data is null) + return false; return (data[0] & 0x1) != 0; } public static float GetBattTemperature() { - byte[] data = InpOut.ReadMemory(BATH_BATL, 2); + var data = inpOut?.ReadMemory(BATH_BATL, 2); + if (data is null) + return 0; int value = (data[0] << 8) + data[1]; return (float)(value - 0x0AAC) / 10.0f; } @@ -111,12 +150,12 @@ namespace CommonHelpers private static void SetGain(ushort gain) { byte[] data = BitConverter.GetBytes(gain); - InpOut.WriteMemory(GNLO_GNHI, data); + inpOut?.WriteMemory(GNLO_GNHI, data); } private static void SetRampRate(byte rampRate) { byte[] data = BitConverter.GetBytes(rampRate); - InpOut.WriteMemory(FRPR, data); + inpOut?.WriteMemory(FRPR, data); } } } diff --git a/FanControl/FanControlForm.cs b/FanControl/FanControlForm.cs index fc0f914..0d6bd30 100644 --- a/FanControl/FanControlForm.cs +++ b/FanControl/FanControlForm.cs @@ -1,24 +1,11 @@ using CommonHelpers; using ExternalHelpers; -using FanControl.Properties; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Drawing; -using System.Linq; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; namespace FanControl { public partial class FanControlForm : Form { - private FanController fanControl = new FanController(); + private FanController fanControl; private StartupManager startupManager = new StartupManager( "Steam Deck Fan Control", "Starts Steam Deck Fan Control on Windows startup." @@ -29,10 +16,12 @@ namespace FanControl public FanControlForm() { InitializeComponent(); - SharedData_Update(); Text += " v" + Application.ProductVersion.ToString(); - Instance.Open(Text, "Global\\FanControlOnce"); + Instance.Open(Text, true, "Global\\FanControlOnce"); + + fanControl = new FanController(); + SharedData_Update(); notifyIcon.Text = Text; notifyIcon.Visible = true; @@ -155,13 +144,17 @@ namespace FanControl setFanMode((FanMode)value.Desired); } - sharedData.SetValue(new FanModeSetting() { Current = fanControl.Mode }); + sharedData.SetValue(new FanModeSetting() + { + Current = fanControl.Mode, + KernelDriversLoaded = Instance.UseKernelDrivers ? KernelDriversLoaded.Yes : KernelDriversLoaded.No + }); } private void fanLoopTimer_Tick(object sender, EventArgs e) { SharedData_Update(); - fanControl.Update(); + fanControl.Update(Visible); } private void propertyGridUpdateTimer_Tick(object sender, EventArgs e) @@ -171,7 +164,11 @@ namespace FanControl propertyGrid1.Refresh(); sensorWarningLabel.Visible = fanControl.IsAnyInvalid(); - notifyIcon.Text = String.Format("Fan: {0} RPM Mode: {1}", fanControl.CurrentRPM, fanControl.Mode); + + if (fanControl.IsActive) + notifyIcon.Text = String.Format("Fan: {0} RPM Mode: {1}", fanControl.CurrentRPM, fanControl.Mode); + else + notifyIcon.Text = String.Format("Mode: {0}", fanControl.Mode); } private void toolStripMenuItemStartupOnBoot_Click(object sender, EventArgs e) diff --git a/FanControl/FanController.cs b/FanControl/FanController.cs index 7bdb437..ed6feae 100644 --- a/FanControl/FanController.cs +++ b/FanControl/FanController.cs @@ -22,7 +22,7 @@ namespace FanControl [CategoryAttribute("Fan")] [NotifyParentProperty(true)] - public ushort CurrentRPM { get; private set; } + public ushort? CurrentRPM { get; private set; } [CategoryAttribute("Fan")] [NotifyParentProperty(true)] @@ -30,7 +30,7 @@ namespace FanControl public ushort DesiredRPM { get; private set; } [CategoryAttribute("Board")] - public String PDVersion { get; private set; } = Vlv0100.GetFirmwareVersion().ToString("X"); + public String PDVersion { get; private set; } = Vlv0100.FirmwareVersion.ToString("X"); public FanController() { @@ -71,10 +71,14 @@ namespace FanControl return rpm; } - public void Update() + public bool IsActive + { + get { return Vlv0100.IsOpen; } + } + + public void Update(bool visible) { var mutex = Instance.WaitGlobalMutex(200); - if (mutex is null) { // If we cannot acquire mutex slightly increase FAN to compensate just in case @@ -84,6 +88,17 @@ namespace FanControl try { + if (Mode == FanMode.Default && !visible) + { + Instance.UseKernelDrivers = false; + return; + } + else if (!Vlv0100.IsOpen) + { + Instance.UseKernelDrivers = true; + SetMode(Mode); + } + foreach (var sensor in allSensors.Values) sensor.Reset(); @@ -112,6 +127,7 @@ namespace FanControl break; default: + Instance.UseKernelDrivers = true; Vlv0100.SetFanControl(true); break; } diff --git a/PerformanceOverlay/Controller.cs b/PerformanceOverlay/Controller.cs index 9ae43cd..be11e0f 100644 --- a/PerformanceOverlay/Controller.cs +++ b/PerformanceOverlay/Controller.cs @@ -1,16 +1,7 @@ using CommonHelpers; using ExternalHelpers; -using Microsoft.VisualBasic.Logging; using RTSSSharedMemoryNET; -using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using static System.Net.Mime.MediaTypeNames; namespace PerformanceOverlay { @@ -38,7 +29,7 @@ namespace PerformanceOverlay contextMenu = new System.Windows.Forms.ContextMenuStrip(components); SharedData_Update(); - Instance.Open(TitleWithVersion, "Global\\PerformanceOverlay"); + Instance.Open(TitleWithVersion, true, "Global\\PerformanceOverlay"); showItem = new ToolStripMenuItem("&Show OSD"); showItem.Click += ShowItem_Click; @@ -60,6 +51,11 @@ namespace PerformanceOverlay contextMenu.Items.Add(new ToolStripSeparator()); + var kernelDriversItem = new ToolStripMenuItem("Use &Kernel Drivers"); + kernelDriversItem.Click += delegate { Instance.UseKernelDrivers = !Instance.UseKernelDrivers; }; + contextMenu.Opening += delegate { kernelDriversItem.Checked = Instance.UseKernelDrivers; }; + contextMenu.Items.Add(kernelDriversItem); + if (startupManager.IsAvailable) { var startupItem = new ToolStripMenuItem("Run On Startup"); @@ -172,12 +168,19 @@ namespace PerformanceOverlay Settings.Default.Save(); updateContextItems(contextMenu); } + + if (Enum.IsDefined(value.DesiredKernelDriversLoaded)) + { + Instance.UseKernelDrivers = (KernelDriversLoaded)value.DesiredKernelDriversLoaded == KernelDriversLoaded.Yes; + updateContextItems(contextMenu); + } } sharedData.SetValue(new OverlayModeSetting() { Current = Settings.Default.OSDModeParsed, - CurrentEnabled = Settings.Default.ShowOSD ? OverlayEnabled.Yes : OverlayEnabled.No + CurrentEnabled = Settings.Default.ShowOSD ? OverlayEnabled.Yes : OverlayEnabled.No, + KernelDriversLoaded = Instance.UseKernelDrivers ? KernelDriversLoaded.Yes : KernelDriversLoaded.No }); } diff --git a/PerformanceOverlay/Sensors.cs b/PerformanceOverlay/Sensors.cs index c99e32f..4795130 100644 --- a/PerformanceOverlay/Sensors.cs +++ b/PerformanceOverlay/Sensors.cs @@ -39,7 +39,7 @@ namespace PerformanceOverlay public class UserValueSensor : ValueSensor { - public delegate float ValueDelegate(); + public delegate float? ValueDelegate(); public ValueDelegate Value { get; set; } @@ -316,7 +316,7 @@ namespace PerformanceOverlay { Value = delegate () { - return (float)CommonHelpers.Vlv0100.GetFanRPM(); + return CommonHelpers.Vlv0100.GetFanRPM(); }, Format = "F0" } @@ -352,7 +352,7 @@ namespace PerformanceOverlay return true; }); } - + public string? GetValue(String name) { if (!AllSensors.ContainsKey(name)) diff --git a/PowerControl/Helpers/AMD/RyzenSMU.cs b/PowerControl/Helpers/AMD/RyzenSMU.cs index 2bc94dc..0b969e6 100644 --- a/PowerControl/Helpers/AMD/RyzenSMU.cs +++ b/PowerControl/Helpers/AMD/RyzenSMU.cs @@ -18,6 +18,7 @@ namespace PowerControl.Helpers.AMD IntPtr mappedAddress; IntPtr physicalHandle; + InpOut? inpOut; public RyzenSMU() { @@ -42,7 +43,8 @@ namespace PowerControl.Helpers.AMD try { - mappedAddress = InpOut.MapPhysToLin(MMIO_ADDR, MMIO_SIZE, out physicalHandle); + inpOut = new InpOut(); + mappedAddress = inpOut.MapPhysToLin(MMIO_ADDR, MMIO_SIZE, out physicalHandle); } catch (Exception e) { @@ -59,9 +61,11 @@ namespace PowerControl.Helpers.AMD return; GC.SuppressFinalize(this); - InpOut.UnmapPhysicalMemory(physicalHandle, mappedAddress); + inpOut?.UnmapPhysicalMemory(physicalHandle, mappedAddress); mappedAddress = IntPtr.Zero; physicalHandle = IntPtr.Zero; + using (inpOut) { } + inpOut = null; } private uint RregRaw(uint reg) diff --git a/PowerControl/MenuStack.cs b/PowerControl/MenuStack.cs index 667d9e1..d34a756 100644 --- a/PowerControl/MenuStack.cs +++ b/PowerControl/MenuStack.cs @@ -433,6 +433,30 @@ namespace PowerControl } }, new Menu.MenuItemWithOptions() + { + Name = "OSD Kernel Drivers", + ApplyDelay = 500, + OptionsValues = delegate() + { + return Enum.GetValues().Select(item => (object)item).ToArray(); + }, + CurrentValue = delegate() + { + if (SharedData.GetExistingValue(out var value)) + return value.KernelDriversLoaded; + return null; + }, + ApplyValue = delegate(object selected) + { + if (!SharedData.GetExistingValue(out var value)) + return null; + value.DesiredKernelDriversLoaded = (KernelDriversLoaded)selected; + if (!SharedData.SetExistingValue(value)) + return null; + return selected; + } + }, + new Menu.MenuItemWithOptions() { Name = "FAN", ApplyDelay = 500, diff --git a/RELEASE.md b/RELEASE.md index 3e78478..0963d0e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,6 +6,8 @@ - Fix right stick serving as mouse in `X360` mode - Improve build scripts in `scripts/` - Show notification on controller changed +- Try to disable usage of Kernel Drivers (when FAN in Default, and OSD Kernel Drivers are disabled) + to allow apps to work with Anti-Cheat detections ## 0.4.x