moel@1: /*
moel@1:   
moel@1:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1: 
moel@1:   The contents of this file are subject to the Mozilla Public License Version
moel@1:   1.1 (the "License"); you may not use this file except in compliance with
moel@1:   the License. You may obtain a copy of the License at
moel@1:  
moel@1:   http://www.mozilla.org/MPL/
moel@1: 
moel@1:   Software distributed under the License is distributed on an "AS IS" basis,
moel@1:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1:   for the specific language governing rights and limitations under the License.
moel@1: 
moel@1:   The Original Code is the Open Hardware Monitor code.
moel@1: 
moel@1:   The Initial Developer of the Original Code is 
moel@1:   Michael Möller <m.moeller@gmx.ch>.
moel@1:   Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1:   the Initial Developer. All Rights Reserved.
moel@1: 
moel@1:   Contributor(s):
moel@1: 
moel@1:   Alternatively, the contents of this file may be used under the terms of
moel@1:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@1:   of those above. If you wish to allow use of your version of this file only
moel@1:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@1:   use your version of this file under the terms of the MPL, indicate your
moel@1:   decision by deleting the provisions above and replace them with the notice
moel@1:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@1:   the provisions above, a recipient may use your version of this file under
moel@1:   the terms of any one of the MPL, the GPL or the LGPL.
moel@1:  
moel@1: */
moel@1: 
moel@1: using System;
moel@1: using System.Runtime.InteropServices;
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@3:     public const int ATI_VENDOR_ID1 = 1002;
moel@3:     public const int ATI_VENDOR_ID2 = 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@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: }