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 sw_timer,
106 int32_t interval, 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);
147 /* TODO: need to implement things related with sw_timer */
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");
158 vblank_info = calloc(1, sizeof *vblank_info);
160 wl_resource_destroy(vblank_resource);
161 wl_resource_post_no_memory(resource);
162 TDM_ERR("alloc failed");
166 TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
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);
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);
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));
186 vblank_info->resource = vblank_resource;
187 vblank_info->private_server = private_server;
189 wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
190 destroy_vblank_callback);
192 LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
195 static const struct wl_tdm_interface tdm_implementation = {
196 _tdm_server_cb_wait_vblank,
200 _tdm_server_bind(struct wl_client *client, void *data,
201 uint32_t version, uint32_t id)
203 struct wl_resource *resource;
205 resource = wl_resource_create(client, &wl_tdm_interface, version, id);
207 wl_client_post_no_memory(client);
211 TDM_DBG("tdm server binding");
213 wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
217 tdm_server_init(tdm_private_loop *private_loop)
219 tdm_private_server *private_server;
222 debug = getenv("TDM_DEBUG_SERVER");
223 if (debug && (strstr(debug, "1")))
224 tdm_debug_server = 1;
226 if (private_loop->private_server)
227 return TDM_ERROR_NONE;
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);
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;
237 private_server = calloc(1, sizeof *private_server);
238 if (!private_server) {
239 TDM_ERR("alloc failed");
240 return TDM_ERROR_OUT_OF_MEMORY;
243 LIST_INITHEAD(&private_server->vblank_list);
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;
252 private_loop->private_server = private_server;
253 keep_private_server = private_server;
255 return TDM_ERROR_NONE;
259 tdm_server_deinit(tdm_private_loop *private_loop)
261 tdm_server_vblank_info *v = NULL, *vv = NULL;
262 tdm_private_server *private_server;
264 if (!private_loop->private_server)
267 private_server = private_loop->private_server;
269 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
270 wl_resource_destroy(v->resource);
273 free(private_server);
274 private_loop->private_server = NULL;
275 keep_private_server = NULL;