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