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;
113 tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
117 TDM_DBG("The tdm client requests vblank");
119 if (tdm_debug_server) {
120 unsigned long curr = tdm_helper_get_time_in_micros();
121 unsigned long reqtime = (req_sec * 1000000) + req_usec;
122 if (curr - reqtime > 1000) /* 1ms */
123 TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
126 tdm_display_get_output_count(private_loop->dpy, &count);
128 for (i = 0; i < count; i++) {
129 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
130 tdm_output_conn_status status;
131 const char *model = NULL;
133 ret = tdm_output_get_conn_status(output, &status);
134 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
137 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
141 if (strncmp(model, name, TDM_NAME_LEN))
149 wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME,
150 "There is no '%s' output", name);
151 TDM_ERR("There is no '%s' output", name);
155 tdm_output_get_dpms(found, &dpms_value);
157 if (dpms_value != TDM_OUTPUT_DPMS_ON && !sw_timer) {
158 wl_resource_post_error(resource, WL_TDM_ERROR_DPMS_OFF,
159 "dpms '%s'", tdm_get_dpms_str(dpms_value));
160 TDM_ERR("dpms '%s'", tdm_get_dpms_str(dpms_value));
164 vblank_info = calloc(1, sizeof *vblank_info);
166 wl_resource_post_no_memory(resource);
167 TDM_ERR("alloc failed");
171 TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
174 wl_resource_create(client, &wl_tdm_vblank_interface,
175 wl_resource_get_version(resource), id);
176 if (!vblank_resource) {
177 wl_resource_post_no_memory(resource);
178 TDM_ERR("wl_resource_create failed");
182 if (dpms_value == TDM_OUTPUT_DPMS_ON) {
183 ret = tdm_output_wait_vblank(found, interval, 0,
184 _tdm_server_cb_output_vblank, vblank_info);
185 if (ret != TDM_ERROR_NONE) {
186 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
187 "couldn't wait vblank for %s", name);
188 TDM_ERR("couldn't wait vblank for %s", name);
189 goto destroy_resource;
191 } else if (sw_timer) {
192 /* TODO: need to implement things related with sw_timer */
193 if (ret != TDM_ERROR_NONE) {
194 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
195 "not implemented yet");
196 TDM_ERR("not implemented yet");
197 goto destroy_resource;
200 wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED,
201 "bad implementation");
202 TDM_NEVER_GET_HERE();
203 goto destroy_resource;
206 vblank_info->resource = vblank_resource;
207 vblank_info->private_server = private_server;
209 wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
210 destroy_vblank_callback);
212 LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
215 wl_resource_destroy(vblank_resource);
220 static const struct wl_tdm_interface tdm_implementation = {
221 _tdm_server_cb_wait_vblank,
225 _tdm_server_bind(struct wl_client *client, void *data,
226 uint32_t version, uint32_t id)
228 struct wl_resource *resource;
230 resource = wl_resource_create(client, &wl_tdm_interface, version, id);
232 wl_client_post_no_memory(client);
236 TDM_DBG("tdm server binding");
238 wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
242 tdm_server_init(tdm_private_loop *private_loop)
244 tdm_private_server *private_server;
247 debug = getenv("TDM_DEBUG_SERVER");
248 if (debug && (strstr(debug, "1")))
249 tdm_debug_server = 1;
251 if (private_loop->private_server)
252 return TDM_ERROR_NONE;
254 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
255 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
257 if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
258 TDM_ERR("createing a tdm-socket failed");
259 return TDM_ERROR_OPERATION_FAILED;
262 private_server = calloc(1, sizeof *private_server);
263 if (!private_server) {
264 TDM_ERR("alloc failed");
265 return TDM_ERROR_OUT_OF_MEMORY;
268 LIST_INITHEAD(&private_server->vblank_list);
270 if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
271 private_loop, _tdm_server_bind)) {
272 TDM_ERR("creating a global resource failed");
273 free(private_server);
274 return TDM_ERROR_OUT_OF_MEMORY;
277 private_loop->private_server = private_server;
278 keep_private_server = private_server;
280 return TDM_ERROR_NONE;
284 tdm_server_deinit(tdm_private_loop *private_loop)
286 tdm_server_vblank_info *v = NULL, *vv = NULL;
287 tdm_private_server *private_server;
289 if (!private_loop->private_server)
292 private_server = private_loop->private_server;
294 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
295 wl_resource_destroy(v->resource);
298 free(private_server);
299 private_loop->private_server = NULL;
300 keep_private_server = NULL;