7562d4cc1d605a1237b1531ae35e11d866e2e428
[platform/core/uifw/libtdm.git] / src / tdm.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43
44 static tdm_private_layer*
45 _tdm_display_find_private_layer(tdm_private_output *private_output, tdm_layer *layer_backend)
46 {
47     tdm_private_layer *private_layer = NULL;
48
49     LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
50     {
51         if (private_layer->layer_backend == layer_backend)
52             return private_layer;
53     }
54
55     return NULL;
56 }
57
58 static tdm_private_output*
59 _tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output_backend)
60 {
61     tdm_private_output *private_output = NULL;
62
63     LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
64     {
65         if (private_output->output_backend == output_backend)
66             return private_output;
67     }
68
69     return NULL;
70 }
71
72 static void
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
74 {
75     free(caps_pp->formats);
76     memset(caps_pp, 0, sizeof(tdm_caps_pp));
77 }
78
79 static void
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
81 {
82     free(caps_capture->formats);
83     memset(caps_capture, 0, sizeof(tdm_caps_capture));
84 }
85
86 static void
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
88 {
89     free(caps_layer->formats);
90     free(caps_layer->props);
91     memset(caps_layer, 0, sizeof(tdm_caps_layer));
92 }
93
94 static void
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
96 {
97     free(caps_output->modes);
98     free(caps_output->props);
99     memset(caps_output, 0, sizeof(tdm_caps_output));
100 }
101
102 static void
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
104 {
105     tdm_private_capture *c = NULL, *cc = NULL;
106
107     LIST_DEL(&private_layer->link);
108
109     LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110         tdm_capture_destroy_internal(c);
111
112     _tdm_display_destroy_caps_layer(&private_layer->caps);
113
114     free(private_layer);
115 }
116
117 static void
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
119 {
120     tdm_private_layer *l = NULL, *ll = NULL;
121     tdm_private_capture *c = NULL, *cc = NULL;
122     tdm_private_vblank_handler *v = NULL, *vv = NULL;
123     tdm_private_commit_handler *m = NULL, *mm = NULL;
124
125     LIST_DEL(&private_output->link);
126
127     free(private_output->layers_ptr);
128
129     LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link)
130     {
131         LIST_DEL(&v->link);
132         free(v);
133     }
134
135     LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link)
136     {
137         LIST_DEL(&m->link);
138         free(m);
139     }
140
141     LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
142         tdm_capture_destroy_internal(c);
143
144     LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
145         _tdm_display_destroy_private_layer(l);
146
147     _tdm_display_destroy_caps_output(&private_output->caps);
148
149     free(private_output);
150 }
151
152 static void
153 _tdm_display_destroy_private_display(tdm_private_display *private_display)
154 {
155     tdm_private_output *o = NULL, *oo = NULL;
156     tdm_private_pp *p = NULL, *pp = NULL;
157
158     free(private_display->outputs_ptr);
159
160     LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
161         tdm_pp_destroy_internal(p);
162
163     LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
164         _tdm_display_destroy_private_output(o);
165
166     _tdm_display_destroy_caps_pp(&private_display->caps_pp);
167     _tdm_display_destroy_caps_capture(&private_display->caps_capture);
168
169     private_display->capabilities = 0;
170     private_display->caps_display.max_layer_count = -1;
171 }
172
173 static tdm_error
174 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
175 {
176     tdm_func_display *func_display = &private_display->func_display;
177     char buf[1024];
178     int bufsize = sizeof(buf);
179     char *str_buf = buf;
180     int *len_buf = &bufsize;
181     int i;
182     tdm_error ret;
183
184     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
185         return TDM_ERROR_NONE;
186
187     if (!func_display->display_get_pp_capability)
188     {
189         TDM_ERR("no display_get_pp_capability()");
190         return TDM_ERROR_BAD_MODULE;
191     }
192
193     ret = func_display->display_get_pp_capability(private_display->bdata, caps);
194     if (ret != TDM_ERROR_NONE)
195     {
196         TDM_ERR("display_get_pp_capability() failed");
197         return TDM_ERROR_BAD_MODULE;
198     }
199
200     TDM_DBG("pp capabilities: %x", caps->capabilities);
201     buf[0] = '\0';
202     for (i = 0; i < caps->format_count; i++)
203         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
204     TDM_DBG("pp formats: %s", buf);
205     TDM_DBG("pp min  : %dx%d", caps->min_w, caps->min_h);
206     TDM_DBG("pp max  : %dx%d", caps->max_w, caps->max_h);
207     TDM_DBG("pp align: %d", caps->preferred_align);
208
209     return TDM_ERROR_NONE;
210 }
211
212 static tdm_error
213 _tdm_display_update_caps_capture(tdm_private_display *private_display, tdm_caps_capture *caps)
214 {
215     tdm_func_display *func_display = &private_display->func_display;
216     char buf[1024];
217     int bufsize = sizeof(buf);
218     char *str_buf = buf;
219     int *len_buf = &bufsize;
220     int i;
221     tdm_error ret;
222
223     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
224         return TDM_ERROR_NONE;
225
226     if (!func_display->display_get_capture_capability)
227     {
228         TDM_ERR("no display_get_capture_capability()");
229         return TDM_ERROR_BAD_MODULE;
230     }
231
232     ret = func_display->display_get_capture_capability(private_display->bdata, caps);
233     if (ret != TDM_ERROR_NONE)
234     {
235         TDM_ERR("display_get_capture_capability() failed");
236         return TDM_ERROR_BAD_MODULE;
237     }
238
239     buf[0] = '\0';
240     for (i = 0; i < caps->format_count; i++)
241         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
242     TDM_DBG("capture formats: %s", buf);
243
244     return TDM_ERROR_NONE;
245 }
246
247 static tdm_error
248 _tdm_display_update_caps_layer(tdm_private_display *private_display,
249                                tdm_layer *layer_backend, tdm_caps_layer *caps)
250 {
251     tdm_func_layer *func_layer = &private_display->func_layer;
252     char buf[1024];
253     int bufsize = sizeof(buf);
254     char *str_buf = buf;
255     int *len_buf = &bufsize;
256     int i;
257     tdm_error ret;
258
259     if (!func_layer->layer_get_capability)
260     {
261         TDM_ERR("no layer_get_capability()");
262         return TDM_ERROR_BAD_MODULE;
263     }
264
265     ret = func_layer->layer_get_capability(layer_backend, caps);
266     if (ret != TDM_ERROR_NONE)
267     {
268         TDM_ERR("layer_get_capability() failed");
269         return TDM_ERROR_BAD_MODULE;
270     }
271
272     TDM_DBG("layer capabilities: %x", caps->capabilities);
273     TDM_DBG("layer zpos : %d", caps->zpos);
274     buf[0] = '\0';
275     for (i = 0; i < caps->format_count; i++)
276         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
277     TDM_DBG("layer formats: %s", buf);
278     for (i = 0; i < caps->prop_count; i++)
279         TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
280
281     return TDM_ERROR_NONE;
282 }
283
284 static tdm_error
285 _tdm_display_update_caps_output(tdm_private_display *private_display,
286                                 tdm_output *output_backend, tdm_caps_output *caps)
287 {
288     tdm_func_output *func_output = &private_display->func_output;
289     int i;
290     tdm_error ret;
291
292     if (!func_output->output_get_capability)
293     {
294         TDM_ERR("no output_get_capability()");
295         return TDM_ERROR_BAD_MODULE;
296     }
297
298     ret = func_output->output_get_capability(output_backend, caps);
299     if (ret != TDM_ERROR_NONE)
300     {
301         TDM_ERR("output_get_capability() failed");
302         return TDM_ERROR_BAD_MODULE;
303     }
304
305     TDM_DBG("output maker: %s", caps->maker);
306     TDM_DBG("output model: %s", caps->model);
307     TDM_DBG("output name: %s", caps->name);
308     TDM_DBG("output status: %d", caps->status);
309     TDM_DBG("output type : %d", caps->type);
310     for (i = 0; i < caps->prop_count; i++)
311         TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
312     for (i = 0; i < caps->mode_count; i++)
313         TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
314                  caps->modes[i].name, caps->modes[i].width, caps->modes[i].height,
315                  caps->modes[i].refresh, caps->modes[i].flags, caps->modes[i].type);
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     {
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     }
346     else
347         _tdm_display_destroy_caps_layer(&private_layer->caps);
348
349     ret = _tdm_display_update_caps_layer(private_display, layer_backend, &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, output_backend);
370     if (!private_output)
371     {
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     }
385     else
386         _tdm_display_destroy_caps_output(&private_output->caps);
387
388     ret = _tdm_display_update_caps_output(private_display, output_backend, &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     {
398         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
399         if (ret != TDM_ERROR_NONE)
400             goto failed_update;
401     }
402
403     free(layers);
404
405     return TDM_ERROR_NONE;
406 failed_update:
407     _tdm_display_destroy_private_output(private_output);
408     free(layers);
409     return ret;
410 }
411
412 static tdm_error
413 _tdm_display_update_internal(tdm_private_display *private_display, 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     {
425         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
426         if (ret != TDM_ERROR_NONE)
427             goto failed_update;
428
429         ret = _tdm_display_update_caps_capture(private_display, &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, &output_count, &ret);
435     if (ret != TDM_ERROR_NONE)
436         goto failed_update;
437
438     for (i = 0; i < output_count; i++)
439     {
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
456 EXTERN tdm_error
457 tdm_display_update(tdm_display *dpy)
458 {
459     tdm_private_display *private_display;
460     tdm_error ret;
461
462     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
463
464     private_display = dpy;
465     pthread_mutex_lock(&private_display->lock);
466
467     ret = _tdm_display_update_internal(private_display, 1);
468
469     pthread_mutex_unlock(&private_display->lock);
470
471     return ret;
472 }
473
474 #define SUFFIX_MODULE    ".so"
475 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
476
477 int tdm_debug;
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     {
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     {
512         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
513         return TDM_ERROR_BAD_MODULE;
514     }
515
516     if (!module->init)
517     {
518         TDM_ERR("'%s' doesn't have init function", name);
519         return TDM_ERROR_BAD_MODULE;
520     }
521
522     if (!module->deinit)
523     {
524         TDM_ERR("'%s' doesn't have deinit function", name);
525         return TDM_ERROR_BAD_MODULE;
526     }
527
528     return TDM_ERROR_NONE;
529 }
530
531 static tdm_error
532 _tdm_display_check_backend_functions(tdm_private_display *private_display)
533 {
534     tdm_func_display *func_display = &private_display->func_display;
535     tdm_func_output *func_output = &private_display->func_output;
536     tdm_func_layer *func_layer = &private_display->func_layer;
537     tdm_error ret;
538
539     /* below functions should be implemented in backend side */
540
541     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
542     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
543     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
544     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
545     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
546     TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
547
548     ret = func_display->display_get_capabilitiy(private_display->bdata,
549                                                 &private_display->caps_display);
550     if (ret != TDM_ERROR_NONE)
551     {
552         TDM_ERR("display_get_capabilitiy() failed");
553         return TDM_ERROR_BAD_MODULE;
554     }
555
556     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
557     {
558         tdm_func_pp *func_pp = &private_display->func_pp;
559         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
560         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
561         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
562         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
563         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
564     }
565
566     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
567     {
568         tdm_func_capture *func_capture = &private_display->func_capture;
569         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
570         TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
571         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
572         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
573         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
574         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, 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, 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     module = dlopen(path, RTLD_LAZY);
591     if (!module)
592     {
593         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
594         return TDM_ERROR_BAD_MODULE;
595     }
596
597     module_data = dlsym(module, "tdm_backend_module_data");
598     if (!module_data)
599     {
600         TDM_ERR("'%s' doesn't have data object", file);
601         ret = TDM_ERROR_BAD_MODULE;
602         goto failed_load;
603     }
604
605     /* check if version, init() and deinit() are valid or not */
606     ret = _tdm_display_check_module(module_data);
607     if (ret != TDM_ERROR_NONE)
608         goto failed_load;
609
610     /* We don't care if backend_data is NULL or not. It's up to backend. */
611     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
612     if (ret != TDM_ERROR_NONE)
613     {
614         TDM_ERR("'%s' init failed", file);
615         goto failed_load;
616     }
617
618     ret = _tdm_display_check_backend_functions(private_display);
619     if (ret != TDM_ERROR_NONE)
620     {
621         module_data->deinit(private_display->bdata);
622         private_display->bdata = NULL;
623         goto failed_load;
624     }
625
626     private_display->module_data = module_data;
627     private_display->module = module;
628
629     TDM_INFO("Success to load module(%s)", file);
630
631     return TDM_ERROR_NONE;
632 failed_load:
633     dlclose(module);
634     return ret;
635 }
636
637 static tdm_error
638 _tdm_display_load_module(tdm_private_display *private_display)
639 {
640     const char *module_name;
641     struct dirent **namelist;
642     int n;
643     tdm_error ret = 0;
644
645     module_name = getenv("TDM_MODULE");
646     if (!module_name)
647         module_name = DEFAULT_MODULE;
648
649     /* load bufmgr priv from default lib */
650     ret = _tdm_display_load_module_with_file(private_display, module_name);
651     if (ret == TDM_ERROR_NONE)
652         return TDM_ERROR_NONE;
653
654     /* load bufmgr priv from configured path */
655     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
656     if (n < 0)
657     {
658         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
659         return TDM_ERROR_BAD_MODULE;
660     }
661
662     ret = TDM_ERROR_BAD_MODULE;
663     while (n--)
664     {
665         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
666             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
667
668         free(namelist[n]);
669     }
670     free(namelist);
671
672     return ret;
673 }
674
675 static void
676 _tdm_display_unload_module(tdm_private_display *private_display)
677 {
678     if (private_display->module_data)
679         private_display->module_data->deinit(private_display->bdata);
680     if (private_display->module)
681         dlclose(private_display->module);
682
683     private_display->bdata = NULL;
684     private_display->module_data = NULL;
685     private_display->module = NULL;
686 }
687
688 EXTERN tdm_display*
689 tdm_display_init(tdm_error *error)
690 {
691     tdm_private_display *private_display = NULL;
692     const char *debug;
693     tdm_error ret;
694
695     pthread_mutex_lock(&gLock);
696
697     if (g_private_display)
698     {
699         g_private_display->init_count++;
700         pthread_mutex_unlock(&gLock);
701         if (error)
702             *error = TDM_ERROR_NONE;
703         return g_private_display;
704     }
705
706     debug = getenv("TDM_DEBUG");
707     if (debug && (strstr(debug, "1")))
708         tdm_debug = 1;
709
710     private_display = calloc(1, sizeof(tdm_private_display));
711     if (!private_display)
712     {
713         ret = TDM_ERROR_OUT_OF_MEMORY;
714         TDM_ERR("'private_display != NULL' failed");
715         goto failed_alloc;
716     }
717
718     if (pthread_mutex_init(&private_display->lock, NULL))
719     {
720         ret = TDM_ERROR_OPERATION_FAILED;
721         TDM_ERR("mutex init failed: %m");
722         goto failed_mutex_init;
723     }
724
725     ret = _tdm_display_load_module(private_display);
726     if (ret != TDM_ERROR_NONE)
727         goto failed_load;
728
729     ret = _tdm_display_update_internal(private_display, 0);
730     if (ret != TDM_ERROR_NONE)
731         goto failed_update;
732
733     private_display->init_count = 1;
734
735     g_private_display = private_display;
736
737     if (error)
738         *error = TDM_ERROR_NONE;
739
740     pthread_mutex_unlock(&gLock);
741
742     return (tdm_display*)private_display;
743
744 failed_update:
745     _tdm_display_unload_module(private_display);
746 failed_load:
747     pthread_mutex_destroy(&private_display->lock);
748 failed_mutex_init:
749     free(private_display);
750 failed_alloc:
751     tdm_debug = 0;
752     if (error)
753         *error = ret;
754     pthread_mutex_unlock(&gLock);
755     return NULL;
756 }
757
758 EXTERN void
759 tdm_display_deinit(tdm_display *dpy)
760 {
761     tdm_private_display *private_display = dpy;
762
763     if (!private_display)
764         return;
765
766     pthread_mutex_lock(&gLock);
767
768     private_display->init_count--;
769     if (private_display->init_count > 0)
770     {
771         pthread_mutex_unlock(&gLock);
772         return;
773     }
774
775     pthread_mutex_lock(&private_display->lock);
776
777     _tdm_display_destroy_private_display(private_display);
778     _tdm_display_unload_module(private_display);
779
780     pthread_mutex_unlock(&private_display->lock);
781
782     pthread_mutex_destroy(&private_display->lock);
783     free(private_display);
784     tdm_debug = 0;
785
786     pthread_mutex_unlock(&gLock);
787 }
788