add tdm_caps_display
[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->caps_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->caps_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_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, 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->caps_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_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, 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_DBG("layer capabilities: %x", caps->capabilities);
270     TDM_DBG("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_DBG("layer formats: %s", buf);
275     for (i = 0; i < caps->prop_count; i++)
276         TDM_DBG("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_DBG("output status: %d", caps->status);
302     TDM_DBG("output type : %d", caps->type);
303     for (i = 0; i < caps->prop_count; i++)
304         TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
305     for (i = 0; i < caps->mode_count; i++)
306         TDM_DBG("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_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
310     TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
311     TDM_DBG("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, int pipe)
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         private_output->pipe = pipe;
371
372         LIST_INITHEAD(&private_output->layer_list);
373         LIST_INITHEAD(&private_output->capture_list);
374         LIST_INITHEAD(&private_output->vblank_handler_list);
375         LIST_INITHEAD(&private_output->commit_handler_list);
376     }
377     else
378         _tdm_display_destroy_caps_output(&private_output->caps);
379
380     ret = _tdm_display_update_caps_output(private_display, output, &private_output->caps);
381     if (ret != TDM_ERROR_NONE)
382         return ret;
383
384     layers = func_display->output_get_layers(output, &layer_count, &ret);
385     if (ret != TDM_ERROR_NONE)
386         goto failed_update;
387
388     for (i = 0; i < layer_count; i++)
389     {
390         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
391         if (ret != TDM_ERROR_NONE)
392             goto failed_update;
393     }
394
395     free(layers);
396
397     return TDM_ERROR_NONE;
398 failed_update:
399     _tdm_display_destroy_private_output(private_output);
400     free(layers);
401     return ret;
402 }
403
404 static tdm_error
405 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
406 {
407     tdm_func_display *func_display = &private_display->func_display;
408     tdm_output **outputs = NULL;
409     int output_count = 0, i;
410     tdm_error ret;
411
412     LIST_INITHEAD(&private_display->output_list);
413     LIST_INITHEAD(&private_display->pp_list);
414
415     if (!only_display)
416     {
417         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
418         if (ret != TDM_ERROR_NONE)
419             goto failed_update;
420
421         ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
422         if (ret != TDM_ERROR_NONE)
423             goto failed_update;
424     }
425
426     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
427     if (ret != TDM_ERROR_NONE)
428         goto failed_update;
429
430     for (i = 0; i < output_count; i++)
431     {
432         ret = _tdm_display_update_output(private_display, outputs[i], i);
433         if (ret != TDM_ERROR_NONE)
434             goto failed_update;
435     }
436
437     free(outputs);
438
439     return TDM_ERROR_NONE;
440
441 failed_update:
442     _tdm_display_destroy_private_display(private_display);
443     free(outputs);
444     return ret;
445 }
446
447
448 EXTERN tdm_error
449 tdm_display_update(tdm_display *dpy)
450 {
451     tdm_private_display *private_display;
452     tdm_error ret;
453
454     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
455
456     private_display = dpy;
457     pthread_mutex_lock(&private_display->lock);
458
459     ret = _tdm_display_update_internal(private_display, 1);
460
461     pthread_mutex_unlock(&private_display->lock);
462
463     return ret;
464 }
465
466 #define SUFFIX_MODULE    ".so"
467 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
468
469 int tdm_debug;
470
471 static tdm_private_display *g_private_display;
472 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
473
474 static tdm_error
475 _tdm_display_check_module(tdm_backend_module *module)
476 {
477     const char *name;
478     const char *vendor;
479     int major, minor;
480     int abimaj, abimin;
481
482     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
483     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
484
485     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
486
487     name = module->name ? module->name : "unknown";
488     vendor = module->vendor ? module->vendor : "unknown";
489     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
490     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
491
492     TDM_INFO("TDM module name: %s", name);
493     TDM_INFO("'%s' vendor: %s", name, vendor);
494     TDM_INFO("'%s' version: %d.%d", name, major, minor);
495
496     if (major != abimaj)
497     {
498         TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
499         return TDM_ERROR_BAD_MODULE;
500     }
501
502     if (minor > abimin)
503     {
504         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
505         return TDM_ERROR_BAD_MODULE;
506     }
507
508     if (!module->init)
509     {
510         TDM_ERR("'%s' doesn't have init function", name);
511         return TDM_ERROR_BAD_MODULE;
512     }
513
514     if (!module->deinit)
515     {
516         TDM_ERR("'%s' doesn't have deinit function", name);
517         return TDM_ERROR_BAD_MODULE;
518     }
519
520     return TDM_ERROR_NONE;
521 }
522
523 static tdm_error
524 _tdm_display_check_backend_functions(tdm_private_display *private_display)
525 {
526     tdm_func_display *func_display = &private_display->func_display;
527     tdm_error ret;
528
529     /* below functions should be implemented in backend side */
530
531     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
532     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
533     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
534     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_capability, TDM_ERROR_BAD_MODULE);
535     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
536     TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
537
538     ret = func_display->display_get_capabilitiy(private_display->bdata,
539                                                 &private_display->caps_display);
540     if (ret != TDM_ERROR_NONE)
541     {
542         TDM_ERR("display_get_capabilitiy() failed");
543         return TDM_ERROR_BAD_MODULE;
544     }
545
546     if (private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_PP)
547     {
548         tdm_func_pp *func_pp = &private_display->func_pp;
549         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
550         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
551         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
552         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
553         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
554     }
555
556     if (private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
557     {
558         tdm_func_capture *func_capture = &private_display->func_capture;
559         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
560         TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
561         TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
562         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
563         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
564         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
565     }
566
567     return TDM_ERROR_NONE;
568 }
569
570 static tdm_error
571 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
572 {
573     char path[PATH_MAX] = {0,};
574     tdm_backend_module *module_data;
575     void *module;
576     tdm_error ret;
577
578     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
579
580     module = dlopen(path, RTLD_LAZY);
581     if (!module)
582     {
583         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
584         return TDM_ERROR_BAD_MODULE;
585     }
586
587     module_data = dlsym(module, "tdm_backend_module_data");
588     if (!module_data)
589     {
590         TDM_ERR("'%s' doesn't have data object", file);
591         ret = TDM_ERROR_BAD_MODULE;
592         goto failed_load;
593     }
594
595     /* check if version, init() and deinit() are valid or not */
596     ret = _tdm_display_check_module(module_data);
597     if (ret != TDM_ERROR_NONE)
598         goto failed_load;
599
600     /* We don't care if backend_data is NULL or not. It's up to backend. */
601     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
602     if (ret != TDM_ERROR_NONE)
603     {
604         TDM_ERR("'%s' init failed", file);
605         goto failed_load;
606     }
607
608     ret = _tdm_display_check_backend_functions(private_display);
609     if (ret != TDM_ERROR_NONE)
610     {
611         module_data->deinit(private_display->bdata);
612         private_display->bdata = NULL;
613         goto failed_load;
614     }
615
616     private_display->module_data = module_data;
617     private_display->module = module;
618
619     TDM_INFO("Success to load module(%s)", file);
620
621     return TDM_ERROR_NONE;
622 failed_load:
623     dlclose(module);
624     return ret;
625 }
626
627 static tdm_error
628 _tdm_display_load_module(tdm_private_display *private_display)
629 {
630     const char *module_name;
631     struct dirent **namelist;
632     int n;
633     tdm_error ret = 0;
634
635     module_name = getenv("TDM_MODULE");
636     if (!module_name)
637         module_name = DEFAULT_MODULE;
638
639     /* load bufmgr priv from default lib */
640     ret = _tdm_display_load_module_with_file(private_display, module_name);
641     if (ret == TDM_ERROR_NONE)
642         return TDM_ERROR_NONE;
643
644     /* load bufmgr priv from configured path */
645     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
646     if (n < 0)
647     {
648         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
649         return TDM_ERROR_BAD_MODULE;
650     }
651
652     ret = TDM_ERROR_BAD_MODULE;
653     while (n--)
654     {
655         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
656             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
657
658         free(namelist[n]);
659     }
660     free(namelist);
661
662     return ret;
663 }
664
665 static void
666 _tdm_display_unload_module(tdm_private_display *private_display)
667 {
668     if (private_display->module_data)
669         private_display->module_data->deinit(private_display->bdata);
670     if (private_display->module)
671         dlclose(private_display->module);
672
673     private_display->bdata = NULL;
674     private_display->module_data = NULL;
675     private_display->module = NULL;
676 }
677
678 EXTERN tdm_display*
679 tdm_display_init(tdm_error *error)
680 {
681     tdm_private_display *private_display = NULL;
682     const char *debug;
683     tdm_error ret;
684
685     pthread_mutex_lock(&gLock);
686
687     if (g_private_display)
688     {
689         g_private_display->init_count++;
690         pthread_mutex_unlock(&gLock);
691         if (error)
692             *error = TDM_ERROR_NONE;
693         return g_private_display;
694     }
695
696     debug = getenv("TDM_DEBUG");
697     if (debug && (strstr(debug, "1")))
698         tdm_debug = 1;
699
700     private_display = calloc(1, sizeof(tdm_private_display));
701     if (!private_display)
702     {
703         ret = TDM_ERROR_OUT_OF_MEMORY;
704         TDM_ERR("'private_display != NULL' failed");
705         goto failed_alloc;
706     }
707
708     if (pthread_mutex_init(&private_display->lock, NULL))
709     {
710         ret = TDM_ERROR_OPERATION_FAILED;
711         TDM_ERR("mutex init failed: %m");
712         goto failed_mutex_init;
713     }
714
715     ret = _tdm_display_load_module(private_display);
716     if (ret != TDM_ERROR_NONE)
717         goto failed_load;
718
719     ret = _tdm_display_update_internal(private_display, 0);
720     if (ret != TDM_ERROR_NONE)
721         goto failed_update;
722
723     private_display->init_count = 1;
724
725     g_private_display = private_display;
726
727     if (error)
728         *error = TDM_ERROR_NONE;
729
730     pthread_mutex_unlock(&gLock);
731
732     return (tdm_display*)private_display;
733
734 failed_update:
735     _tdm_display_unload_module(private_display);
736 failed_load:
737     pthread_mutex_destroy(&private_display->lock);
738 failed_mutex_init:
739     free(private_display);
740 failed_alloc:
741     tdm_debug = 0;
742     if (error)
743         *error = ret;
744     pthread_mutex_unlock(&gLock);
745     return NULL;
746 }
747
748 EXTERN void
749 tdm_display_deinit(tdm_display *dpy)
750 {
751     tdm_private_display *private_display = dpy;
752
753     if (!private_display)
754         return;
755
756     pthread_mutex_lock(&gLock);
757
758     private_display->init_count--;
759     if (private_display->init_count > 0)
760     {
761         pthread_mutex_unlock(&gLock);
762         return;
763     }
764
765     pthread_mutex_lock(&private_display->lock);
766
767     _tdm_display_destroy_private_display(private_display);
768     _tdm_display_unload_module(private_display);
769
770     pthread_mutex_unlock(&private_display->lock);
771
772     pthread_mutex_destroy(&private_display->lock);
773     free(private_display);
774     tdm_debug = 0;
775
776     pthread_mutex_unlock(&gLock);
777 }
778