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