750f12bf45a14bd4fd33561b0d31f315dd09d315
[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)
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 == layer)
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)
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 == output)
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     private_display->capabilities = 0;
169 }
170
171 static tdm_error
172 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
173 {
174     tdm_func_display *func_display = &private_display->func_display;
175     char buf[1024];
176     int bufsize = sizeof(buf);
177     char *str_buf = buf;
178     int *len_buf = &bufsize;
179     int i;
180     tdm_error ret;
181
182     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
183         return TDM_ERROR_NONE;
184
185     if (!func_display->display_get_pp_capability)
186     {
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     {
194         TDM_ERR("display_get_pp_capability() failed");
195         return TDM_ERROR_BAD_MODULE;
196     }
197
198     TDM_INFO("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_INFO("pp formats: %s", buf);
203     TDM_INFO("pp min  : %dx%d", caps->min_w, caps->min_h);
204     TDM_INFO("pp max  : %dx%d", caps->max_w, caps->max_h);
205     TDM_INFO("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, 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     {
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, caps);
231     if (ret != TDM_ERROR_NONE)
232     {
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_INFO("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, tdm_layer *layer, tdm_caps_layer *caps)
247 {
248     tdm_func_display *func_display = &private_display->func_display;
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_display->layer_get_capability)
257     {
258         TDM_ERR("no layer_get_capability()");
259         return TDM_ERROR_BAD_MODULE;
260     }
261
262     ret = func_display->layer_get_capability(layer, caps);
263     if (ret != TDM_ERROR_NONE)
264     {
265         TDM_ERR("layer_get_capability() failed");
266         return TDM_ERROR_BAD_MODULE;
267     }
268
269     TDM_INFO("layer capabilities: %x", caps->capabilities);
270     TDM_INFO("layer zpos : %d", caps->zpos);
271     buf[0] = '\0';
272     for (i = 0; i < caps->format_count; i++)
273         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
274     TDM_INFO("layer formats: %s", buf);
275     for (i = 0; i < caps->prop_count; i++)
276         TDM_INFO("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
277
278     return TDM_ERROR_NONE;
279 }
280
281 static tdm_error
282 _tdm_display_update_caps_output(tdm_private_display *private_display, tdm_output *output, tdm_caps_output *caps)
283 {
284     tdm_func_display *func_display = &private_display->func_display;
285     int i;
286     tdm_error ret;
287
288     if (!func_display->output_get_capability)
289     {
290         TDM_ERR("no output_get_capability()");
291         return TDM_ERROR_BAD_MODULE;
292     }
293
294     ret = func_display->output_get_capability(output, caps);
295     if (ret != TDM_ERROR_NONE)
296     {
297         TDM_ERR("output_get_capability() failed");
298         return TDM_ERROR_BAD_MODULE;
299     }
300
301     TDM_INFO("output status: %d", caps->status);
302     TDM_INFO("output type : %d", caps->type);
303     for (i = 0; i < caps->prop_count; i++)
304         TDM_INFO("output props: %d, %s", caps->props[i].id, caps->props[i].name);
305     for (i = 0; i < caps->mode_count; i++)
306         TDM_INFO("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
307                  caps->modes[i]->name, caps->modes[i]->width, caps->modes[i]->height,
308                  caps->modes[i]->refresh, caps->modes[i]->flags, caps->modes[i]->type);
309     TDM_INFO("output min  : %dx%d", caps->min_w, caps->min_h);
310     TDM_INFO("output max  : %dx%d", caps->max_w, caps->max_h);
311     TDM_INFO("output align: %d", caps->preferred_align);
312
313     return TDM_ERROR_NONE;
314 }
315
316 static tdm_error
317 _tdm_display_update_layer(tdm_private_display *private_display,
318                           tdm_private_output *private_output,
319                           tdm_layer *layer)
320 {
321     tdm_private_layer *private_layer;
322     tdm_error ret;
323
324     private_layer = _tdm_display_find_private_layer(private_output, layer);
325     if (!private_layer)
326     {
327         private_layer = calloc(1, sizeof(tdm_private_layer));
328         TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
329
330         LIST_ADD(&private_layer->link, &private_output->layer_list);
331         private_layer->func_display = &private_display->func_display;
332         private_layer->private_display = private_display;
333         private_layer->private_output = private_output;
334         private_layer->layer = layer;
335
336         LIST_INITHEAD(&private_layer->capture_list);
337     }
338     else
339         _tdm_display_destroy_caps_layer(&private_layer->caps);
340
341     ret = _tdm_display_update_caps_layer(private_display, layer, &private_layer->caps);
342     if (ret != TDM_ERROR_NONE)
343         goto failed_update;
344
345     return TDM_ERROR_NONE;
346 failed_update:
347     _tdm_display_destroy_private_layer(private_layer);
348     return ret;
349 }
350
351 static tdm_error
352 _tdm_display_update_output(tdm_private_display *private_display, tdm_output *output)
353 {
354     tdm_func_display *func_display = &private_display->func_display;
355     tdm_private_output *private_output = NULL;
356     tdm_layer **layers = NULL;
357     int layer_count = 0, i;
358     tdm_error ret;
359
360     private_output = _tdm_display_find_private_output(private_display, output);
361     if (!private_output)
362     {
363         private_output = calloc(1, sizeof(tdm_private_output));
364         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
365
366         LIST_ADD(&private_output->link, &private_display->output_list);
367         private_output->func_display = func_display;
368         private_output->private_display = private_display;
369         private_output->output = output;
370
371         LIST_INITHEAD(&private_output->layer_list);
372         LIST_INITHEAD(&private_output->capture_list);
373         LIST_INITHEAD(&private_output->vblank_handler_list);
374         LIST_INITHEAD(&private_output->commit_handler_list);
375     }
376     else
377         _tdm_display_destroy_caps_output(&private_output->caps);
378
379     ret = _tdm_display_update_caps_output(private_display, output, &private_output->caps);
380     if (ret != TDM_ERROR_NONE)
381         return ret;
382
383     layers = func_display->output_get_layers(output, &layer_count, &ret);
384     if (ret != TDM_ERROR_NONE)
385         goto failed_update;
386
387     for (i = 0; i < layer_count; i++)
388     {
389         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
390         if (ret != TDM_ERROR_NONE)
391             goto failed_update;
392     }
393
394     free(layers);
395
396     return TDM_ERROR_NONE;
397 failed_update:
398     _tdm_display_destroy_private_output(private_output);
399     free(layers);
400     return ret;
401 }
402
403 static tdm_error
404 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
405 {
406     tdm_func_display *func_display = &private_display->func_display;
407     tdm_output **outputs = NULL;
408     int output_count = 0, i;
409     tdm_error ret;
410
411     LIST_INITHEAD(&private_display->output_list);
412     LIST_INITHEAD(&private_display->pp_list);
413
414     if (!only_display)
415     {
416         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
417         if (ret != TDM_ERROR_NONE)
418             goto failed_update;
419
420         ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
421         if (ret != TDM_ERROR_NONE)
422             goto failed_update;
423     }
424
425     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
426     if (ret != TDM_ERROR_NONE)
427         goto failed_update;
428
429     for (i = 0; i < output_count; i++)
430     {
431         ret = _tdm_display_update_output(private_display, outputs[i]);
432         if (ret != TDM_ERROR_NONE)
433             goto failed_update;
434     }
435
436     free(outputs);
437
438     return TDM_ERROR_NONE;
439
440 failed_update:
441     _tdm_display_destroy_private_display(private_display);
442     free(outputs);
443     return ret;
444 }
445
446
447 EXTERN tdm_error
448 tdm_display_update(tdm_display *dpy)
449 {
450     tdm_private_display *private_display;
451     tdm_error ret;
452
453     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
454
455     private_display = dpy;
456     pthread_mutex_lock(&private_display->lock);
457
458     ret = _tdm_display_update_internal(private_display, 1);
459
460     pthread_mutex_unlock(&private_display->lock);
461
462     return ret;
463 }
464
465 #define SUFFIX_MODULE    ".so"
466 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
467
468 int tdm_debug;
469
470 static tdm_private_display *g_private_display;
471 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
472
473 static tdm_error
474 _tdm_display_check_module(tdm_backend_module *module)
475 {
476     const char *name;
477     const char *vendor;
478     int major, minor;
479     int abimaj, abimin;
480
481     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
482     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
483
484     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
485
486     name = module->name ? module->name : "unknown";
487     vendor = module->vendor ? module->vendor : "unknown";
488     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
489     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
490
491     TDM_INFO("TDM module name: %s", name);
492     TDM_INFO("'%s' vendor: %s", name, vendor);
493     TDM_INFO("'%s' version: %d.%d", name, major, minor);
494
495     if (major != abimaj)
496     {
497         TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
498         return TDM_ERROR_BAD_MODULE;
499     }
500
501     if (minor > abimin)
502     {
503         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
504         return TDM_ERROR_BAD_MODULE;
505     }
506
507     if (!module->init)
508     {
509         TDM_ERR("'%s' doesn't have init function", name);
510         return TDM_ERROR_BAD_MODULE;
511     }
512
513     if (!module->deinit)
514     {
515         TDM_ERR("'%s' doesn't have deinit function", name);
516         return TDM_ERROR_BAD_MODULE;
517     }
518
519     return TDM_ERROR_NONE;
520 }
521
522 static tdm_error
523 _tdm_display_check_backend_functions(tdm_private_display *private_display)
524 {
525     tdm_func_display *func_display = &private_display->func_display;
526     tdm_error ret;
527
528     /* below functions should be implemented in backend side */
529
530     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
531     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
532     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
533     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_capability, TDM_ERROR_BAD_MODULE);
534     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
535     TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
536
537     ret = func_display->display_get_capabilitiy(private_display->bdata,
538                                                 &private_display->capabilities);
539     if (ret != TDM_ERROR_NONE)
540     {
541         TDM_ERR("display_get_capabilitiy() failed");
542         return TDM_ERROR_BAD_MODULE;
543     }
544
545     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
546     {
547         tdm_func_pp *func_pp = &private_display->func_pp;
548         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
549         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
550         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
551         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
552         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
553     }
554
555     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
556     {
557         tdm_func_capture *func_capture = &private_display->func_capture;
558         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
559         TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
560         TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
561         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
562         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
563         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
564     }
565
566     return TDM_ERROR_NONE;
567 }
568
569 static tdm_error
570 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
571 {
572     char path[PATH_MAX] = {0,};
573     tdm_backend_module *module_data;
574     void *module;
575     tdm_error ret;
576
577     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
578
579     module = dlopen(path, RTLD_LAZY);
580     if (!module)
581     {
582         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
583         return TDM_ERROR_BAD_MODULE;
584     }
585
586     module_data = dlsym(module, "tdm_backend_module_data");
587     if (!module_data)
588     {
589         TDM_ERR("'%s' doesn't have data object", file);
590         ret = TDM_ERROR_BAD_MODULE;
591         goto failed_load;
592     }
593
594     /* check if version, init() and deinit() are valid or not */
595     ret = _tdm_display_check_module(module_data);
596     if (ret != TDM_ERROR_NONE)
597         goto failed_load;
598
599     /* We don't care if backend_data is NULL or not. It's up to backend. */
600     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
601     if (ret != TDM_ERROR_NONE)
602     {
603         TDM_ERR("'%s' init failed", file);
604         goto failed_load;
605     }
606
607     ret = _tdm_display_check_backend_functions(private_display);
608     if (ret != TDM_ERROR_NONE)
609     {
610         module_data->deinit(private_display->bdata);
611         private_display->bdata = NULL;
612         goto failed_load;
613     }
614
615     private_display->module_data = module_data;
616     private_display->module = module;
617
618     TDM_INFO("Success to load module(%s)\n", file);
619
620     return TDM_ERROR_NONE;
621 failed_load:
622     dlclose(module);
623     return ret;
624 }
625
626 static tdm_error
627 _tdm_display_load_module(tdm_private_display *private_display)
628 {
629     const char *module_name;
630     struct dirent **namelist;
631     int n;
632     tdm_error ret = 0;
633
634     module_name = getenv("TDM_MODULE");
635     if (!module_name)
636         module_name = DEFAULT_MODULE;
637
638     /* load bufmgr priv from default lib */
639     ret = _tdm_display_load_module_with_file(private_display, module_name);
640     if (ret == TDM_ERROR_NONE)
641         return TDM_ERROR_NONE;
642
643     /* load bufmgr priv from configured path */
644     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
645     if (n < 0)
646     {
647         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
648         return TDM_ERROR_BAD_MODULE;
649     }
650
651     ret = TDM_ERROR_BAD_MODULE;
652     while (n--)
653     {
654         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
655             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
656
657         free(namelist[n]);
658     }
659     free(namelist);
660
661     return ret;
662 }
663
664 static void
665 _tdm_display_unload_module(tdm_private_display *private_display)
666 {
667     if (private_display->module_data)
668         private_display->module_data->deinit(private_display->bdata);
669     if (private_display->module)
670         dlclose(private_display->module);
671
672     private_display->bdata = NULL;
673     private_display->module_data = NULL;
674     private_display->module = NULL;
675 }
676
677 EXTERN tdm_display*
678 tdm_display_init(tdm_error *error)
679 {
680     tdm_private_display *private_display = NULL;
681     const char *debug;
682     tdm_error ret;
683
684     pthread_mutex_lock(&gLock);
685
686     if (g_private_display)
687     {
688         g_private_display->init_count++;
689         pthread_mutex_unlock(&gLock);
690         return g_private_display;
691     }
692
693     debug = getenv("TDM_DEBUG");
694     if (debug && (strstr(debug, "1")))
695         tdm_debug = 1;
696
697     private_display = calloc(1, sizeof(tdm_private_display));
698     if (!private_display)
699     {
700         ret = TDM_ERROR_OUT_OF_MEMORY;
701         TDM_ERR("'private_display != NULL' failed");
702         goto failed_alloc;
703     }
704
705     if (pthread_mutex_init(&private_display->lock, NULL))
706     {
707         ret = TDM_ERROR_OPERATION_FAILED;
708         TDM_ERR("mutex init failed: %m");
709         goto failed_mutex_init;
710     }
711
712     ret = _tdm_display_load_module(private_display);
713     if (ret != TDM_ERROR_NONE)
714         goto failed_load;
715
716     ret = _tdm_display_update_internal(private_display, 0);
717     if (ret != TDM_ERROR_NONE)
718         goto failed_update;
719
720     private_display->init_count = 1;
721
722     g_private_display = private_display;
723
724     pthread_mutex_unlock(&gLock);
725
726     return (tdm_display*)private_display;
727
728 failed_update:
729     _tdm_display_unload_module(private_display);
730 failed_load:
731     pthread_mutex_destroy(&private_display->lock);
732 failed_mutex_init:
733     free(private_display);
734 failed_alloc:
735     tdm_debug = 0;
736     if (error)
737         *error = ret;
738     pthread_mutex_unlock(&gLock);
739     return NULL;
740 }
741
742 EXTERN void
743 tdm_display_deinit(tdm_display *dpy)
744 {
745     tdm_private_display *private_display = dpy;
746
747     if (!private_display)
748         return;
749
750     pthread_mutex_lock(&gLock);
751
752     private_display->init_count--;
753     if (private_display->init_count > 0)
754     {
755         pthread_mutex_unlock(&gLock);
756         return;
757     }
758
759     pthread_mutex_lock(&private_display->lock);
760
761     _tdm_display_destroy_private_display(private_display);
762     _tdm_display_unload_module(private_display);
763
764     pthread_mutex_unlock(&private_display->lock);
765
766     pthread_mutex_destroy(&private_display->lock);
767     free(private_display);
768     tdm_debug = 0;
769
770     pthread_mutex_unlock(&gLock);
771 }
772