fix deadlock and enhance lock/unlock to protect the backend module's data
[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 #include "tdm_helper.h"
44
45 pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER;
46 int tdm_mutex_locked;
47
48 static tdm_private_layer *
49 _tdm_display_find_private_layer(tdm_private_output *private_output,
50                                 tdm_layer *layer_backend)
51 {
52         tdm_private_layer *private_layer = NULL;
53
54         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
55                 if (private_layer->layer_backend == layer_backend)
56                         return private_layer;
57         }
58
59         return NULL;
60 }
61
62 static tdm_private_output *
63 _tdm_display_find_private_output(tdm_private_display *private_display,
64                                  tdm_output *output_backend)
65 {
66         tdm_private_output *private_output = NULL;
67
68         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
69                 if (private_output->output_backend == output_backend)
70                         return private_output;
71         }
72
73         return NULL;
74 }
75
76 INTERN tdm_private_output *
77 tdm_display_find_output_stamp(tdm_private_display *private_display,
78                               unsigned long stamp)
79 {
80         tdm_private_output *private_output = NULL;
81
82         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
83                 if (private_output->stamp == stamp)
84                         return private_output;
85         }
86
87         return NULL;
88 }
89
90 static void
91 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
92 {
93         free(caps_pp->formats);
94         memset(caps_pp, 0, sizeof(tdm_caps_pp));
95 }
96
97 static void
98 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
99 {
100         free(caps_capture->formats);
101         memset(caps_capture, 0, sizeof(tdm_caps_capture));
102 }
103
104 static void
105 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
106 {
107         free(caps_layer->formats);
108         free(caps_layer->props);
109         memset(caps_layer, 0, sizeof(tdm_caps_layer));
110 }
111
112 static void
113 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
114 {
115         free(caps_output->modes);
116         free(caps_output->props);
117         memset(caps_output, 0, sizeof(tdm_caps_output));
118 }
119
120 static void
121 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
122 {
123         tdm_private_capture *c = NULL, *cc = NULL;
124
125         LIST_DEL(&private_layer->link);
126
127         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
128         tdm_capture_destroy_internal(c);
129
130         _tdm_display_destroy_caps_layer(&private_layer->caps);
131
132         free(private_layer);
133 }
134
135 static void
136 _tdm_display_destroy_private_output(tdm_private_output *private_output)
137 {
138         tdm_private_layer *l = NULL, *ll = NULL;
139         tdm_private_capture *c = NULL, *cc = NULL;
140         tdm_private_vblank_handler *v = NULL, *vv = NULL;
141         tdm_private_commit_handler *m = NULL, *mm = NULL;
142         tdm_private_change_handler *h = NULL, *hh = NULL;
143
144         LIST_DEL(&private_output->link);
145
146         free(private_output->layers_ptr);
147
148         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
149                 LIST_DEL(&v->link);
150                 free(v);
151         }
152
153         LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
154                 LIST_DEL(&m->link);
155                 free(m);
156         }
157
158         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
159                 LIST_DEL(&h->link);
160                 free(h);
161         }
162
163         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
164                 LIST_DEL(&h->link);
165                 free(h);
166         }
167
168         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
169         tdm_capture_destroy_internal(c);
170
171         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
172         _tdm_display_destroy_private_layer(l);
173
174         _tdm_display_destroy_caps_output(&private_output->caps);
175
176         private_output->stamp = 0;
177         free(private_output);
178 }
179
180 static void
181 _tdm_display_destroy_private_display(tdm_private_display *private_display)
182 {
183         tdm_private_output *o = NULL, *oo = NULL;
184         tdm_private_pp *p = NULL, *pp = NULL;
185
186         free(private_display->outputs_ptr);
187
188         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
189         tdm_pp_destroy_internal(p);
190
191         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
192         _tdm_display_destroy_private_output(o);
193
194         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
195         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
196
197         private_display->capabilities = 0;
198         private_display->caps_display.max_layer_count = -1;
199 }
200
201 static tdm_error
202 _tdm_display_update_caps_pp(tdm_private_display *private_display,
203                             tdm_caps_pp *caps)
204 {
205         tdm_func_display *func_display = &private_display->func_display;
206         char buf[1024];
207         int bufsize = sizeof(buf);
208         char *str_buf = buf;
209         int *len_buf = &bufsize;
210         int i;
211         tdm_error ret;
212
213         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
214                 return TDM_ERROR_NONE;
215
216         if (!func_display->display_get_pp_capability) {
217                 TDM_ERR("no display_get_pp_capability()");
218                 return TDM_ERROR_BAD_MODULE;
219         }
220
221         ret = func_display->display_get_pp_capability(private_display->bdata, caps);
222         if (ret != TDM_ERROR_NONE) {
223                 TDM_ERR("display_get_pp_capability() failed");
224                 return TDM_ERROR_BAD_MODULE;
225         }
226
227         TDM_DBG("pp capabilities: %x", caps->capabilities);
228         buf[0] = '\0';
229         for (i = 0; i < caps->format_count; i++)
230                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
231         TDM_DBG("pp formats: %s", buf);
232         TDM_DBG("pp min  : %dx%d", caps->min_w, caps->min_h);
233         TDM_DBG("pp max  : %dx%d", caps->max_w, caps->max_h);
234         TDM_DBG("pp align: %d", caps->preferred_align);
235
236         return TDM_ERROR_NONE;
237 }
238
239 static tdm_error
240 _tdm_display_update_caps_capture(tdm_private_display *private_display,
241                                  tdm_caps_capture *caps)
242 {
243         tdm_func_display *func_display = &private_display->func_display;
244         char buf[1024];
245         int bufsize = sizeof(buf);
246         char *str_buf = buf;
247         int *len_buf = &bufsize;
248         int i;
249         tdm_error ret;
250
251         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
252                 return TDM_ERROR_NONE;
253
254         if (!func_display->display_get_capture_capability) {
255                 TDM_ERR("no display_get_capture_capability()");
256                 return TDM_ERROR_BAD_MODULE;
257         }
258
259         ret = func_display->display_get_capture_capability(private_display->bdata,
260                         caps);
261         if (ret != TDM_ERROR_NONE) {
262                 TDM_ERR("display_get_capture_capability() failed");
263                 return TDM_ERROR_BAD_MODULE;
264         }
265
266         buf[0] = '\0';
267         for (i = 0; i < caps->format_count; i++)
268                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
269         TDM_DBG("capture formats: %s", buf);
270
271         return TDM_ERROR_NONE;
272 }
273
274 static tdm_error
275 _tdm_display_update_caps_layer(tdm_private_display *private_display,
276                                tdm_layer *layer_backend, tdm_caps_layer *caps)
277 {
278         tdm_func_layer *func_layer = &private_display->func_layer;
279         char buf[1024];
280         int bufsize = sizeof(buf);
281         char *str_buf = buf;
282         int *len_buf = &bufsize;
283         int i;
284         tdm_error ret;
285
286         if (!func_layer->layer_get_capability) {
287                 TDM_ERR("no layer_get_capability()");
288                 return TDM_ERROR_BAD_MODULE;
289         }
290
291         ret = func_layer->layer_get_capability(layer_backend, caps);
292         if (ret != TDM_ERROR_NONE) {
293                 TDM_ERR("layer_get_capability() failed");
294                 return TDM_ERROR_BAD_MODULE;
295         }
296
297         TDM_DBG("layer capabilities: %x", caps->capabilities);
298         TDM_DBG("layer zpos : %d", caps->zpos);
299         buf[0] = '\0';
300         for (i = 0; i < caps->format_count; i++)
301                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
302         TDM_DBG("layer formats: %s", buf);
303         for (i = 0; i < caps->prop_count; i++)
304                 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
305
306         return TDM_ERROR_NONE;
307 }
308
309 static tdm_error
310 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
311                                 tdm_output *output_backend, tdm_caps_output *caps)
312 {
313         tdm_func_output *func_output = &private_display->func_output;
314         char temp[TDM_NAME_LEN];
315         int i;
316         tdm_error ret;
317
318         if (!func_output->output_get_capability) {
319                 TDM_ERR("no output_get_capability()");
320                 return TDM_ERROR_BAD_MODULE;
321         }
322
323         ret = func_output->output_get_capability(output_backend, caps);
324         if (ret != TDM_ERROR_NONE) {
325                 TDM_ERR("output_get_capability() failed");
326                 return TDM_ERROR_BAD_MODULE;
327         }
328
329         /* FIXME: Use model for tdm client to distinguish amoung outputs */
330         snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
331         snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
332
333         TDM_DBG("output maker: %s", caps->maker);
334         TDM_DBG("output model: %s", caps->model);
335         TDM_DBG("output name: %s", caps->name);
336         TDM_DBG("output status: %d", caps->status);
337         TDM_DBG("output type : %d", caps->type);
338         for (i = 0; i < caps->prop_count; i++)
339                 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
340         for (i = 0; i < caps->mode_count; i++) {
341                 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
342                         caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
343                         caps->modes[i].flags, caps->modes[i].type);
344                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
345                         caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
346                         caps->modes[i].htotal, caps->modes[i].hskew);
347                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
348                         caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
349                         caps->modes[i].vtotal, caps->modes[i].vscan);
350         }
351         TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
352         TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
353         TDM_DBG("output align: %d", caps->preferred_align);
354
355         return TDM_ERROR_NONE;
356 }
357
358 static tdm_error
359 _tdm_display_update_layer(tdm_private_display *private_display,
360                           tdm_private_output *private_output,
361                           tdm_layer *layer_backend)
362 {
363         tdm_private_layer *private_layer;
364         tdm_error ret;
365
366         private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
367         if (!private_layer) {
368                 private_layer = calloc(1, sizeof(tdm_private_layer));
369                 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
370
371                 LIST_ADD(&private_layer->link, &private_output->layer_list);
372                 private_layer->private_display = private_display;
373                 private_layer->private_output = private_output;
374                 private_layer->layer_backend = layer_backend;
375
376                 LIST_INITHEAD(&private_layer->capture_list);
377
378                 private_layer->usable = 1;
379         } else
380                 _tdm_display_destroy_caps_layer(&private_layer->caps);
381
382         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
383                                              &private_layer->caps);
384         if (ret != TDM_ERROR_NONE)
385                 goto failed_update;
386
387         return TDM_ERROR_NONE;
388 failed_update:
389         _tdm_display_destroy_private_layer(private_layer);
390         return ret;
391 }
392
393 static tdm_error
394 _tdm_display_update_output(tdm_private_display *private_display,
395                            tdm_output *output_backend, int pipe)
396 {
397         tdm_func_output *func_output = &private_display->func_output;
398         tdm_private_output *private_output = NULL;
399         tdm_layer **layers = NULL;
400         int layer_count = 0, i;
401         tdm_error ret;
402
403         private_output = _tdm_display_find_private_output(private_display,
404                          output_backend);
405         if (!private_output) {
406                 private_output = calloc(1, sizeof(tdm_private_output));
407                 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
408
409                 private_output->stamp = tdm_helper_get_time_in_millis();
410                 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
411                         private_output->stamp++;
412
413                 LIST_ADD(&private_output->link, &private_display->output_list);
414
415                 private_output->private_display = private_display;
416                 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
417                 private_output->output_backend = output_backend;
418                 private_output->pipe = pipe;
419
420                 LIST_INITHEAD(&private_output->layer_list);
421                 LIST_INITHEAD(&private_output->capture_list);
422                 LIST_INITHEAD(&private_output->vblank_handler_list);
423                 LIST_INITHEAD(&private_output->commit_handler_list);
424                 LIST_INITHEAD(&private_output->change_handler_list_main);
425                 LIST_INITHEAD(&private_output->change_handler_list_sub);
426
427                 if (func_output->output_set_status_handler)
428                         func_output->output_set_status_handler(private_output->output_backend,
429                                                                tdm_output_cb_status,
430                                                                private_output);
431
432         } else
433                 _tdm_display_destroy_caps_output(&private_output->caps);
434
435         ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
436                                               &private_output->caps);
437         if (ret != TDM_ERROR_NONE)
438                 return ret;
439
440         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
441         if (ret != TDM_ERROR_NONE)
442                 goto failed_update;
443
444         for (i = 0; i < layer_count; i++) {
445                 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
446                 if (ret != TDM_ERROR_NONE)
447                         goto failed_update;
448         }
449
450         free(layers);
451
452         return TDM_ERROR_NONE;
453 failed_update:
454         _tdm_display_destroy_private_output(private_output);
455         free(layers);
456         return ret;
457 }
458
459 static tdm_error
460 _tdm_display_update_internal(tdm_private_display *private_display,
461                              int only_display)
462 {
463         tdm_func_display *func_display = &private_display->func_display;
464         tdm_output **outputs = NULL;
465         int output_count = 0, i;
466         tdm_error ret;
467
468         LIST_INITHEAD(&private_display->output_list);
469         LIST_INITHEAD(&private_display->pp_list);
470         LIST_INITHEAD(&private_display->capture_list);
471
472         if (!only_display) {
473                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
474                 if (ret != TDM_ERROR_NONE)
475                         goto failed_update;
476
477                 ret = _tdm_display_update_caps_capture(private_display,
478                                                        &private_display->caps_capture);
479                 if (ret != TDM_ERROR_NONE)
480                         goto failed_update;
481         }
482
483         outputs = func_display->display_get_outputs(private_display->bdata,
484                         &output_count, &ret);
485         if (ret != TDM_ERROR_NONE)
486                 goto failed_update;
487
488         for (i = 0; i < output_count; i++) {
489                 ret = _tdm_display_update_output(private_display, outputs[i], i);
490                 if (ret != TDM_ERROR_NONE)
491                         goto failed_update;
492         }
493
494         free(outputs);
495
496         return TDM_ERROR_NONE;
497
498 failed_update:
499         _tdm_display_destroy_private_display(private_display);
500         free(outputs);
501         return ret;
502 }
503
504 EXTERN tdm_error
505 tdm_display_update(tdm_display *dpy)
506 {
507         tdm_private_display *private_display;
508         tdm_error ret;
509
510         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
511
512         private_display = dpy;
513         _pthread_mutex_lock(&private_display->lock);
514
515         ret = _tdm_display_update_internal(private_display, 1);
516
517         _pthread_mutex_unlock(&private_display->lock);
518
519         return ret;
520 }
521
522 #define SUFFIX_MODULE    ".so"
523 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
524
525 int tdm_debug;
526 int tdm_debug_buffer;
527 int tdm_debug_thread;
528 int tdm_debug_mutex;
529
530 static tdm_private_display *g_private_display;
531 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
532
533 static tdm_error
534 _tdm_display_check_module(tdm_backend_module *module)
535 {
536         const char *name;
537         const char *vendor;
538         int major, minor;
539         int abimaj, abimin;
540
541         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
542         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
543
544         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
545
546         name = module->name ? module->name : "unknown";
547         vendor = module->vendor ? module->vendor : "unknown";
548         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
549         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
550
551         TDM_INFO("TDM module name: %s", name);
552         TDM_INFO("'%s' vendor: %s", name, vendor);
553         TDM_INFO("'%s' version: %d.%d", name, major, minor);
554
555         if (major != abimaj) {
556                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
557                 return TDM_ERROR_BAD_MODULE;
558         }
559
560         if (minor > abimin) {
561                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
562                 return TDM_ERROR_BAD_MODULE;
563         }
564
565         if (!module->init) {
566                 TDM_ERR("'%s' doesn't have init function", name);
567                 return TDM_ERROR_BAD_MODULE;
568         }
569
570         if (!module->deinit) {
571                 TDM_ERR("'%s' doesn't have deinit function", name);
572                 return TDM_ERROR_BAD_MODULE;
573         }
574
575         return TDM_ERROR_NONE;
576 }
577
578 static tdm_error
579 _tdm_display_check_backend_functions(tdm_private_display *private_display)
580 {
581         tdm_func_display *func_display = &private_display->func_display;
582         tdm_func_output *func_output = &private_display->func_output;
583         tdm_func_layer *func_layer = &private_display->func_layer;
584         tdm_error ret;
585
586         /* below functions should be implemented in backend side */
587
588         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
589         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
590                                TDM_ERROR_BAD_MODULE);
591         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
592         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
593                                TDM_ERROR_BAD_MODULE);
594         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
595         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
596
597         ret = func_display->display_get_capabilitiy(private_display->bdata,
598                         &private_display->caps_display);
599         if (ret != TDM_ERROR_NONE) {
600                 TDM_ERR("display_get_capabilitiy() failed");
601                 return TDM_ERROR_BAD_MODULE;
602         }
603
604         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
605                 tdm_func_pp *func_pp = &private_display->func_pp;
606                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
607                                        TDM_ERROR_BAD_MODULE);
608                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
609                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
610                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
611                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
612         }
613
614         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
615                 tdm_func_capture *func_capture = &private_display->func_capture;
616                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
617                                        TDM_ERROR_BAD_MODULE);
618                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
619                                        TDM_ERROR_BAD_MODULE);
620                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
621                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
622                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
623                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
624                                        TDM_ERROR_BAD_MODULE);
625         }
626
627         return TDM_ERROR_NONE;
628 }
629
630 static tdm_error
631 _tdm_display_load_module_with_file(tdm_private_display *private_display,
632                                    const char *file)
633 {
634         char path[PATH_MAX] = {0,};
635         tdm_backend_module *module_data;
636         void *module;
637         tdm_error ret;
638
639         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
640
641         TDM_TRACE_BEGIN(Load_Backend);
642
643         module = dlopen(path, RTLD_LAZY);
644         if (!module) {
645                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
646                 TDM_TRACE_END();
647                 return TDM_ERROR_BAD_MODULE;
648         }
649
650         module_data = dlsym(module, "tdm_backend_module_data");
651         if (!module_data) {
652                 TDM_ERR("'%s' doesn't have data object", file);
653                 ret = TDM_ERROR_BAD_MODULE;
654                 TDM_TRACE_END();
655                 goto failed_load;
656         }
657
658         private_display->module_data = module_data;
659         private_display->module = module;
660
661         /* check if version, init() and deinit() are valid or not */
662         ret = _tdm_display_check_module(module_data);
663         if (ret != TDM_ERROR_NONE)
664                 goto failed_load;
665
666         TDM_TRACE_END();
667
668         /* We don't care if backend_data is NULL or not. It's up to backend. */
669         TDM_TRACE_BEGIN(Init_Backend);
670         private_display->bdata = module_data->init((tdm_display *)private_display,
671                                  &ret);
672         TDM_TRACE_END();
673         if (ret != TDM_ERROR_NONE) {
674                 TDM_ERR("'%s' init failed", file);
675                 goto failed_load;
676         }
677
678         ret = _tdm_display_check_backend_functions(private_display);
679         if (ret != TDM_ERROR_NONE) {
680                 module_data->deinit(private_display->bdata);
681                 private_display->bdata = NULL;
682                 goto failed_load;
683         }
684
685         TDM_INFO("Success to load module(%s)", file);
686
687         return TDM_ERROR_NONE;
688 failed_load:
689         dlclose(module);
690         private_display->module_data = NULL;
691         private_display->module = NULL;
692         return ret;
693 }
694
695 static tdm_error
696 _tdm_display_load_module(tdm_private_display *private_display)
697 {
698         const char *module_name;
699         struct dirent **namelist;
700         int n;
701         tdm_error ret = 0;
702
703         module_name = getenv("TDM_MODULE");
704         if (!module_name)
705                 module_name = DEFAULT_MODULE;
706
707         /* load bufmgr priv from default lib */
708         ret = _tdm_display_load_module_with_file(private_display, module_name);
709         if (ret == TDM_ERROR_NONE)
710                 return TDM_ERROR_NONE;
711
712         /* load bufmgr priv from configured path */
713         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
714         if (n < 0) {
715                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
716                 return TDM_ERROR_BAD_MODULE;
717         }
718
719         ret = TDM_ERROR_BAD_MODULE;
720         while (n--) {
721                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
722                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
723
724                 free(namelist[n]);
725         }
726         free(namelist);
727
728         return ret;
729 }
730
731 static void
732 _tdm_display_unload_module(tdm_private_display *private_display)
733 {
734         if (private_display->module_data)
735                 private_display->module_data->deinit(private_display->bdata);
736         if (private_display->module)
737                 dlclose(private_display->module);
738
739         private_display->bdata = NULL;
740         private_display->module_data = NULL;
741         private_display->module = NULL;
742 }
743
744 EXTERN tdm_display *
745 tdm_display_init(tdm_error *error)
746 {
747         tdm_private_display *private_display = NULL;
748         const char *debug;
749         tdm_error ret;
750
751         _pthread_mutex_lock(&gLock);
752
753         if (g_private_display) {
754                 g_private_display->init_count++;
755                 _pthread_mutex_unlock(&gLock);
756                 if (error)
757                         *error = TDM_ERROR_NONE;
758                 return g_private_display;
759         }
760
761         debug = getenv("TDM_DEBUG");
762         if (debug && (strstr(debug, "1")))
763                 tdm_debug = 1;
764
765         debug = getenv("TDM_DEBUG_BUFFER");
766         if (debug && (strstr(debug, "1")))
767                 tdm_debug_buffer = 1;
768
769         debug = getenv("TDM_DEBUG_THREAD");
770         if (debug && (strstr(debug, "1")))
771                 tdm_debug_thread = 1;
772
773         debug = getenv("TDM_DEBUG_MUTEX");
774         if (debug && (strstr(debug, "1")))
775                 tdm_debug_mutex = 1;
776
777         private_display = calloc(1, sizeof(tdm_private_display));
778         if (!private_display) {
779                 ret = TDM_ERROR_OUT_OF_MEMORY;
780                 TDM_ERR("'private_display != NULL' failed");
781                 goto failed_alloc;
782         }
783
784         if (pthread_mutex_init(&private_display->lock, NULL)) {
785                 ret = TDM_ERROR_OPERATION_FAILED;
786                 TDM_ERR("mutex init failed: %m");
787                 goto failed_mutex_init;
788         }
789
790         _pthread_mutex_lock(&private_display->lock);
791
792         ret = tdm_event_loop_init(private_display);
793         if (ret != TDM_ERROR_NONE)
794                 goto failed_event;
795
796         ret = _tdm_display_load_module(private_display);
797         if (ret != TDM_ERROR_NONE)
798                 goto failed_load;
799
800 #ifdef INIT_BUFMGR
801         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
802         if (tdm_drm_fd >= 0) {
803                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
804                 close(tdm_drm_fd);
805                 if (!private_display->bufmgr) {
806                         TDM_ERR("tbm_bufmgr_init failed");
807                         goto failed_update;
808                 } else {
809                         TDM_INFO("tbm_bufmgr_init successed");
810                 }
811         }
812 #endif
813
814         TDM_TRACE_BEGIN(Update_Display);
815         ret = _tdm_display_update_internal(private_display, 0);
816         TDM_TRACE_END();
817         if (ret != TDM_ERROR_NONE)
818                 goto failed_update;
819
820         tdm_event_loop_create_backend_source(private_display);
821
822         private_display->init_count = 1;
823
824         g_private_display = private_display;
825
826         if (error)
827                 *error = TDM_ERROR_NONE;
828
829         _pthread_mutex_unlock(&private_display->lock);
830         _pthread_mutex_unlock(&gLock);
831
832         return (tdm_display *)private_display;
833
834 failed_update:
835         _tdm_display_unload_module(private_display);
836 failed_load:
837         tdm_event_loop_deinit(private_display);
838 failed_event:
839         _pthread_mutex_unlock(&private_display->lock);
840         pthread_mutex_destroy(&private_display->lock);
841 failed_mutex_init:
842         free(private_display);
843 failed_alloc:
844         tdm_debug = 0;
845         tdm_debug_buffer = 0;
846         if (error)
847                 *error = ret;
848         _pthread_mutex_unlock(&gLock);
849         return NULL;
850 }
851
852 EXTERN void
853 tdm_display_deinit(tdm_display *dpy)
854 {
855         tdm_private_display *private_display = dpy;
856
857         if (!private_display)
858                 return;
859
860         _pthread_mutex_lock(&gLock);
861
862         private_display->init_count--;
863         if (private_display->init_count > 0) {
864                 _pthread_mutex_unlock(&gLock);
865                 return;
866         }
867
868         _pthread_mutex_lock(&private_display->lock);
869
870         tdm_event_loop_deinit(private_display);
871
872         _tdm_display_destroy_private_display(private_display);
873         _tdm_display_unload_module(private_display);
874
875 #ifdef INIT_BUFMGR
876         if (private_display->bufmgr)
877                 tbm_bufmgr_deinit(private_display->bufmgr);
878 #endif
879
880         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
881
882         _pthread_mutex_unlock(&private_display->lock);
883
884         pthread_mutex_destroy(&private_display->lock);
885         free(private_display);
886         g_private_display = NULL;
887         tdm_debug = 0;
888         tdm_debug_buffer = 0;
889
890         _pthread_mutex_unlock(&gLock);
891
892         TDM_INFO("done");
893 }
894