update for beta release
[framework/uifw/e17.git] / src / modules / cpufreq / e_mod_main.c
1 #include "e.h"
2 #include "e_mod_main.h"
3
4 #ifdef __FreeBSD__
5 #include <sys/types.h>
6 #include <sys/sysctl.h>
7 #endif
8
9 /* gadcon requirements */
10 static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
11 static void _gc_shutdown(E_Gadcon_Client *gcc);
12 static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient);
13 static const char *_gc_label(E_Gadcon_Client_Class *client_class);
14 static Evas_Object *_gc_icon(E_Gadcon_Client_Class *client_class, Evas *evas);
15 static const char *_gc_id_new(E_Gadcon_Client_Class *client_class);
16 /* and actually define the gadcon class that this module provides (just 1) */
17 static const E_Gadcon_Client_Class _gadcon_class =
18 {
19    GADCON_CLIENT_CLASS_VERSION, "cpufreq",
20      {
21         _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, NULL
22      },
23    E_GADCON_CLIENT_STYLE_PLAIN
24 };
25
26 /* actual module specifics */
27 typedef struct _Instance Instance;
28
29 struct _Instance
30 {
31    E_Gadcon_Client *gcc;
32    Evas_Object *o_cpu;
33 };
34
35 static void _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
36 static void _menu_cb_post(void *data, E_Menu *m);
37 static void _cpufreq_set_governor(const char *governor);
38 static void _cpufreq_set_frequency(int frequency);
39 static Eina_Bool _cpufreq_cb_check(void *data);
40 static Status *_cpufreq_status_new();
41 static void _cpufreq_status_free(Status *s);
42 static int _cpufreq_status_check_available(Status *s);
43 static int _cpufreq_status_check_current(Status *s);
44 static int _cpufreq_cb_sort(const void *item1, const void *item2);
45 static void _cpufreq_face_update_available(Instance *inst);
46 static void _cpufreq_face_update_current(Instance *inst);
47 static void _cpufreq_face_cb_set_frequency(void *data, Evas_Object *o, const char *emission, const char *source);
48 static void _cpufreq_face_cb_set_governor(void *data, Evas_Object *o, const char *emission, const char *source);
49 static Eina_Bool _cpufreq_event_cb_powersave(void *data __UNUSED__, int type, void *event);
50
51 static void _cpufreq_menu_fast(void *data, E_Menu *m, E_Menu_Item *mi);
52 static void _cpufreq_menu_medium(void *data, E_Menu *m, E_Menu_Item *mi);
53 static void _cpufreq_menu_normal(void *data, E_Menu *m, E_Menu_Item *mi);
54 static void _cpufreq_menu_slow(void *data, E_Menu *m, E_Menu_Item *mi);
55 static void _cpufreq_menu_very_slow(void *data, E_Menu *m, E_Menu_Item *mi);
56 static void _cpufreq_menu_restore_governor(void *data, E_Menu *m, E_Menu_Item *mi);
57 static void _cpufreq_menu_auto_powersave(void *data, E_Menu *m, E_Menu_Item *mi);
58 static void _cpufreq_menu_governor(void *data, E_Menu *m, E_Menu_Item *mi);
59 static void _cpufreq_menu_powersave_governor(void *data, E_Menu *m, E_Menu_Item *mi);
60 static void _cpufreq_menu_frequency(void *data, E_Menu *m, E_Menu_Item *mi);
61 static void _cpufreq_poll_interval_update(void);
62
63 static E_Config_DD *conf_edd = NULL;
64
65 Config *cpufreq_config = NULL;
66
67 static E_Gadcon_Client *
68 _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
69 {
70    Evas_Object *o;
71    E_Gadcon_Client *gcc;
72    Instance *inst;
73
74    inst = E_NEW(Instance, 1);
75
76    o = edje_object_add(gc->evas);
77    e_theme_edje_object_set(o, "base/theme/modules/cpufreq",
78                            "e/modules/cpufreq/main");
79    edje_object_signal_callback_add(o, "e,action,governor,next", "*", 
80                                    _cpufreq_face_cb_set_governor, NULL);
81    edje_object_signal_callback_add(o, "e,action,frequency,increase", "*", 
82                                    _cpufreq_face_cb_set_frequency, NULL);
83    edje_object_signal_callback_add(o, "e,action,frequency,decrease", "*", 
84                                    _cpufreq_face_cb_set_frequency, NULL);
85
86    gcc = e_gadcon_client_new(gc, name, id, style, o);
87    gcc->data = inst;
88
89    inst->gcc = gcc;
90    inst->o_cpu = o;
91
92    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
93                                   _button_cb_mouse_down, inst);
94    cpufreq_config->instances = 
95      eina_list_append(cpufreq_config->instances, inst);
96    if (cpufreq_config->status) _cpufreq_status_free(cpufreq_config->status);
97    cpufreq_config->status = _cpufreq_status_new();
98    _cpufreq_cb_check(NULL);
99    _cpufreq_face_update_available(inst);
100
101    cpufreq_config->handler = 
102      ecore_event_handler_add(E_EVENT_POWERSAVE_UPDATE,
103                              _cpufreq_event_cb_powersave, NULL);
104    return gcc;
105 }
106
107 static void
108 _gc_shutdown(E_Gadcon_Client *gcc)
109 {
110    Instance *inst;
111
112    inst = gcc->data;
113    cpufreq_config->instances = 
114      eina_list_remove(cpufreq_config->instances, inst);
115    evas_object_del(inst->o_cpu);
116    free(inst);
117
118    if (cpufreq_config->handler) 
119      ecore_event_handler_del(cpufreq_config->handler);
120 }
121
122 static void
123 _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient __UNUSED__)
124 {
125    e_gadcon_client_aspect_set(gcc, 16, 16);
126    e_gadcon_client_min_size_set(gcc, 16, 16);
127 }
128
129 static const char *
130 _gc_label(E_Gadcon_Client_Class *client_class __UNUSED__)
131 {
132    return _("Cpufreq");
133 }
134
135 static Evas_Object *
136 _gc_icon(E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas)
137 {
138    Evas_Object *o;
139    char buf[PATH_MAX];
140
141    o = edje_object_add(evas);
142    snprintf(buf, sizeof(buf), "%s/e-module-cpufreq.edj",
143             e_module_dir_get(cpufreq_config->module));
144    edje_object_file_set(o, buf, "icon");
145    return o;
146 }
147
148 static const char *
149 _gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__)
150 {
151    static char idbuff[32];
152
153    snprintf(idbuff, sizeof(idbuff), "%s.%d", _gadcon_class.name, 
154             eina_list_count(cpufreq_config->instances));
155    return idbuff;
156 }
157
158 static void
159 _button_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
160 {
161    Instance *inst;
162    Evas_Event_Mouse_Down *ev;
163    
164    if (cpufreq_config->menu) return;
165      
166    inst = data;
167    ev = event_info;
168
169    if (ev->button == 1)
170      {
171         E_Menu *mg, *mo;
172         E_Menu_Item *mi;
173         Eina_List *l;
174         int cx, cy;
175         char buf[256];
176
177         mo = e_menu_new();
178         cpufreq_config->menu_poll = mo;
179
180         mi = e_menu_item_new(mo);
181         e_menu_item_label_set(mi, _("Fast (4 ticks)"));
182         e_menu_item_radio_set(mi, 1);
183         e_menu_item_radio_group_set(mi, 1);
184         if (cpufreq_config->poll_interval <= 4) e_menu_item_toggle_set(mi, 1);
185         e_menu_item_callback_set(mi, _cpufreq_menu_fast, NULL);
186
187         mi = e_menu_item_new(mo);
188         e_menu_item_label_set(mi, _("Medium (8 ticks)"));
189         e_menu_item_radio_set(mi, 1);
190         e_menu_item_radio_group_set(mi, 1);
191         if (cpufreq_config->poll_interval > 4) e_menu_item_toggle_set(mi, 1);
192         e_menu_item_callback_set(mi, _cpufreq_menu_medium, NULL);
193
194         mi = e_menu_item_new(mo);
195         e_menu_item_label_set(mi, _("Normal (32 ticks)"));
196         e_menu_item_radio_set(mi, 1);
197         e_menu_item_radio_group_set(mi, 1);
198         if (cpufreq_config->poll_interval >= 32) e_menu_item_toggle_set(mi, 1);
199         e_menu_item_callback_set(mi, _cpufreq_menu_normal, NULL);
200
201         mi = e_menu_item_new(mo);
202         e_menu_item_label_set(mi, _("Slow (64 ticks)"));
203         e_menu_item_radio_set(mi, 1);
204         e_menu_item_radio_group_set(mi, 1);
205         if (cpufreq_config->poll_interval >= 64) e_menu_item_toggle_set(mi, 1);
206         e_menu_item_callback_set(mi, _cpufreq_menu_slow, NULL);
207
208         mi = e_menu_item_new(mo);
209         e_menu_item_label_set(mi, _("Very Slow (256 ticks)"));
210         e_menu_item_radio_set(mi, 1);
211         e_menu_item_radio_group_set(mi, 1);
212         if (cpufreq_config->poll_interval >= 128) 
213           e_menu_item_toggle_set(mi, 1);
214         e_menu_item_callback_set(mi, _cpufreq_menu_very_slow, NULL);
215
216         if (cpufreq_config->status->governors)
217           {
218              mo = e_menu_new();
219              cpufreq_config->menu_governor = mo;
220
221              for (l = cpufreq_config->status->governors; l; l = l->next)
222                {
223                   mi = e_menu_item_new(mo);
224                   if (!strcmp(l->data, "userspace"))
225                     e_menu_item_label_set(mi, _("Manual"));
226                   else if (!strcmp(l->data, "ondemand"))
227                     e_menu_item_label_set(mi, _("Automatic"));
228                   else if (!strcmp(l->data, "conservative"))
229                     e_menu_item_label_set(mi, _("Lower Power Automatic"));
230                   else if (!strcmp(l->data, "powersave"))
231                     e_menu_item_label_set(mi, _("Minimum Speed"));
232                   else if (!strcmp(l->data, "performance"))
233                     e_menu_item_label_set(mi, _("Maximum Speed"));
234                   e_menu_item_radio_set(mi, 1);
235                   e_menu_item_radio_group_set(mi, 1);
236                   if (!strcmp(cpufreq_config->status->cur_governor, l->data))
237                     e_menu_item_toggle_set(mi, 1);
238                   e_menu_item_callback_set(mi, _cpufreq_menu_governor, l->data);
239                }
240
241              e_menu_item_separator_set(e_menu_item_new(mo), 1);
242
243              mi = e_menu_item_new(mo);
244              e_menu_item_label_set(mi, _("Restore CPU Power Policy"));
245              e_menu_item_check_set(mi, 1);
246              e_menu_item_toggle_set(mi, cpufreq_config->restore_governor);
247              e_menu_item_callback_set(mi, _cpufreq_menu_restore_governor, NULL);
248
249              mo = e_menu_new();
250              cpufreq_config->menu_powersave = mo;
251
252              for (l = cpufreq_config->status->governors; l; l = l->next)
253                {
254                   if (!strcmp(l->data, "userspace"))
255                     continue;
256
257                   mi = e_menu_item_new(mo);
258                   if (!strcmp(l->data, "ondemand"))
259                     e_menu_item_label_set(mi, _("Automatic"));
260                   else if (!strcmp(l->data, "conservative"))
261                     e_menu_item_label_set(mi, _("Lower Power Automatic"));
262                   else if (!strcmp(l->data, "powersave"))
263                     e_menu_item_label_set(mi, _("Minimum Speed"));
264                   else if (!strcmp(l->data, "performance"))
265                     e_menu_item_label_set(mi, _("Maximum Speed"));
266
267                   e_menu_item_radio_set(mi, 1);
268                   e_menu_item_radio_group_set(mi, 1);
269                   if (cpufreq_config->powersave_governor
270                       && !strcmp(cpufreq_config->powersave_governor, l->data))
271                     e_menu_item_toggle_set(mi, 1);
272                   e_menu_item_callback_set(mi, _cpufreq_menu_powersave_governor, l->data);
273                }
274
275              e_menu_item_separator_set(e_menu_item_new(mo), 1);
276
277              mi = e_menu_item_new(mo);
278              e_menu_item_label_set(mi, _("Automatic powersaving"));
279              e_menu_item_check_set(mi, 1);
280              e_menu_item_toggle_set(mi, cpufreq_config->auto_powersave);
281              e_menu_item_callback_set(mi, _cpufreq_menu_auto_powersave, NULL);
282           }
283
284         if ((cpufreq_config->status->frequencies) &&
285             (cpufreq_config->status->can_set_frequency))
286           {
287              mo = e_menu_new();
288              cpufreq_config->menu_frequency = mo;
289
290              for (l = cpufreq_config->status->frequencies; l; l = l->next)
291                {
292                   int frequency;
293
294                   frequency = (long)l->data;
295                   mi = e_menu_item_new(mo);
296                   if (frequency < 1000000)
297                     snprintf(buf, sizeof(buf), _("%i MHz"), frequency / 1000);
298                   else
299                     snprintf(buf, sizeof(buf), _("%i.%i GHz"),
300                              frequency / 1000000, (frequency % 1000000) / 100000);
301                   buf[sizeof(buf) - 1] = 0;
302                   e_menu_item_label_set(mi, buf);
303                   e_menu_item_radio_set(mi, 1);
304                   e_menu_item_radio_group_set(mi, 1);
305                   if (cpufreq_config->status->cur_frequency == frequency)
306                     e_menu_item_toggle_set(mi, 1);
307                   e_menu_item_callback_set(mi, _cpufreq_menu_frequency, l->data);
308                }
309           }
310
311         mg = e_menu_new();
312         mi = e_menu_item_new(mg);
313         e_menu_item_label_set(mi, _("Time Between Updates"));
314         e_menu_item_submenu_set(mi, cpufreq_config->menu_poll);
315
316         if (cpufreq_config->menu_governor)
317           {
318              mi = e_menu_item_new(mg);
319              e_menu_item_label_set(mi, _("Set CPU Power Policy"));
320              e_menu_item_submenu_set(mi, cpufreq_config->menu_governor);
321           }
322
323         if (cpufreq_config->menu_frequency)
324           {
325              mi = e_menu_item_new(mg);
326              e_menu_item_label_set(mi, _("Set CPU Speed"));
327              e_menu_item_submenu_set(mi, cpufreq_config->menu_frequency);
328           }
329         if (cpufreq_config->menu_powersave)
330           {
331              mi = e_menu_item_new(mg);
332              e_menu_item_label_set(mi, _("Powersaving behavior"));
333              e_menu_item_submenu_set(mi, cpufreq_config->menu_powersave);
334           }
335
336         e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon,
337                                           &cx, &cy, NULL, NULL);
338         cpufreq_config->menu = mg;
339         e_menu_post_deactivate_callback_set(mg, _menu_cb_post, inst);
340
341         e_gadcon_locked_set(inst->gcc->gadcon, 1); 
342
343         e_menu_activate_mouse(mg,
344                               e_util_zone_current_get(e_manager_current_get()),
345                               cx + ev->output.x, cy + ev->output.y, 1, 1,
346                               E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
347      }
348    else if (ev->button == 3)
349      {
350         E_Menu *m;
351         int cx, cy;
352         
353         m = e_menu_new();
354         m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0);
355         cpufreq_config->menu = m;
356         e_menu_post_deactivate_callback_set(m, _menu_cb_post, NULL);
357
358         e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon,
359                                           &cx, &cy, NULL, NULL);
360
361         e_menu_activate_mouse(m,
362                               e_util_zone_current_get(e_manager_current_get()),
363                               cx + ev->output.x, cy + ev->output.y, 1, 1,
364                               E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
365      }
366 }
367
368 static void
369 _menu_cb_post(void *data, E_Menu *m __UNUSED__)
370 {
371    Instance *inst = data;
372
373    if (inst)
374      e_gadcon_locked_set(inst->gcc->gadcon, 0); 
375
376    if (!cpufreq_config->menu) return;
377    e_object_del(E_OBJECT(cpufreq_config->menu));
378    cpufreq_config->menu = NULL;
379    if (cpufreq_config->menu_poll) 
380      e_object_del(E_OBJECT(cpufreq_config->menu_poll));
381    cpufreq_config->menu_poll = NULL;
382    if (cpufreq_config->menu_governor) 
383      e_object_del(E_OBJECT(cpufreq_config->menu_governor));
384    cpufreq_config->menu_governor = NULL;
385    if (cpufreq_config->menu_frequency) 
386      e_object_del(E_OBJECT(cpufreq_config->menu_frequency));
387    cpufreq_config->menu_frequency = NULL;
388    if (cpufreq_config->menu_powersave) 
389      e_object_del(E_OBJECT(cpufreq_config->menu_powersave));
390    cpufreq_config->menu_powersave = NULL;
391 }
392
393 static void
394 _cpufreq_set_governor(const char *governor)
395 {
396    char buf[PATH_MAX];
397    int ret;
398
399    snprintf(buf, sizeof(buf),
400             "%s %s %s", cpufreq_config->set_exe_path, "governor", governor);
401    ret = system(buf);
402    if (ret != 0)
403      {
404         E_Dialog *dia;
405         E_Container *con;
406
407         con = e_container_current_get(e_manager_current_get());
408         if (!(dia = e_dialog_new(con, "E", "_e_mod_cpufreq_error_setfreq")))
409           return;
410         e_dialog_title_set(dia, "Enlightenment Cpufreq Module");
411         e_dialog_icon_set(dia, "enlightenment", 64);
412         e_dialog_text_set(dia, _("There was an error trying to set the<br>"
413                                  "cpu frequency governor via the module's<br>"
414                                  "setfreq utility."));
415         e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
416         e_win_centered_set(dia->win, 1);
417         e_dialog_show(dia);
418      }
419 }
420
421 static void
422 _cpufreq_set_frequency(int frequency)
423 {
424    char buf[PATH_MAX];
425    int ret;
426
427 #ifdef __FreeBSD__
428    frequency /= 1000;
429 #endif
430    if (!cpufreq_config->status->can_set_frequency)
431      {
432         E_Dialog *dia;
433         E_Container *con;
434
435         con = e_container_current_get(e_manager_current_get());
436         if (!(dia = e_dialog_new(con, "E", "_e_mod_cpufreq_error_setfreq")))
437           return;
438         e_dialog_title_set(dia, "Enlightenment Cpufreq Module");
439         e_dialog_icon_set(dia, "enlightenment", 64);
440         e_dialog_text_set(dia, _("Your kernel does not support setting the<br>"
441                                  "CPU frequency at all. You may be missing<br>"
442                                  "Kernel modules or features, or your CPU<br>"
443                                  "simply does not support this feature."));
444         e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
445         e_win_centered_set(dia->win, 1);
446         e_dialog_show(dia);
447         return;
448      }
449
450    // change it to "userspace"
451    _cpufreq_set_governor("userspace");
452
453    snprintf(buf, sizeof(buf),
454             "%s %s %i", cpufreq_config->set_exe_path, "frequency", frequency);
455    ret = system(buf);
456    if (ret != 0)
457      {
458         E_Dialog *dia;
459         E_Container *con;
460
461         con = e_container_current_get(e_manager_current_get());
462         if (!(dia = e_dialog_new(con, "E", "_e_mod_cpufreq_error_setfreq")))
463           return;
464         e_dialog_title_set(dia, "Enlightenment Cpufreq Module");
465         e_dialog_icon_set(dia, "enlightenment", 64);
466         e_dialog_text_set(dia, _("There was an error trying to set the<br>"
467                                  "cpu frequency setting via the module's<br>"
468                                  "setfreq utility."));
469         e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
470         e_win_centered_set(dia->win, 1);
471         e_dialog_show(dia);
472      }
473 }
474
475 static Eina_Bool
476 _cpufreq_cb_check(void *data __UNUSED__)
477 {
478    Instance *inst;
479    Eina_List *l;
480    int active;
481
482    if (cpufreq_config->menu_poll) return ECORE_CALLBACK_RENEW;
483    active = cpufreq_config->status->active;
484    if (_cpufreq_status_check_current(cpufreq_config->status))
485      {
486         for (l = cpufreq_config->instances; l; l = l->next)
487           {
488              inst = l->data;
489              _cpufreq_face_update_current(inst);
490           }
491      }
492    if (active != cpufreq_config->status->active)
493      {
494         for (l = cpufreq_config->instances; l; l = l->next)
495           {
496              inst = l->data;
497              if (cpufreq_config->status->active == 0)
498                edje_object_signal_emit(inst->o_cpu, "e,state,disabled", "e");
499              else if (cpufreq_config->status->active == 1)
500                edje_object_signal_emit(inst->o_cpu, "e,state,enabled", "e");
501           }
502      }
503
504    return ECORE_CALLBACK_RENEW;
505 }
506
507 static Status *
508 _cpufreq_status_new()
509 {
510    Status *s;
511
512    s = E_NEW(Status, 1);
513    if (!s) return NULL;
514    s->active = -1;
515    return s;
516 }
517
518 static void
519 _cpufreq_status_free(Status *s)
520 {
521    Eina_List *l;
522
523    if (s->frequencies) eina_list_free(s->frequencies);
524    if (s->governors)
525      {
526         for (l = s->governors; l; l = l->next) free(l->data);
527         eina_list_free(s->governors);
528      }
529    if (s->cur_governor) free(s->cur_governor);
530    if (s->orig_governor) eina_stringshare_del(s->orig_governor);
531    free(s);
532 }
533
534 static int
535 _cpufreq_cb_sort(const void *item1, const void *item2)
536 {
537    int a, b;
538
539    a = (long)item1;
540    b = (long)item2;
541    if (a < b) return -1;
542    else if (a > b) return 1;
543    return 0;
544 }
545
546 static int
547 _cpufreq_status_check_available(Status *s)
548 {
549    char buf[PATH_MAX];
550    Eina_List *l;
551   // FIXME: this sssumes all cores accept the same freqs/ might be wrong
552 #ifdef __FreeBSD__
553    int freq, i;
554    size_t len = 0;
555    char *freqs, *pos, *q;
556
557    /* read freq_levels sysctl and store it in freq */
558    len = sizeof(buf);
559    if (sysctlbyname("dev.cpu.0.freq_levels", buf, &len, NULL, 0) == 0)
560      {
561         /* sysctl returns 0 on success */
562         if (s->frequencies)
563           {
564              eina_list_free(s->frequencies);
565              s->frequencies = NULL;
566           }
567
568         /* parse freqs and store the frequencies in s->frequencies */
569         pos = buf;
570         while (pos)
571           {
572              q = strchr(pos, '/');
573              if (!q) break;
574
575              *q = '\0';
576              freq = atoi(pos);
577              freq *= 1000;
578              s->frequencies = eina_list_append(s->frequencies, (void *)freq);
579
580              pos = q + 1;
581              pos = strchr(pos, ' ');
582           }
583      }
584
585    /* sort is not necessary because freq_levels is already sorted */
586    /* freebsd doesn't have governors */
587    if (s->governors)
588      {
589         for (l = s->governors; l; l = l->next) free(l->data);
590         eina_list_free(s->governors);
591         s->governors = NULL;
592      }
593 #else
594    FILE *f;
595
596    f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r");
597    if (f)
598      {
599         char *freq;
600
601         if (s->frequencies)
602           {
603              eina_list_free(s->frequencies);
604              s->frequencies = NULL;
605           }
606
607         fgets(buf, sizeof(buf), f);
608         buf[sizeof(buf) - 1] = 0;
609         fclose(f);
610
611         freq = strtok(buf, " ");
612         do
613           {
614              if (atoi(freq) != 0)
615                {
616                   s->frequencies = eina_list_append(s->frequencies,
617                                                     (void *) (long)atoi(freq));
618                }
619              freq = strtok(NULL, " ");
620           }
621         while (freq);
622
623         s->frequencies = eina_list_sort(s->frequencies,
624                                         eina_list_count(s->frequencies),
625                                         _cpufreq_cb_sort);
626      }
627
628    f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", "r");
629    if (f)
630      {
631         char *gov;
632
633         if (s->governors)
634           {
635              for (l = s->governors; l; l = l->next)
636                free(l->data);
637              eina_list_free(s->governors);
638              s->governors = NULL;
639           }
640
641         fgets(buf, sizeof(buf), f);
642         buf[sizeof(buf) - 1] = 0;
643         fclose(f);
644
645         gov = strtok(buf, " ");
646         do
647           {
648              while ((*gov) && (isspace(*gov))) gov++;
649              if (strlen(gov) != 0)
650                s->governors = eina_list_append(s->governors, strdup(gov));
651              gov = strtok(NULL, " ");
652           }
653         while (gov);
654
655         s->governors = 
656           eina_list_sort(s->governors, eina_list_count(s->governors),
657                          (int (*)(const void *, const void *))strcmp);
658      }
659 #endif
660    return 1;
661 }
662
663 static int
664 _cpufreq_status_check_current(Status *s)
665 {
666    char buf[PATH_MAX];
667    int i;
668    FILE *f;
669    int ret = 0;
670    int frequency = 0;
671    int frequency_min = 0x7fffffff;
672    int frequency_max = 0;
673    int freqtot = 0;
674 #ifdef __FreeBSD__
675    int len = 4;
676
677    s->active = 0;
678    /* frequency is stored in dev.cpu.0.freq */
679    if (sysctlbyname("dev.cpu.0.freq", &frequency, &len, NULL, 0) == 0)
680      {
681         frequency *= 1000;
682         if (frequency != s->cur_frequency) ret = 1;
683         s->cur_frequency = frequency;
684         s->active = 1;
685      }
686
687    /* hardcoded for testing */
688    s->can_set_frequency = 1;
689    s->cur_governor = NULL;
690 #else
691    s->active = 0;
692
693    _cpufreq_status_check_available(s);
694    // average out frequencies of all cores
695    for (i = 0; i < 64; i++)
696     {
697       snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_cur_freq", i);
698       f = fopen(buf, "r");
699       if (f)
700         {
701           fgets(buf, sizeof(buf), f);
702           buf[sizeof(buf) - 1] = 0;
703           fclose(f);
704           
705           frequency = atoi(buf);
706           if (frequency > frequency_max) frequency_max = frequency;
707           if (frequency < frequency_min) frequency_min = frequency;
708           freqtot += frequency;
709           s->active = 1;
710         }
711       else
712         break;
713     }
714   if (i < 1) i = 1;
715   frequency = freqtot / i;
716   if (frequency != s->cur_frequency) ret = 1;
717   if (frequency_min != s->cur_min_frequency) ret = 1;
718   if (frequency_max != s->cur_max_frequency) ret = 1;
719   s->cur_frequency = frequency;
720   s->cur_min_frequency = frequency_min;
721   s->cur_max_frequency = frequency_max;
722   
723 //  printf("%i | %i %i\n", frequency, frequency_min, frequency_max);
724   
725   // FIXME: this sssumes all cores are on the same governor
726    f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed", "r");
727    if (f)
728      {
729         s->can_set_frequency = 1;
730         fclose(f);
731      }
732    else
733      {
734         s->can_set_frequency = 0;
735      }
736
737    f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r");
738    if (f)
739      {
740         char *p;
741         
742         buf[0] = 0;
743         fgets(buf, sizeof(buf), f);
744         buf[sizeof(buf) - 1] = 0;
745         fclose(f);
746         for (p = buf; (*p != 0) && (isalnum(*p)); p++);
747         *p = 0;
748
749         if ((!s->cur_governor) || (strcmp(buf, s->cur_governor)))
750           {
751              ret = 1;
752
753              if (s->cur_governor) free(s->cur_governor);
754              s->cur_governor = strdup(buf);
755
756              for (i = strlen(s->cur_governor) - 1; i >= 0; i--)
757                {
758                   if (isspace(s->cur_governor[i]))
759                     s->cur_governor[i] = 0;
760                   else
761                     break;
762                }
763           }
764      }
765 #endif
766    return ret;
767 }
768
769 static void
770 _cpufreq_face_update_available(Instance *inst)
771 {
772    Edje_Message_Int_Set *frequency_msg;
773    Edje_Message_String_Set *governor_msg;
774    Eina_List *l;
775    int i;
776    int count;
777
778    count = eina_list_count(cpufreq_config->status->frequencies);
779    frequency_msg = malloc(sizeof(Edje_Message_Int_Set) + (count - 1) * sizeof(int));
780    EINA_SAFETY_ON_NULL_RETURN(frequency_msg);
781    frequency_msg->count = count;
782    for (l = cpufreq_config->status->frequencies, i = 0; l; l = l->next, i++)
783      frequency_msg->val[i] = (long)l->data;
784    edje_object_message_send(inst->o_cpu, EDJE_MESSAGE_INT_SET, 1, frequency_msg);
785    free(frequency_msg);
786
787    count = eina_list_count(cpufreq_config->status->governors);
788    governor_msg = malloc(sizeof(Edje_Message_String_Set) + (count - 1) * sizeof(char *));
789    governor_msg->count = count;
790    for (l = cpufreq_config->status->governors, i = 0; l; l = l->next, i++)
791      governor_msg->str[i] = (char *)l->data;
792    edje_object_message_send(inst->o_cpu, EDJE_MESSAGE_STRING_SET, 2, governor_msg);
793    free(governor_msg);
794 }
795
796 static void
797 _cpufreq_face_update_current(Instance *inst)
798 {
799    Edje_Message_Int_Set *frequency_msg;
800    Edje_Message_String governor_msg;
801
802    frequency_msg = malloc(sizeof(Edje_Message_Int_Set) + (sizeof(int) * 4));
803    EINA_SAFETY_ON_NULL_RETURN(frequency_msg);
804    frequency_msg->count = 5;
805    frequency_msg->val[0] = cpufreq_config->status->cur_frequency;
806    frequency_msg->val[1] = cpufreq_config->status->can_set_frequency;
807    frequency_msg->val[2] = cpufreq_config->status->cur_min_frequency;
808    frequency_msg->val[3] = cpufreq_config->status->cur_max_frequency;
809    frequency_msg->val[4] = 0; // pad
810    edje_object_message_send(inst->o_cpu, EDJE_MESSAGE_INT_SET, 3,
811                             frequency_msg);
812    free(frequency_msg);
813
814    /* BSD crashes here without the if-condition
815     * since it has no governors (yet) */
816    if (cpufreq_config->status->cur_governor)
817      {
818         governor_msg.str = cpufreq_config->status->cur_governor;
819         edje_object_message_send(inst->o_cpu, EDJE_MESSAGE_STRING, 4,
820                                  &governor_msg);
821      }
822 }
823
824 static void
825 _cpufreq_face_cb_set_frequency(void *data __UNUSED__, Evas_Object *obj __UNUSED__, const char *emission, const char *src __UNUSED__)
826 {
827    Eina_List *l;
828    int next_frequency = 0;
829
830    for (l = cpufreq_config->status->frequencies; l; l = l->next)
831      {
832         if (cpufreq_config->status->cur_frequency == (long)l->data)
833           {
834              if (!strcmp(emission, "e,action,frequency,increase"))
835                {
836                   if (l->next) next_frequency = (long)l->next->data;
837                   break;
838                }
839              else if (!strcmp(emission, "e,action,frequency,decrease"))
840                {
841                   if (l->prev) next_frequency = (long)l->prev->data;
842                   break;
843                }
844              else
845                break;
846           }
847      }
848    if (next_frequency != 0) _cpufreq_set_frequency(next_frequency);
849 }
850
851 static void
852 _cpufreq_face_cb_set_governor(void *data __UNUSED__, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *src __UNUSED__)
853 {
854    Eina_List *l;
855    char *next_governor = NULL;
856
857    for (l = cpufreq_config->status->governors; l; l = l->next)
858      {
859         if (!strcmp(l->data, cpufreq_config->status->cur_governor))
860           {
861              if (l->next)
862                next_governor = l->next->data;
863              else
864                next_governor = cpufreq_config->status->governors->data;
865              break;
866           }
867      }
868    if (next_governor) _cpufreq_set_governor(next_governor);
869 }
870
871 static Eina_Bool
872 _cpufreq_event_cb_powersave(void *data __UNUSED__, int type, void *event)
873 {
874    E_Event_Powersave_Update *ev;
875    Eina_List *l;
876    Eina_Bool has_powersave = EINA_FALSE;
877    Eina_Bool has_conservative = EINA_FALSE;
878
879    if (type != E_EVENT_POWERSAVE_UPDATE) return ECORE_CALLBACK_PASS_ON;
880    if (!cpufreq_config->auto_powersave) return ECORE_CALLBACK_PASS_ON;
881
882    ev = event;
883    if (!cpufreq_config->status->orig_governor)
884      cpufreq_config->status->orig_governor = eina_stringshare_add(cpufreq_config->status->cur_governor);
885
886    for (l = cpufreq_config->status->governors; l; l = l->next)
887      {
888         if (!strcmp(l->data, "conservative"))
889           has_conservative = EINA_TRUE;
890         else if (!strcmp(l->data, "powersave"))
891           has_powersave = EINA_TRUE;
892      }
893
894    switch(ev->mode)
895      {
896       case E_POWERSAVE_MODE_NONE:
897       case E_POWERSAVE_MODE_LOW:
898          _cpufreq_set_governor(cpufreq_config->status->orig_governor);
899          eina_stringshare_del(cpufreq_config->status->orig_governor);
900          cpufreq_config->status->orig_governor = NULL;
901          break;
902       case E_POWERSAVE_MODE_MEDIUM:
903       case E_POWERSAVE_MODE_HIGH:
904          if ((cpufreq_config->powersave_governor) || (has_conservative))
905            {
906               if (cpufreq_config->powersave_governor)
907                 _cpufreq_set_governor(cpufreq_config->powersave_governor);
908               else
909                 _cpufreq_set_governor("conservative");
910               break;
911            }
912       case E_POWERSAVE_MODE_EXTREME:
913          if (has_powersave)
914            _cpufreq_set_governor("powersave");
915          break;
916      }
917
918    return ECORE_CALLBACK_PASS_ON;
919 }
920
921 static void
922 _cpufreq_menu_fast(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
923 {
924    cpufreq_config->poll_interval = 4;
925    _cpufreq_poll_interval_update();
926 }
927
928 static void
929 _cpufreq_menu_medium(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
930 {
931    cpufreq_config->poll_interval = 8;
932    _cpufreq_poll_interval_update();
933 }
934
935 static void
936 _cpufreq_menu_normal(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
937 {
938    cpufreq_config->poll_interval = 32;
939    _cpufreq_poll_interval_update();
940 }
941
942 static void
943 _cpufreq_menu_slow(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
944 {
945    cpufreq_config->poll_interval = 64;
946    _cpufreq_poll_interval_update();
947 }
948
949 static void
950 _cpufreq_menu_very_slow(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
951 {
952    cpufreq_config->poll_interval = 256;
953    _cpufreq_poll_interval_update();
954 }
955
956 static void
957 _cpufreq_menu_restore_governor(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi)
958 {
959    cpufreq_config->restore_governor = e_menu_item_toggle_get(mi);
960    if ((!cpufreq_config->governor) ||
961        (strcmp(cpufreq_config->status->cur_governor, cpufreq_config->governor)))
962      {
963         eina_stringshare_replace(&cpufreq_config->governor, 
964                                  cpufreq_config->status->cur_governor);
965      }
966    e_config_save_queue();
967 }
968
969 static void
970 _cpufreq_menu_auto_powersave(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi)
971 {
972    cpufreq_config->auto_powersave = e_menu_item_toggle_get(mi);
973    e_config_save_queue();
974 }
975
976 static void
977 _cpufreq_menu_governor(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
978 {
979    const char *governor;
980
981    governor = data;
982    if (governor)
983      {
984         _cpufreq_set_governor(governor);
985         eina_stringshare_replace(&cpufreq_config->governor, governor);
986      }
987    e_config_save_queue();
988 }
989
990 static void
991 _cpufreq_menu_powersave_governor(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
992 {
993    const char *governor;
994
995    governor = data;
996    if (governor)
997      eina_stringshare_replace(&cpufreq_config->powersave_governor, governor);
998    e_config_save_queue();
999 }
1000
1001 static void
1002 _cpufreq_menu_frequency(void * data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
1003 {
1004    int frequency;
1005
1006    frequency = (long)data;
1007    if (frequency > 0) _cpufreq_set_frequency(frequency);
1008 }
1009
1010 static void 
1011 _cpufreq_poll_interval_update(void) 
1012 {
1013    if (cpufreq_config->frequency_check_poller)
1014      ecore_poller_del(cpufreq_config->frequency_check_poller);
1015    cpufreq_config->frequency_check_poller =
1016      ecore_poller_add(ECORE_POLLER_CORE, cpufreq_config->poll_interval,
1017                       _cpufreq_cb_check, NULL);
1018    e_config_save_queue();
1019 }
1020
1021 /* module setup */
1022 EAPI E_Module_Api e_modapi =
1023 {
1024    E_MODULE_API_VERSION, "Cpufreq"
1025 };
1026
1027 EAPI void *
1028 e_modapi_init(E_Module *m)
1029 {
1030    char buf[PATH_MAX];
1031    Eina_List *l;
1032
1033    conf_edd = E_CONFIG_DD_NEW("Cpufreq_Config", Config);
1034 #undef T
1035 #undef D
1036 #define T Config
1037 #define D conf_edd
1038    E_CONFIG_VAL(D, T, config_version, INT);
1039    E_CONFIG_VAL(D, T, poll_interval, INT);
1040    E_CONFIG_VAL(D, T, restore_governor, INT);
1041    E_CONFIG_VAL(D, T, auto_powersave, INT);
1042    E_CONFIG_VAL(D, T, powersave_governor, STR);
1043    E_CONFIG_VAL(D, T, governor, STR);
1044
1045    cpufreq_config = e_config_domain_load("module.cpufreq", conf_edd);
1046    if ((cpufreq_config) && 
1047        (cpufreq_config->config_version != CPUFREQ_CONFIG_VERSION))
1048      E_FREE(cpufreq_config);
1049
1050    if (!cpufreq_config)
1051      {
1052         cpufreq_config = E_NEW(Config, 1);
1053         cpufreq_config->config_version = CPUFREQ_CONFIG_VERSION;
1054         cpufreq_config->poll_interval = 32;
1055         cpufreq_config->restore_governor = 0;
1056         cpufreq_config->auto_powersave = 1;
1057         cpufreq_config->powersave_governor = NULL;
1058         cpufreq_config->governor = NULL;
1059      }
1060    E_CONFIG_LIMIT(cpufreq_config->poll_interval, 1, 1024);
1061
1062    snprintf(buf, sizeof(buf), "%s/%s/freqset", 
1063             e_module_dir_get(m), MODULE_ARCH);
1064    cpufreq_config->set_exe_path = strdup(buf);
1065    cpufreq_config->frequency_check_poller =
1066      ecore_poller_add(ECORE_POLLER_CORE, cpufreq_config->poll_interval,
1067                       _cpufreq_cb_check, NULL);
1068    cpufreq_config->status = _cpufreq_status_new();
1069
1070    _cpufreq_status_check_available(cpufreq_config->status);
1071    if ((cpufreq_config->restore_governor) && (cpufreq_config->governor))
1072      {
1073         /* If the governor is available, restore it */
1074         for (l = cpufreq_config->status->governors; l; l = l->next)
1075           {
1076              if (!strcmp(l->data, cpufreq_config->governor))
1077                {
1078                   _cpufreq_set_governor(cpufreq_config->governor);
1079                   break;
1080                }
1081           }
1082      }
1083
1084    cpufreq_config->module = m;
1085
1086    e_gadcon_provider_register(&_gadcon_class);
1087    return m;
1088 }
1089
1090 EAPI int
1091 e_modapi_shutdown(E_Module *m __UNUSED__)
1092 {
1093    e_gadcon_provider_unregister(&_gadcon_class);
1094
1095    if (cpufreq_config->frequency_check_poller)
1096      ecore_poller_del(cpufreq_config->frequency_check_poller);
1097    if (cpufreq_config->menu)
1098      {
1099         e_menu_post_deactivate_callback_set(cpufreq_config->menu, NULL, NULL);
1100         e_object_del(E_OBJECT(cpufreq_config->menu));
1101         cpufreq_config->menu = NULL;
1102      }
1103    if (cpufreq_config->menu_poll)
1104      {
1105         e_menu_post_deactivate_callback_set(cpufreq_config->menu_poll, NULL, NULL);
1106         e_object_del(E_OBJECT(cpufreq_config->menu_poll));
1107         cpufreq_config->menu_poll = NULL;
1108      }
1109    if (cpufreq_config->menu_governor)
1110      {
1111         e_menu_post_deactivate_callback_set(cpufreq_config->menu_governor, NULL, NULL);
1112         e_object_del(E_OBJECT(cpufreq_config->menu_governor));
1113         cpufreq_config->menu_governor = NULL;
1114      }
1115    if (cpufreq_config->menu_frequency)
1116      {
1117         e_menu_post_deactivate_callback_set(cpufreq_config->menu_frequency, NULL, NULL);
1118         e_object_del(E_OBJECT(cpufreq_config->menu_frequency));
1119         cpufreq_config->menu_frequency = NULL;
1120      }
1121    if (cpufreq_config->menu_powersave)
1122      {
1123         e_menu_post_deactivate_callback_set(cpufreq_config->menu_powersave, NULL, NULL);
1124         e_object_del(E_OBJECT(cpufreq_config->menu_powersave));
1125         cpufreq_config->menu_powersave = NULL;
1126      }
1127    if (cpufreq_config->governor)
1128      eina_stringshare_del(cpufreq_config->governor);
1129    if (cpufreq_config->status) _cpufreq_status_free(cpufreq_config->status);
1130    E_FREE(cpufreq_config->set_exe_path);
1131    free(cpufreq_config);
1132    cpufreq_config = NULL;
1133    E_CONFIG_DD_FREE(conf_edd);
1134    return 1;
1135 }
1136
1137 EAPI int
1138 e_modapi_save(E_Module *m __UNUSED__)
1139 {
1140    e_config_domain_save("module.cpufreq", conf_edd, cpufreq_config);
1141    return 1;
1142 }