moel@1: /*
moel@1:  
moel@344:   This Source Code Form is subject to the terms of the Mozilla Public
moel@344:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@1:  
moel@344:   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344: 	
moel@1: */
moel@1: 
moel@1: using System;
moel@1: using System.Runtime.InteropServices;
moel@333: using System.Text.RegularExpressions;
moel@1: 
moel@1: namespace OpenHardwareMonitor.Hardware.ATI {
moel@1:   
moel@1:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct ADLAdapterInfo {
moel@1:     public int Size;
moel@1:     public int AdapterIndex;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string UDID;
moel@1:     public int BusNumber;
moel@3:     public int DeviceNumber;
moel@1:     public int FunctionNumber;
moel@1:     public int VendorID;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string AdapterName;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string DisplayName;
moel@1:     public int Present;
moel@1:     public int Exist;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string DriverPath;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string DriverPathExt;
moel@1:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL.ADL_MAX_PATH)]
moel@1:     public string PNPString;
moel@1:     public int OSDisplayIndex;
moel@1:   }
moel@1: 
moel@1:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct ADLPMActivity {
moel@1:     public int Size;
moel@1:     public int EngineClock;
moel@1:     public int MemoryClock;
moel@1:     public int Vddc;
moel@1:     public int ActivityPercent;
moel@1:     public int CurrentPerformanceLevel;
moel@1:     public int CurrentBusSpeed;
moel@1:     public int CurrentBusLanes;
moel@1:     public int MaximumBusLanes;
moel@1:     public int Reserved;
moel@1:   }
moel@1: 
moel@1:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct ADLTemperature {
moel@1:     public int Size;
moel@1:     public int Temperature;
moel@1:   }
moel@1: 
moel@1:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct ADLFanSpeedValue {
moel@1:     public int Size;
moel@1:     public int SpeedType;
moel@1:     public int FanSpeed;
moel@1:     public int Flags;
moel@1:   }
moel@1: 
moel@1:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct ADLFanSpeedInfo {
moel@1:     public int Size;
moel@1:     public int Flags;
moel@1:     public int MinPercent;
moel@1:     public int MaxPercent;
moel@1:     public int MinRPM;
moel@1:     public int MaxRPM;
moel@1:   }
moel@1: 
moel@165:   internal class ADL {
moel@1:     public const int ADL_MAX_PATH = 256;
moel@1:     public const int ADL_MAX_ADAPTERS = 40;
moel@1:     public const int ADL_MAX_DISPLAYS = 40;
moel@1:     public const int ADL_MAX_DEVICENAME = 32;
moel@6:     public const int ADL_OK = 0;
moel@15:     public const int ADL_ERR = -1;
moel@1:     public const int ADL_DRIVER_OK = 0;
moel@1:     public const int ADL_MAX_GLSYNC_PORTS = 8;
moel@1:     public const int ADL_MAX_GLSYNC_PORT_LEDS = 8;
moel@1:     public const int ADL_MAX_NUM_DISPLAYMODES = 1024;
moel@1: 
moel@1:     public const int ADL_DL_FANCTRL_SPEED_TYPE_PERCENT = 1;
moel@1:     public const int ADL_DL_FANCTRL_SPEED_TYPE_RPM = 2;
moel@1: 
moel@1:     public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ = 1;
moel@1:     public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE = 2;
moel@1:     public const int ADL_DL_FANCTRL_SUPPORTS_RPM_READ = 4;
moel@1:     public const int ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE = 8;
moel@247:     public const int ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED = 1;
moel@1: 
moel@333:     public const int ATI_VENDOR_ID = 0x1002;
moel@3: 
moel@1:     private delegate int ADL_Main_Control_CreateDelegate(
moel@1:       ADL_Main_Memory_AllocDelegate callback, int enumConnectedAdapters);
moel@1:     private delegate int ADL_Adapter_AdapterInfo_GetDelegate(IntPtr info,
moel@1:       int size);
moel@1: 
moel@1:     public delegate int ADL_Main_Control_DestroyDelegate();
moel@1:     public delegate int ADL_Adapter_NumberOfAdapters_GetDelegate(
moel@1:       ref int numAdapters);    
moel@1:     public delegate int ADL_Adapter_ID_GetDelegate(int adapterIndex,
moel@1:       out int adapterID);
moel@12:     public delegate int ADL_Display_AdapterID_GetDelegate(int adapterIndex,
moel@12:       out int adapterID);      	
moel@1:     public delegate int ADL_Adapter_Active_GetDelegate(int adapterIndex,
moel@1:       out int status);
moel@1:     public delegate int ADL_Overdrive5_CurrentActivity_GetDelegate(
moel@1:       int iAdapterIndex, ref ADLPMActivity activity);
moel@1:     public delegate int ADL_Overdrive5_Temperature_GetDelegate(int adapterIndex,
moel@1:         int thermalControllerIndex, ref ADLTemperature temperature);
moel@1:     public delegate int ADL_Overdrive5_FanSpeed_GetDelegate(int adapterIndex,
moel@1:         int thermalControllerIndex, ref	ADLFanSpeedValue fanSpeedValue);
moel@1:     public delegate int ADL_Overdrive5_FanSpeedInfo_GetDelegate(
moel@1:       int adapterIndex, int thermalControllerIndex,
moel@1:       ref ADLFanSpeedInfo fanSpeedInfo);
moel@247:     public delegate int ADL_Overdrive5_FanSpeedToDefault_SetDelegate(
moel@247:       int adapterIndex, int thermalControllerIndex);
moel@247:     public delegate int ADL_Overdrive5_FanSpeed_SetDelegate(int adapterIndex,
moel@247:       int thermalControllerIndex, ref	ADLFanSpeedValue fanSpeedValue);
moel@1: 
moel@1:     private static ADL_Main_Control_CreateDelegate
moel@1:       _ADL_Main_Control_Create;
moel@1:     private static ADL_Adapter_AdapterInfo_GetDelegate
moel@1:       _ADL_Adapter_AdapterInfo_Get;
moel@1: 
moel@167:     public static ADL_Main_Control_DestroyDelegate
moel@1:       ADL_Main_Control_Destroy;
moel@1:     public static ADL_Adapter_NumberOfAdapters_GetDelegate
moel@1:       ADL_Adapter_NumberOfAdapters_Get;
moel@12:     public static ADL_Adapter_ID_GetDelegate 
moel@12:       _ADL_Adapter_ID_Get;
moel@12:     public static ADL_Display_AdapterID_GetDelegate 
moel@12:       _ADL_Display_AdapterID_Get;
moel@12:     public static ADL_Adapter_Active_GetDelegate 
moel@1:       ADL_Adapter_Active_Get;
moel@1:     public static ADL_Overdrive5_CurrentActivity_GetDelegate
moel@1:       ADL_Overdrive5_CurrentActivity_Get;
moel@1:     public static ADL_Overdrive5_Temperature_GetDelegate
moel@1:       ADL_Overdrive5_Temperature_Get;
moel@1:     public static ADL_Overdrive5_FanSpeed_GetDelegate
moel@1:       ADL_Overdrive5_FanSpeed_Get;
moel@1:     public static ADL_Overdrive5_FanSpeedInfo_GetDelegate
moel@1:       ADL_Overdrive5_FanSpeedInfo_Get;
moel@247:     public static ADL_Overdrive5_FanSpeedToDefault_SetDelegate
moel@247:       ADL_Overdrive5_FanSpeedToDefault_Set;
moel@247:     public static ADL_Overdrive5_FanSpeed_SetDelegate
moel@247:       ADL_Overdrive5_FanSpeed_Set;
moel@1: 
moel@8:     private static string dllName;
moel@1: 
moel@1:     private static void GetDelegate<T>(string entryPoint, out T newDelegate)
moel@1:       where T : class 
moel@1:     {
moel@8:       DllImportAttribute attribute = new DllImportAttribute(dllName);
moel@1:       attribute.CallingConvention = CallingConvention.StdCall;
moel@1:       attribute.PreserveSig = true;
moel@1:       attribute.EntryPoint = entryPoint;
moel@1:       PInvokeDelegateFactory.CreateDelegate(attribute, out newDelegate);
moel@1:     }
moel@1: 
moel@8:     private static void CreateDelegates(string name) {
moel@195:       int p = (int)Environment.OSVersion.Platform;
moel@8:       if ((p == 4) || (p == 128))
moel@8:         dllName = name + ".so";
moel@8:       else
moel@8:         dllName = name + ".dll";
moel@8: 
moel@8:       GetDelegate("ADL_Main_Control_Create",
moel@8:         out _ADL_Main_Control_Create);
moel@8:       GetDelegate("ADL_Adapter_AdapterInfo_Get",
moel@8:         out _ADL_Adapter_AdapterInfo_Get);
moel@8:       GetDelegate("ADL_Main_Control_Destroy",
moel@8:         out ADL_Main_Control_Destroy);
moel@8:       GetDelegate("ADL_Adapter_NumberOfAdapters_Get",
moel@8:         out ADL_Adapter_NumberOfAdapters_Get);
moel@8:       GetDelegate("ADL_Adapter_ID_Get",
moel@12:         out _ADL_Adapter_ID_Get);
moel@12:       GetDelegate("ADL_Display_AdapterID_Get", 
moel@12:         out _ADL_Display_AdapterID_Get);
moel@8:       GetDelegate("ADL_Adapter_Active_Get",
moel@8:         out ADL_Adapter_Active_Get);
moel@8:       GetDelegate("ADL_Overdrive5_CurrentActivity_Get",
moel@8:         out ADL_Overdrive5_CurrentActivity_Get);
moel@8:       GetDelegate("ADL_Overdrive5_Temperature_Get",
moel@8:         out ADL_Overdrive5_Temperature_Get);
moel@8:       GetDelegate("ADL_Overdrive5_FanSpeed_Get",
moel@8:         out ADL_Overdrive5_FanSpeed_Get);
moel@8:       GetDelegate("ADL_Overdrive5_FanSpeedInfo_Get",
moel@8:         out ADL_Overdrive5_FanSpeedInfo_Get);
moel@247:       GetDelegate("ADL_Overdrive5_FanSpeedToDefault_Set",
moel@247:         out ADL_Overdrive5_FanSpeedToDefault_Set);
moel@247:       GetDelegate("ADL_Overdrive5_FanSpeed_Set",
moel@247:         out ADL_Overdrive5_FanSpeed_Set);
moel@8:     }
moel@8: 
moel@1:     static ADL() {
moel@8:       CreateDelegates("atiadlxx");
moel@1:     }
moel@1: 
moel@1:     private ADL() { }
moel@1: 
moel@1:     public static int ADL_Main_Control_Create(int enumConnectedAdapters) {
moel@8:       try {
moel@160:         try {
moel@160:           return _ADL_Main_Control_Create(Main_Memory_Alloc,
moel@160:             enumConnectedAdapters);
moel@160:         } catch {
moel@160:           CreateDelegates("atiadlxy");
moel@160:           return _ADL_Main_Control_Create(Main_Memory_Alloc,
moel@160:             enumConnectedAdapters);
moel@160:         }
moel@160:       } catch {
moel@195:         return ADL_ERR;
moel@8:       }
moel@1:     }
moel@1: 
moel@1:     public static int ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo[] info) {
moel@1:       int elementSize = Marshal.SizeOf(typeof(ADLAdapterInfo));
moel@1:       int size = info.Length * elementSize;
moel@1:       IntPtr ptr = Marshal.AllocHGlobal(size);
moel@1:       int result = _ADL_Adapter_AdapterInfo_Get(ptr, size);
moel@1:       for (int i = 0; i < info.Length; i++)
moel@1:         info[i] = (ADLAdapterInfo)
moel@1:           Marshal.PtrToStructure((IntPtr)((long)ptr + i * elementSize),
moel@1:           typeof(ADLAdapterInfo));
moel@1:       Marshal.FreeHGlobal(ptr);
moel@333: 
moel@333:       // the ADLAdapterInfo.VendorID field reported by ADL is wrong on 
moel@333:       // Windows systems (parse error), so we fix this here
moel@333:       for (int i = 0; i < info.Length; i++) {
moel@333:         // try Windows UDID format
moel@333:         Match m = Regex.Match(info[i].UDID, "PCI_VEN_([A-Fa-f0-9]{1,4})&.*");
moel@333:         if (m.Success && m.Groups.Count == 2) {
moel@333:           info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 16);
moel@333:           continue;
moel@333:         }
moel@333:         // if above failed, try Unix UDID format
moel@333:         m = Regex.Match(info[i].UDID, "[0-9]+:[0-9]+:([0-9]+):[0-9]+:[0-9]+");
moel@333:         if (m.Success && m.Groups.Count == 2) {
moel@333:           info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 10);
moel@333:         }
moel@333:       }
moel@333: 
moel@1:       return result;
moel@1:     }
moel@1: 
moel@12:     public static int ADL_Adapter_ID_Get(int adapterIndex,
moel@12:       out int adapterID) {
moel@12:       try {
moel@12:         return _ADL_Adapter_ID_Get(adapterIndex, out adapterID);
moel@12:       } catch (EntryPointNotFoundException) {
moel@12:         try {
moel@12:           return _ADL_Display_AdapterID_Get(adapterIndex, out adapterID);
moel@12:         } catch (EntryPointNotFoundException) {
moel@12:           adapterID = 1;
moel@12:           return ADL_OK;
moel@12:         }
moel@12:       }
moel@12:     }
moel@12: 
moel@1:     private delegate IntPtr ADL_Main_Memory_AllocDelegate(int size);
moel@1: 
moel@200:     // create a Main_Memory_Alloc delegate and keep it alive
moel@200:     private static ADL_Main_Memory_AllocDelegate Main_Memory_Alloc =
moel@200:       delegate(int size) {
moel@200:         return Marshal.AllocHGlobal(size);
moel@200:       };
moel@1: 
moel@1:     private static void Main_Memory_Free(IntPtr buffer) {
moel@1:       if (IntPtr.Zero != buffer)
moel@1:         Marshal.FreeHGlobal(buffer);
moel@1:     }
moel@1:   }
moel@1: }