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