add sw_timer param
[platform/core/uifw/libtdm.git] / src / tdm_server.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43 #include "tdm-server-protocol.h"
44
45 /* CAUTION:
46  * - tdm server doesn't care about thread things.
47  * - DO NOT use the TDM internal functions here.
48  */
49
50 struct _tdm_private_server {
51         struct list_head vblank_list;
52 };
53
54 typedef struct _tdm_server_vblank_info {
55         struct list_head link;
56         struct wl_resource *resource;
57         tdm_private_server *private_server;
58 } tdm_server_vblank_info;
59
60 static tdm_private_server *keep_private_server;
61 static int tdm_debug_server;
62
63 static void
64 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
65                              unsigned int tv_sec, unsigned int tv_usec,
66                              void *user_data)
67 {
68         tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
69         tdm_server_vblank_info *found;
70
71         if (!keep_private_server)
72                 return;
73
74         LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
75                        tdm_server_vblank_info, link, found);
76         if (!found) {
77                 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
78                 return;
79         }
80
81         if (tdm_debug_server) {
82                 unsigned long curr = tdm_helper_get_time_in_micros();
83                 unsigned long vtime = (tv_sec * 1000000) + tv_usec;
84                 if (curr - vtime > 1000) /* 1ms */
85                         TDM_WRN("delay: %d us", (int)(curr - vtime));
86         }
87
88         TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
89
90         wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
91         wl_resource_destroy(vblank_info->resource);
92 }
93
94 static void
95 destroy_vblank_callback(struct wl_resource *resource)
96 {
97         tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
98         LIST_DEL(&vblank_info->link);
99         free(vblank_info);
100 }
101
102 static void
103 _tdm_server_cb_wait_vblank(struct wl_client *client,
104                            struct wl_resource *resource,
105                            uint32_t id, const char *name, int32_t sw_timer,
106                            int32_t interval, uint32_t req_sec, uint32_t req_usec)
107 {
108         tdm_private_loop *private_loop = wl_resource_get_user_data(resource);
109         tdm_private_server *private_server = private_loop->private_server;
110         tdm_server_vblank_info *vblank_info;
111         struct wl_resource *vblank_resource;
112         tdm_output *found = NULL;
113         int count = 0, i;
114         tdm_error ret;
115
116         TDM_DBG("The tdm client requests vblank");
117
118         tdm_display_get_output_count(private_loop->dpy, &count);
119
120         for (i = 0; i < count; i++) {
121                 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
122                 tdm_output_conn_status status;
123                 const char *model = NULL;
124
125                 ret = tdm_output_get_conn_status(output, &status);
126                 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
127                         continue;
128
129                 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
130                 if (ret || !model)
131                         continue;
132
133                 if (strncmp(model, name, TDM_NAME_LEN))
134                         continue;
135
136                 found = output;
137                 break;
138         }
139
140         if (!found) {
141                 wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME,
142                                        "There is no '%s' output", name);
143                 TDM_ERR("There is no '%s' output", name);
144                 return;
145         }
146
147         /* TODO: need to implement things related with sw_timer */
148
149         vblank_resource =
150                 wl_resource_create(client, &wl_tdm_vblank_interface,
151                                    wl_resource_get_version(resource), id);
152         if (!vblank_resource) {
153                 wl_resource_post_no_memory(resource);
154                 TDM_ERR("wl_resource_create failed");
155                 return;
156         }
157
158         vblank_info = calloc(1, sizeof *vblank_info);
159         if (!vblank_info) {
160                 wl_resource_destroy(vblank_resource);
161                 wl_resource_post_no_memory(resource);
162                 TDM_ERR("alloc failed");
163                 return;
164         }
165
166         TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
167
168         ret = tdm_output_wait_vblank(found, interval, 0,
169                                      _tdm_server_cb_output_vblank, vblank_info);
170         if (ret != TDM_ERROR_NONE) {
171                 wl_resource_destroy(vblank_resource);
172                 free(vblank_info);
173                 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
174                                        "couldn't wait vblank for %s", name);
175                 TDM_ERR("couldn't wait vblank for %s", name);
176                 return;
177         }
178
179         if (tdm_debug_server) {
180                 unsigned long curr = tdm_helper_get_time_in_micros();
181                 unsigned long reqtime = (req_sec * 1000000) + req_usec;
182                 if (curr - reqtime > 1000) /* 1ms */
183                         TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
184         }
185
186         vblank_info->resource = vblank_resource;
187         vblank_info->private_server = private_server;
188
189         wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
190                                        destroy_vblank_callback);
191
192         LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
193 }
194
195 static const struct wl_tdm_interface tdm_implementation = {
196         _tdm_server_cb_wait_vblank,
197 };
198
199 static void
200 _tdm_server_bind(struct wl_client *client, void *data,
201                  uint32_t version, uint32_t id)
202 {
203         struct wl_resource *resource;
204
205         resource = wl_resource_create(client, &wl_tdm_interface, version, id);
206         if (!resource) {
207                 wl_client_post_no_memory(client);
208                 return;
209         }
210
211         TDM_DBG("tdm server binding");
212
213         wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
214 }
215
216 INTERN tdm_error
217 tdm_server_init(tdm_private_loop *private_loop)
218 {
219         tdm_private_server *private_server;
220         const char *debug;
221
222         debug = getenv("TDM_DEBUG_SERVER");
223         if (debug && (strstr(debug, "1")))
224                 tdm_debug_server = 1;
225
226         if (private_loop->private_server)
227                 return TDM_ERROR_NONE;
228
229         TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
230         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
231
232         if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
233                 TDM_ERR("createing a tdm-socket failed");
234                 return TDM_ERROR_OPERATION_FAILED;
235         }
236
237         private_server = calloc(1, sizeof *private_server);
238         if (!private_server) {
239                 TDM_ERR("alloc failed");
240                 return TDM_ERROR_OUT_OF_MEMORY;
241         }
242
243         LIST_INITHEAD(&private_server->vblank_list);
244
245         if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
246                               private_loop, _tdm_server_bind)) {
247                 TDM_ERR("creating a global resource failed");
248                 free(private_server);
249                 return TDM_ERROR_OUT_OF_MEMORY;
250         }
251
252         private_loop->private_server = private_server;
253         keep_private_server = private_server;
254
255         return TDM_ERROR_NONE;
256 }
257
258 INTERN void
259 tdm_server_deinit(tdm_private_loop *private_loop)
260 {
261         tdm_server_vblank_info *v = NULL, *vv = NULL;
262         tdm_private_server *private_server;
263
264         if (!private_loop->private_server)
265                 return;
266
267         private_server = private_loop->private_server;
268
269         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
270                 wl_resource_destroy(v->resource);
271         }
272
273         free(private_server);
274         private_loop->private_server = NULL;
275         keep_private_server = NULL;
276 }