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