resource: Operate based on resource id
[platform/core/system/pass.git] / src / resource / resource-display.c
1 /*
2  * PASS (Power Aware System Service) - Display Resource Driver
3  *
4  * Copyright (c) 2022 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  * @file        resource-display.c
21  * @brief       TBD
22  * @ingroup     TBD
23  */
24
25 #include <glib.h>
26 #include <unistd.h>
27
28 #include <util/common.h>
29 #include <util/devices.h>
30 #include <util/log.h>
31 #include <util/gdbus-util.h>
32 #include <util/thread.h>
33
34 #include <libsyscommon/resource-manager.h>
35 #include <libsyscommon/resource-type.h>
36 #include <libsyscommon/resource-device.h>
37
38 #include <resource-monitor/resource-monitor.h>
39
40 #define DBUS_ENLIGHTENMENT_NAME         "org.enlightenment.wm"
41 #define DBUS_ENLIGHTENMENT_PATH         "/org/enlightenment/wm"
42 #define DBUS_ENLIGHTENMENT_INTERFACE    "org.enlightenment.wm.info"
43 #define DBUS_ENLIGHTENMENT_FPS_FUNC     "get_fps_info"
44
45 #define DISPLAY_SAMPLE_RATE_MSEC 1000
46
47 struct display_context {
48         char *device_name;
49         int index;
50 };
51
52 struct display_fps_data {
53         unsigned int type;
54         char output[128];
55         int zpos;
56         unsigned int window;
57         double fps;
58 };
59
60 struct display_fps_monitor {
61         int holder;
62         int resource_count;
63         double *last_fps;
64         struct thread *thread;
65         GMutex display_lock;
66 };
67
68 static struct display_fps_monitor g_fps_monitor;
69
70 static int display_read_fps(int resource_index)
71 {
72         int ret = 0;
73         GDBusConnection *conn;
74         GDBusMessage *msg, *reply;
75         GVariant *result, *value;
76         GError *err = NULL;
77         struct display_fps_data fps_data;
78
79         /* Connect dbus interface and receive message */
80         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
81         if (err) {
82                 g_clear_error(&err);
83                 return -EINVAL;
84         }
85
86         msg = g_dbus_message_new_method_call(DBUS_ENLIGHTENMENT_NAME,
87                                         DBUS_ENLIGHTENMENT_PATH,
88                                         DBUS_ENLIGHTENMENT_INTERFACE,
89                                         DBUS_ENLIGHTENMENT_FPS_FUNC);
90         if (!msg) {
91                 ret = -EINVAL;
92                 goto err_conn;
93         }
94
95         reply = g_dbus_connection_send_message_with_reply_sync(conn, msg,
96                                         G_DBUS_SEND_MESSAGE_FLAGS_NONE,
97                                         G_MAXINT, NULL, NULL, &err);
98         if (err) {
99                 g_clear_error(&err);
100                 ret = -EINVAL;
101                 goto err_msg;
102         }
103
104         if (g_dbus_message_get_message_type(reply) == G_DBUS_MESSAGE_TYPE_ERROR) {
105                 ret = -EINVAL;
106                 goto err_reply;
107         }
108
109         /* Parse the received data */
110         result = g_variant_get_child_value(g_dbus_message_get_body(reply), 0);
111         if (g_variant_n_children(result) == 0) {
112                 fps_data.fps = 0.0;
113                 goto out;
114         }
115
116         /* Get the fps information according to the index of resource_device */
117         value = g_variant_get_child_value(result, resource_index);
118         g_variant_get(value, "(usiud)",
119                         &fps_data.type, fps_data.output, &fps_data.zpos,
120                         &fps_data.window, &fps_data.fps);
121
122 out:
123         __atomic_store((&g_fps_monitor.last_fps[resource_index]),
124                         &fps_data.fps, __ATOMIC_RELEASE);
125
126 err_reply:
127         g_object_unref(reply);
128 err_msg:
129         g_object_unref(msg);
130 err_conn:
131         g_dbus_connection_flush(conn, NULL, NULL, NULL);
132
133         return ret;
134 }
135
136 static int display_get_fps(int resource_id,
137                                 const struct syscommon_resman_resource_attribute *attr,
138                                 void *data)
139 {
140         struct display_context *ctx;
141         double *fps = (double *)data;
142
143         if (resource_id < 0 || !attr || !data)
144                 return -EINVAL;
145
146         ctx = syscommon_resman_get_resource_privdata(resource_id);
147         if (!ctx)
148                 return -EINVAL;
149
150         if (!ctx->device_name) {
151                 _E("%s: DISPLAY_CTRL_DEVICE_ID is not yet initialized\n",
152                                 syscommon_resman_get_resource_name(resource_id));
153                 return -EINVAL;
154         }
155
156         __atomic_load(&g_fps_monitor.last_fps[ctx->index], fps, __ATOMIC_ACQUIRE);
157
158         return 0;
159 }
160
161 static int display_get_name(int resource_id,
162                                 const struct syscommon_resman_resource_attribute *attr,
163                                 void *data)
164 {
165         struct display_context *ctx;
166         char *buf = (char *)data;
167
168         if (resource_id < 0 || !attr || !data)
169                 return -EINVAL;
170
171         ctx = syscommon_resman_get_resource_privdata(resource_id);
172         if (!ctx)
173                 return -EINVAL;
174
175         if (!ctx->device_name) {
176                 _E("%s: DISPLAY_CTRL_DEVICE_ID is not yet initialized\n",
177                                 syscommon_resman_get_resource_name(resource_id));
178                 return -EINVAL;
179         }
180
181         strncpy(buf, ctx->device_name, BUFF_MAX);
182
183         return 0;
184 }
185
186 static const struct syscommon_resman_resource_attribute display_attrs[] = {
187         {
188                 .name   = "DISPLAY_ATTR_FPS",
189                 .id     = DISPLAY_ATTR_FPS,
190                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE,
191                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
192                 .ops    = {
193                         .get = display_get_fps,
194                 },
195         }, {
196                 .name   = "DISPLAY_ATTR_NAME",
197                 .id     = DISPLAY_ATTR_NAME,
198                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_STRING,
199                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
200                 .ops    = {
201                         .get = display_get_name,
202                 },
203         },
204 };
205
206 static int display_setup_device_id(int resource_id,
207                                 const struct syscommon_resman_resource_control *ctrl,
208                                 const void *data)
209 {
210         struct display_context *ctx;
211         const struct syscommon_resman_resource_device *device;
212         int resource_index = (int)(intptr_t)data;
213
214         if (resource_id < 0 || !ctrl)
215                 return -EINVAL;
216
217         ctx = syscommon_resman_get_resource_privdata(resource_id);
218         if (!ctx)
219                 return -EINVAL;
220
221         device = syscommon_resman_find_resource_device(syscommon_resman_get_resource_type(resource_id), resource_index);
222         if (!device) {
223                 _E("Not available resource: type: %s, index: %d\n",
224                                 syscommon_resman_get_resource_name(resource_id), resource_index);
225                 return -EINVAL;
226         }
227
228         if (ctx->device_name)
229                 free(ctx->device_name);
230
231         ctx->device_name = g_strdup(device->name);
232         ctx->index = resource_index;
233
234         return 0;
235 }
236
237 static const struct syscommon_resman_resource_control display_ctrls[] = {
238         {
239                 .name = "DISPLAY_CTRL_DEVICE_ID",
240                 .id = DISPLAY_CTRL_DEVICE_ID,
241                 .ops = {
242                         .set = display_setup_device_id,
243                 },
244         },
245 };
246
247 static int display_monitor_func(void *data, void **result)
248 {
249         int i;
250
251         for (i = 0; i < g_fps_monitor.resource_count; i++)
252                 display_read_fps(i);
253
254         return THREAD_RETURN_CONTINUE;
255 }
256
257 static int display_create(int resource_id)
258 {
259         int ret = 0;
260         struct display_context *ctx;
261
262         ctx = calloc(1, sizeof(struct display_context));
263         if (!ctx)
264                 return -ENOMEM;
265
266         ctx->index = -1;
267
268         syscommon_resman_set_resource_privdata(resource_id, ctx);
269
270         g_mutex_lock(&g_fps_monitor.display_lock);
271         if (g_fps_monitor.holder++ == 0)
272                 resume_thread(g_fps_monitor.thread);
273         g_mutex_unlock(&g_fps_monitor.display_lock);
274
275         return ret;
276 }
277
278 static void display_delete(int resource_id)
279 {
280         struct display_context *ctx;
281
282         if (resource_id < 0)
283                 return;
284
285         ctx = syscommon_resman_get_resource_privdata(resource_id);
286         if (!ctx)
287                 return;
288
289         if (ctx->device_name)
290                 free(ctx->device_name);
291
292         free(ctx);
293         syscommon_resman_set_resource_privdata(resource_id, NULL);
294
295         g_mutex_lock(&g_fps_monitor.display_lock);
296         if (--g_fps_monitor.holder == 0)
297                 suspend_thread(g_fps_monitor.thread);
298         g_mutex_unlock(&g_fps_monitor.display_lock);
299 }
300
301 static int display_init(void)
302 {
303         int ret;
304
305         g_fps_monitor.resource_count = syscommon_resman_get_resource_device_count(RESOURCE_TYPE_DISPLAY);
306         if (g_fps_monitor.resource_count < 0)
307                 return g_fps_monitor.resource_count;
308
309         g_fps_monitor.last_fps = calloc(g_fps_monitor.resource_count, sizeof(double));
310         if (!g_fps_monitor.last_fps)
311                 return -ENOMEM;
312
313         ret = create_timer_thread(&g_fps_monitor.thread, DISPLAY_SAMPLE_RATE_MSEC,
314                         display_monitor_func, NULL);
315
316         return ret;
317 }
318
319 static void display_exit(void)
320 {
321         if (g_fps_monitor.thread) {
322                 destroy_thread(g_fps_monitor.thread);
323                 g_fps_monitor.thread = NULL;
324         }
325
326         if (g_fps_monitor.last_fps) {
327                 free(g_fps_monitor.last_fps);
328                 g_fps_monitor.last_fps = NULL;
329         }
330
331         g_fps_monitor.resource_count = 0;
332 }
333
334 static const struct syscommon_resman_resource_driver display_resource_driver = {
335         .name           = "DISPLAY",
336         .type           = RESOURCE_TYPE_DISPLAY,
337         .attrs          = display_attrs,
338         .num_attrs      = ARRAY_SIZE(display_attrs),
339         .ctrls          = display_ctrls,
340         .num_ctrls      = ARRAY_SIZE(display_ctrls),
341         .ops            = {
342                 .create = display_create,
343                 .delete = display_delete,
344                 .init = display_init,
345                 .exit = display_exit,
346         },
347 };
348 SYSCOMMON_RESMAN_RESOURCE_DRIVER_REGISTER(&display_resource_driver)