fixed compilation error on 64bits with ATI/AMD GPU support.
[psensor.git] / src / lib / amd.c
1 /*
2  * Copyright (C) 2010-2011 thgreasi@gmail.com, jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #ifndef LINUX
20 #define LINUX 1
21 #endif
22 #ifdef HAVE_LIBATIADL
23         /* AMD id for the aticonfig */
24         int amd_id;
25 #endif
26
27 #include <locale.h>
28 #include <libintl.h>
29 #define _(str) gettext(str)
30
31 #include <dlfcn.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <adl_sdk.h>
37
38 #include "psensor.h"
39
40 typedef int (*ADL_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int);
41 typedef int (*ADL_MAIN_CONTROL_DESTROY)();
42 typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int *);
43 typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int);
44 typedef int (*ADL_ADAPTER_ACTIVE_GET) (int, int*);
45 typedef int (*ADL_OVERDRIVE5_TEMPERATURE_GET) (int, int, ADLTemperature*);
46 typedef int (*ADL_OVERDRIVE5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
47
48 static ADL_MAIN_CONTROL_CREATE            adl_main_control_create;
49 static ADL_MAIN_CONTROL_DESTROY           adl_main_control_destroy;
50 static ADL_ADAPTER_NUMBEROFADAPTERS_GET   adl_adapter_numberofadapters_get;
51 static ADL_ADAPTER_ADAPTERINFO_GET        adl_adapter_adapterinfo_get;
52 static ADL_ADAPTER_ACTIVE_GET             adl_adapter_active_get;
53 static ADL_OVERDRIVE5_TEMPERATURE_GET     adl_overdrive5_temperature_get;
54 static ADL_OVERDRIVE5_FANSPEED_GET        adl_overdrive5_fanspeed_get;
55
56 static void *hdll;
57 static int adl_main_control_done;
58 static int *active_amd_adapters;
59
60 /* Memory allocation function */
61 static void __stdcall *adl_main_memory_alloc(int isize)
62 {
63         void *lpbuffer = malloc(isize);
64         return lpbuffer;
65 }
66
67 static void *getprocaddress(void *plibrary, const char * name)
68 {
69         return dlsym(plibrary, name);
70 }
71
72 /*
73   Returns the temperature (Celcius) of an AMD/Ati GPU.
74 */
75 static double get_temp(struct psensor *sensor)
76 {
77         ADLTemperature temperature;
78
79         temperature.iSize = sizeof(ADLTemperature);
80         temperature.iTemperature = -273;
81         if (ADL_OK != adl_overdrive5_temperature_get(sensor->amd_id,
82                  0, &temperature))
83                 return UNKNOWN_DBL_VALUE;
84
85         return temperature.iTemperature/1000;
86 }
87
88 static double get_fanspeed(struct psensor *sensor)
89 {
90         ADLFanSpeedValue fanspeedvalue;
91
92         fanspeedvalue.iSize = sizeof(ADLFanSpeedValue);
93         fanspeedvalue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
94         fanspeedvalue.iFanSpeed = -1;
95         if (ADL_OK != adl_overdrive5_fanspeed_get(sensor->amd_id,
96                  0, &fanspeedvalue))
97                 return UNKNOWN_DBL_VALUE;
98
99         return fanspeedvalue.iFanSpeed;
100 }
101
102 static struct psensor *create_sensor(int id, int values_len)
103 {
104         char name[200];
105         char *sid;
106         int sensor_type;
107
108         struct psensor *s;
109
110         if (id & 1) {/* odd number ids represent fan sensors */
111                 id = id >> 1;
112                 sprintf(name, "GPU%dfan", id);
113                 sensor_type = SENSOR_TYPE_AMD_FAN;
114         } else {/* even number ids represent temperature sensors */
115                 id = id >> 1;
116                 sprintf(name, "GPU%dtemp", id);
117                 sensor_type = SENSOR_TYPE_AMD_TEMP;
118         }
119
120         sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
121         sprintf(sid, "amd %s", name);
122
123         s = psensor_create(sid, strdup(name),
124                            sensor_type, values_len);
125
126         s->amd_id = active_amd_adapters[id];
127
128         return s;
129 }
130
131 /*
132   Returns the number of AMD/Ati GPU sensors (temperature and fan
133   speed).
134
135   Return 0 if no AMD/Ati gpus or cannot get information.
136 */
137 static int init()
138 {
139         LPAdapterInfo lpadapterinfo = NULL;
140         int i, inumberadapters, inumberadaptersactive = 0;
141         int lpstatus, iadapterindex;
142
143         hdll = NULL;
144         adl_main_control_done = 0;
145         active_amd_adapters = NULL;
146         hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
147
148         if (!hdll) {
149                 fprintf(stderr,
150                         _("ERROR: ADL library not found!\n"));
151                 return 0;
152         }
153
154         adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
155                  getprocaddress(hdll, "ADL_Main_Control_Create");
156         adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
157                  getprocaddress(hdll, "ADL_Main_Control_Destroy");
158         adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
159                  getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
160         adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
161                  getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
162         adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
163                  getprocaddress(hdll, "ADL_Adapter_Active_Get");
164         adl_overdrive5_temperature_get = (ADL_OVERDRIVE5_TEMPERATURE_GET)
165                  getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
166         adl_overdrive5_fanspeed_get = (ADL_OVERDRIVE5_FANSPEED_GET)
167                  getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
168         if (!adl_main_control_create ||
169                 !adl_main_control_destroy ||
170                 !adl_adapter_numberofadapters_get ||
171                 !adl_adapter_adapterinfo_get ||
172                 !adl_overdrive5_temperature_get ||
173                 !adl_overdrive5_fanspeed_get) {
174                 fprintf(stderr,
175                         _("ERROR: ADL's API is missing!\n"));
176                 return 0;
177         }
178
179         /* Initialize ADL. The second parameter is 1, which means:
180            retrieve adapter information only for adapters that
181            are physically present and enabled in the system */
182         if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
183                 fprintf(stderr,
184                         _("ERROR: ADL Initialization Error!\n"));
185                 return 0;
186         }
187         adl_main_control_done = 1;
188
189         /* Obtain the number of adapters for the system */
190         if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
191                 fprintf(stderr,
192                         _("ERROR: Cannot get the number of adapters!\n"));
193                 return 0;
194         }
195
196         if (!inumberadapters)
197                 return 0;
198
199         lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
200         memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
201
202         /* Get the AdapterInfo structure for all adapters in the system */
203         adl_adapter_adapterinfo_get(lpadapterinfo,
204                                     sizeof(AdapterInfo) * inumberadapters);
205
206         /* Repeat for all available adapters in the system */
207         for (i = 0; i < inumberadapters; i++) {
208
209                 iadapterindex = lpadapterinfo[i].iAdapterIndex;
210
211                 if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
212                         continue;
213                 if (lpstatus != ADL_TRUE)
214                         /* count only if the adapter is active */
215                         continue;
216
217                 if (!active_amd_adapters) {
218                         active_amd_adapters = (int *) malloc(sizeof(int));
219                         inumberadaptersactive = 1;
220                 } else {
221                         ++inumberadaptersactive;
222                         active_amd_adapters = (int *)realloc
223                                 (active_amd_adapters,
224                                  sizeof(int)*inumberadaptersactive);
225                 }
226                 active_amd_adapters[inumberadaptersactive-1] = iadapterindex;
227         }
228
229         free(lpadapterinfo);
230
231         /* Each Adapter has one GPU temperature sensor and one fan
232            control sensor */
233         return 2*inumberadaptersactive;
234 }
235
236 void amd_psensor_list_update(struct psensor **sensors)
237 {
238         struct psensor **ss, *s;
239
240         ss = sensors;
241         while (*ss) {
242                 s = *ss;
243
244                 if (s->type == SENSOR_TYPE_AMD_TEMP)
245                         psensor_set_current_value(s, get_temp(s));
246                 else if (s->type == SENSOR_TYPE_AMD_FAN)
247                         psensor_set_current_value(s, get_fanspeed(s));
248
249                 ss++;
250         }
251 }
252
253 struct psensor * *
254 amd_psensor_list_add(struct psensor **sensors, int values_len)
255 {
256         int i, n;
257         struct psensor **tmp, **ss, *s;
258
259         n = init();
260
261         ss = sensors;
262         for (i = 0; i < n; i++) {
263                 s = create_sensor(i, values_len);
264
265                 tmp = psensor_list_add(ss, s);
266
267                 if (ss != tmp)
268                         free(ss);
269
270                 ss = tmp;
271         }
272
273         return ss;
274 }
275
276 void amd_cleanup()
277 {
278         if (hdll) {
279                 if (adl_main_control_done)
280                         adl_main_control_destroy();
281                 dlclose(hdll);
282         }
283
284         if (active_amd_adapters) {
285                 free(active_amd_adapters);
286                 active_amd_adapters = NULL;
287         }
288 }