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