implement new mechanism for smooth transition from DEVICE to CLIENT
[platform/core/uifw/libtdm.git] / src / tdm.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_backend.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44 #include <tbm_drm_helper.h>
45
46 pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER;
47 int tdm_mutex_locked;
48 const char *tdm_mutex_lock_func;
49 int tdm_mutex_lock_line;
50 const char *tdm_mutex_unlock_func;
51 int tdm_mutex_unlock_line;
52
53 /* LCOV_EXCL_START */
54 static tdm_private_layer *
55 _tdm_display_find_private_layer(tdm_private_output *private_output,
56                                                                 tdm_layer *layer_backend)
57 {
58         tdm_private_layer *private_layer = NULL;
59
60         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
61                 if (private_layer->layer_backend == layer_backend)
62                         return private_layer;
63         }
64
65         return NULL;
66 }
67
68 static tdm_private_output *
69 _tdm_display_find_private_output(tdm_private_display *private_display,
70                                                                  tdm_output *output_backend)
71 {
72         tdm_private_output *private_output = NULL;
73
74         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
75                 if (private_output->output_backend == output_backend)
76                         return private_output;
77         }
78
79         return NULL;
80 }
81
82 INTERN tdm_private_output *
83 tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp)
84 {
85         tdm_private_output *private_output = NULL;
86
87         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
88                 if (private_output->stamp == stamp)
89                         return private_output;
90         }
91
92         return NULL;
93 }
94
95 static void
96 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
97 {
98         if (caps_pp->formats)
99                 free(caps_pp->formats);
100
101         memset(caps_pp, 0, sizeof(tdm_caps_pp));
102 }
103
104 static void
105 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
106 {
107         if (caps_capture->formats)
108                 free(caps_capture->formats);
109
110         memset(caps_capture, 0, sizeof(tdm_caps_capture));
111 }
112
113 static void
114 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
115 {
116         if (caps_layer->formats)
117                 free(caps_layer->formats);
118
119         if (caps_layer->props)
120                 free(caps_layer->props);
121
122         memset(caps_layer, 0, sizeof(tdm_caps_layer));
123 }
124
125 static void
126 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
127 {
128         if (caps_output->modes)
129                 free(caps_output->modes);
130
131         if (caps_output->props)
132                 free(caps_output->props);
133
134         memset(caps_output, 0, sizeof(tdm_caps_output));
135 }
136
137 static void
138 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
139 {
140         tdm_private_capture *c = NULL, *cc = NULL;
141
142         LIST_DEL(&private_layer->link);
143
144         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
145         tdm_capture_destroy_internal(c);
146
147         _tdm_display_destroy_caps_layer(&private_layer->caps);
148
149         free(private_layer);
150 }
151
152 static void
153 _tdm_display_destroy_private_output(tdm_private_output *private_output)
154 {
155         tdm_private_display *private_display = private_output->private_display;
156         tdm_private_layer *l = NULL, *ll = NULL;
157         tdm_private_hwc_window *hw = NULL, *hww = NULL;
158         tdm_private_capture *c = NULL, *cc = NULL;
159         tdm_private_vblank_handler *v = NULL, *vv = NULL;
160         tdm_private_output_commit_handler *om = NULL, *omm = NULL;
161         tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
162         tdm_private_change_handler *h = NULL, *hh = NULL;
163
164         LIST_DEL(&private_output->link);
165
166         free(private_output->layers_ptr);
167
168         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
169                 LIST_DEL(&v->link);
170                 free(v);
171         }
172
173         LIST_FOR_EACH_ENTRY_SAFE(om, omm, &private_output->output_commit_handler_list, link) {
174                 LIST_DEL(&om->link);
175                 free(om);
176         }
177
178         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) {
179                 LIST_DEL(&lm->link);
180                 free(lm);
181         }
182
183         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) {
184                 LIST_DEL(&lm->link);
185                 free(lm);
186         }
187
188         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
189                 LIST_DEL(&h->link);
190                 free(h);
191         }
192
193         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
194                 LIST_DEL(&h->link);
195                 free(h);
196         }
197
198         if (private_output->vblank) {
199                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
200                 _pthread_mutex_unlock(&private_display->lock);
201                 tdm_vblank_destroy(private_output->vblank);
202                 _pthread_mutex_lock(&private_display->lock);
203         }
204
205         if (private_output->ttrace_vblank) {
206                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
207                 _pthread_mutex_unlock(&private_display->lock);
208                 tdm_vblank_destroy(private_output->ttrace_vblank);
209                 _pthread_mutex_lock(&private_display->lock);
210         }
211
212         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
213         tdm_capture_destroy_internal(c);
214
215         LIST_FOR_EACH_ENTRY_SAFE(hw, hww, &private_output->hwc_window_list, link)
216         tdm_hwc_window_destroy_internal(hw);
217
218         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
219         _tdm_display_destroy_private_layer(l);
220
221         _tdm_display_destroy_caps_output(&private_output->caps);
222
223         if (private_output->dpms_changed_timer)
224                 tdm_event_loop_source_remove(private_output->dpms_changed_timer);
225
226         tdm_event_loop_source_remove(private_output->need_validate.event_source);
227         close(private_output->need_validate.event_fd);
228
229         private_output->stamp = 0;
230         free(private_output);
231 }
232
233 static void
234 _tdm_display_destroy_private_display(tdm_private_display *private_display)
235 {
236         tdm_private_output *o = NULL, *oo = NULL;
237         tdm_private_pp *p = NULL, *pp = NULL;
238
239         free(private_display->outputs_ptr);
240         if (private_display->outputs) {
241                 free(private_display->outputs);
242                 private_display->outputs = NULL;
243         }
244
245         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
246         tdm_pp_destroy_internal(p);
247
248         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
249         _tdm_display_destroy_private_output(o);
250
251         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
252         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
253
254         private_display->capabilities = 0;
255         private_display->caps_display.max_layer_count = 0;
256 }
257
258 static tdm_error
259 _tdm_display_update_caps_pp(tdm_private_display *private_display,
260                                                         tdm_caps_pp *caps)
261 {
262         tdm_func_display *func_display = &private_display->func_display;
263         tdm_error ret;
264
265         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
266                 return TDM_ERROR_NONE;
267
268         if (!func_display->display_get_pp_capability) {
269                 TDM_ERR("no display_get_pp_capability()");
270                 return TDM_ERROR_BAD_MODULE;
271         }
272
273         ret = func_display->display_get_pp_capability(private_display->bdata, caps);
274         if (ret != TDM_ERROR_NONE) {
275                 TDM_ERR("display_get_pp_capability() failed");
276                 return TDM_ERROR_BAD_MODULE;
277         }
278
279         return TDM_ERROR_NONE;
280 }
281
282 static tdm_error
283 _tdm_display_update_caps_capture(tdm_private_display *private_display,
284                                                                  tdm_caps_capture *caps)
285 {
286         tdm_func_display *func_display = &private_display->func_display;
287         tdm_error ret;
288
289         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
290                 return TDM_ERROR_NONE;
291
292         if (!func_display->display_get_capture_capability) {
293                 TDM_ERR("no display_get_capture_capability()");
294                 return TDM_ERROR_BAD_MODULE;
295         }
296
297         ret = func_display->display_get_capture_capability(private_display->bdata, caps);
298         if (ret != TDM_ERROR_NONE) {
299                 TDM_ERR("display_get_capture_capability() failed");
300                 return TDM_ERROR_BAD_MODULE;
301         }
302
303         return TDM_ERROR_NONE;
304 }
305
306 static tdm_error
307 _tdm_display_update_caps_layer(tdm_private_display *private_display,
308                                                            tdm_layer *layer_backend, tdm_caps_layer *caps)
309 {
310         tdm_func_layer *func_layer = &private_display->func_layer;
311         tdm_error ret;
312
313         if (!func_layer->layer_get_capability) {
314                 TDM_ERR("no layer_get_capability()");
315                 return TDM_ERROR_BAD_MODULE;
316         }
317
318         ret = func_layer->layer_get_capability(layer_backend, caps);
319         if (ret != TDM_ERROR_NONE) {
320                 TDM_ERR("layer_get_capability() failed");
321                 return TDM_ERROR_BAD_MODULE;
322         }
323
324         return TDM_ERROR_NONE;
325 }
326
327 static tdm_error
328 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
329                                                                 tdm_output *output_backend, tdm_caps_output *caps)
330 {
331         tdm_func_output *func_output = &private_display->func_output;
332         char temp[TDM_NAME_LEN];
333         tdm_error ret;
334         double stamp;
335
336         if (!func_output->output_get_capability) {
337                 TDM_ERR("no output_get_capability()");
338                 return TDM_ERROR_BAD_MODULE;
339         }
340
341         stamp = tdm_helper_get_time();
342         ret = func_output->output_get_capability(output_backend, caps);
343         TDM_DBG("backend output_get_capability() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
344
345         if (ret != TDM_ERROR_NONE) {
346                 TDM_ERR("output_get_capability() failed");
347                 return TDM_ERROR_BAD_MODULE;
348         }
349
350         /* FIXME: Use model for tdm client to distinguish amoung outputs */
351         snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
352         snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
353
354         return TDM_ERROR_NONE;
355 }
356
357 static tdm_error
358 _tdm_display_update_layer(tdm_private_display *private_display,
359                                                   tdm_private_output *private_output,
360                                                   tdm_layer *layer_backend, int index)
361 {
362         tdm_private_layer *private_layer;
363         tdm_error ret;
364
365         private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
366         if (!private_layer) {
367                 private_layer = calloc(1, sizeof(tdm_private_layer));
368                 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
369
370                 LIST_ADDTAIL(&private_layer->link, &private_output->layer_list);
371                 private_layer->index = index;
372                 private_layer->private_display = private_display;
373                 private_layer->private_output = private_output;
374                 private_layer->layer_backend = layer_backend;
375
376                 LIST_INITHEAD(&private_layer->capture_list);
377
378                 private_layer->usable = 1;
379         } else
380                 _tdm_display_destroy_caps_layer(&private_layer->caps);
381
382         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
383                                                                                  &private_layer->caps);
384         if (ret != TDM_ERROR_NONE)
385                 goto failed_update;
386
387         return TDM_ERROR_NONE;
388 failed_update:
389         _tdm_display_destroy_private_layer(private_layer);
390         return ret;
391 }
392
393 INTERN tdm_error
394 tdm_display_update_output(tdm_private_display *private_display,
395                                                   tdm_output *output_backend, int pipe)
396 {
397         tdm_func_output *func_output = &private_display->func_output;
398         tdm_private_output *private_output = NULL;
399         tdm_layer **layers = NULL;
400         int layer_count = 0, i;
401         tdm_error ret;
402
403         private_output = _tdm_display_find_private_output(private_display, output_backend);
404         if (!private_output) {
405                 private_output = calloc(1, sizeof(tdm_private_output));
406                 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
407
408                 private_output->stamp = tdm_helper_get_time();
409                 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
410                         private_output->stamp++;
411
412                 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
413
414                 private_output->private_display = private_display;
415                 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
416                 private_output->output_backend = output_backend;
417                 private_output->pipe = pipe;
418                 private_output->index = pipe;
419
420                 LIST_INITHEAD(&private_output->layer_list);
421                 LIST_INITHEAD(&private_output->hwc_window_list);
422                 LIST_INITHEAD(&private_output->capture_list);
423                 LIST_INITHEAD(&private_output->vblank_handler_list);
424                 LIST_INITHEAD(&private_output->output_commit_handler_list);
425                 LIST_INITHEAD(&private_output->layer_commit_handler_list);
426                 LIST_INITHEAD(&private_output->pending_commit_handler_list);
427                 LIST_INITHEAD(&private_output->change_handler_list_main);
428                 LIST_INITHEAD(&private_output->change_handler_list_sub);
429
430                 if (func_output->output_set_status_handler) {
431                         func_output->output_set_status_handler(private_output->output_backend,
432                                                                                                    tdm_output_cb_status,
433                                                                                                    private_output);
434                         private_output->regist_change_cb = 1;
435                 }
436
437                 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
438                                                                                           &private_output->caps);
439                 if (ret != TDM_ERROR_NONE)
440                         return ret;
441         } else {
442                 tdm_caps_output new_caps;
443
444                 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
445                                                                                           &new_caps);
446                 if (ret != TDM_ERROR_NONE)
447                         return ret;
448
449                 /* FIXME: This is very ugly. need to fix after the TDM ABI is changed. */
450                 if (private_output->caps.status != new_caps.status) {
451                         _tdm_display_destroy_caps_output(&private_output->caps);
452                         private_output->caps = new_caps;
453                         private_output->current_mode = NULL;
454                 } else {
455                         tdm_output_mode *old_modes = private_output->caps.modes;
456                         unsigned int old_mode_count = private_output->caps.mode_count;
457                         if (new_caps.modes)
458                                 free(new_caps.modes);
459                         new_caps.modes = old_modes;
460                         new_caps.mode_count = old_mode_count;
461                         if (private_output->caps.props)
462                                 free(private_output->caps.props);
463                         private_output->caps = new_caps;
464                 }
465         }
466
467         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
468         if (ret != TDM_ERROR_NONE)
469                 goto failed_update;
470
471         for (i = 0; i < layer_count; i++) {
472                 ret = _tdm_display_update_layer(private_display, private_output, layers[i], i);
473                 if (ret != TDM_ERROR_NONE)
474                         goto failed_update;
475         }
476
477         free(layers);
478
479         return TDM_ERROR_NONE;
480 failed_update:
481         _tdm_display_destroy_private_output(private_output);
482         free(layers);
483         return ret;
484 }
485
486 static tdm_output **
487 _tdm_display_set_main_first(tdm_output **outputs, int index)
488 {
489         tdm_output *output_tmp = NULL;
490
491         if (index == 0)
492                 return outputs;
493
494         output_tmp = outputs[0];
495         outputs[0] = outputs[index];
496         outputs[index] = output_tmp;
497
498         return outputs;
499 }
500
501 static tdm_output **
502 _tdm_display_get_ordered_outputs(tdm_private_display *private_display, int *count)
503 {
504         tdm_func_display *func_display = &private_display->func_display;
505         tdm_output **outputs = NULL;
506         tdm_output **new_outputs = NULL;
507         tdm_output *output_dsi = NULL;
508         tdm_output *output_lvds = NULL;
509         tdm_output *output_hdmia = NULL;
510         tdm_output *output_hdmib = NULL;
511         int i, output_count = 0, output_connected_count = 0;
512         int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
513         tdm_error ret;
514
515         /* don't change list order if not init time */
516         if (private_display->outputs)
517                 return private_display->outputs;
518
519         outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
520         if (ret != TDM_ERROR_NONE)
521                 goto failed_get_outputs;
522
523         *count = output_count;
524
525         if (output_count == 0)
526                 goto failed_get_outputs;
527         else if (output_count == 1) {
528                 private_display->outputs = outputs;
529                 return outputs;
530         }
531
532         /* count connected outputs */
533         for (i = 0; i < output_count; i++) {
534                 tdm_func_output *func_output = &private_display->func_output;
535                 tdm_caps_output caps;
536                 memset(&caps, 0, sizeof(tdm_caps_output));
537
538                 if (!func_output->output_get_capability) {
539                         TDM_ERR("no output_get_capability()");
540                         goto failed_get_outputs;
541                 }
542
543                 ret = func_output->output_get_capability(outputs[i], &caps);
544                 if (ret != TDM_ERROR_NONE) {
545                         TDM_ERR("output_get_capability() failed");
546                         goto failed_get_outputs;
547                 }
548
549                 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
550                         output_connected_count++;
551
552                         switch (caps.type) {
553                         case TDM_OUTPUT_TYPE_DSI:
554                                 output_dsi = outputs[i];
555                                 index_dsi = i;
556                                 break;
557                         case TDM_OUTPUT_TYPE_LVDS:
558                                 output_lvds = outputs[i];
559                                 index_lvds = i;
560                                 break;
561                         case TDM_OUTPUT_TYPE_HDMIA:
562                                 output_hdmia = outputs[i];
563                                 index_hdmia = i;
564                                 break;
565                         case TDM_OUTPUT_TYPE_HDMIB:
566                                 output_hdmib = outputs[i];
567                                 index_hdmib = i;
568                                 break;
569                         default:
570                                 break;
571                         }
572                 }
573
574                 _tdm_display_destroy_caps_output(&caps);
575         }
576
577         /* ordering : main output is first */
578         /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
579           * But hdmi is possible, so set hdmi to main display.
580           * If connected only one output, it is main output.
581           * If connected outputs over 2, has priority like below.
582           * (dsi > lvds > hdmi > else)
583           */
584         if (output_connected_count == 0) {
585                 /* hdmi > dsi > lvds > else */
586                 if (output_hdmia != NULL)
587                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
588                 else if (output_hdmib != NULL)
589                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
590                 else if (output_dsi != NULL)
591                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
592                 else if (output_lvds != NULL)
593                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
594                 else
595                         new_outputs = outputs;
596         } else { /* (output_connected_count > 1) */
597                 /* dsi > lvds > hdmi > else */
598                 if (output_dsi != NULL)
599                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
600                 else if (output_lvds != NULL)
601                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
602                 else if (output_hdmia != NULL)
603                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
604                 else if (output_hdmib != NULL)
605                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
606                 else
607                         new_outputs = outputs;
608         }
609
610         private_display->outputs = new_outputs;
611
612         return new_outputs;
613
614 failed_get_outputs:
615         free(outputs);
616         *count = 0;
617         return NULL;
618 }
619
620 static tdm_error
621 _tdm_display_update_internal(tdm_private_display *private_display,
622                                                          int only_display)
623 {
624         tdm_output **outputs = NULL;
625         int output_count = 0, i;
626         tdm_error ret = TDM_ERROR_NONE;
627
628         LIST_INITHEAD(&private_display->output_list);
629         LIST_INITHEAD(&private_display->pp_list);
630         LIST_INITHEAD(&private_display->capture_list);
631
632         if (!only_display) {
633                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
634                 if (ret != TDM_ERROR_NONE)
635                         goto failed_update;
636
637                 ret = _tdm_display_update_caps_capture(private_display,
638                                                                                            &private_display->caps_capture);
639                 if (ret != TDM_ERROR_NONE)
640                         goto failed_update;
641         }
642
643         outputs = _tdm_display_get_ordered_outputs(private_display, &output_count);
644         if (!outputs)
645                 goto failed_update;
646
647         for (i = 0; i < output_count; i++) {
648                 ret = tdm_display_update_output(private_display, outputs[i], i);
649                 if (ret != TDM_ERROR_NONE)
650                         goto failed_update;
651         }
652
653         return TDM_ERROR_NONE;
654
655 failed_update:
656         _tdm_display_destroy_private_display(private_display);
657         return ret;
658 }
659 /* LCOV_EXCL_STOP */
660
661 EXTERN tdm_error
662 tdm_display_update(tdm_display *dpy)
663 {
664         tdm_private_display *private_display;
665         tdm_error ret;
666
667         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
668         TDM_RETURN_VAL_IF_FAIL(tdm_display_is_valid(dpy), TDM_ERROR_INVALID_PARAMETER);
669
670         private_display = dpy;
671         _pthread_mutex_lock(&private_display->lock);
672
673         ret = _tdm_display_update_internal(private_display, 1);
674
675         _pthread_mutex_unlock(&private_display->lock);
676
677         return ret;
678 }
679
680 #define SUFFIX_MODULE    ".so"
681 #define TDM_DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
682 #define TDM_DUMMY_MODULE     "libtdm-dummy"SUFFIX_MODULE
683
684 int tdm_debug_module;
685 int tdm_debug_dump;
686 int tdm_ttrace_module;
687 int tdm_ttrace_output;
688
689 static tdm_private_display *g_private_display;
690 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
691
692 /* LCOV_EXCL_START */
693 static tdm_error
694 _tdm_display_check_module(tdm_backend_module *module)
695 {
696         int major, minor;
697
698         TDM_INFO("TDM ABI version : %d.%d",
699                          TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
700
701         if (!module->name) {
702                 TDM_ERR("TDM backend doesn't have name");
703                 return TDM_ERROR_BAD_MODULE;
704         }
705
706         if (!module->vendor) {
707                 TDM_ERR("TDM backend doesn't have vendor");
708                 return TDM_ERROR_BAD_MODULE;
709         }
710
711         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
712         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
713
714         TDM_INFO("TDM module name: %s", module->name);
715         TDM_INFO("'%s' vendor: %s", module->name, module->vendor);
716         TDM_INFO("'%s' version: %d.%d", module->name, major, minor);
717
718         if (major != TDM_MAJOR_VERSION) {
719                 TDM_ERR("'%s' major version mismatch, %d != %d",
720                                 module->name, major, TDM_MAJOR_VERSION);
721                 return TDM_ERROR_BAD_MODULE;
722         }
723
724         if (minor > TDM_MINOR_VERSION) {
725                 TDM_ERR("'%s' minor version(%d) is newer than %d",
726                                 module->name, minor, TDM_MINOR_VERSION);
727                 return TDM_ERROR_BAD_MODULE;
728         }
729
730         if (!module->init) {
731                 TDM_ERR("'%s' doesn't have init function", module->name);
732                 return TDM_ERROR_BAD_MODULE;
733         }
734
735         if (!module->deinit) {
736                 TDM_ERR("'%s' doesn't have deinit function", module->name);
737                 return TDM_ERROR_BAD_MODULE;
738         }
739
740         return TDM_ERROR_NONE;
741 }
742
743 static tdm_error
744 _tdm_display_check_backend_functions(tdm_private_display *private_display)
745 {
746         tdm_func_display *func_display = &private_display->func_display;
747         tdm_func_output *func_output = &private_display->func_output;
748         tdm_func_layer *func_layer = &private_display->func_layer;
749         tdm_error ret;
750
751         /* below functions should be implemented in backend side */
752
753         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
754         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
755         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
756         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
757         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
758
759         ret = func_display->display_get_capability(private_display->bdata, &private_display->caps_display);
760         if (ret != TDM_ERROR_NONE) {
761                 TDM_ERR("display_get_capability() failed");
762                 return TDM_ERROR_BAD_MODULE;
763         }
764
765         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
766                 tdm_func_pp *func_pp = &private_display->func_pp;
767                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
768                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
769                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
770                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
771                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
772         }
773
774         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
775                 tdm_func_capture *func_capture = &private_display->func_capture;
776                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
777                 if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)
778                         TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
779                 if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)
780                         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
781                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
782                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
783                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
784         }
785
786         return TDM_ERROR_NONE;
787 }
788
789 static tdm_error
790 _tdm_display_load_module_with_file(tdm_private_display *private_display,
791                                                                    const char *file)
792 {
793         char path[PATH_MAX] = {0,};
794         tdm_backend_module *module_data;
795         void *module;
796         tdm_error ret;
797         double stamp;
798         int size;
799
800         size = snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
801         if (size >= (int)sizeof(path)) {
802                 TDM_WRN("too long: %s/%s", TDM_MODULE_PATH, file);
803                 return TDM_ERROR_BAD_MODULE;
804         };
805
806         stamp = tdm_helper_get_time();
807
808         TDM_TRACE_BEGIN("TDM_Load_Backend");
809         module = dlopen(path, RTLD_LAZY);
810         if (!module) {
811                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
812                 TDM_TRACE_END();
813                 return TDM_ERROR_BAD_MODULE;
814         }
815
816         module_data = dlsym(module, "tdm_backend_module_data");
817         if (!module_data) {
818                 TDM_ERR("'%s' doesn't have data object", file);
819                 ret = TDM_ERROR_BAD_MODULE;
820                 TDM_TRACE_END();
821                 goto failed_load;
822         }
823         TDM_TRACE_END();
824
825         TDM_DBG("dlopen, dlsym time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
826
827         private_display->module_data = module_data;
828         private_display->module = module;
829
830         /* check if version, init() and deinit() are valid or not */
831         ret = _tdm_display_check_module(module_data);
832         if (ret != TDM_ERROR_NONE)
833                 goto failed_load;
834
835         /* We don't care if backend_data is NULL or not. It's up to backend. */
836         TDM_TRACE_BEGIN("TDM_Init_Backend");
837         stamp = tdm_helper_get_time();
838         private_display->bdata = module_data->init((tdm_display *)private_display, &ret);
839         TDM_DBG("backend init() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
840         TDM_TRACE_END();
841
842         if (ret != TDM_ERROR_NONE) {
843                 TDM_ERR("failed to init '%s' module", module_data->name);
844                 goto failed_load;
845         }
846
847         ret = _tdm_display_check_backend_functions(private_display);
848         if (ret != TDM_ERROR_NONE) {
849                 module_data->deinit(private_display->bdata);
850                 private_display->bdata = NULL;
851                 goto failed_load;
852         }
853
854         TDM_INFO("Success to load '%s' module", module_data->name);
855
856         return TDM_ERROR_NONE;
857 failed_load:
858         dlclose(module);
859         private_display->module_data = NULL;
860         private_display->module = NULL;
861         return ret;
862 }
863
864 static tdm_error
865 _tdm_display_load_module(tdm_private_display *private_display)
866 {
867         const char *module_name;
868         struct dirent **namelist;
869         int n, len;
870         tdm_error ret = 0;
871
872         module_name = getenv("TDM_MODULE");
873         if (!module_name)
874                 module_name = TDM_DEFAULT_MODULE;
875
876         len = strlen(module_name);
877         if (len > TDM_NAME_LEN - 1) {
878                 TDM_ERR("TDM_MODULE is too long\n");
879                 return TDM_ERROR_OPERATION_FAILED;
880         }
881
882         /* load bufmgr priv from default lib */
883         ret = _tdm_display_load_module_with_file(private_display, module_name);
884         if (ret == TDM_ERROR_NONE)
885                 return TDM_ERROR_NONE;
886
887         /* load bufmgr priv from dummy lib */
888         ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE);
889         if (ret == TDM_ERROR_NONE)
890                 return TDM_ERROR_NONE;
891
892         /* load bufmgr priv from configured path */
893         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
894         if (n < 0) {
895                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
896                 return TDM_ERROR_BAD_MODULE;
897         }
898
899         ret = TDM_ERROR_BAD_MODULE;
900         while (n--) {
901                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
902                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
903
904                 free(namelist[n]);
905         }
906         free(namelist);
907
908         return ret;
909 }
910
911 static void
912 _tdm_display_unload_module(tdm_private_display *private_display)
913 {
914         if (private_display->module_data)
915                 private_display->module_data->deinit(private_display->bdata);
916         if (private_display->module)
917                 dlclose(private_display->module);
918
919         private_display->bdata = NULL;
920         private_display->module_data = NULL;
921         private_display->module = NULL;
922 }
923 /* LCOV_EXCL_STOP */
924
925 EXTERN tdm_display *
926 tdm_display_init(tdm_error *error)
927 {
928         tdm_private_display *private_display = NULL;
929         const char *str;
930         tdm_error ret;
931         double stamp1, stamp2, start;
932
933         pthread_mutex_lock(&gLock);
934
935         if (g_private_display) {
936                 g_private_display->init_count++;
937                 pthread_mutex_unlock(&gLock);
938                 if (error)
939                         *error = TDM_ERROR_NONE;
940                 return g_private_display;
941         }
942
943         start = stamp1 = tdm_helper_get_time();
944
945         private_display = calloc(1, sizeof(tdm_private_display));
946         if (!private_display) {
947                 /* LCOV_EXCL_START */
948                 ret = TDM_ERROR_OUT_OF_MEMORY;
949                 TDM_ERR("'private_display != NULL' failed");
950                 goto failed_alloc;
951                 /* LCOV_EXCL_STOP */
952         }
953
954         str = getenv("TDM_DEBUG_MODULE");
955         if (str)
956                 tdm_display_enable_debug_module(str);
957
958         str = getenv("TDM_DEBUG_DUMP");
959         if (str)
960                 tdm_display_enable_dump(private_display, str, NULL, NULL);
961
962         str = getenv("TDM_DEBUG_PATH");
963         if (str)
964                 tdm_display_enable_path(str);
965
966         if (pthread_mutex_init(&private_display->lock, NULL)) {
967                 /* LCOV_EXCL_START */
968                 ret = TDM_ERROR_OPERATION_FAILED;
969                 TDM_ERR("mutex init failed: %m");
970                 goto failed_mutex_init;
971                 /* LCOV_EXCL_STOP */
972         }
973
974         _pthread_mutex_lock(&private_display->lock);
975
976         stamp2 = tdm_helper_get_time();
977         TDM_DBG("prepare init time: %.3f ms", (stamp2 - stamp1) * 1000.0);
978         stamp1 = stamp2;
979
980         ret = tdm_event_loop_init(private_display);
981         if (ret != TDM_ERROR_NONE)
982                 goto failed_event;
983
984         stamp2 = tdm_helper_get_time();
985         TDM_DBG("creating event loop time: %.3f ms", (stamp2 - stamp1) * 1000.0);
986         stamp1 = stamp2;
987
988         ret = _tdm_display_load_module(private_display);
989         if (ret != TDM_ERROR_NONE)
990                 goto failed_load;
991
992         stamp2 = tdm_helper_get_time();
993         TDM_DBG("loading backend time: %.3f ms", (stamp2 - stamp1) * 1000.0);
994         stamp1 = stamp2;
995
996 #ifdef INIT_BUFMGR
997         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
998         if (tdm_drm_fd >= 0) {
999                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
1000                 close(tdm_drm_fd);
1001                 if (!private_display->bufmgr) {
1002                         TDM_ERR("tbm_bufmgr_init failed");
1003                         goto failed_update;
1004                 } else {
1005                         TDM_INFO("tbm_bufmgr_init successed");
1006                 }
1007
1008                 stamp2 = tdm_helper_get_time();
1009                 TDM_DBG("initializing bufmgr time: %.3f ms", (stamp2 - stamp1) * 1000.0);
1010                 stamp1 = stamp2;
1011         }
1012 #endif
1013
1014         TDM_TRACE_BEGIN("TDM_Update_Display");
1015         ret = _tdm_display_update_internal(private_display, 0);
1016         TDM_TRACE_END();
1017         if (ret != TDM_ERROR_NONE)
1018                 goto failed_update;
1019
1020         stamp2 = tdm_helper_get_time();
1021         TDM_DBG("updating display time: %.3f ms", (stamp2 - stamp1) * 1000.0);
1022         stamp1 = stamp2;
1023
1024         tdm_event_loop_create_backend_source(private_display);
1025
1026         private_display->init_count = 1;
1027         g_private_display = private_display;
1028
1029         tdm_private_output *o = NULL;
1030         LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) {
1031                 if (o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)
1032                         tdm_output_need_validate_event_init(o);
1033         }
1034
1035         /* the COMMIT_PER_VBLANK functionality is ability of an output to support
1036          * several operational modes (commit_per_vblank modes) related to tdm_commit;
1037          * this functionality can be turned off which means a default mode */
1038         str = getenv("TDM_COMMIT_PER_VBLANK");
1039         if (str) {
1040                 tdm_private_output *o = NULL;
1041                 char *end;
1042                 int mode = strtol(str, &end, 10);
1043
1044                 /* outputs which support hwc capability can work only
1045                  * if commit_per_vblank mode is '0' (default mode) */
1046                 LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link)
1047                         if (!(o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC))
1048                                 tdm_output_choose_commit_per_vblank_mode(o, mode);
1049         }
1050
1051         if (error)
1052                 *error = TDM_ERROR_NONE;
1053
1054         _pthread_mutex_unlock(&private_display->lock);
1055         pthread_mutex_unlock(&gLock);
1056
1057         TDM_INFO("init time: %.3f ms", (tdm_helper_get_time() - start) * 1000.0);
1058
1059         return (tdm_display *)private_display;
1060
1061 /* LCOV_EXCL_START */
1062 failed_update:
1063         _tdm_display_unload_module(private_display);
1064 failed_load:
1065         tdm_event_loop_stop(private_display);
1066         tdm_event_loop_deinit(private_display);
1067 failed_event:
1068         _pthread_mutex_unlock(&private_display->lock);
1069         pthread_mutex_destroy(&private_display->lock);
1070 failed_mutex_init:
1071         free(private_display);
1072 failed_alloc:
1073         if (error)
1074                 *error = ret;
1075         pthread_mutex_unlock(&gLock);
1076         return NULL;
1077 /* LCOV_EXCL_STOP */
1078 }
1079
1080 EXTERN void
1081 tdm_display_deinit(tdm_display *dpy)
1082 {
1083         tdm_private_display *private_display = dpy;
1084
1085         if (!private_display)
1086                 return;
1087
1088         TDM_RETURN_IF_FAIL(tdm_display_is_valid(dpy));
1089
1090         pthread_mutex_lock(&gLock);
1091
1092         private_display->init_count--;
1093         if (private_display->init_count > 0) {
1094                 pthread_mutex_unlock(&gLock);
1095                 return;
1096         }
1097
1098         /* dont move the position of lock/unlock. all resource should be protected
1099          * during destroying. after tdm_event_loop_deinit, we don't worry about thread
1100          * things because it's finalized.
1101          */
1102         _pthread_mutex_lock(&private_display->lock);
1103         tdm_event_loop_stop(private_display);
1104         _tdm_display_destroy_private_display(private_display);
1105         _tdm_display_unload_module(private_display);
1106         _pthread_mutex_unlock(&private_display->lock);
1107
1108         tdm_event_loop_deinit(private_display);
1109
1110 #ifdef INIT_BUFMGR
1111         if (private_display->bufmgr)
1112                 tbm_bufmgr_deinit(private_display->bufmgr);
1113 #endif
1114
1115         tbm_drm_helper_unset_tbm_master_fd();
1116
1117         pthread_mutex_destroy(&private_display->lock);
1118         free(private_display);
1119         g_private_display = NULL;
1120
1121         if (tdm_debug_dump_dir) {
1122                 free(tdm_debug_dump_dir);
1123                 tdm_debug_dump_dir = NULL;
1124         }
1125
1126         pthread_mutex_unlock(&gLock);
1127
1128         TDM_INFO("done");
1129 }
1130
1131 INTERN int
1132 tdm_display_is_valid(tdm_display *dpy)
1133 {
1134         if (dpy != NULL && dpy == g_private_display)
1135                 return 1;
1136         return 0;
1137 }
1138
1139 INTERN int
1140 tdm_output_is_valid(tdm_output *output)
1141 {
1142         tdm_private_output *o = NULL, *private_output = output;
1143         if (output && g_private_display)
1144                 LIST_FOR_EACH_ENTRY(o, &g_private_display->output_list, link)
1145                         if (o == private_output)
1146                                 return 1;
1147         return 0;
1148 }
1149
1150 /* LCOV_EXCL_START */
1151 INTERN int
1152 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1153 {
1154         tdm_backend_module *module = private_display->module_data;
1155
1156         if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1157                 return 0;
1158
1159         if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1160                 return 0;
1161
1162         return 1;
1163 }
1164
1165 INTERN tdm_error
1166 tdm_display_enable_debug_module(const char*modules)
1167 {
1168         char temp[TDM_PATH_LEN];
1169         char *arg;
1170         char *end;
1171
1172         snprintf(temp, TDM_PATH_LEN, "%s", modules);
1173
1174         tdm_debug_module = 0;
1175
1176         arg = strtok_r(temp, TDM_DELIM, &end);
1177         while (arg) {
1178                 if (!strncmp(arg, "none", 4)) {
1179                         tdm_debug_module = 0;
1180                         return TDM_ERROR_NONE;
1181                 }
1182                 if (!strncmp(arg, "all", 3)) {
1183                         tdm_debug_module = 0xFFFFFFFF;
1184                         return TDM_ERROR_NONE;
1185                 }
1186                 if (!strncmp(arg, "buffer", 6))
1187                         tdm_debug_module |= TDM_DEBUG_BUFFER;
1188                 else if (!strncmp(arg, "thread", 6))
1189                         tdm_debug_module |= TDM_DEBUG_THREAD;
1190                 else if (!strncmp(arg, "mutex", 5))
1191                         tdm_debug_module |= TDM_DEBUG_MUTEX;
1192                 else if (!strncmp(arg, "vblank", 6))
1193                         tdm_debug_module |= TDM_DEBUG_VBLANK;
1194                 else if (!strncmp(arg, "commit", 6))
1195                         tdm_debug_module |= TDM_DEBUG_COMMIT;
1196
1197                 arg = strtok_r(NULL, TDM_DELIM, &end);
1198         }
1199
1200         TDM_INFO("module debugging... '%s'", modules);
1201
1202         return TDM_ERROR_NONE;
1203 }
1204
1205 INTERN tdm_error
1206 tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_str, char *reply, int *len)
1207 {
1208         char temp[TDM_PATH_LEN] = {0,}, temp2[TDM_PATH_LEN] = {0,};
1209         char *path = NULL, *path2;
1210         char *arg;
1211         char *end;
1212
1213         snprintf(temp2, TDM_PATH_LEN, "%s", dump_str);
1214         path2 = strtostr(temp, TDM_PATH_LEN, temp2, "@");
1215         if (!path2 || path2[0] == '\0')
1216                 path2 = TDM_DUMP_DIR;
1217         else
1218                 path2++;
1219
1220         tdm_debug_dump = 0;
1221
1222         snprintf(temp, sizeof(temp), "%s", dump_str);
1223         arg = strtok_r(temp, ",", &end);
1224         TDM_GOTO_IF_FAIL(arg != NULL, done);
1225
1226         if (!strncmp(arg, "none", 4)) {
1227                 tdm_debug_dump = 0;
1228                 TDM_SNPRINTF(reply, len, "path: %s\n", (tdm_debug_dump_dir) ? : "unknown");
1229                 if (tdm_debug_dump_dir) {
1230                         free(tdm_debug_dump_dir);
1231                         tdm_debug_dump_dir = NULL;
1232                 }
1233                 goto done;
1234         }
1235
1236         path = tdm_helper_dump_make_directory(path2, reply, len);
1237         TDM_GOTO_IF_FAIL(path != NULL, done);
1238
1239         if (!strncmp(arg, "current", 7)) {
1240                 tdm_private_output *o = NULL;
1241                 if (!private_display) {
1242                         TDM_WRN("no private_display");
1243                         goto done;
1244                 }
1245
1246                 LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) {
1247                         tdm_private_layer *l = NULL;
1248                         LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1249                                 char str[TDM_PATH_LEN];
1250                                 if (l->usable || l->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)
1251                                         continue;
1252                                 if (!l->showing_buffer)
1253                                         continue;
1254                                 snprintf(str, TDM_PATH_LEN, "layer_%d_%d", o->index, l->index);
1255                                 tdm_helper_dump_buffer_str(l->showing_buffer->buffer, path, str);
1256                         }
1257                 }
1258
1259                 TDM_SNPRINTF(reply, len, "path: %s\n", path);
1260                 goto done;
1261         }
1262
1263         TDM_SNPRINTF(reply, len, "dump: %s\n", arg);
1264
1265         while (arg) {
1266                 if (!strncmp(arg, "all", 3)) {
1267                         tdm_debug_dump = 0xFFFFFFFF;
1268                         goto done;
1269                 } else if (!strncmp(arg, "layer", 5)) {
1270                         tdm_debug_dump |= TDM_DUMP_FLAG_LAYER;
1271                 } else if (!strncmp(arg, "pp", 2)) {
1272                         tdm_debug_dump |= TDM_DUMP_FLAG_PP;
1273                 } else if (!strncmp(arg, "capture", 7)) {
1274                         tdm_debug_dump |= TDM_DUMP_FLAG_CAPTURE;
1275                 } else if (!strncmp(arg, "window", 6)) {
1276                         tdm_debug_dump |= TDM_DUMP_FLAG_WINDOW;
1277                 } else
1278                         goto done;
1279
1280                 arg = strtok_r(NULL, ",", &end);
1281         }
1282
1283         if (tdm_debug_dump_dir)
1284                 free(tdm_debug_dump_dir);
1285
1286         tdm_debug_dump_dir = strndup(path, TDM_PATH_LEN);
1287
1288         TDM_INFO("dump... '%s'", dump_str);
1289
1290 done:
1291         if (path)
1292                 free(path);
1293
1294         return TDM_ERROR_NONE;
1295 }
1296
1297 INTERN tdm_error
1298 tdm_display_enable_path(const char *path)
1299 {
1300         static int old_stdout = -1;
1301         char fd_name[TDM_PATH_LEN];
1302         int  log_fd = -1;
1303         FILE *log_fl;
1304
1305         if (old_stdout == -1)
1306                 old_stdout = dup(STDOUT_FILENO);
1307
1308         tdm_log_enable_dlog(0);
1309
1310         snprintf(fd_name, TDM_PATH_LEN, "%s", path);
1311
1312         log_fl = fopen(fd_name, "a");
1313         if (!log_fl) {
1314                 TDM_ERR("failed: open file(%s)\n", fd_name);
1315                 return TDM_ERROR_OPERATION_FAILED;
1316         }
1317
1318         fflush(stderr);
1319         close(STDOUT_FILENO);
1320
1321         setvbuf(log_fl, NULL, _IOLBF, 512);
1322         log_fd = fileno(log_fl);
1323
1324         dup2(log_fd, STDOUT_FILENO);
1325         fclose(log_fl);
1326
1327         return TDM_ERROR_NONE;
1328 }
1329
1330 static void
1331 _tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
1332                                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
1333 {
1334         tdm_error ret = TDM_ERROR_NONE;
1335
1336         TDM_TRACE_MARK("VSYNC");
1337
1338         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
1339         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
1340 }
1341
1342 INTERN tdm_error
1343 tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable)
1344 {
1345         tdm_private_display *private_display = dpy;
1346         tdm_private_output *private_output = NULL;
1347         const tdm_output_mode *mode = NULL;
1348         tdm_vblank *vblank = NULL;
1349         tdm_error ret = TDM_ERROR_NONE;
1350
1351         if (!enable) {
1352                 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
1353                         if (private_output->ttrace_vblank)
1354                                 tdm_vblank_destroy(private_output->ttrace_vblank);
1355                         private_output->ttrace_vblank = NULL;
1356                 }
1357                 return TDM_ERROR_NONE;
1358         }
1359
1360         private_output = output;
1361         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
1362
1363         if (private_output->ttrace_vblank)
1364                 return TDM_ERROR_NONE;
1365
1366         vblank = tdm_vblank_create(private_display, output, &ret);
1367         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret);
1368
1369         ret = tdm_output_get_mode(output, &mode);
1370         TDM_GOTO_IF_FAIL(mode != NULL, enable_fail);
1371
1372         ret = tdm_vblank_set_fps(vblank, mode->vrefresh);
1373         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1374
1375         ret = tdm_vblank_set_enable_fake(vblank, 1);
1376         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1377
1378         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
1379         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1380
1381         private_output->ttrace_vblank = vblank;
1382
1383         return TDM_ERROR_NONE;
1384
1385 enable_fail:
1386         if (vblank)
1387                 tdm_vblank_destroy(vblank);
1388
1389         return ret;
1390 }
1391
1392 INTERN tdm_error
1393 tdm_display_enable_ttrace(tdm_private_display *private_display, const char *ttrace, int output_id, char *reply, int *len)
1394 {
1395         char temp[TDM_PATH_LEN];
1396         char *arg;
1397         char *end;
1398         tdm_output *output;
1399         tdm_error ret;
1400         tdm_output_type type;
1401
1402         snprintf(temp, TDM_PATH_LEN, "%s", ttrace);
1403
1404         tdm_ttrace_output = output_id;
1405         tdm_ttrace_module = 0;
1406
1407         output = tdm_display_get_output(private_display, output_id, &ret);
1408         if (!output) {
1409                 TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id);
1410                 return ret;
1411         }
1412
1413         ret = tdm_output_get_output_type(output, &type);
1414         if (ret != TDM_ERROR_NONE) {
1415                 TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id);
1416                 return ret;
1417         }
1418
1419         arg = strtok_r(temp, TDM_DELIM, &end);
1420         while (arg) {
1421                 if (!strncmp(arg, "none", 4))
1422                         tdm_ttrace_module = 0;
1423                 else if (!strncmp(arg, "all", 3))
1424                         tdm_ttrace_module = 0xFFFFFFFF;
1425                 else if (!strncmp(arg, "vblank", 6))
1426                         tdm_ttrace_module |= TDM_TTRACE_VBLANK;
1427                 else if (!strncmp(arg, "client", 6))
1428                         tdm_ttrace_module |= TDM_TTRACE_CLIENT;
1429                 else if (!strncmp(arg, "layer", 5))
1430                         tdm_ttrace_module |= TDM_TTRACE_LAYER;
1431                 else if (!strncmp(arg, "pp", 2))
1432                         tdm_ttrace_module |= TDM_TTRACE_PP;
1433                 else if (!strncmp(arg, "capture", 7))
1434                         tdm_ttrace_module |= TDM_TTRACE_CAPTURE;
1435                 else  {
1436                         tdm_ttrace_module = 0;
1437                         tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
1438                         tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
1439                         TDM_SNPRINTF(reply, len, "unknown option: '%s'\n", arg);
1440                         return TDM_ERROR_NONE;
1441                 }
1442
1443                 arg = strtok_r(NULL, TDM_DELIM, &end);
1444         }
1445
1446         TDM_SNPRINTF(reply, len, "ttrace debugging... '%s' %x\n", ttrace, tdm_ttrace_module);
1447
1448         if (tdm_ttrace_module & TDM_TTRACE_VBLANK)
1449                 tdm_display_enable_ttrace_vblank(private_display, output, 1);
1450         else
1451                 tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
1452
1453         if (tdm_ttrace_module & TDM_TTRACE_CLIENT)
1454                 tdm_server_enable_ttrace_client_vblank(private_display, output, 1);
1455         else
1456                 tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
1457
1458         return TDM_ERROR_NONE;
1459 }
1460
1461 INTERN tdm_error
1462 tdm_display_enable_fps(tdm_private_display *private_display, int enable)
1463 {
1464         private_display->print_fps = enable;
1465
1466         TDM_INFO("print fps: %s", (enable) ? "enable" : "disable");
1467
1468         return TDM_ERROR_NONE;
1469 }
1470 /* LCOV_EXCL_STOP */