checking backend ABI version
[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     {
314         TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
315                  caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
316                  caps->modes[i].flags, caps->modes[i].type);
317         TDM_DBG("\t\t %d, %d, %d, %d, %d",
318                  caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
319                  caps->modes[i].htotal, caps->modes[i].hskew);
320         TDM_DBG("\t\t %d, %d, %d, %d, %d",
321                  caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
322                  caps->modes[i].vtotal, caps->modes[i].vscan);
323     }
324     TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
325     TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
326     TDM_DBG("output align: %d", caps->preferred_align);
327
328     return TDM_ERROR_NONE;
329 }
330
331 static tdm_error
332 _tdm_display_update_layer(tdm_private_display *private_display,
333                           tdm_private_output *private_output,
334                           tdm_layer *layer_backend)
335 {
336     tdm_private_layer *private_layer;
337     tdm_error ret;
338
339     private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
340     if (!private_layer)
341     {
342         private_layer = calloc(1, sizeof(tdm_private_layer));
343         TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
344
345         LIST_ADD(&private_layer->link, &private_output->layer_list);
346         private_layer->private_display = private_display;
347         private_layer->private_output = private_output;
348         private_layer->layer_backend = layer_backend;
349
350         LIST_INITHEAD(&private_layer->capture_list);
351
352         private_layer->usable = 1;
353     }
354     else
355         _tdm_display_destroy_caps_layer(&private_layer->caps);
356
357     ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
358     if (ret != TDM_ERROR_NONE)
359         goto failed_update;
360
361     return TDM_ERROR_NONE;
362 failed_update:
363     _tdm_display_destroy_private_layer(private_layer);
364     return ret;
365 }
366
367 static tdm_error
368 _tdm_display_update_output(tdm_private_display *private_display,
369                            tdm_output *output_backend, int pipe)
370 {
371     tdm_func_output *func_output = &private_display->func_output;
372     tdm_private_output *private_output = NULL;
373     tdm_layer **layers = NULL;
374     int layer_count = 0, i;
375     tdm_error ret;
376
377     private_output = _tdm_display_find_private_output(private_display, output_backend);
378     if (!private_output)
379     {
380         private_output = calloc(1, sizeof(tdm_private_output));
381         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
382
383         LIST_ADD(&private_output->link, &private_display->output_list);
384         private_output->private_display = private_display;
385         private_output->output_backend = output_backend;
386         private_output->pipe = pipe;
387
388         LIST_INITHEAD(&private_output->layer_list);
389         LIST_INITHEAD(&private_output->capture_list);
390         LIST_INITHEAD(&private_output->vblank_handler_list);
391         LIST_INITHEAD(&private_output->commit_handler_list);
392     }
393     else
394         _tdm_display_destroy_caps_output(&private_output->caps);
395
396     ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
397     if (ret != TDM_ERROR_NONE)
398         return ret;
399
400     layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
401     if (ret != TDM_ERROR_NONE)
402         goto failed_update;
403
404     for (i = 0; i < layer_count; i++)
405     {
406         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
407         if (ret != TDM_ERROR_NONE)
408             goto failed_update;
409     }
410
411     free(layers);
412
413     return TDM_ERROR_NONE;
414 failed_update:
415     _tdm_display_destroy_private_output(private_output);
416     free(layers);
417     return ret;
418 }
419
420 static tdm_error
421 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
422 {
423     tdm_func_display *func_display = &private_display->func_display;
424     tdm_output **outputs = NULL;
425     int output_count = 0, i;
426     tdm_error ret;
427
428     LIST_INITHEAD(&private_display->output_list);
429     LIST_INITHEAD(&private_display->pp_list);
430
431     if (!only_display)
432     {
433         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
434         if (ret != TDM_ERROR_NONE)
435             goto failed_update;
436
437         ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
438         if (ret != TDM_ERROR_NONE)
439             goto failed_update;
440     }
441
442     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
443     if (ret != TDM_ERROR_NONE)
444         goto failed_update;
445
446     for (i = 0; i < output_count; i++)
447     {
448         ret = _tdm_display_update_output(private_display, outputs[i], i);
449         if (ret != TDM_ERROR_NONE)
450             goto failed_update;
451     }
452
453     free(outputs);
454
455     return TDM_ERROR_NONE;
456
457 failed_update:
458     _tdm_display_destroy_private_display(private_display);
459     free(outputs);
460     return ret;
461 }
462
463 static tdm_error
464 _tdm_display_init_bufmgr(tdm_private_display *private_display)
465 {
466     tdm_func_display *func_display = &private_display->func_display;
467     int buffer_fd = -1;
468     tdm_error ret;
469
470     if (func_display->display_get_buffer_fd)
471     {
472         ret = func_display->display_get_buffer_fd(private_display->bdata, &buffer_fd);
473         if (ret != TDM_ERROR_NONE)
474         {
475             TDM_ERR("failed to get buffer fd");
476             return ret;
477         }
478     }
479
480     private_display->bufmgr = tbm_bufmgr_init(buffer_fd);
481     if (!private_display->bufmgr)
482     {
483         TDM_ERR("failed to init TBM bufmgr: fd(%d)", buffer_fd);
484         return TDM_ERROR_OUT_OF_MEMORY;
485     }
486
487     TDM_INFO("init TBM bufmgr: fd(%d)", buffer_fd);
488
489     return TDM_ERROR_NONE;
490 }
491
492
493 EXTERN tdm_error
494 tdm_display_update(tdm_display *dpy)
495 {
496     tdm_private_display *private_display;
497     tdm_error ret;
498
499     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
500
501     private_display = dpy;
502     pthread_mutex_lock(&private_display->lock);
503
504     ret = _tdm_display_update_internal(private_display, 1);
505
506     pthread_mutex_unlock(&private_display->lock);
507
508     return ret;
509 }
510
511 #define SUFFIX_MODULE    ".so"
512 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
513
514 int tdm_debug;
515
516 static tdm_private_display *g_private_display;
517 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
518
519 static tdm_error
520 _tdm_display_check_module(tdm_backend_module *module)
521 {
522     const char *name;
523     const char *vendor;
524     int major, minor;
525     int abimaj, abimin;
526
527     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
528     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
529
530     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
531
532     name = module->name ? module->name : "unknown";
533     vendor = module->vendor ? module->vendor : "unknown";
534     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
535     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
536
537     TDM_INFO("TDM module name: %s", name);
538     TDM_INFO("'%s' vendor: %s", name, vendor);
539     TDM_INFO("'%s' version: %d.%d", name, major, minor);
540
541     if (major != abimaj)
542     {
543         TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
544         return TDM_ERROR_BAD_MODULE;
545     }
546
547     if (minor > abimin)
548     {
549         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
550         return TDM_ERROR_BAD_MODULE;
551     }
552
553     if (!module->init)
554     {
555         TDM_ERR("'%s' doesn't have init function", name);
556         return TDM_ERROR_BAD_MODULE;
557     }
558
559     if (!module->deinit)
560     {
561         TDM_ERR("'%s' doesn't have deinit function", name);
562         return TDM_ERROR_BAD_MODULE;
563     }
564
565     return TDM_ERROR_NONE;
566 }
567
568 static tdm_error
569 _tdm_display_check_backend_functions(tdm_private_display *private_display)
570 {
571     tdm_func_display *func_display = &private_display->func_display;
572     tdm_func_output *func_output = &private_display->func_output;
573     tdm_func_layer *func_layer = &private_display->func_layer;
574     tdm_error ret;
575
576     /* below functions should be implemented in backend side */
577
578     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
579     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
580     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
581     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
582     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
583     TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
584
585     ret = func_display->display_get_capabilitiy(private_display->bdata,
586                                                 &private_display->caps_display);
587     if (ret != TDM_ERROR_NONE)
588     {
589         TDM_ERR("display_get_capabilitiy() failed");
590         return TDM_ERROR_BAD_MODULE;
591     }
592
593     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
594     {
595         tdm_func_pp *func_pp = &private_display->func_pp;
596         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
597         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
598         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
599         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
600         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
601     }
602
603     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
604     {
605         tdm_func_capture *func_capture = &private_display->func_capture;
606         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
607         TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
608         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
609         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
610         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
611         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
612     }
613
614     return TDM_ERROR_NONE;
615 }
616
617 static tdm_error
618 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
619 {
620     char path[PATH_MAX] = {0,};
621     tdm_backend_module *module_data;
622     void *module;
623     tdm_error ret;
624
625     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
626
627     module = dlopen(path, RTLD_LAZY);
628     if (!module)
629     {
630         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
631         return TDM_ERROR_BAD_MODULE;
632     }
633
634     module_data = dlsym(module, "tdm_backend_module_data");
635     if (!module_data)
636     {
637         TDM_ERR("'%s' doesn't have data object", file);
638         ret = TDM_ERROR_BAD_MODULE;
639         goto failed_load;
640     }
641
642     private_display->module_data = module_data;
643     private_display->module = module;
644
645     /* check if version, init() and deinit() are valid or not */
646     ret = _tdm_display_check_module(module_data);
647     if (ret != TDM_ERROR_NONE)
648         goto failed_load;
649
650     /* We don't care if backend_data is NULL or not. It's up to backend. */
651     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
652     if (ret != TDM_ERROR_NONE)
653     {
654         TDM_ERR("'%s' init failed", file);
655         goto failed_load;
656     }
657
658     ret = _tdm_display_check_backend_functions(private_display);
659     if (ret != TDM_ERROR_NONE)
660     {
661         module_data->deinit(private_display->bdata);
662         private_display->bdata = NULL;
663         goto failed_load;
664     }
665
666     TDM_INFO("Success to load module(%s)", file);
667
668     return TDM_ERROR_NONE;
669 failed_load:
670     dlclose(module);
671     private_display->module_data = NULL;
672     private_display->module = NULL;
673     return ret;
674 }
675
676 static tdm_error
677 _tdm_display_load_module(tdm_private_display *private_display)
678 {
679     const char *module_name;
680     struct dirent **namelist;
681     int n;
682     tdm_error ret = 0;
683
684     module_name = getenv("TDM_MODULE");
685     if (!module_name)
686         module_name = DEFAULT_MODULE;
687
688     /* load bufmgr priv from default lib */
689     ret = _tdm_display_load_module_with_file(private_display, module_name);
690     if (ret == TDM_ERROR_NONE)
691         return TDM_ERROR_NONE;
692
693     /* load bufmgr priv from configured path */
694     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
695     if (n < 0)
696     {
697         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
698         return TDM_ERROR_BAD_MODULE;
699     }
700
701     ret = TDM_ERROR_BAD_MODULE;
702     while (n--)
703     {
704         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
705             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
706
707         free(namelist[n]);
708     }
709     free(namelist);
710
711     return ret;
712 }
713
714 static void
715 _tdm_display_unload_module(tdm_private_display *private_display)
716 {
717     if (private_display->module_data)
718         private_display->module_data->deinit(private_display->bdata);
719     if (private_display->module)
720         dlclose(private_display->module);
721
722     private_display->bdata = NULL;
723     private_display->module_data = NULL;
724     private_display->module = NULL;
725 }
726
727 EXTERN tdm_display*
728 tdm_display_init(tdm_error *error)
729 {
730     tdm_private_display *private_display = NULL;
731     const char *debug;
732     tdm_error ret;
733
734     pthread_mutex_lock(&gLock);
735
736     if (g_private_display)
737     {
738         g_private_display->init_count++;
739         pthread_mutex_unlock(&gLock);
740         if (error)
741             *error = TDM_ERROR_NONE;
742         return g_private_display;
743     }
744
745     debug = getenv("TDM_DEBUG");
746     if (debug && (strstr(debug, "1")))
747         tdm_debug = 1;
748
749     private_display = calloc(1, sizeof(tdm_private_display));
750     if (!private_display)
751     {
752         ret = TDM_ERROR_OUT_OF_MEMORY;
753         TDM_ERR("'private_display != NULL' failed");
754         goto failed_alloc;
755     }
756
757     if (pthread_mutex_init(&private_display->lock, NULL))
758     {
759         ret = TDM_ERROR_OPERATION_FAILED;
760         TDM_ERR("mutex init failed: %m");
761         goto failed_mutex_init;
762     }
763
764     ret = _tdm_display_load_module(private_display);
765     if (ret != TDM_ERROR_NONE)
766         goto failed_load;
767
768     ret = _tdm_display_update_internal(private_display, 0);
769     if (ret != TDM_ERROR_NONE)
770         goto failed_update;
771
772     ret = _tdm_display_init_bufmgr(private_display);
773     if (ret != TDM_ERROR_NONE)
774         goto failed_update;
775
776     private_display->init_count = 1;
777
778     g_private_display = private_display;
779
780     if (error)
781         *error = TDM_ERROR_NONE;
782
783     pthread_mutex_unlock(&gLock);
784
785     return (tdm_display*)private_display;
786
787 failed_update:
788     _tdm_display_unload_module(private_display);
789 failed_load:
790     pthread_mutex_destroy(&private_display->lock);
791 failed_mutex_init:
792     free(private_display);
793 failed_alloc:
794     tdm_debug = 0;
795     if (error)
796         *error = ret;
797     pthread_mutex_unlock(&gLock);
798     return NULL;
799 }
800
801 EXTERN void
802 tdm_display_deinit(tdm_display *dpy)
803 {
804     tdm_private_display *private_display = dpy;
805
806     if (!private_display)
807         return;
808
809     pthread_mutex_lock(&gLock);
810
811     private_display->init_count--;
812     if (private_display->init_count > 0)
813     {
814         pthread_mutex_unlock(&gLock);
815         return;
816     }
817
818     pthread_mutex_lock(&private_display->lock);
819
820     if (private_display->bufmgr)
821         tbm_bufmgr_deinit(private_display->bufmgr);
822
823     _tdm_display_destroy_private_display(private_display);
824     _tdm_display_unload_module(private_display);
825
826     pthread_mutex_unlock(&private_display->lock);
827
828     pthread_mutex_destroy(&private_display->lock);
829     free(private_display);
830     tdm_debug = 0;
831
832     pthread_mutex_unlock(&gLock);
833 }
834