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