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