mirror of
https://github.com/ayufan/steam-deck-tools.git
synced 2025-12-06 07:12:01 +01:00
216 lines
6.8 KiB
C#
216 lines
6.8 KiB
C#
namespace CommonHelpers
|
|
{
|
|
public class Vlv0100 : IDisposable
|
|
{
|
|
// Those addresses are taken from DSDT for VLV0100
|
|
// and might change at any time with a BIOS update
|
|
// Purpose: https://lore.kernel.org/lkml/20220206022023.376142-1-andrew.smirnov@gmail.com/
|
|
// Addresses: DSDT.txt
|
|
static IntPtr FSLO_FSHI = new IntPtr(0xFE700B00 + 0x92);
|
|
static IntPtr GNLO_GNHI = new IntPtr(0xFE700B00 + 0x95);
|
|
static IntPtr FRPR = new IntPtr(0xFE700B00 + 0x97);
|
|
static IntPtr FNRL_FNRH = new IntPtr(0xFE700300 + 0xB0);
|
|
static IntPtr FNCK = new IntPtr(0xFE700300 + 0x9F);
|
|
static IntPtr BATH_BATL = new IntPtr(0xFE700400 + 0x6E);
|
|
static IntPtr PDFV = new IntPtr(0xFE700C00 + 0x4C);
|
|
static IntPtr XBID = new IntPtr(0xFE700300 + 0xBD);
|
|
static IntPtr PDCT = new IntPtr(0xFE700C00 + 0x01);
|
|
static IntPtr MCBL = new IntPtr(0xFE700B00 + 0x9F);
|
|
static ushort IO6C = 0x6C;
|
|
|
|
public const ushort MAX_FAN_RPM = 0x1C84;
|
|
|
|
public struct DeviceVersion
|
|
{
|
|
public ushort Firmware { get; set; }
|
|
public byte BoardID { get; set; }
|
|
public byte PDCS { get; set; }
|
|
|
|
public bool BatteryTempLE { get; set; }
|
|
public bool MaxBatteryCharge { get; set; }
|
|
|
|
public bool IsSupported(ushort deviceFirmware, byte deviceBoardID, byte devicePDCS)
|
|
{
|
|
if (Firmware != 0 && Firmware != deviceFirmware)
|
|
return false;
|
|
if (BoardID != 0 && BoardID != deviceBoardID)
|
|
return false;
|
|
if (PDCS != 0 && PDCS != devicePDCS)
|
|
return false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
private static readonly DeviceVersion[] deviceVersions = {
|
|
// Steam Deck - LCD version
|
|
new DeviceVersion() { Firmware = 0xB030, BoardID = 0x6, PDCS = 0 /* 0x2B */, BatteryTempLE = false },
|
|
new DeviceVersion() { Firmware = 0xB030, BoardID = 0xA, PDCS = 0 /* 0x2B */, BatteryTempLE = false, MaxBatteryCharge = true },
|
|
|
|
// Steam Deck - OLED version
|
|
// new DeviceVersion() { Firmware = 0x1030, BoardID = 0x5, PDCS = 0 /* 0x2F */, BatteryTempLE = true },
|
|
new DeviceVersion() { Firmware = 0x1050, BoardID = 0x5, PDCS = 0 /* 0x2F */, BatteryTempLE = true, MaxBatteryCharge = true }
|
|
};
|
|
|
|
public static Vlv0100 Instance = new Vlv0100();
|
|
|
|
~Vlv0100()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
GC.SuppressFinalize(this);
|
|
Close();
|
|
}
|
|
|
|
private InpOut? inpOut;
|
|
|
|
public bool IsOpen
|
|
{
|
|
get { return inpOut is not null; }
|
|
}
|
|
|
|
public DeviceVersion? SupportedDevice
|
|
{
|
|
get { return deviceVersions.FirstOrDefault((v) => v.IsSupported(FirmwareVersion, BoardID, PDCS)); }
|
|
}
|
|
|
|
public bool IsSupported
|
|
{
|
|
get { return SupportedDevice is not null; }
|
|
}
|
|
|
|
public ushort FirmwareVersion { get; private set; }
|
|
public byte BoardID { get; private set; }
|
|
public byte PDCS { get; private set; }
|
|
|
|
public bool Open()
|
|
{
|
|
if (inpOut != null)
|
|
return true;
|
|
|
|
try
|
|
{
|
|
inpOut = new InpOut();
|
|
|
|
var data = inpOut?.ReadMemory(PDFV, 2);
|
|
if (data is not null)
|
|
FirmwareVersion = BitConverter.ToUInt16(data);
|
|
else
|
|
FirmwareVersion = 0xFFFF;
|
|
|
|
data = inpOut?.ReadMemory(XBID, 1);
|
|
if (data is not null)
|
|
BoardID = data[0];
|
|
else
|
|
BoardID = 0xFF;
|
|
|
|
data = inpOut?.ReadMemory(PDCT, 1);
|
|
if (data is not null)
|
|
PDCS = data[0];
|
|
else
|
|
PDCS = 0xFF;
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.TraceException("VLV0100", "InpOut", e);
|
|
Close();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
SetFanControl(false);
|
|
using (inpOut) { }
|
|
inpOut = null;
|
|
}
|
|
|
|
public ushort GetFanDesiredRPM()
|
|
{
|
|
var data = inpOut?.ReadMemory(FSLO_FSHI, 2);
|
|
if (data is null)
|
|
return 0;
|
|
return BitConverter.ToUInt16(data);
|
|
}
|
|
|
|
public ushort? GetFanRPM()
|
|
{
|
|
var data = inpOut?.ReadMemory(FNRL_FNRH, 2);
|
|
if (data is null)
|
|
return null;
|
|
return BitConverter.ToUInt16(data);
|
|
}
|
|
|
|
public void SetFanControl(Boolean userControlled)
|
|
{
|
|
SetGain(10);
|
|
SetRampRate(userControlled ? (byte)10 : (byte)20);
|
|
|
|
inpOut?.DlPortWritePortUchar(IO6C, userControlled ? (byte)0xCC : (byte)0xCD);
|
|
}
|
|
|
|
public void SetFanDesiredRPM(ushort rpm)
|
|
{
|
|
if (rpm > MAX_FAN_RPM)
|
|
rpm = MAX_FAN_RPM;
|
|
|
|
byte[] data = BitConverter.GetBytes(rpm);
|
|
inpOut?.WriteMemory(FSLO_FSHI, data);
|
|
}
|
|
|
|
public bool GetFanCheck()
|
|
{
|
|
var data = inpOut?.ReadMemory(FNCK, 1);
|
|
if (data is null)
|
|
return false;
|
|
return (data[0] & 0x1) != 0;
|
|
}
|
|
|
|
public float GetBattTemperature()
|
|
{
|
|
var data = inpOut?.ReadMemory(BATH_BATL, 2);
|
|
if (data is null)
|
|
return 0;
|
|
int value = SupportedDevice?.BatteryTempLE == true ?
|
|
((data[1] << 8) + data[0]) :
|
|
((data[0] << 8) + data[1]);
|
|
return (float)(value - 0x0AAC) / 10.0f;
|
|
}
|
|
|
|
public int? GetMaxBatteryCharge()
|
|
{
|
|
if (SupportedDevice?.MaxBatteryCharge != true)
|
|
return null;
|
|
var data = inpOut?.ReadMemory(MCBL, 1);
|
|
if (data is null)
|
|
return null;
|
|
if (data[0] > 100)
|
|
return null;
|
|
return data[0];
|
|
}
|
|
public void SetMaxBatteryCharge(int chargeLimit)
|
|
{
|
|
if (SupportedDevice?.MaxBatteryCharge != true)
|
|
return;
|
|
if (chargeLimit < 0 || chargeLimit > 100)
|
|
return;
|
|
byte[] data = BitConverter.GetBytes(chargeLimit);
|
|
inpOut?.WriteMemory(MCBL, data);
|
|
}
|
|
|
|
private void SetGain(ushort gain)
|
|
{
|
|
byte[] data = BitConverter.GetBytes(gain);
|
|
inpOut?.WriteMemory(GNLO_GNHI, data);
|
|
}
|
|
private void SetRampRate(byte rampRate)
|
|
{
|
|
byte[] data = BitConverter.GetBytes(rampRate);
|
|
inpOut?.WriteMemory(FRPR, data);
|
|
}
|
|
}
|
|
}
|