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 tdm_private_loop *private_loop;
52 struct list_head client_list;
53 struct list_head vblank_list;
56 typedef struct _tdm_server_client_info {
57 struct list_head link;
58 tdm_private_server *private_server;
59 struct wl_resource *resource;
60 } tdm_server_client_info;
62 typedef struct _tdm_server_vblank_info {
63 struct list_head link;
64 tdm_server_client_info *client_info;
65 struct wl_resource *resource;
66 } tdm_server_vblank_info;
68 static tdm_private_server *keep_private_server;
69 static int tdm_debug_server;
72 _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence,
73 unsigned int tv_sec, unsigned int tv_usec,
76 tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data;
77 tdm_server_vblank_info *found;
79 if (!keep_private_server)
82 LIST_FIND_ITEM(vblank_info, &keep_private_server->vblank_list,
83 tdm_server_vblank_info, link, found);
85 TDM_DBG("vblank_info(%p) is destroyed", vblank_info);
89 if (tdm_debug_server) {
90 unsigned long curr = tdm_helper_get_time_in_micros();
91 unsigned long vtime = (tv_sec * 1000000) + tv_usec;
92 if (curr - vtime > 1000) /* 1ms */
93 TDM_WRN("delay: %d us", (int)(curr - vtime));
96 TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource));
98 wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec);
99 wl_resource_destroy(vblank_info->resource);
103 destroy_vblank_callback(struct wl_resource *resource)
105 tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource);
106 LIST_DEL(&vblank_info->link);
111 _tdm_server_client_cb_destroy(struct wl_client *client, struct wl_resource *resource)
113 wl_resource_destroy(resource);
117 _tdm_server_client_cb_wait_vblank(struct wl_client *client,
118 struct wl_resource *resource,
119 uint32_t id, const char *name,
120 int32_t sw_timer, int32_t interval,
121 uint32_t req_sec, uint32_t req_usec)
123 tdm_server_client_info *client_info = wl_resource_get_user_data(resource);
124 tdm_private_server *private_server = client_info->private_server;
125 tdm_private_loop *private_loop = private_server->private_loop;
126 tdm_server_vblank_info *vblank_info;
127 struct wl_resource *vblank_resource;
128 tdm_output *found = NULL;
129 tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
133 TDM_DBG("The tdm client requests vblank");
135 if (tdm_debug_server) {
136 unsigned long curr = tdm_helper_get_time_in_micros();
137 unsigned long reqtime = (req_sec * 1000000) + req_usec;
138 if (curr - reqtime > 1000) /* 1ms */
139 TDM_WRN("delay(req): %d us", (int)(curr - reqtime));
142 tdm_display_get_output_count(private_loop->dpy, &count);
144 for (i = 0; i < count; i++) {
145 tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL);
146 tdm_output_conn_status status;
147 const char *model = NULL;
149 ret = tdm_output_get_conn_status(output, &status);
150 if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
153 ret = tdm_output_get_model_info(output, NULL, &model, NULL);
157 if (strncmp(model, name, TDM_NAME_LEN))
165 wl_resource_post_error(resource, WL_TDM_CLIENT_ERROR_INVALID_NAME,
166 "There is no '%s' output", name);
167 TDM_ERR("There is no '%s' output", name);
171 tdm_output_get_dpms(found, &dpms_value);
173 if (dpms_value != TDM_OUTPUT_DPMS_ON && !sw_timer) {
174 wl_resource_post_error(resource, WL_TDM_CLIENT_ERROR_DPMS_OFF,
175 "dpms '%s'", tdm_get_dpms_str(dpms_value));
176 TDM_ERR("dpms '%s'", tdm_get_dpms_str(dpms_value));
180 vblank_info = calloc(1, sizeof *vblank_info);
182 wl_resource_post_no_memory(resource);
183 TDM_ERR("alloc failed");
187 TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval);
190 wl_resource_create(client, &wl_tdm_vblank_interface,
191 wl_resource_get_version(resource), id);
192 if (!vblank_resource) {
193 wl_resource_post_no_memory(resource);
194 TDM_ERR("wl_resource_create failed");
198 if (dpms_value == TDM_OUTPUT_DPMS_ON) {
199 ret = tdm_output_wait_vblank(found, interval, 0,
200 _tdm_server_cb_output_vblank, vblank_info);
201 if (ret != TDM_ERROR_NONE) {
202 wl_resource_post_error(resource, WL_TDM_CLIENT_ERROR_OPERATION_FAILED,
203 "couldn't wait vblank for %s", name);
204 TDM_ERR("couldn't wait vblank for %s", name);
205 goto destroy_resource;
207 } else if (sw_timer) {
208 /* TODO: need to implement things related with sw_timer */
209 if (ret != TDM_ERROR_NONE) {
210 wl_resource_post_error(resource, WL_TDM_CLIENT_ERROR_OPERATION_FAILED,
211 "not implemented yet");
212 TDM_ERR("not implemented yet");
213 goto destroy_resource;
216 wl_resource_post_error(resource, WL_TDM_CLIENT_ERROR_OPERATION_FAILED,
217 "bad implementation");
218 TDM_NEVER_GET_HERE();
219 goto destroy_resource;
222 vblank_info->resource = vblank_resource;
223 vblank_info->client_info = client_info;
225 wl_resource_set_implementation(vblank_resource, NULL, vblank_info,
226 destroy_vblank_callback);
228 LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list);
231 wl_resource_destroy(vblank_resource);
236 static const struct wl_tdm_client_interface tdm_client_implementation = {
237 _tdm_server_client_cb_destroy,
238 _tdm_server_client_cb_wait_vblank,
242 destroy_client_callback(struct wl_resource *resource)
244 tdm_server_client_info *client_info = wl_resource_get_user_data(resource);
246 LIST_DEL(&client_info->link);
251 _tdm_server_cb_create_client(struct wl_client *client,
252 struct wl_resource *resource, uint32_t id)
254 tdm_private_server *private_server = wl_resource_get_user_data(resource);
255 tdm_server_client_info *client_info;
256 struct wl_resource *client_resource;
258 client_info = calloc(1, sizeof *client_info);
260 wl_resource_post_no_memory(resource);
261 TDM_ERR("alloc failed");
266 wl_resource_create(client, &wl_tdm_client_interface,
267 wl_resource_get_version(resource), id);
268 if (!client_resource) {
269 wl_resource_post_no_memory(resource);
271 TDM_ERR("wl_resource_create failed");
275 client_info->private_server = private_server;
276 client_info->resource = client_resource;
278 wl_resource_set_implementation(client_resource, &tdm_client_implementation,
279 client_info, destroy_client_callback);
281 LIST_ADDTAIL(&client_info->link, &private_server->client_list);
284 static const struct wl_tdm_interface tdm_implementation = {
285 _tdm_server_cb_create_client,
289 _tdm_server_bind(struct wl_client *client, void *data,
290 uint32_t version, uint32_t id)
292 struct wl_resource *resource;
294 resource = wl_resource_create(client, &wl_tdm_interface, version, id);
296 wl_client_post_no_memory(client);
300 TDM_DBG("tdm server binding");
302 wl_resource_set_implementation(resource, &tdm_implementation, data, NULL);
306 tdm_server_init(tdm_private_loop *private_loop)
308 tdm_private_server *private_server;
311 debug = getenv("TDM_DEBUG_SERVER");
312 if (debug && (strstr(debug, "1")))
313 tdm_debug_server = 1;
315 if (private_loop->private_server)
316 return TDM_ERROR_NONE;
318 TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED);
319 TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED);
321 if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) {
322 TDM_ERR("createing a tdm-socket failed");
323 return TDM_ERROR_OPERATION_FAILED;
326 private_server = calloc(1, sizeof *private_server);
327 if (!private_server) {
328 TDM_ERR("alloc failed");
329 return TDM_ERROR_OUT_OF_MEMORY;
332 LIST_INITHEAD(&private_server->client_list);
333 LIST_INITHEAD(&private_server->vblank_list);
335 if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1,
336 private_server, _tdm_server_bind)) {
337 TDM_ERR("creating a global resource failed");
338 free(private_server);
339 return TDM_ERROR_OUT_OF_MEMORY;
342 private_server->private_loop = private_loop;
343 private_loop->private_server = private_server;
344 keep_private_server = private_server;
346 return TDM_ERROR_NONE;
350 tdm_server_deinit(tdm_private_loop *private_loop)
352 tdm_server_vblank_info *v = NULL, *vv = NULL;
353 tdm_server_client_info *c = NULL, *cc = NULL;
354 tdm_private_server *private_server;
356 if (!private_loop->private_server)
359 private_server = private_loop->private_server;
361 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) {
362 wl_resource_destroy(v->resource);
365 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_server->client_list, link) {
366 wl_resource_destroy(c->resource);
369 free(private_server);
370 private_loop->private_server = NULL;
371 keep_private_server = NULL;