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