Initialize Tizen 2.3
[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 "pmqos.h"
33
34 #define DEFAULT_PMQOS_TIMER             3000
35
36 #define PMQOS_CONF_PATH         "/etc/deviced/pmqos.conf"
37
38 struct pmqos_cpu {
39         char name[NAME_MAX];
40         Ecore_Timer *timer;
41 };
42
43 static dd_list *pmqos_head;
44
45 int set_cpu_pmqos(const char *name, int val)
46 {
47         char scenario[100];
48
49         snprintf(scenario, sizeof(scenario), "%s%s", name, (val ? "Lock" : "Unlock"));
50         _D("Set pm scenario : %s", scenario);
51         device_notify(DEVICE_NOTIFIER_PMQOS, (void *)scenario);
52         return device_set_property(DEVICE_TYPE_CPU, PROP_CPU_PM_SCENARIO, (int)scenario);
53 }
54
55 static int pmqos_cpu_cancel(const char *name)
56 {
57         dd_list *elem;
58         struct pmqos_cpu *cpu;
59
60         /* Find previous request */
61         DD_LIST_FOREACH(pmqos_head, elem, cpu) {
62                 if (!strcmp(cpu->name, name))
63                         break;
64         }
65
66         /* In case of already end up request */
67         if(!cpu) {
68                 _I("%s request is already canceled", name);
69                 return 0;
70         }
71
72         /* Set cpu unlock */
73         set_cpu_pmqos(cpu->name, false);
74
75         /* Delete previous request */
76         DD_LIST_REMOVE(pmqos_head, cpu);
77         ecore_timer_del(cpu->timer);
78         free(cpu);
79
80         return 0;
81 }
82
83 static Eina_Bool pmqos_cpu_timer(void *data)
84 {
85         char *name = (char*)data;
86         int ret;
87
88         _I("%s request will be unlocked", name);
89         ret = pmqos_cpu_cancel(name);
90         if (ret < 0)
91                 _E("Can not find %s request", name);
92
93         free(name);
94         return ECORE_CALLBACK_CANCEL;
95 }
96
97 static int pmqos_cpu_request(const char *name, int val)
98 {
99         dd_list *elem;
100         struct pmqos_cpu *cpu;
101         Ecore_Timer *timer;
102         bool locked = false;
103
104         /* Check valid parameter */
105         if (val > DEFAULT_PMQOS_TIMER) {
106                 _I("The timer value cannot be higher than default time value(%dms)", DEFAULT_PMQOS_TIMER);
107                 val = DEFAULT_PMQOS_TIMER;
108         }
109
110         /* Find previous request */
111         DD_LIST_FOREACH(pmqos_head, elem, cpu) {
112                 if (!strcmp(cpu->name, name)) {
113                         ecore_timer_reset(cpu->timer);
114                         locked = true;
115                         break;
116                 }
117         }
118
119         /* In case of first request */
120         if (!cpu) {
121                 /* Add new timer */
122                 timer = ecore_timer_add(val/1000.f, pmqos_cpu_timer, (void*)strdup(name));
123                 if (!timer)
124                         return -EPERM;
125
126                 cpu = malloc(sizeof(struct pmqos_cpu));
127                 if (!cpu) {
128                         ecore_timer_del(timer);
129                         return -ENOMEM;
130                 }
131                 snprintf(cpu->name, sizeof(cpu->name), "%s", name);
132                 cpu->timer = timer;
133                 DD_LIST_APPEND(pmqos_head, cpu);
134         }
135
136         /* Set cpu lock */
137         if(!locked) {
138                 set_cpu_pmqos(cpu->name, true);
139         }
140
141         return 0;
142 }
143
144 static int pmqos_powersaving(void *data)
145 {
146         return set_cpu_pmqos("PowerSaving", (int)data);
147 }
148
149 static int pmqos_lowbat(void *data)
150 {
151         return set_cpu_pmqos("LowBattery", (int)data);
152 }
153
154 static int pmqos_emergency(void *data)
155 {
156         return set_cpu_pmqos("Emergency", (int)data);
157 }
158
159 static int pmqos_poweroff(void *data)
160 {
161         return set_cpu_pmqos("PowerOff", (int)data);
162 }
163
164 static DBusMessage *dbus_pmqos_handler(E_DBus_Object *obj, DBusMessage *msg)
165 {
166         DBusMessageIter iter;
167         DBusMessage *reply;
168         const char *member;
169         int val, ret;
170
171         if (!dbus_message_get_args(msg, NULL,
172                                 DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID)) {
173                 _E("there is no message");
174                 ret = -EINVAL;
175                 goto error;
176         }
177
178         if (val < 0) {
179                 ret = -EINVAL;
180                 goto error;
181         }
182
183         member = dbus_message_get_member(msg);
184
185         if (val)
186                 ret = pmqos_cpu_request(member, val);
187         else
188                 ret = pmqos_cpu_cancel(member);
189
190 error:
191         reply = dbus_message_new_method_return(msg);
192         dbus_message_iter_init_append(reply, &iter);
193         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
194         return reply;
195 }
196
197 static DBusMessage *dbus_wifi_pmqos_handler(E_DBus_Object *obj, DBusMessage *msg)
198 {
199         DBusMessageIter iter;
200         DBusMessage *reply;
201         const char *member;
202         char name[NAME_MAX];
203         int bps, val, ret;
204
205         if (!dbus_message_get_args(msg, NULL,
206                                 DBUS_TYPE_INT32, &bps,
207                                 DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID)) {
208                 _E("there is no message");
209                 ret = -EINVAL;
210                 goto error;
211         }
212
213         if (bps < 0 || val < 0) {
214                 ret = -EINVAL;
215                 goto error;
216         }
217
218         member = dbus_message_get_member(msg);
219
220         /* combine bps and member */
221         snprintf(name, sizeof(name), "%s%d", member, bps);
222
223         if (val)
224                 ret = pmqos_cpu_request(name, val);
225         else
226                 ret = pmqos_cpu_cancel(name);
227
228 error:
229         reply = dbus_message_new_method_return(msg);
230         dbus_message_iter_init_append(reply, &iter);
231         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
232         return reply;
233 }
234
235 static DBusMessage *dbus_getdefaultlocktime(E_DBus_Object *obj, DBusMessage *msg)
236 {
237         DBusMessageIter iter;
238         DBusMessage *reply;
239         int ret;
240
241         ret = DEFAULT_PMQOS_TIMER;
242
243         reply = dbus_message_new_method_return(msg);
244         dbus_message_iter_init_append(reply, &iter);
245         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
246         return reply;
247 }
248
249 static int get_methods_from_conf(const char *path, struct edbus_method **edbus_methods)
250 {
251         struct edbus_method *methods;
252         struct pmqos_scenario scenarios = {0,};
253         int i, ret;
254
255         /* get pmqos table from conf */
256         ret = get_pmqos_table(path, &scenarios);
257         if (ret < 0) {
258                 /* release scenarios memory */
259                 release_pmqos_table(&scenarios);
260                 return ret;
261         }
262
263         /* if do not support scenario */
264         if (!scenarios.support)
265                 return 0;
266
267         /* if do not have scenarios */
268         if (scenarios.num <= 0)
269                 return 0;
270
271         /* allocate edbus methods structure */
272         methods = malloc(sizeof(struct edbus_method)*scenarios.num);
273         if (!methods) {
274                 _E("failed to allocate methods memory : %s", strerror(errno));
275                 /* release scenarios memory */
276                 release_pmqos_table(&scenarios);
277                 return -errno;
278         }
279
280         /* set edbus_methods structure */
281         for (i = 0; i < scenarios.num; ++i) {
282
283                 /* if this scenario does not support */
284                 if (!scenarios.list[i].support) {
285                         _I("do not support [%s] scenario", scenarios.list[i].name);
286                         continue;
287                 }
288
289                 methods[i].member = scenarios.list[i].name;
290                 methods[i].signature = "i";
291                 methods[i].reply_signature = "i";
292                 methods[i].func = dbus_pmqos_handler;
293                 _D("support [%s] scenario", scenarios.list[i].name);
294         }
295
296         *edbus_methods = methods;
297         return scenarios.num;
298 }
299
300 /* Add pmqos name as alphabetically */
301 static const struct edbus_method edbus_methods[] = {
302         { "AppLaunch",            "i",    "i", dbus_pmqos_handler },
303         { "BeautyShot",           "i",    "i", dbus_pmqos_handler },
304         { "Browser",              "i",    "i", dbus_pmqos_handler },
305         { "BrowserDash",          "i",    "i", dbus_pmqos_handler },
306         { "BrowserJavaScript",    "i",    "i", dbus_pmqos_handler },
307         { "BrowserLoading",       "i",    "i", dbus_pmqos_handler },
308         { "BrowserScroll",        "i",    "i", dbus_pmqos_handler },
309         { "CallSound",            "i",    "i", dbus_pmqos_handler },
310         { "CameraBurstShot",      "i",    "i", dbus_pmqos_handler },
311         { "CameraCaptureAtRec",   "i",    "i", dbus_pmqos_handler },
312         { "CameraPreview",        "i",    "i", dbus_pmqos_handler },
313         { "CameraSoundAndShot",   "i",    "i", dbus_pmqos_handler },
314         { "Emergency",            "i",    "i", dbus_pmqos_handler },
315         { "GalleryRotation",      "i",    "i", dbus_pmqos_handler },
316         { "GetDefaultLockTime",  NULL,    "i", dbus_getdefaultlocktime },
317         { "GpsSerialCno",         "i",    "i", dbus_pmqos_handler },
318         { "GpuBoost",             "i",    "i", dbus_pmqos_handler },
319         { "GpuWakeup",            "i",    "i", dbus_pmqos_handler },
320         { "ImageViewer",          "i",    "i", dbus_pmqos_handler },
321         { "IMEInput",             "i",    "i", dbus_pmqos_handler },
322         { "LockScreen",           "i",    "i", dbus_pmqos_handler },
323         { "LowBattery",           "i",    "i", dbus_pmqos_handler },
324         { "MtpSendFile",          "i",    "i", dbus_pmqos_handler },
325         { "PowerSaving",          "i",    "i", dbus_pmqos_handler },
326         { "ProcessCrashed",       "i",    "i", dbus_pmqos_handler },
327         { "ReservedMode",         "i",    "i", dbus_pmqos_handler },
328         { "ScreenMirroring",      "i",    "i", dbus_pmqos_handler },
329         { "SmemoZoom",            "i",    "i", dbus_pmqos_handler },
330         { "SVoice",               "i",    "i", dbus_pmqos_handler },
331         { "WebappLaunch",         "i",    "i", dbus_pmqos_handler },
332         { "WifiThroughput",      "ii",    "i", dbus_wifi_pmqos_handler },
333         { "PowerOff",             "i",    "i", dbus_pmqos_handler },
334         { "WebAppDrag",           "i",    "i", dbus_pmqos_handler },
335         { "WebAppFlick",          "i",    "i", dbus_pmqos_handler },
336         { "SensorWakeup",          "i",    "i", dbus_pmqos_handler },
337 };
338
339 static void pmqos_init(void *data)
340 {
341         struct edbus_method *methods = NULL;
342         int ret, size;
343
344         /* register edbus methods */
345         ret = register_edbus_method(DEVICED_PATH_PMQOS, edbus_methods, ARRAY_SIZE(edbus_methods));
346         if (ret < 0)
347                 _E("fail to init edbus method(%d)", ret);
348
349         /* get methods from config file */
350         size = get_methods_from_conf(PMQOS_CONF_PATH, &methods);
351         if (size < 0)
352                 _E("failed to load configuration file(%s)", PMQOS_CONF_PATH);
353
354         /* register edbus methods for pmqos */
355         if (methods) {
356                 ret = register_edbus_method(DEVICED_PATH_PMQOS, methods, size);
357                 if (ret < 0)
358                         _E("fail to init edbus method from conf(%d)", ret);
359                 free(methods);
360         }
361
362         /* register notifier for each event */
363         register_notifier(DEVICE_NOTIFIER_PMQOS_POWERSAVING, pmqos_powersaving);
364         register_notifier(DEVICE_NOTIFIER_PMQOS_LOWBAT, pmqos_lowbat);
365         register_notifier(DEVICE_NOTIFIER_PMQOS_EMERGENCY, pmqos_emergency);
366         register_notifier(DEVICE_NOTIFIER_PMQOS_POWEROFF, pmqos_poweroff);
367 }
368
369 static void pmqos_exit(void *data)
370 {
371         /* unregister notifier for each event */
372         unregister_notifier(DEVICE_NOTIFIER_PMQOS_POWERSAVING, pmqos_powersaving);
373         unregister_notifier(DEVICE_NOTIFIER_PMQOS_LOWBAT, pmqos_lowbat);
374         unregister_notifier(DEVICE_NOTIFIER_PMQOS_EMERGENCY, pmqos_emergency);
375         unregister_notifier(DEVICE_NOTIFIER_PMQOS_POWEROFF, pmqos_poweroff);
376 }
377
378 static const struct device_ops pmqos_device_ops = {
379         .priority = DEVICE_PRIORITY_NORMAL,
380         .name     = "pmqos",
381         .init     = pmqos_init,
382         .exit     = pmqos_exit,
383 };
384
385 DEVICE_OPS_REGISTER(&pmqos_device_ops)