Skip to content

Commit

Permalink
Kernel driver and EC access code improvements
Browse files Browse the repository at this point in the history
- Fix CreateFile() errors potentially not getting caught

- Attempt to connect to an existing installed WinRing0 driver before attempting an install ourselves

- Only uninstall the WinRing0 driver if it's not being used by any other programs

- Only attempt to read/write EC if the EC driver connection is open
  • Loading branch information
Sparronator9999 committed Jul 24, 2024
1 parent 11a9980 commit c8048d0
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 21 deletions.
17 changes: 10 additions & 7 deletions MSIFanControl.ECAccess/Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public bool Install()
{
ErrorCode = 0;

// Make sure the file we're trying to install actually exists:
try
{
string fullPath = Path.GetFullPath(DriverPath);
Expand All @@ -91,7 +92,6 @@ public bool Install()
return false;
}

// Otherwise, we need to install the service ourselves.
// Try to open the Service Control Manager:
IntPtr hSCM = AdvApi32.OpenSCManager(null, null, AdvApi32.SCMAccess.All);
if (hSCM == IntPtr.Zero)
Expand Down Expand Up @@ -238,21 +238,24 @@ public bool Open()
FileAttributes.Normal,
IntPtr.Zero);

if (hDevice != IntPtr.Zero)
// Apparently CreateFileW() can return -1 instead of 0 for some reason
if (hDevice == IntPtr.Zero || hDevice == new IntPtr(-1))
{
Status |= DriverStatus.Open;
return true;
ErrorCode = Marshal.GetLastWin32Error();
return false;
}
ErrorCode = Marshal.GetLastWin32Error();
return false;


Status |= DriverStatus.Open;
return true;
}
return true;
}

/// <summary>
/// Closes the connection to the device driver, if open.
/// </summary>
private void Close()
public void Close()
{
if (hDevice != IntPtr.Zero)
{
Expand Down
79 changes: 65 additions & 14 deletions MSIFanControl.ECAccess/EC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,21 @@ public EC()
/// </returns>
public bool LoadDriver()
{
return _Driver.Install() && _Driver.Open();
// Attempt to open an already installed WinRing0 driver first
if (_Driver.Open())
{
return true;
}

// If opening the driver fails, uninstall (if installed) and reinstall it
_Driver.Uninstall();
if (!_Driver.Install())
{
_Driver.Uninstall();
return false;
}

return _Driver.Open();
}

/// <summary>
Expand All @@ -108,7 +122,17 @@ public bool LoadDriver()
/// </remarks>
public void UnloadDriver()
{
_Driver.Uninstall();
if (GetRefCount() <= 1)
{
// only uninstall the driver if we're the last program using it
// (Driver.Uninstall() calles Driver.Close() internally)
_Driver.Uninstall();
}
else
{
// otherwise, just close the handle to the driver
_Driver.Close();
}
}

/// <summary>
Expand All @@ -119,11 +143,16 @@ public void UnloadDriver()
public bool ReadByte(byte register, out byte value)
{
value = 0;
for (int i = 0; i < RW_MAX_RETRIES; i++)

// only attempt to read EC if driver connection has been opened
if ((_Driver.Status & DriverStatus.Open) == DriverStatus.Open)
{
if (TryReadByte(register, out value))
for (int i = 0; i < RW_MAX_RETRIES; i++)
{
return true;
if (TryReadByte(register, out value))
{
return true;
}
}
}
return false;
Expand All @@ -136,13 +165,18 @@ public bool ReadByte(byte register, out byte value)
/// <param name="value">The value to write at the register.</param>
public bool WriteByte(byte register, byte value)
{
for (int i = 0; i < RW_MAX_RETRIES; i++)
// only attempt to write EC if driver connection has been opened
if ((_Driver.Status & DriverStatus.Open) == DriverStatus.Open)
{
if (TryWriteByte(register, value))
for (int i = 0; i < RW_MAX_RETRIES; i++)
{
return true;
if (TryWriteByte(register, value))
{
return true;
}
}
}

return false;
}

Expand All @@ -158,13 +192,19 @@ public bool WriteByte(byte register, byte value)
public bool ReadWord(byte register, out ushort value, bool bigEndian = false)
{
value = 0;
for (int i = 0; i < RW_MAX_RETRIES; i++)

// only attempt to read EC if driver connection has been opened
if ((_Driver.Status & DriverStatus.Open) == DriverStatus.Open)
{
if (TryReadWord(register, bigEndian, out value))
for (int i = 0; i < RW_MAX_RETRIES; i++)
{
return true;
if (TryReadWord(register, bigEndian, out value))
{
return true;
}
}
}

return false;
}

Expand All @@ -179,13 +219,18 @@ public bool ReadWord(byte register, out ushort value, bool bigEndian = false)
/// </param>
public bool WriteWord(byte register, ushort value, bool bigEndian = false)
{
for (int i = 0; i < RW_MAX_RETRIES; i++)
// only attempt to write EC if driver connection has been opened
if ((_Driver.Status & DriverStatus.Open) == DriverStatus.Open)
{
if (TryWriteWord(register, value, bigEndian))
for (int i = 0; i < RW_MAX_RETRIES; i++)
{
return true;
if (TryWriteWord(register, value, bigEndian))
{
return true;
}
}
}

return false;
}

Expand Down Expand Up @@ -337,6 +382,12 @@ private bool WriteIOPort(ushort port, byte value)
return _Driver.IOControl((uint)Ring0Control.WriteIOPortByte, input, null);
}

private uint GetRefCount()
{
uint refCount = 0;
return _Driver.IOControl((uint)Ring0Control.GetRefCount, ref refCount, out refCount) ? refCount : 0;
}

/// <summary>
/// Gets the status of the WinRing0 driver.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions MSIFanControl.ECAccess/MSIFanControl.ECAccess.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MSIFanControl.Logging\MSIFanControl.Logs.csproj">
<Project>{5c611048-093e-48ac-b525-5c24817081bb}</Project>
<Name>MSIFanControl.Logs</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
Expand Down

0 comments on commit c8048d0

Please sign in to comment.