794540f73624028aed30de709a500590e1125587
[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_display *func_display = &private_display->func_display;
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_display->layer_get_capability)
260     {
261         TDM_ERR("no layer_get_capability()");
262         return TDM_ERROR_BAD_MODULE;
263     }
264
265     ret = func_display->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_display *func_display = &private_display->func_display;
289     int i;
290     tdm_error ret;
291
292     if (!func_display->output_get_capability)
293     {
294         TDM_ERR("no output_get_capability()");
295         return TDM_ERROR_BAD_MODULE;
296     }
297
298     ret = func_display->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 status: %d", caps->status);
306     TDM_DBG("output type : %d", caps->type);
307     for (i = 0; i < caps->prop_count; i++)
308         TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
309     for (i = 0; i < caps->mode_count; i++)
310         TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
311                  caps->modes[i].name, caps->modes[i].width, caps->modes[i].height,
312                  caps->modes[i].refresh, caps->modes[i].flags, caps->modes[i].type);
313     TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
314     TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
315     TDM_DBG("output align: %d", caps->preferred_align);
316
317     return TDM_ERROR_NONE;
318 }
319
320 static tdm_error
321 _tdm_display_update_layer(tdm_private_display *private_display,
322                           tdm_private_output *private_output,
323                           tdm_layer *layer_backend)
324 {
325     tdm_private_layer *private_layer;
326     tdm_error ret;
327
328     private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
329     if (!private_layer)
330     {
331         private_layer = calloc(1, sizeof(tdm_private_layer));
332         TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
333
334         LIST_ADD(&private_layer->link, &private_output->layer_list);
335         private_layer->func_display = &private_display->func_display;
336         private_layer->private_display = private_display;
337         private_layer->private_output = private_output;
338         private_layer->layer_backend = layer_backend;
339
340         LIST_INITHEAD(&private_layer->capture_list);
341
342         private_layer->usable = 1;
343     }
344     else
345         _tdm_display_destroy_caps_layer(&private_layer->caps);
346
347     ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
348     if (ret != TDM_ERROR_NONE)
349         goto failed_update;
350
351     return TDM_ERROR_NONE;
352 failed_update:
353     _tdm_display_destroy_private_layer(private_layer);
354     return ret;
355 }
356
357 static tdm_error
358 _tdm_display_update_output(tdm_private_display *private_display,
359                            tdm_output *output_backend, int pipe)
360 {
361     tdm_func_display *func_display = &private_display->func_display;
362     tdm_private_output *private_output = NULL;
363     tdm_layer **layers = NULL;
364     int layer_count = 0, i;
365     tdm_error ret;
366
367     private_output = _tdm_display_find_private_output(private_display, output_backend);
368     if (!private_output)
369     {
370         private_output = calloc(1, sizeof(tdm_private_output));
371         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
372
373         LIST_ADD(&private_output->link, &private_display->output_list);
374         private_output->func_display = func_display;
375         private_output->private_display = private_display;
376         private_output->output_backend = output_backend;
377         private_output->pipe = pipe;
378
379         LIST_INITHEAD(&private_output->layer_list);
380         LIST_INITHEAD(&private_output->capture_list);
381         LIST_INITHEAD(&private_output->vblank_handler_list);
382         LIST_INITHEAD(&private_output->commit_handler_list);
383     }
384     else
385         _tdm_display_destroy_caps_output(&private_output->caps);
386
387     ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
388     if (ret != TDM_ERROR_NONE)
389         return ret;
390
391     layers = func_display->output_get_layers(output_backend, &layer_count, &ret);
392     if (ret != TDM_ERROR_NONE)
393         goto failed_update;
394
395     for (i = 0; i < layer_count; i++)
396     {
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, int only_display)
413 {
414     tdm_func_display *func_display = &private_display->func_display;
415     tdm_output **outputs = NULL;
416     int output_count = 0, i;
417     tdm_error ret;
418
419     LIST_INITHEAD(&private_display->output_list);
420     LIST_INITHEAD(&private_display->pp_list);
421
422     if (!only_display)
423     {
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, &private_display->caps_capture);
429         if (ret != TDM_ERROR_NONE)
430             goto failed_update;
431     }
432
433     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
434     if (ret != TDM_ERROR_NONE)
435         goto failed_update;
436
437     for (i = 0; i < output_count; i++)
438     {
439         ret = _tdm_display_update_output(private_display, outputs[i], i);
440         if (ret != TDM_ERROR_NONE)
441             goto failed_update;
442     }
443
444     free(outputs);
445
446     return TDM_ERROR_NONE;
447
448 failed_update:
449     _tdm_display_destroy_private_display(private_display);
450     free(outputs);
451     return ret;
452 }
453
454
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
478 static tdm_private_display *g_private_display;
479 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
480
481 static tdm_error
482 _tdm_display_check_module(tdm_backend_module *module)
483 {
484     const char *name;
485     const char *vendor;
486     int major, minor;
487     int abimaj, abimin;
488
489     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
490     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
491
492     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
493
494     name = module->name ? module->name : "unknown";
495     vendor = module->vendor ? module->vendor : "unknown";
496     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
497     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
498
499     TDM_INFO("TDM module name: %s", name);
500     TDM_INFO("'%s' vendor: %s", name, vendor);
501     TDM_INFO("'%s' version: %d.%d", name, major, minor);
502
503     if (major != abimaj)
504     {
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     {
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     {
517         TDM_ERR("'%s' doesn't have init function", name);
518         return TDM_ERROR_BAD_MODULE;
519     }
520
521     if (!module->deinit)
522     {
523         TDM_ERR("'%s' doesn't have deinit function", name);
524         return TDM_ERROR_BAD_MODULE;
525     }
526
527     return TDM_ERROR_NONE;
528 }
529
530 static tdm_error
531 _tdm_display_check_backend_functions(tdm_private_display *private_display)
532 {
533     tdm_func_display *func_display = &private_display->func_display;
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, 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_display->output_get_capability, TDM_ERROR_BAD_MODULE);
542     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
543     TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
544
545     ret = func_display->display_get_capabilitiy(private_display->bdata,
546                                                 &private_display->caps_display);
547     if (ret != TDM_ERROR_NONE)
548     {
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     {
555         tdm_func_pp *func_pp = &private_display->func_pp;
556         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, 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     {
565         tdm_func_capture *func_capture = &private_display->func_capture;
566         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
567         TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
568         TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
569         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
570         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
571         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
572     }
573
574     return TDM_ERROR_NONE;
575 }
576
577 static tdm_error
578 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
579 {
580     char path[PATH_MAX] = {0,};
581     tdm_backend_module *module_data;
582     void *module;
583     tdm_error ret;
584
585     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
586
587     module = dlopen(path, RTLD_LAZY);
588     if (!module)
589     {
590         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
591         return TDM_ERROR_BAD_MODULE;
592     }
593
594     module_data = dlsym(module, "tdm_backend_module_data");
595     if (!module_data)
596     {
597         TDM_ERR("'%s' doesn't have data object", file);
598         ret = TDM_ERROR_BAD_MODULE;
599         goto failed_load;
600     }
601
602     /* check if version, init() and deinit() are valid or not */
603     ret = _tdm_display_check_module(module_data);
604     if (ret != TDM_ERROR_NONE)
605         goto failed_load;
606
607     /* We don't care if backend_data is NULL or not. It's up to backend. */
608     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
609     if (ret != TDM_ERROR_NONE)
610     {
611         TDM_ERR("'%s' init failed", file);
612         goto failed_load;
613     }
614
615     ret = _tdm_display_check_backend_functions(private_display);
616     if (ret != TDM_ERROR_NONE)
617     {
618         module_data->deinit(private_display->bdata);
619         private_display->bdata = NULL;
620         goto failed_load;
621     }
622
623     private_display->module_data = module_data;
624     private_display->module = module;
625
626     TDM_INFO("Success to load module(%s)", file);
627
628     return TDM_ERROR_NONE;
629 failed_load:
630     dlclose(module);
631     return ret;
632 }
633
634 static tdm_error
635 _tdm_display_load_module(tdm_private_display *private_display)
636 {
637     const char *module_name;
638     struct dirent **namelist;
639     int n;
640     tdm_error ret = 0;
641
642     module_name = getenv("TDM_MODULE");
643     if (!module_name)
644         module_name = DEFAULT_MODULE;
645
646     /* load bufmgr priv from default lib */
647     ret = _tdm_display_load_module_with_file(private_display, module_name);
648     if (ret == TDM_ERROR_NONE)
649         return TDM_ERROR_NONE;
650
651     /* load bufmgr priv from configured path */
652     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
653     if (n < 0)
654     {
655         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
656         return TDM_ERROR_BAD_MODULE;
657     }
658
659     ret = TDM_ERROR_BAD_MODULE;
660     while (n--)
661     {
662         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
663             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
664
665         free(namelist[n]);
666     }
667     free(namelist);
668
669     return ret;
670 }
671
672 static void
673 _tdm_display_unload_module(tdm_private_display *private_display)
674 {
675     if (private_display->module_data)
676         private_display->module_data->deinit(private_display->bdata);
677     if (private_display->module)
678         dlclose(private_display->module);
679
680     private_display->bdata = NULL;
681     private_display->module_data = NULL;
682     private_display->module = NULL;
683 }
684
685 EXTERN tdm_display*
686 tdm_display_init(tdm_error *error)
687 {
688     tdm_private_display *private_display = NULL;
689     const char *debug;
690     tdm_error ret;
691
692     pthread_mutex_lock(&gLock);
693
694     if (g_private_display)
695     {
696         g_private_display->init_count++;
697         pthread_mutex_unlock(&gLock);
698         if (error)
699             *error = TDM_ERROR_NONE;
700         return g_private_display;
701     }
702
703     debug = getenv("TDM_DEBUG");
704     if (debug && (strstr(debug, "1")))
705         tdm_debug = 1;
706
707     private_display = calloc(1, sizeof(tdm_private_display));
708     if (!private_display)
709     {
710         ret = TDM_ERROR_OUT_OF_MEMORY;
711         TDM_ERR("'private_display != NULL' failed");
712         goto failed_alloc;
713     }
714
715     if (pthread_mutex_init(&private_display->lock, NULL))
716     {
717         ret = TDM_ERROR_OPERATION_FAILED;
718         TDM_ERR("mutex init failed: %m");
719         goto failed_mutex_init;
720     }
721
722     ret = _tdm_display_load_module(private_display);
723     if (ret != TDM_ERROR_NONE)
724         goto failed_load;
725
726     ret = _tdm_display_update_internal(private_display, 0);
727     if (ret != TDM_ERROR_NONE)
728         goto failed_update;
729
730     private_display->init_count = 1;
731
732     g_private_display = private_display;
733
734     if (error)
735         *error = TDM_ERROR_NONE;
736
737     pthread_mutex_unlock(&gLock);
738
739     return (tdm_display*)private_display;
740
741 failed_update:
742     _tdm_display_unload_module(private_display);
743 failed_load:
744     pthread_mutex_destroy(&private_display->lock);
745 failed_mutex_init:
746     free(private_display);
747 failed_alloc:
748     tdm_debug = 0;
749     if (error)
750         *error = ret;
751     pthread_mutex_unlock(&gLock);
752     return NULL;
753 }
754
755 EXTERN void
756 tdm_display_deinit(tdm_display *dpy)
757 {
758     tdm_private_display *private_display = dpy;
759
760     if (!private_display)
761         return;
762
763     pthread_mutex_lock(&gLock);
764
765     private_display->init_count--;
766     if (private_display->init_count > 0)
767     {
768         pthread_mutex_unlock(&gLock);
769         return;
770     }
771
772     pthread_mutex_lock(&private_display->lock);
773
774     _tdm_display_destroy_private_display(private_display);
775     _tdm_display_unload_module(private_display);
776
777     pthread_mutex_unlock(&private_display->lock);
778
779     pthread_mutex_destroy(&private_display->lock);
780     free(private_display);
781     tdm_debug = 0;
782
783     pthread_mutex_unlock(&gLock);
784 }
785