set the initial dpms value to be off
[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 static tdm_private_layer *
46 _tdm_display_find_private_layer(tdm_private_output *private_output,
47                                 tdm_layer *layer_backend)
48 {
49         tdm_private_layer *private_layer = NULL;
50
51         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
52                 if (private_layer->layer_backend == layer_backend)
53                         return private_layer;
54         }
55
56         return NULL;
57 }
58
59 static tdm_private_output *
60 _tdm_display_find_private_output(tdm_private_display *private_display,
61                                  tdm_output *output_backend)
62 {
63         tdm_private_output *private_output = NULL;
64
65         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
66                 if (private_output->output_backend == output_backend)
67                         return private_output;
68         }
69
70         return NULL;
71 }
72
73 INTERN tdm_private_output *
74 tdm_display_find_output_stamp(tdm_private_display *private_display,
75                               unsigned long stamp)
76 {
77         tdm_private_output *private_output = NULL;
78
79         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
80                 if (private_output->stamp == stamp)
81                         return private_output;
82         }
83
84         return NULL;
85 }
86
87 static void
88 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
89 {
90         free(caps_pp->formats);
91         memset(caps_pp, 0, sizeof(tdm_caps_pp));
92 }
93
94 static void
95 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
96 {
97         free(caps_capture->formats);
98         memset(caps_capture, 0, sizeof(tdm_caps_capture));
99 }
100
101 static void
102 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
103 {
104         free(caps_layer->formats);
105         free(caps_layer->props);
106         memset(caps_layer, 0, sizeof(tdm_caps_layer));
107 }
108
109 static void
110 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
111 {
112         free(caps_output->modes);
113         free(caps_output->props);
114         memset(caps_output, 0, sizeof(tdm_caps_output));
115 }
116
117 static void
118 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
119 {
120         tdm_private_capture *c = NULL, *cc = NULL;
121
122         LIST_DEL(&private_layer->link);
123
124         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
125         tdm_capture_destroy_internal(c);
126
127         _tdm_display_destroy_caps_layer(&private_layer->caps);
128
129         free(private_layer);
130 }
131
132 static void
133 _tdm_display_destroy_private_output(tdm_private_output *private_output)
134 {
135         tdm_private_layer *l = NULL, *ll = NULL;
136         tdm_private_capture *c = NULL, *cc = NULL;
137         tdm_private_vblank_handler *v = NULL, *vv = NULL;
138         tdm_private_commit_handler *m = NULL, *mm = NULL;
139         tdm_private_change_handler *h = NULL, *hh = NULL;
140
141         LIST_DEL(&private_output->link);
142
143         free(private_output->layers_ptr);
144
145         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
146                 LIST_DEL(&v->link);
147                 free(v);
148         }
149
150         LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
151                 LIST_DEL(&m->link);
152                 free(m);
153         }
154
155         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
156                 LIST_DEL(&h->link);
157                 free(h);
158         }
159
160         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
161                 LIST_DEL(&h->link);
162                 free(h);
163         }
164
165         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
166         tdm_capture_destroy_internal(c);
167
168         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
169         _tdm_display_destroy_private_layer(l);
170
171         _tdm_display_destroy_caps_output(&private_output->caps);
172
173         private_output->stamp = 0;
174         free(private_output);
175 }
176
177 static void
178 _tdm_display_destroy_private_display(tdm_private_display *private_display)
179 {
180         tdm_private_output *o = NULL, *oo = NULL;
181         tdm_private_pp *p = NULL, *pp = NULL;
182
183         free(private_display->outputs_ptr);
184
185         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
186         tdm_pp_destroy_internal(p);
187
188         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
189         _tdm_display_destroy_private_output(o);
190
191         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
192         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
193
194         private_display->capabilities = 0;
195         private_display->caps_display.max_layer_count = -1;
196 }
197
198 static tdm_error
199 _tdm_display_update_caps_pp(tdm_private_display *private_display,
200                             tdm_caps_pp *caps)
201 {
202         tdm_func_display *func_display = &private_display->func_display;
203         char buf[1024];
204         int bufsize = sizeof(buf);
205         char *str_buf = buf;
206         int *len_buf = &bufsize;
207         int i;
208         tdm_error ret;
209
210         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
211                 return TDM_ERROR_NONE;
212
213         if (!func_display->display_get_pp_capability) {
214                 TDM_ERR("no display_get_pp_capability()");
215                 return TDM_ERROR_BAD_MODULE;
216         }
217
218         ret = func_display->display_get_pp_capability(private_display->bdata, caps);
219         if (ret != TDM_ERROR_NONE) {
220                 TDM_ERR("display_get_pp_capability() failed");
221                 return TDM_ERROR_BAD_MODULE;
222         }
223
224         TDM_DBG("pp capabilities: %x", caps->capabilities);
225         buf[0] = '\0';
226         for (i = 0; i < caps->format_count; i++)
227                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
228         TDM_DBG("pp formats: %s", buf);
229         TDM_DBG("pp min  : %dx%d", caps->min_w, caps->min_h);
230         TDM_DBG("pp max  : %dx%d", caps->max_w, caps->max_h);
231         TDM_DBG("pp align: %d", caps->preferred_align);
232
233         return TDM_ERROR_NONE;
234 }
235
236 static tdm_error
237 _tdm_display_update_caps_capture(tdm_private_display *private_display,
238                                  tdm_caps_capture *caps)
239 {
240         tdm_func_display *func_display = &private_display->func_display;
241         char buf[1024];
242         int bufsize = sizeof(buf);
243         char *str_buf = buf;
244         int *len_buf = &bufsize;
245         int i;
246         tdm_error ret;
247
248         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
249                 return TDM_ERROR_NONE;
250
251         if (!func_display->display_get_capture_capability) {
252                 TDM_ERR("no display_get_capture_capability()");
253                 return TDM_ERROR_BAD_MODULE;
254         }
255
256         ret = func_display->display_get_capture_capability(private_display->bdata,
257                         caps);
258         if (ret != TDM_ERROR_NONE) {
259                 TDM_ERR("display_get_capture_capability() failed");
260                 return TDM_ERROR_BAD_MODULE;
261         }
262
263         buf[0] = '\0';
264         for (i = 0; i < caps->format_count; i++)
265                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
266         TDM_DBG("capture formats: %s", buf);
267
268         return TDM_ERROR_NONE;
269 }
270
271 static tdm_error
272 _tdm_display_update_caps_layer(tdm_private_display *private_display,
273                                tdm_layer *layer_backend, tdm_caps_layer *caps)
274 {
275         tdm_func_layer *func_layer = &private_display->func_layer;
276         char buf[1024];
277         int bufsize = sizeof(buf);
278         char *str_buf = buf;
279         int *len_buf = &bufsize;
280         int i;
281         tdm_error ret;
282
283         if (!func_layer->layer_get_capability) {
284                 TDM_ERR("no layer_get_capability()");
285                 return TDM_ERROR_BAD_MODULE;
286         }
287
288         ret = func_layer->layer_get_capability(layer_backend, caps);
289         if (ret != TDM_ERROR_NONE) {
290                 TDM_ERR("layer_get_capability() failed");
291                 return TDM_ERROR_BAD_MODULE;
292         }
293
294         TDM_DBG("layer capabilities: %x", caps->capabilities);
295         TDM_DBG("layer zpos : %d", caps->zpos);
296         buf[0] = '\0';
297         for (i = 0; i < caps->format_count; i++)
298                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
299         TDM_DBG("layer formats: %s", buf);
300         for (i = 0; i < caps->prop_count; i++)
301                 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
302
303         return TDM_ERROR_NONE;
304 }
305
306 static tdm_error
307 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
308                                 tdm_output *output_backend, tdm_caps_output *caps)
309 {
310         tdm_func_output *func_output = &private_display->func_output;
311         char temp[TDM_NAME_LEN];
312         int i;
313         tdm_error ret;
314
315         if (!func_output->output_get_capability) {
316                 TDM_ERR("no output_get_capability()");
317                 return TDM_ERROR_BAD_MODULE;
318         }
319
320         ret = func_output->output_get_capability(output_backend, caps);
321         if (ret != TDM_ERROR_NONE) {
322                 TDM_ERR("output_get_capability() failed");
323                 return TDM_ERROR_BAD_MODULE;
324         }
325
326         /* FIXME: Use model for tdm client to distinguish amoung outputs */
327         snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
328         snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
329
330         TDM_DBG("output maker: %s", caps->maker);
331         TDM_DBG("output model: %s", caps->model);
332         TDM_DBG("output name: %s", caps->name);
333         TDM_DBG("output status: %d", caps->status);
334         TDM_DBG("output type : %d", caps->type);
335         for (i = 0; i < caps->prop_count; i++)
336                 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
337         for (i = 0; i < caps->mode_count; i++) {
338                 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
339                         caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
340                         caps->modes[i].flags, caps->modes[i].type);
341                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
342                         caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
343                         caps->modes[i].htotal, caps->modes[i].hskew);
344                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
345                         caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
346                         caps->modes[i].vtotal, caps->modes[i].vscan);
347         }
348         TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
349         TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
350         TDM_DBG("output align: %d", caps->preferred_align);
351
352         return TDM_ERROR_NONE;
353 }
354
355 static tdm_error
356 _tdm_display_update_layer(tdm_private_display *private_display,
357                           tdm_private_output *private_output,
358                           tdm_layer *layer_backend)
359 {
360         tdm_private_layer *private_layer;
361         tdm_error ret;
362
363         private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
364         if (!private_layer) {
365                 private_layer = calloc(1, sizeof(tdm_private_layer));
366                 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
367
368                 LIST_ADD(&private_layer->link, &private_output->layer_list);
369                 private_layer->private_display = private_display;
370                 private_layer->private_output = private_output;
371                 private_layer->layer_backend = layer_backend;
372
373                 LIST_INITHEAD(&private_layer->capture_list);
374
375                 private_layer->usable = 1;
376         } else
377                 _tdm_display_destroy_caps_layer(&private_layer->caps);
378
379         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
380                                              &private_layer->caps);
381         if (ret != TDM_ERROR_NONE)
382                 goto failed_update;
383
384         return TDM_ERROR_NONE;
385 failed_update:
386         _tdm_display_destroy_private_layer(private_layer);
387         return ret;
388 }
389
390 static tdm_error
391 _tdm_display_update_output(tdm_private_display *private_display,
392                            tdm_output *output_backend, int pipe)
393 {
394         tdm_func_output *func_output = &private_display->func_output;
395         tdm_private_output *private_output = NULL;
396         tdm_layer **layers = NULL;
397         int layer_count = 0, i;
398         tdm_error ret;
399
400         private_output = _tdm_display_find_private_output(private_display,
401                          output_backend);
402         if (!private_output) {
403                 private_output = calloc(1, sizeof(tdm_private_output));
404                 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
405
406                 private_output->stamp = tdm_helper_get_time_in_millis();
407                 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
408                         private_output->stamp++;
409
410                 LIST_ADD(&private_output->link, &private_display->output_list);
411
412                 private_output->private_display = private_display;
413                 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
414                 private_output->output_backend = output_backend;
415                 private_output->pipe = pipe;
416
417                 LIST_INITHEAD(&private_output->layer_list);
418                 LIST_INITHEAD(&private_output->capture_list);
419                 LIST_INITHEAD(&private_output->vblank_handler_list);
420                 LIST_INITHEAD(&private_output->commit_handler_list);
421                 LIST_INITHEAD(&private_output->change_handler_list_main);
422                 LIST_INITHEAD(&private_output->change_handler_list_sub);
423
424                 if (func_output->output_set_status_handler)
425                         func_output->output_set_status_handler(private_output->output_backend,
426                                                                tdm_output_cb_status,
427                                                                private_output);
428
429         } else
430                 _tdm_display_destroy_caps_output(&private_output->caps);
431
432         ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
433                                               &private_output->caps);
434         if (ret != TDM_ERROR_NONE)
435                 return ret;
436
437         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
438         if (ret != TDM_ERROR_NONE)
439                 goto failed_update;
440
441         for (i = 0; i < layer_count; i++) {
442                 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
443                 if (ret != TDM_ERROR_NONE)
444                         goto failed_update;
445         }
446
447         free(layers);
448
449         return TDM_ERROR_NONE;
450 failed_update:
451         _tdm_display_destroy_private_output(private_output);
452         free(layers);
453         return ret;
454 }
455
456 static tdm_error
457 _tdm_display_update_internal(tdm_private_display *private_display,
458                              int only_display)
459 {
460         tdm_func_display *func_display = &private_display->func_display;
461         tdm_output **outputs = NULL;
462         int output_count = 0, i;
463         tdm_error ret;
464
465         LIST_INITHEAD(&private_display->output_list);
466         LIST_INITHEAD(&private_display->pp_list);
467         LIST_INITHEAD(&private_display->capture_list);
468
469         if (!only_display) {
470                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
471                 if (ret != TDM_ERROR_NONE)
472                         goto failed_update;
473
474                 ret = _tdm_display_update_caps_capture(private_display,
475                                                        &private_display->caps_capture);
476                 if (ret != TDM_ERROR_NONE)
477                         goto failed_update;
478         }
479
480         outputs = func_display->display_get_outputs(private_display->bdata,
481                         &output_count, &ret);
482         if (ret != TDM_ERROR_NONE)
483                 goto failed_update;
484
485         for (i = 0; i < output_count; i++) {
486                 ret = _tdm_display_update_output(private_display, outputs[i], i);
487                 if (ret != TDM_ERROR_NONE)
488                         goto failed_update;
489         }
490
491         free(outputs);
492
493         return TDM_ERROR_NONE;
494
495 failed_update:
496         _tdm_display_destroy_private_display(private_display);
497         free(outputs);
498         return ret;
499 }
500
501 EXTERN tdm_error
502 tdm_display_update(tdm_display *dpy)
503 {
504         tdm_private_display *private_display;
505         tdm_error ret;
506
507         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
508
509         private_display = dpy;
510         _pthread_mutex_lock(&private_display->lock);
511
512         ret = _tdm_display_update_internal(private_display, 1);
513
514         _pthread_mutex_unlock(&private_display->lock);
515
516         return ret;
517 }
518
519 #define SUFFIX_MODULE    ".so"
520 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
521
522 int tdm_debug;
523 int tdm_debug_buffer;
524 int tdm_debug_thread;
525 int tdm_debug_mutex;
526
527 static tdm_private_display *g_private_display;
528 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
529
530 static tdm_error
531 _tdm_display_check_module(tdm_backend_module *module)
532 {
533         const char *name;
534         const char *vendor;
535         int major, minor;
536         int abimaj, abimin;
537
538         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
539         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
540
541         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
542
543         name = module->name ? module->name : "unknown";
544         vendor = module->vendor ? module->vendor : "unknown";
545         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
546         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
547
548         TDM_INFO("TDM module name: %s", name);
549         TDM_INFO("'%s' vendor: %s", name, vendor);
550         TDM_INFO("'%s' version: %d.%d", name, major, minor);
551
552         if (major != abimaj) {
553                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
554                 return TDM_ERROR_BAD_MODULE;
555         }
556
557         if (minor > abimin) {
558                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
559                 return TDM_ERROR_BAD_MODULE;
560         }
561
562         if (!module->init) {
563                 TDM_ERR("'%s' doesn't have init function", name);
564                 return TDM_ERROR_BAD_MODULE;
565         }
566
567         if (!module->deinit) {
568                 TDM_ERR("'%s' doesn't have deinit function", name);
569                 return TDM_ERROR_BAD_MODULE;
570         }
571
572         return TDM_ERROR_NONE;
573 }
574
575 static tdm_error
576 _tdm_display_check_backend_functions(tdm_private_display *private_display)
577 {
578         tdm_func_display *func_display = &private_display->func_display;
579         tdm_func_output *func_output = &private_display->func_output;
580         tdm_func_layer *func_layer = &private_display->func_layer;
581         tdm_error ret;
582
583         /* below functions should be implemented in backend side */
584
585         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
586         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
587                                TDM_ERROR_BAD_MODULE);
588         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
589         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
590                                TDM_ERROR_BAD_MODULE);
591         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
592         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
593
594         ret = func_display->display_get_capabilitiy(private_display->bdata,
595                         &private_display->caps_display);
596         if (ret != TDM_ERROR_NONE) {
597                 TDM_ERR("display_get_capabilitiy() failed");
598                 return TDM_ERROR_BAD_MODULE;
599         }
600
601         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
602                 tdm_func_pp *func_pp = &private_display->func_pp;
603                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
604                                        TDM_ERROR_BAD_MODULE);
605                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
606                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
607                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
608                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
609         }
610
611         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
612                 tdm_func_capture *func_capture = &private_display->func_capture;
613                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
614                                        TDM_ERROR_BAD_MODULE);
615                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
616                                        TDM_ERROR_BAD_MODULE);
617                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
618                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
619                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
620                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
621                                        TDM_ERROR_BAD_MODULE);
622         }
623
624         return TDM_ERROR_NONE;
625 }
626
627 static tdm_error
628 _tdm_display_load_module_with_file(tdm_private_display *private_display,
629                                    const char *file)
630 {
631         char path[PATH_MAX] = {0,};
632         tdm_backend_module *module_data;
633         void *module;
634         tdm_error ret;
635
636         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
637
638         TDM_TRACE_BEGIN(Load_Backend);
639
640         module = dlopen(path, RTLD_LAZY);
641         if (!module) {
642                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
643                 TDM_TRACE_END();
644                 return TDM_ERROR_BAD_MODULE;
645         }
646
647         module_data = dlsym(module, "tdm_backend_module_data");
648         if (!module_data) {
649                 TDM_ERR("'%s' doesn't have data object", file);
650                 ret = TDM_ERROR_BAD_MODULE;
651                 TDM_TRACE_END();
652                 goto failed_load;
653         }
654
655         private_display->module_data = module_data;
656         private_display->module = module;
657
658         /* check if version, init() and deinit() are valid or not */
659         ret = _tdm_display_check_module(module_data);
660         if (ret != TDM_ERROR_NONE)
661                 goto failed_load;
662
663         TDM_TRACE_END();
664
665         /* We don't care if backend_data is NULL or not. It's up to backend. */
666         TDM_TRACE_BEGIN(Init_Backend);
667         private_display->bdata = module_data->init((tdm_display *)private_display,
668                                  &ret);
669         TDM_TRACE_END();
670         if (ret != TDM_ERROR_NONE) {
671                 TDM_ERR("'%s' init failed", file);
672                 goto failed_load;
673         }
674
675         ret = _tdm_display_check_backend_functions(private_display);
676         if (ret != TDM_ERROR_NONE) {
677                 module_data->deinit(private_display->bdata);
678                 private_display->bdata = NULL;
679                 goto failed_load;
680         }
681
682         TDM_INFO("Success to load module(%s)", file);
683
684         return TDM_ERROR_NONE;
685 failed_load:
686         dlclose(module);
687         private_display->module_data = NULL;
688         private_display->module = NULL;
689         return ret;
690 }
691
692 static tdm_error
693 _tdm_display_load_module(tdm_private_display *private_display)
694 {
695         const char *module_name;
696         struct dirent **namelist;
697         int n;
698         tdm_error ret = 0;
699
700         module_name = getenv("TDM_MODULE");
701         if (!module_name)
702                 module_name = DEFAULT_MODULE;
703
704         /* load bufmgr priv from default lib */
705         ret = _tdm_display_load_module_with_file(private_display, module_name);
706         if (ret == TDM_ERROR_NONE)
707                 return TDM_ERROR_NONE;
708
709         /* load bufmgr priv from configured path */
710         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
711         if (n < 0) {
712                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
713                 return TDM_ERROR_BAD_MODULE;
714         }
715
716         ret = TDM_ERROR_BAD_MODULE;
717         while (n--) {
718                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
719                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
720
721                 free(namelist[n]);
722         }
723         free(namelist);
724
725         return ret;
726 }
727
728 static void
729 _tdm_display_unload_module(tdm_private_display *private_display)
730 {
731         if (private_display->module_data)
732                 private_display->module_data->deinit(private_display->bdata);
733         if (private_display->module)
734                 dlclose(private_display->module);
735
736         private_display->bdata = NULL;
737         private_display->module_data = NULL;
738         private_display->module = NULL;
739 }
740
741 EXTERN tdm_display *
742 tdm_display_init(tdm_error *error)
743 {
744         tdm_private_display *private_display = NULL;
745         const char *debug;
746         tdm_error ret;
747
748         _pthread_mutex_lock(&gLock);
749
750         if (g_private_display) {
751                 g_private_display->init_count++;
752                 _pthread_mutex_unlock(&gLock);
753                 if (error)
754                         *error = TDM_ERROR_NONE;
755                 return g_private_display;
756         }
757
758         debug = getenv("TDM_DEBUG");
759         if (debug && (strstr(debug, "1")))
760                 tdm_debug = 1;
761
762         debug = getenv("TDM_DEBUG_BUFFER");
763         if (debug && (strstr(debug, "1")))
764                 tdm_debug_buffer = 1;
765
766         debug = getenv("TDM_DEBUG_THREAD");
767         if (debug && (strstr(debug, "1")))
768                 tdm_debug_thread = 1;
769
770         debug = getenv("TDM_DEBUG_MUTEX");
771         if (debug && (strstr(debug, "1")))
772                 tdm_debug_mutex = 1;
773
774         private_display = calloc(1, sizeof(tdm_private_display));
775         if (!private_display) {
776                 ret = TDM_ERROR_OUT_OF_MEMORY;
777                 TDM_ERR("'private_display != NULL' failed");
778                 goto failed_alloc;
779         }
780
781         if (pthread_mutex_init(&private_display->lock, NULL)) {
782                 ret = TDM_ERROR_OPERATION_FAILED;
783                 TDM_ERR("mutex init failed: %m");
784                 goto failed_mutex_init;
785         }
786
787         ret = tdm_event_loop_init(private_display);
788         if (ret != TDM_ERROR_NONE)
789                 goto failed_event;
790
791         ret = _tdm_display_load_module(private_display);
792         if (ret != TDM_ERROR_NONE)
793                 goto failed_load;
794
795 #ifdef INIT_BUFMGR
796         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
797         if (tdm_drm_fd >= 0) {
798                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
799                 close(tdm_drm_fd);
800                 if (!private_display->bufmgr) {
801                         TDM_ERR("tbm_bufmgr_init failed");
802                         goto failed_update;
803                 } else {
804                         TDM_INFO("tbm_bufmgr_init successed");
805                 }
806         }
807 #endif
808
809         TDM_TRACE_BEGIN(Update_Display);
810         ret = _tdm_display_update_internal(private_display, 0);
811         TDM_TRACE_END();
812         if (ret != TDM_ERROR_NONE)
813                 goto failed_update;
814
815         tdm_event_loop_create_backend_source(private_display);
816
817         private_display->init_count = 1;
818
819         g_private_display = private_display;
820
821         if (error)
822                 *error = TDM_ERROR_NONE;
823
824         _pthread_mutex_unlock(&gLock);
825
826         return (tdm_display *)private_display;
827
828 failed_update:
829         _tdm_display_unload_module(private_display);
830 failed_load:
831         tdm_event_loop_deinit(private_display);
832 failed_event:
833         pthread_mutex_destroy(&private_display->lock);
834 failed_mutex_init:
835         free(private_display);
836 failed_alloc:
837         tdm_debug = 0;
838         tdm_debug_buffer = 0;
839         if (error)
840                 *error = ret;
841         _pthread_mutex_unlock(&gLock);
842         return NULL;
843 }
844
845 EXTERN void
846 tdm_display_deinit(tdm_display *dpy)
847 {
848         tdm_private_display *private_display = dpy;
849
850         if (!private_display)
851                 return;
852
853         _pthread_mutex_lock(&gLock);
854
855         private_display->init_count--;
856         if (private_display->init_count > 0) {
857                 _pthread_mutex_unlock(&gLock);
858                 return;
859         }
860
861         _pthread_mutex_lock(&private_display->lock);
862
863         tdm_event_loop_deinit(private_display);
864
865         _tdm_display_destroy_private_display(private_display);
866         _tdm_display_unload_module(private_display);
867
868 #ifdef INIT_BUFMGR
869         if (private_display->bufmgr)
870                 tbm_bufmgr_deinit(private_display->bufmgr);
871 #endif
872
873         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
874
875         _pthread_mutex_unlock(&private_display->lock);
876
877         pthread_mutex_destroy(&private_display->lock);
878         free(private_display);
879         g_private_display = NULL;
880         tdm_debug = 0;
881         tdm_debug_buffer = 0;
882
883         _pthread_mutex_unlock(&gLock);
884 }
885