1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
41 #include "tdm_private.h"
43 #include "tdm-server-protocol.h"
46 * - tdm server doesn't care about thread things.
47 * - DO NOT use the TDM internal functions here.
50 struct _tdm_private_server {
51 struct list_head vblank_list;
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;
60 static tdm_private_server *keep_private_server;
61 static int tdm_debug_server;
64 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
65 unsigned int tv_sec, unsigned int tv_usec,
68 tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
69 tdm_server_vblank_info *found;
71 if (!keep_private_server)
74 LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
75 tdm_server_vblank_info, link, found);
77 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
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));
88 TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
90 wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
91 wl_resource_destroy(vblank_info->resource);
95 destroy_vblank_callback(struct wl_resource *resource)
97 tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
98 LIST_DEL(&vblank_info->link);
103 _tdm_server_cb_wait_vblank(struct wl_client *client,
104 struct wl_resource *resource,
105 uint32_t id, const char *name, int32_t interval,
106 uint32_t req_sec, uint32_t req_usec)
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;
116 TDM_DBG("The tdm client requests vblank");
118 tdm_display_get_output_count(private_loop->dpy, &count);
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;
125 ret = tdm_output_get_conn_status(output, &status);
126 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
129 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
133 if (strncmp(model, name, TDM_NAME_LEN))
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);
148 wl_resource_create(client, &wl_tdm_vblank_interface,
149 wl_resource_get_version(resource), id);
150 if (!vblank_resource) {
151 wl_resource_post_no_memory(resource);
152 TDM_ERR("wl_resource_create failed");
156 vblank_info = calloc(1, sizeof *vblank_info);
158 wl_resource_destroy(vblank_resource);
159 wl_resource_post_no_memory(resource);
160 TDM_ERR("alloc failed");
164 TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
166 ret = tdm_output_wait_vblank(found, interval, 0,
167 _tdm_server_cb_output_vblank, vblank_info);
168 if (ret != TDM_ERROR_NONE) {
169 wl_resource_destroy(vblank_resource);
171 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
172 "couldn't wait vblank for %s", name);
173 TDM_ERR("couldn't wait vblank for %s", name);
177 if (tdm_debug_server) {
178 unsigned long curr = tdm_helper_get_time_in_micros();
179 unsigned long reqtime = (req_sec * 1000000) + req_usec;
180 if (curr - reqtime > 1000) /* 1ms */
181 TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
184 vblank_info->resource = vblank_resource;
185 vblank_info->private_server = private_server;
187 wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
188 destroy_vblank_callback);
190 LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
193 static const struct wl_tdm_interface tdm_implementation = {
194 _tdm_server_cb_wait_vblank,
198 _tdm_server_bind(struct wl_client *client, void *data,
199 uint32_t version, uint32_t id)
201 struct wl_resource *resource;
203 resource = wl_resource_create(client, &wl_tdm_interface, version, id);
205 wl_client_post_no_memory(client);
209 TDM_DBG("tdm server binding");
211 wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
215 tdm_server_init(tdm_private_loop *private_loop)
217 tdm_private_server *private_server;
220 debug = getenv("TDM_DEBUG_SERVER");
221 if (debug && (strstr(debug, "1")))
222 tdm_debug_server = 1;
224 if (private_loop->private_server)
225 return TDM_ERROR_NONE;
227 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
228 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
230 if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
231 TDM_ERR("createing a tdm-socket failed");
232 return TDM_ERROR_OPERATION_FAILED;
235 private_server = calloc(1, sizeof *private_server);
236 if (!private_server) {
237 TDM_ERR("alloc failed");
238 return TDM_ERROR_OUT_OF_MEMORY;
241 LIST_INITHEAD(&private_server->vblank_list);
243 if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
244 private_loop, _tdm_server_bind)) {
245 TDM_ERR("creating a global resource failed");
246 free(private_server);
247 return TDM_ERROR_OUT_OF_MEMORY;
250 private_loop->private_server = private_server;
251 keep_private_server = private_server;
253 return TDM_ERROR_NONE;
257 tdm_server_deinit(tdm_private_loop *private_loop)
259 tdm_server_vblank_info *v = NULL, *vv = NULL;
260 tdm_private_server *private_server;
262 if (!private_loop->private_server)
265 private_server = private_loop->private_server;
267 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
268 wl_resource_destroy(v->resource);
271 free(private_server);
272 private_loop->private_server = NULL;
273 keep_private_server = NULL;