tizen 2.3 release
[framework/system/deviced.git] / src / pmqos / pmqos.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <limits.h>
23 #include <Ecore.h>
24 #include <device-node.h>
25
26 #include "core/log.h"
27 #include "core/edbus-handler.h"
28 #include "core/devices.h"
29 #include "core/common.h"
30 #include "core/list.h"
31 #include "core/device-notifier.h"
32 #include "powersaver/powersaver.h"
33 #include "pmqos.h"
34
35 #define DEFAULT_PMQOS_TIMER             3000
36
37 #define PMQOS_CONF_PATH         "/etc/deviced/pmqos.conf"
38
39 struct pmqos_cpu {
40         char name[NAME_MAX];
41         Ecore_Timer *timer;
42 };
43
44 static dd_list *pmqos_head;
45
46 int set_cpu_pmqos(const char *name, int val)
47 {
48         char scenario[100];
49
50         snprintf(scenario, sizeof(scenario), "%s%s", name, (val ? "Lock" : "Unlock"));
51         _D("Set pm scenario : %s", scenario);
52         device_notify(DEVICE_NOTIFIER_PMQOS, (void *)scenario);
53         return device_set_property(DEVICE_TYPE_CPU, PROP_CPU_PM_SCENARIO, (int)scenario);
54 }
55
56 static int pmqos_cpu_cancel(const char *name)
57 {
58         dd_list *elem;
59         struct pmqos_cpu *cpu;
60
61         /* Find previous request */
62         DD_LIST_FOREACH(pmqos_head, elem, cpu) {
63                 if (!strcmp(cpu->name, name))
64                         break;
65         }
66
67         /* In case of already end up request */
68         if(!cpu) {
69                 _I("%s request is already canceled", name);
70                 return 0;
71         }
72
73         /* Set cpu unlock */
74         set_cpu_pmqos(cpu->name, false);
75
76         /* Delete previous request */
77         DD_LIST_REMOVE(pmqos_head, cpu);
78         ecore_timer_del(cpu->timer);
79         free(cpu);
80
81         return 0;
82 }
83
84 static Eina_Bool pmqos_cpu_timer(void *data)
85 {
86         char *name = (char*)data;
87         int ret;
88
89         _I("%s request will be unlocked", name);
90         ret = pmqos_cpu_cancel(name);
91         if (ret < 0)
92                 _E("Can not find %s request", name);
93
94         free(name);
95         return ECORE_CALLBACK_CANCEL;
96 }
97
98 static int pmqos_cpu_request(const char *name, int val)
99 {
100         dd_list *elem;
101         struct pmqos_cpu *cpu;
102         Ecore_Timer *timer;
103         bool locked = false;
104
105         /* Check valid parameter */
106         if (val > DEFAULT_PMQOS_TIMER) {
107                 _I("The timer value cannot be higher than default time value(%dms)", DEFAULT_PMQOS_TIMER);
108                 val = DEFAULT_PMQOS_TIMER;
109         }
110
111         /* Find previous request */
112         DD_LIST_FOREACH(pmqos_head, elem, cpu) {
113                 if (!strcmp(cpu->name, name)) {
114                         ecore_timer_reset(cpu->timer);
115                         locked = true;
116                         break;
117                 }
118         }
119
120         /* In case of first request */
121         if (!cpu) {
122                 /* Add new timer */
123                 timer = ecore_timer_add(val/1000.f, pmqos_cpu_timer, (void*)strdup(name));
124                 if (!timer)
125                         return -EPERM;
126
127                 cpu = malloc(sizeof(struct pmqos_cpu));
128                 if (!cpu) {
129                         ecore_timer_del(timer);
130                         return -ENOMEM;
131                 }
132                 snprintf(cpu->name, sizeof(cpu->name), "%s", name);
133                 cpu->timer = timer;
134                 DD_LIST_APPEND(pmqos_head, cpu);
135         }
136
137         /* Set cpu lock */
138         if(!locked) {
139                 set_cpu_pmqos(cpu->name, true);
140         }
141
142         return 0;
143 }
144
145 static int pmqos_powersaving(void *data)
146 {
147         return set_cpu_pmqos("PowerSaving", (int)data);
148 }
149
150 static int pmqos_lowbat(void *data)
151 {
152         return set_cpu_pmqos("LowBattery", (int)data);
153 }
154
155 static int pmqos_emergency(void *data)
156 {
157         return set_cpu_pmqos("Emergency", (int)data);
158 }
159
160 static int pmqos_poweroff(void *data)
161 {
162         return set_cpu_pmqos("PowerOff", (int)data);
163 }
164
165 static int pmqos_ultrapowersaving(void *data)
166 {
167         int mode = (int)data;
168         bool on;
169
170         switch (mode) {
171         case POWERSAVER_OFF:
172         case POWERSAVER_BASIC:
173                 on = false;
174                 break;
175         case POWERSAVER_ENHANCED:
176                 on = true;
177                 break;
178         default:
179                 return -EINVAL;
180         }
181         return set_cpu_pmqos("UltraPowerSaving", (int)on);
182 }
183
184 static int pmqos_hall(void *data)
185 {
186         return pmqos_cpu_request("LockScreen", (int)data);
187 }
188
189 static DBusMessage *dbus_pmqos_handler(E_DBus_Object *obj, DBusMessage *msg)
190 {
191         DBusMessageIter iter;
192         DBusMessage *reply;
193         const char *member;
194         int val, ret;
195
196         if (!dbus_message_get_args(msg, NULL,
197                                 DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID)) {
198                 _E("there is no message");
199                 ret = -EINVAL;
200                 goto error;
201         }
202
203         if (val < 0) {
204                 ret = -EINVAL;
205                 goto error;
206         }
207
208         member = dbus_message_get_member(msg);
209
210         if (val)
211                 ret = pmqos_cpu_request(member, val);
212         else
213                 ret = pmqos_cpu_cancel(member);
214
215 error:
216         reply = dbus_message_new_method_return(msg);
217         dbus_message_iter_init_append(reply, &iter);
218         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
219         return reply;
220 }
221
222 static DBusMessage *dbus_wifi_pmqos_handler(E_DBus_Object *obj, DBusMessage *msg)
223 {
224         DBusMessageIter iter;
225         DBusMessage *reply;
226         const char *member;
227         char name[NAME_MAX];
228         int bps, val, ret;
229
230         if (!dbus_message_get_args(msg, NULL,
231                                 DBUS_TYPE_INT32, &bps,
232                                 DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID)) {
233                 _E("there is no message");
234                 ret = -EINVAL;
235                 goto error;
236         }
237
238         if (bps < 0 || val < 0) {
239                 ret = -EINVAL;
240                 goto error;
241         }
242
243         member = dbus_message_get_member(msg);
244
245         /* combine bps and member */
246         snprintf(name, sizeof(name), "%s%d", member, bps);
247
248         if (val)
249                 ret = pmqos_cpu_request(name, val);
250         else
251                 ret = pmqos_cpu_cancel(name);
252
253 error:
254         reply = dbus_message_new_method_return(msg);
255         dbus_message_iter_init_append(reply, &iter);
256         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
257         return reply;
258 }
259
260 static DBusMessage *dbus_getdefaultlocktime(E_DBus_Object *obj, DBusMessage *msg)
261 {
262         DBusMessageIter iter;
263         DBusMessage *reply;
264         int ret;
265
266         ret = DEFAULT_PMQOS_TIMER;
267
268         reply = dbus_message_new_method_return(msg);
269         dbus_message_iter_init_append(reply, &iter);
270         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
271         return reply;
272 }
273
274 static int get_methods_from_conf(const char *path, struct edbus_method **edbus_methods)
275 {
276         struct edbus_method *methods;
277         struct pmqos_scenario scenarios = {0,};
278         int i, ret;
279
280         /* get pmqos table from conf */
281         ret = get_pmqos_table(path, &scenarios);
282         if (ret < 0) {
283                 /* release scenarios memory */
284                 release_pmqos_table(&scenarios);
285                 return ret;
286         }
287
288         /* if do not support scenario */
289         if (!scenarios.support)
290                 return 0;
291
292         /* if do not have scenarios */
293         if (scenarios.num <= 0)
294                 return 0;
295
296         /* allocate edbus methods structure */
297         methods = malloc(sizeof(struct edbus_method)*scenarios.num);
298         if (!methods) {
299                 _E("failed to allocate methods memory : %s", strerror(errno));
300                 /* release scenarios memory */
301                 release_pmqos_table(&scenarios);
302                 return -errno;
303         }
304
305         /* set edbus_methods structure */
306         for (i = 0; i < scenarios.num; ++i) {
307
308                 /* if this scenario does not support */
309                 if (!scenarios.list[i].support) {
310                         _I("do not support [%s] scenario", scenarios.list[i].name);
311                         continue;
312                 }
313
314                 methods[i].member = scenarios.list[i].name;
315                 methods[i].signature = "i";
316                 methods[i].reply_signature = "i";
317                 methods[i].func = dbus_pmqos_handler;
318                 _D("support [%s] scenario", scenarios.list[i].name);
319         }
320
321         *edbus_methods = methods;
322         return scenarios.num;
323 }
324
325 /* Add pmqos name as alphabetically */
326 static const struct edbus_method edbus_methods[] = {
327         { "AppLaunch",            "i",    "i", dbus_pmqos_handler },
328         { "AppLaunchHome",        "i",    "i", dbus_pmqos_handler },
329         { "BeautyShot",           "i",    "i", dbus_pmqos_handler },
330         { "Browser",              "i",    "i", dbus_pmqos_handler },
331         { "BrowserDash",          "i",    "i", dbus_pmqos_handler },
332         { "BrowserJavaScript",    "i",    "i", dbus_pmqos_handler },
333         { "BrowserLoading",       "i",    "i", dbus_pmqos_handler },
334         { "BrowserScroll",        "i",    "i", dbus_pmqos_handler },
335         { "CallSound",            "i",    "i", dbus_pmqos_handler },
336         { "CameraBurstShot",      "i",    "i", dbus_pmqos_handler },
337         { "CameraCaptureAtRec",   "i",    "i", dbus_pmqos_handler },
338         { "CameraPreview",        "i",    "i", dbus_pmqos_handler },
339         { "CameraSoundAndShot",   "i",    "i", dbus_pmqos_handler },
340         { "ContactSearch",        "i",    "i", dbus_pmqos_handler },
341         { "Emergency",            "i",    "i", dbus_pmqos_handler },
342         { "GalleryScroll",        "i",    "i", dbus_pmqos_handler },
343         { "GalleryRotation",      "i",    "i", dbus_pmqos_handler },
344         { "GetDefaultLockTime",  NULL,    "i", dbus_getdefaultlocktime },
345         { "GpsSerialCno",         "i",    "i", dbus_pmqos_handler },
346         { "GpuBoost",             "i",    "i", dbus_pmqos_handler },
347         { "GpuWakeup",            "i",    "i", dbus_pmqos_handler },
348         { "HomeScreen",           "i",    "i", dbus_pmqos_handler },
349         { "ImageViewer",          "i",    "i", dbus_pmqos_handler },
350         { "IMEInput",             "i",    "i", dbus_pmqos_handler },
351         { "LockScreen",           "i",    "i", dbus_pmqos_handler },
352         { "LowBattery",           "i",    "i", dbus_pmqos_handler },
353         { "MtpSendFile",          "i",    "i", dbus_pmqos_handler },
354         { "MusicPlayLcdOn",       "i",    "i", dbus_pmqos_handler },
355         { "PowerSaving",          "i",    "i", dbus_pmqos_handler },
356         { "ProcessCrashed",       "i",    "i", dbus_pmqos_handler },
357         { "ReservedMode",         "i",    "i", dbus_pmqos_handler },
358         { "ScreenMirroring",      "i",    "i", dbus_pmqos_handler },
359         { "SmemoZoom",            "i",    "i", dbus_pmqos_handler },
360         { "SVoice",               "i",    "i", dbus_pmqos_handler },
361         { "WebappLaunch",         "i",    "i", dbus_pmqos_handler },
362         { "WifiThroughput",      "ii",    "i", dbus_wifi_pmqos_handler },
363         { "PowerOff",             "i",    "i", dbus_pmqos_handler },
364         { "WebAppDrag",           "i",    "i", dbus_pmqos_handler },
365         { "WebAppFlick",          "i",    "i", dbus_pmqos_handler },
366         { "SensorWakeup",          "i",    "i", dbus_pmqos_handler },
367 };
368
369 static int booting_done(void *data)
370 {
371         static int done = 0;
372         struct edbus_method *methods = NULL;
373         int ret, size;
374
375         if (data == NULL)
376                 goto out;
377         done = (int)data;
378         if (!done)
379                 goto out;
380         _I("booting done");
381         /* register edbus methods */
382         ret = register_edbus_method(DEVICED_PATH_PMQOS, edbus_methods, ARRAY_SIZE(edbus_methods));
383         if (ret < 0)
384                 _E("fail to init edbus method(%d)", ret);
385
386         /* get methods from config file */
387         size = get_methods_from_conf(PMQOS_CONF_PATH, &methods);
388         if (size < 0)
389                 _E("failed to load configuration file(%s)", PMQOS_CONF_PATH);
390
391         /* register edbus methods for pmqos */
392         if (methods) {
393                 ret = register_edbus_method(DEVICED_PATH_PMQOS, methods, size);
394                 if (ret < 0)
395                         _E("fail to init edbus method from conf(%d)", ret);
396                 free(methods);
397         }
398
399         /* register notifier for each event */
400         register_notifier(DEVICE_NOTIFIER_PMQOS_POWERSAVING, pmqos_powersaving);
401         register_notifier(DEVICE_NOTIFIER_PMQOS_LOWBAT, pmqos_lowbat);
402         register_notifier(DEVICE_NOTIFIER_PMQOS_EMERGENCY, pmqos_emergency);
403         register_notifier(DEVICE_NOTIFIER_PMQOS_POWEROFF, pmqos_poweroff);
404         register_notifier(DEVICE_NOTIFIER_PMQOS_ULTRAPOWERSAVING,
405             pmqos_ultrapowersaving);
406         register_notifier(DEVICE_NOTIFIER_PMQOS_HALL, pmqos_hall);
407
408 out:
409         return done;
410 }
411
412 static void pmqos_init(void *data)
413 {
414         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
415 }
416
417 static void pmqos_exit(void *data)
418 {
419         /* unregister notifier for each event */
420         unregister_notifier(DEVICE_NOTIFIER_PMQOS_POWERSAVING, pmqos_powersaving);
421         unregister_notifier(DEVICE_NOTIFIER_PMQOS_LOWBAT, pmqos_lowbat);
422         unregister_notifier(DEVICE_NOTIFIER_PMQOS_EMERGENCY, pmqos_emergency);
423         unregister_notifier(DEVICE_NOTIFIER_PMQOS_POWEROFF, pmqos_poweroff);
424         unregister_notifier(DEVICE_NOTIFIER_PMQOS_ULTRAPOWERSAVING,
425             pmqos_ultrapowersaving);
426         unregister_notifier(DEVICE_NOTIFIER_PMQOS_HALL, pmqos_hall);
427 }
428
429 static const struct device_ops pmqos_device_ops = {
430         .priority = DEVICE_PRIORITY_NORMAL,
431         .name     = "pmqos",
432         .init     = pmqos_init,
433         .exit     = pmqos_exit,
434 };
435
436 DEVICE_OPS_REGISTER(&pmqos_device_ops)