add tdm_helper_get_fd & tdm_helper_set_fd
[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
479 static tdm_private_display *g_private_display;
480 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
481
482 static tdm_error
483 _tdm_display_check_module(tdm_backend_module *module)
484 {
485         const char *name;
486         const char *vendor;
487         int major, minor;
488         int abimaj, abimin;
489
490         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
491         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
492
493         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
494
495         name = module->name ? module->name : "unknown";
496         vendor = module->vendor ? module->vendor : "unknown";
497         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
498         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
499
500         TDM_INFO("TDM module name: %s", name);
501         TDM_INFO("'%s' vendor: %s", name, vendor);
502         TDM_INFO("'%s' version: %d.%d", name, major, minor);
503
504         if (major != abimaj) {
505                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
506                 return TDM_ERROR_BAD_MODULE;
507         }
508
509         if (minor > abimin) {
510                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
511                 return TDM_ERROR_BAD_MODULE;
512         }
513
514         if (!module->init) {
515                 TDM_ERR("'%s' doesn't have init function", name);
516                 return TDM_ERROR_BAD_MODULE;
517         }
518
519         if (!module->deinit) {
520                 TDM_ERR("'%s' doesn't have deinit function", name);
521                 return TDM_ERROR_BAD_MODULE;
522         }
523
524         return TDM_ERROR_NONE;
525 }
526
527 static tdm_error
528 _tdm_display_check_backend_functions(tdm_private_display *private_display)
529 {
530         tdm_func_display *func_display = &private_display->func_display;
531         tdm_func_output *func_output = &private_display->func_output;
532         tdm_func_layer *func_layer = &private_display->func_layer;
533         tdm_error ret;
534
535         /* below functions should be implemented in backend side */
536
537         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
538         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
539                                TDM_ERROR_BAD_MODULE);
540         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
541         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
542                                TDM_ERROR_BAD_MODULE);
543         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
544         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
545
546         ret = func_display->display_get_capabilitiy(private_display->bdata,
547                         &private_display->caps_display);
548         if (ret != TDM_ERROR_NONE) {
549                 TDM_ERR("display_get_capabilitiy() failed");
550                 return TDM_ERROR_BAD_MODULE;
551         }
552
553         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
554                 tdm_func_pp *func_pp = &private_display->func_pp;
555                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
556                                        TDM_ERROR_BAD_MODULE);
557                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
558                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
559                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
560                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
561         }
562
563         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
564                 tdm_func_capture *func_capture = &private_display->func_capture;
565                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
566                                        TDM_ERROR_BAD_MODULE);
567                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
568                                        TDM_ERROR_BAD_MODULE);
569                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
570                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
571                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
572                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
573                                        TDM_ERROR_BAD_MODULE);
574         }
575
576         return TDM_ERROR_NONE;
577 }
578
579 static tdm_error
580 _tdm_display_load_module_with_file(tdm_private_display *private_display,
581                                    const char *file)
582 {
583         char path[PATH_MAX] = {0,};
584         tdm_backend_module *module_data;
585         void *module;
586         tdm_error ret;
587
588         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
589
590         TDM_TRACE_BEGIN(Load_Backend);
591
592         module = dlopen(path, RTLD_LAZY);
593         if (!module) {
594                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
595                 TDM_TRACE_END();
596                 return TDM_ERROR_BAD_MODULE;
597         }
598
599         module_data = dlsym(module, "tdm_backend_module_data");
600         if (!module_data) {
601                 TDM_ERR("'%s' doesn't have data object", file);
602                 ret = TDM_ERROR_BAD_MODULE;
603                 TDM_TRACE_END();
604                 goto failed_load;
605         }
606
607         private_display->module_data = module_data;
608         private_display->module = module;
609
610         /* check if version, init() and deinit() are valid or not */
611         ret = _tdm_display_check_module(module_data);
612         if (ret != TDM_ERROR_NONE)
613                 goto failed_load;
614
615         TDM_TRACE_END();
616
617         /* We don't care if backend_data is NULL or not. It's up to backend. */
618         TDM_TRACE_BEGIN(Init_Backend);
619         private_display->bdata = module_data->init((tdm_display *)private_display,
620                                  &ret);
621         TDM_TRACE_END();
622         if (ret != TDM_ERROR_NONE) {
623                 TDM_ERR("'%s' init failed", file);
624                 goto failed_load;
625         }
626
627         ret = _tdm_display_check_backend_functions(private_display);
628         if (ret != TDM_ERROR_NONE) {
629                 module_data->deinit(private_display->bdata);
630                 private_display->bdata = NULL;
631                 goto failed_load;
632         }
633
634         TDM_INFO("Success to load module(%s)", file);
635
636         return TDM_ERROR_NONE;
637 failed_load:
638         dlclose(module);
639         private_display->module_data = NULL;
640         private_display->module = NULL;
641         return ret;
642 }
643
644 static tdm_error
645 _tdm_display_load_module(tdm_private_display *private_display)
646 {
647         const char *module_name;
648         struct dirent **namelist;
649         int n;
650         tdm_error ret = 0;
651
652         module_name = getenv("TDM_MODULE");
653         if (!module_name)
654                 module_name = DEFAULT_MODULE;
655
656         /* load bufmgr priv from default lib */
657         ret = _tdm_display_load_module_with_file(private_display, module_name);
658         if (ret == TDM_ERROR_NONE)
659                 return TDM_ERROR_NONE;
660
661         /* load bufmgr priv from configured path */
662         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
663         if (n < 0) {
664                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
665                 return TDM_ERROR_BAD_MODULE;
666         }
667
668         ret = TDM_ERROR_BAD_MODULE;
669         while (n--) {
670                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
671                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
672
673                 free(namelist[n]);
674         }
675         free(namelist);
676
677         return ret;
678 }
679
680 static void
681 _tdm_display_unload_module(tdm_private_display *private_display)
682 {
683         if (private_display->module_data)
684                 private_display->module_data->deinit(private_display->bdata);
685         if (private_display->module)
686                 dlclose(private_display->module);
687
688         private_display->bdata = NULL;
689         private_display->module_data = NULL;
690         private_display->module = NULL;
691 }
692
693 EXTERN tdm_display *
694 tdm_display_init(tdm_error *error)
695 {
696         tdm_private_display *private_display = NULL;
697         const char *debug;
698         tdm_error ret;
699
700         pthread_mutex_lock(&gLock);
701
702         if (g_private_display) {
703                 g_private_display->init_count++;
704                 pthread_mutex_unlock(&gLock);
705                 if (error)
706                         *error = TDM_ERROR_NONE;
707                 return g_private_display;
708         }
709
710         debug = getenv("TDM_DEBUG");
711         if (debug && (strstr(debug, "1")))
712                 tdm_debug = 1;
713
714         debug = getenv("TDM_DEBUG_BUFFER");
715         if (debug && (strstr(debug, "1")))
716                 tdm_debug_buffer = 1;
717
718         private_display = calloc(1, sizeof(tdm_private_display));
719         if (!private_display) {
720                 ret = TDM_ERROR_OUT_OF_MEMORY;
721                 TDM_ERR("'private_display != NULL' failed");
722                 goto failed_alloc;
723         }
724
725         if (pthread_mutex_init(&private_display->lock, NULL)) {
726                 ret = TDM_ERROR_OPERATION_FAILED;
727                 TDM_ERR("mutex init failed: %m");
728                 goto failed_mutex_init;
729         }
730
731         ret = _tdm_display_load_module(private_display);
732         if (ret != TDM_ERROR_NONE)
733                 goto failed_load;
734
735         TDM_TRACE_BEGIN(Update_Display);
736         ret = _tdm_display_update_internal(private_display, 0);
737         TDM_TRACE_END();
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         tdm_debug_buffer = 0;
761         if (error)
762                 *error = ret;
763         pthread_mutex_unlock(&gLock);
764         return NULL;
765 }
766
767 EXTERN void
768 tdm_display_deinit(tdm_display *dpy)
769 {
770         tdm_private_display *private_display = dpy;
771
772         if (!private_display)
773                 return;
774
775         pthread_mutex_lock(&gLock);
776
777         private_display->init_count--;
778         if (private_display->init_count > 0) {
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         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
789
790         pthread_mutex_unlock(&private_display->lock);
791
792         pthread_mutex_destroy(&private_display->lock);
793         free(private_display);
794         g_private_display = NULL;
795         tdm_debug = 0;
796         tdm_debug_buffer = 0;
797
798         pthread_mutex_unlock(&gLock);
799 }
800