apply wayland coding style
[platform/core/uifw/libtdm.git] / src / tdm.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43
44 static tdm_private_layer *
45 _tdm_display_find_private_layer(tdm_private_output *private_output,
46                                 tdm_layer *layer_backend)
47 {
48         tdm_private_layer *private_layer = NULL;
49
50         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
51                 if (private_layer->layer_backend == layer_backend)
52                         return private_layer;
53         }
54
55         return NULL;
56 }
57
58 static tdm_private_output *
59 _tdm_display_find_private_output(tdm_private_display *private_display,
60                                  tdm_output *output_backend)
61 {
62         tdm_private_output *private_output = NULL;
63
64         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
65                 if (private_output->output_backend == output_backend)
66                         return private_output;
67         }
68
69         return NULL;
70 }
71
72 static void
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
74 {
75         free(caps_pp->formats);
76         memset(caps_pp, 0, sizeof(tdm_caps_pp));
77 }
78
79 static void
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
81 {
82         free(caps_capture->formats);
83         memset(caps_capture, 0, sizeof(tdm_caps_capture));
84 }
85
86 static void
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
88 {
89         free(caps_layer->formats);
90         free(caps_layer->props);
91         memset(caps_layer, 0, sizeof(tdm_caps_layer));
92 }
93
94 static void
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
96 {
97         free(caps_output->modes);
98         free(caps_output->props);
99         memset(caps_output, 0, sizeof(tdm_caps_output));
100 }
101
102 static void
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
104 {
105         tdm_private_capture *c = NULL, *cc = NULL;
106
107         LIST_DEL(&private_layer->link);
108
109         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110         tdm_capture_destroy_internal(c);
111
112         _tdm_display_destroy_caps_layer(&private_layer->caps);
113
114         free(private_layer);
115 }
116
117 static void
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
119 {
120         tdm_private_layer *l = NULL, *ll = NULL;
121         tdm_private_capture *c = NULL, *cc = NULL;
122         tdm_private_vblank_handler *v = NULL, *vv = NULL;
123         tdm_private_commit_handler *m = NULL, *mm = NULL;
124
125         LIST_DEL(&private_output->link);
126
127         free(private_output->layers_ptr);
128
129         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
130                 LIST_DEL(&v->link);
131                 free(v);
132         }
133
134         LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
135                 LIST_DEL(&m->link);
136                 free(m);
137         }
138
139         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
140         tdm_capture_destroy_internal(c);
141
142         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
143         _tdm_display_destroy_private_layer(l);
144
145         _tdm_display_destroy_caps_output(&private_output->caps);
146
147         free(private_output);
148 }
149
150 static void
151 _tdm_display_destroy_private_display(tdm_private_display *private_display)
152 {
153         tdm_private_output *o = NULL, *oo = NULL;
154         tdm_private_pp *p = NULL, *pp = NULL;
155
156         free(private_display->outputs_ptr);
157
158         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
159         tdm_pp_destroy_internal(p);
160
161         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
162         _tdm_display_destroy_private_output(o);
163
164         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
165         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
166
167         private_display->capabilities = 0;
168         private_display->caps_display.max_layer_count = -1;
169 }
170
171 static tdm_error
172 _tdm_display_update_caps_pp(tdm_private_display *private_display,
173                             tdm_caps_pp *caps)
174 {
175         tdm_func_display *func_display = &private_display->func_display;
176         char buf[1024];
177         int bufsize = sizeof(buf);
178         char *str_buf = buf;
179         int *len_buf = &bufsize;
180         int i;
181         tdm_error ret;
182
183         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
184                 return TDM_ERROR_NONE;
185
186         if (!func_display->display_get_pp_capability) {
187                 TDM_ERR("no display_get_pp_capability()");
188                 return TDM_ERROR_BAD_MODULE;
189         }
190
191         ret = func_display->display_get_pp_capability(private_display->bdata, caps);
192         if (ret != TDM_ERROR_NONE) {
193                 TDM_ERR("display_get_pp_capability() failed");
194                 return TDM_ERROR_BAD_MODULE;
195         }
196
197         TDM_DBG("pp capabilities: %x", caps->capabilities);
198         buf[0] = '\0';
199         for (i = 0; i < caps->format_count; i++)
200                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
201         TDM_DBG("pp formats: %s", buf);
202         TDM_DBG("pp min  : %dx%d", caps->min_w, caps->min_h);
203         TDM_DBG("pp max  : %dx%d", caps->max_w, caps->max_h);
204         TDM_DBG("pp align: %d", caps->preferred_align);
205
206         return TDM_ERROR_NONE;
207 }
208
209 static tdm_error
210 _tdm_display_update_caps_capture(tdm_private_display *private_display,
211                                  tdm_caps_capture *caps)
212 {
213         tdm_func_display *func_display = &private_display->func_display;
214         char buf[1024];
215         int bufsize = sizeof(buf);
216         char *str_buf = buf;
217         int *len_buf = &bufsize;
218         int i;
219         tdm_error ret;
220
221         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
222                 return TDM_ERROR_NONE;
223
224         if (!func_display->display_get_capture_capability) {
225                 TDM_ERR("no display_get_capture_capability()");
226                 return TDM_ERROR_BAD_MODULE;
227         }
228
229         ret = func_display->display_get_capture_capability(private_display->bdata,
230                         caps);
231         if (ret != TDM_ERROR_NONE) {
232                 TDM_ERR("display_get_capture_capability() failed");
233                 return TDM_ERROR_BAD_MODULE;
234         }
235
236         buf[0] = '\0';
237         for (i = 0; i < caps->format_count; i++)
238                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
239         TDM_DBG("capture formats: %s", buf);
240
241         return TDM_ERROR_NONE;
242 }
243
244 static tdm_error
245 _tdm_display_update_caps_layer(tdm_private_display *private_display,
246                                tdm_layer *layer_backend, tdm_caps_layer *caps)
247 {
248         tdm_func_layer *func_layer = &private_display->func_layer;
249         char buf[1024];
250         int bufsize = sizeof(buf);
251         char *str_buf = buf;
252         int *len_buf = &bufsize;
253         int i;
254         tdm_error ret;
255
256         if (!func_layer->layer_get_capability) {
257                 TDM_ERR("no layer_get_capability()");
258                 return TDM_ERROR_BAD_MODULE;
259         }
260
261         ret = func_layer->layer_get_capability(layer_backend, caps);
262         if (ret != TDM_ERROR_NONE) {
263                 TDM_ERR("layer_get_capability() failed");
264                 return TDM_ERROR_BAD_MODULE;
265         }
266
267         TDM_DBG("layer capabilities: %x", caps->capabilities);
268         TDM_DBG("layer zpos : %d", caps->zpos);
269         buf[0] = '\0';
270         for (i = 0; i < caps->format_count; i++)
271                 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
272         TDM_DBG("layer formats: %s", buf);
273         for (i = 0; i < caps->prop_count; i++)
274                 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
275
276         return TDM_ERROR_NONE;
277 }
278
279 static tdm_error
280 _tdm_display_update_caps_output(tdm_private_display *private_display,
281                                 tdm_output *output_backend, tdm_caps_output *caps)
282 {
283         tdm_func_output *func_output = &private_display->func_output;
284         int i;
285         tdm_error ret;
286
287         if (!func_output->output_get_capability) {
288                 TDM_ERR("no output_get_capability()");
289                 return TDM_ERROR_BAD_MODULE;
290         }
291
292         ret = func_output->output_get_capability(output_backend, caps);
293         if (ret != TDM_ERROR_NONE) {
294                 TDM_ERR("output_get_capability() failed");
295                 return TDM_ERROR_BAD_MODULE;
296         }
297
298         TDM_DBG("output maker: %s", caps->maker);
299         TDM_DBG("output model: %s", caps->model);
300         TDM_DBG("output name: %s", caps->name);
301         TDM_DBG("output status: %d", caps->status);
302         TDM_DBG("output type : %d", caps->type);
303         for (i = 0; i < caps->prop_count; i++)
304                 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
305         for (i = 0; i < caps->mode_count; i++) {
306                 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
307                         caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
308                         caps->modes[i].flags, caps->modes[i].type);
309                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
310                         caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
311                         caps->modes[i].htotal, caps->modes[i].hskew);
312                 TDM_DBG("\t\t %d, %d, %d, %d, %d",
313                         caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
314                         caps->modes[i].vtotal, caps->modes[i].vscan);
315         }
316         TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
317         TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
318         TDM_DBG("output align: %d", caps->preferred_align);
319
320         return TDM_ERROR_NONE;
321 }
322
323 static tdm_error
324 _tdm_display_update_layer(tdm_private_display *private_display,
325                           tdm_private_output *private_output,
326                           tdm_layer *layer_backend)
327 {
328         tdm_private_layer *private_layer;
329         tdm_error ret;
330
331         private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
332         if (!private_layer) {
333                 private_layer = calloc(1, sizeof(tdm_private_layer));
334                 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
335
336                 LIST_ADD(&private_layer->link, &private_output->layer_list);
337                 private_layer->private_display = private_display;
338                 private_layer->private_output = private_output;
339                 private_layer->layer_backend = layer_backend;
340
341                 LIST_INITHEAD(&private_layer->capture_list);
342
343                 private_layer->usable = 1;
344         } else
345                 _tdm_display_destroy_caps_layer(&private_layer->caps);
346
347         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
348                                              &private_layer->caps);
349         if (ret != TDM_ERROR_NONE)
350                 goto failed_update;
351
352         return TDM_ERROR_NONE;
353 failed_update:
354         _tdm_display_destroy_private_layer(private_layer);
355         return ret;
356 }
357
358 static tdm_error
359 _tdm_display_update_output(tdm_private_display *private_display,
360                            tdm_output *output_backend, int pipe)
361 {
362         tdm_func_output *func_output = &private_display->func_output;
363         tdm_private_output *private_output = NULL;
364         tdm_layer **layers = NULL;
365         int layer_count = 0, i;
366         tdm_error ret;
367
368         private_output = _tdm_display_find_private_output(private_display,
369                          output_backend);
370         if (!private_output) {
371                 private_output = calloc(1, sizeof(tdm_private_output));
372                 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
373
374                 LIST_ADD(&private_output->link, &private_display->output_list);
375                 private_output->private_display = private_display;
376                 private_output->output_backend = output_backend;
377                 private_output->pipe = pipe;
378
379                 LIST_INITHEAD(&private_output->layer_list);
380                 LIST_INITHEAD(&private_output->capture_list);
381                 LIST_INITHEAD(&private_output->vblank_handler_list);
382                 LIST_INITHEAD(&private_output->commit_handler_list);
383         } else
384                 _tdm_display_destroy_caps_output(&private_output->caps);
385
386         ret = _tdm_display_update_caps_output(private_display, output_backend,
387                                               &private_output->caps);
388         if (ret != TDM_ERROR_NONE)
389                 return ret;
390
391         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
392         if (ret != TDM_ERROR_NONE)
393                 goto failed_update;
394
395         for (i = 0; i < layer_count; i++) {
396                 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
397                 if (ret != TDM_ERROR_NONE)
398                         goto failed_update;
399         }
400
401         free(layers);
402
403         return TDM_ERROR_NONE;
404 failed_update:
405         _tdm_display_destroy_private_output(private_output);
406         free(layers);
407         return ret;
408 }
409
410 static tdm_error
411 _tdm_display_update_internal(tdm_private_display *private_display,
412                              int only_display)
413 {
414         tdm_func_display *func_display = &private_display->func_display;
415         tdm_output **outputs = NULL;
416         int output_count = 0, i;
417         tdm_error ret;
418
419         LIST_INITHEAD(&private_display->output_list);
420         LIST_INITHEAD(&private_display->pp_list);
421
422         if (!only_display) {
423                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
424                 if (ret != TDM_ERROR_NONE)
425                         goto failed_update;
426
427                 ret = _tdm_display_update_caps_capture(private_display,
428                                                        &private_display->caps_capture);
429                 if (ret != TDM_ERROR_NONE)
430                         goto failed_update;
431         }
432
433         outputs = func_display->display_get_outputs(private_display->bdata,
434                         &output_count, &ret);
435         if (ret != TDM_ERROR_NONE)
436                 goto failed_update;
437
438         for (i = 0; i < output_count; i++) {
439                 ret = _tdm_display_update_output(private_display, outputs[i], i);
440                 if (ret != TDM_ERROR_NONE)
441                         goto failed_update;
442         }
443
444         free(outputs);
445
446         return TDM_ERROR_NONE;
447
448 failed_update:
449         _tdm_display_destroy_private_display(private_display);
450         free(outputs);
451         return ret;
452 }
453
454 static tdm_error
455 _tdm_display_init_bufmgr(tdm_private_display *private_display)
456 {
457         tdm_func_display *func_display = &private_display->func_display;
458         int buffer_fd = -1;
459         tdm_error ret;
460
461         if (func_display->display_get_buffer_fd) {
462                 ret = func_display->display_get_buffer_fd(private_display->bdata, &buffer_fd);
463                 if (ret != TDM_ERROR_NONE) {
464                         TDM_ERR("failed to get buffer fd");
465                         return ret;
466                 }
467         }
468
469         private_display->bufmgr = tbm_bufmgr_init(buffer_fd);
470         if (!private_display->bufmgr) {
471                 TDM_ERR("failed to init TBM bufmgr: fd(%d)", buffer_fd);
472                 return TDM_ERROR_OUT_OF_MEMORY;
473         }
474
475         TDM_INFO("init TBM bufmgr: fd(%d)", buffer_fd);
476
477         return TDM_ERROR_NONE;
478 }
479
480
481 EXTERN tdm_error
482 tdm_display_update(tdm_display *dpy)
483 {
484         tdm_private_display *private_display;
485         tdm_error ret;
486
487         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
488
489         private_display = dpy;
490         pthread_mutex_lock(&private_display->lock);
491
492         ret = _tdm_display_update_internal(private_display, 1);
493
494         pthread_mutex_unlock(&private_display->lock);
495
496         return ret;
497 }
498
499 #define SUFFIX_MODULE    ".so"
500 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
501
502 int tdm_debug;
503
504 static tdm_private_display *g_private_display;
505 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
506
507 static tdm_error
508 _tdm_display_check_module(tdm_backend_module *module)
509 {
510         const char *name;
511         const char *vendor;
512         int major, minor;
513         int abimaj, abimin;
514
515         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
516         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
517
518         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
519
520         name = module->name ? module->name : "unknown";
521         vendor = module->vendor ? module->vendor : "unknown";
522         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
523         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
524
525         TDM_INFO("TDM module name: %s", name);
526         TDM_INFO("'%s' vendor: %s", name, vendor);
527         TDM_INFO("'%s' version: %d.%d", name, major, minor);
528
529         if (major != abimaj) {
530                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
531                 return TDM_ERROR_BAD_MODULE;
532         }
533
534         if (minor > abimin) {
535                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
536                 return TDM_ERROR_BAD_MODULE;
537         }
538
539         if (!module->init) {
540                 TDM_ERR("'%s' doesn't have init function", name);
541                 return TDM_ERROR_BAD_MODULE;
542         }
543
544         if (!module->deinit) {
545                 TDM_ERR("'%s' doesn't have deinit function", name);
546                 return TDM_ERROR_BAD_MODULE;
547         }
548
549         return TDM_ERROR_NONE;
550 }
551
552 static tdm_error
553 _tdm_display_check_backend_functions(tdm_private_display *private_display)
554 {
555         tdm_func_display *func_display = &private_display->func_display;
556         tdm_func_output *func_output = &private_display->func_output;
557         tdm_func_layer *func_layer = &private_display->func_layer;
558         tdm_error ret;
559
560         /* below functions should be implemented in backend side */
561
562         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
563         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
564                                TDM_ERROR_BAD_MODULE);
565         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
566         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
567                                TDM_ERROR_BAD_MODULE);
568         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
569         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
570
571         ret = func_display->display_get_capabilitiy(private_display->bdata,
572                         &private_display->caps_display);
573         if (ret != TDM_ERROR_NONE) {
574                 TDM_ERR("display_get_capabilitiy() failed");
575                 return TDM_ERROR_BAD_MODULE;
576         }
577
578         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
579                 tdm_func_pp *func_pp = &private_display->func_pp;
580                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
581                                        TDM_ERROR_BAD_MODULE);
582                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
583                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
584                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
585                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
586         }
587
588         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
589                 tdm_func_capture *func_capture = &private_display->func_capture;
590                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
591                                        TDM_ERROR_BAD_MODULE);
592                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
593                                        TDM_ERROR_BAD_MODULE);
594                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
595                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
596                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
597                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
598                                        TDM_ERROR_BAD_MODULE);
599         }
600
601         return TDM_ERROR_NONE;
602 }
603
604 static tdm_error
605 _tdm_display_load_module_with_file(tdm_private_display *private_display,
606                                    const char *file)
607 {
608         char path[PATH_MAX] = {0,};
609         tdm_backend_module *module_data;
610         void *module;
611         tdm_error ret;
612
613         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
614
615         TDM_TRACE_BEGIN(Load_Backend);
616
617         module = dlopen(path, RTLD_LAZY);
618         if (!module) {
619                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
620                 TDM_TRACE_END();
621                 return TDM_ERROR_BAD_MODULE;
622         }
623
624         module_data = dlsym(module, "tdm_backend_module_data");
625         if (!module_data) {
626                 TDM_ERR("'%s' doesn't have data object", file);
627                 ret = TDM_ERROR_BAD_MODULE;
628                 TDM_TRACE_END();
629                 goto failed_load;
630         }
631
632         private_display->module_data = module_data;
633         private_display->module = module;
634
635         /* check if version, init() and deinit() are valid or not */
636         ret = _tdm_display_check_module(module_data);
637         if (ret != TDM_ERROR_NONE)
638                 goto failed_load;
639
640         TDM_TRACE_END();
641
642         /* We don't care if backend_data is NULL or not. It's up to backend. */
643         TDM_TRACE_BEGIN(Init_Backend);
644         private_display->bdata = module_data->init((tdm_display *)private_display,
645                                  &ret);
646         TDM_TRACE_END();
647         if (ret != TDM_ERROR_NONE) {
648                 TDM_ERR("'%s' init failed", file);
649                 goto failed_load;
650         }
651
652         ret = _tdm_display_check_backend_functions(private_display);
653         if (ret != TDM_ERROR_NONE) {
654                 module_data->deinit(private_display->bdata);
655                 private_display->bdata = NULL;
656                 goto failed_load;
657         }
658
659         TDM_INFO("Success to load module(%s)", file);
660
661         return TDM_ERROR_NONE;
662 failed_load:
663         dlclose(module);
664         private_display->module_data = NULL;
665         private_display->module = NULL;
666         return ret;
667 }
668
669 static tdm_error
670 _tdm_display_load_module(tdm_private_display *private_display)
671 {
672         const char *module_name;
673         struct dirent **namelist;
674         int n;
675         tdm_error ret = 0;
676
677         module_name = getenv("TDM_MODULE");
678         if (!module_name)
679                 module_name = DEFAULT_MODULE;
680
681         /* load bufmgr priv from default lib */
682         ret = _tdm_display_load_module_with_file(private_display, module_name);
683         if (ret == TDM_ERROR_NONE)
684                 return TDM_ERROR_NONE;
685
686         /* load bufmgr priv from configured path */
687         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
688         if (n < 0) {
689                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
690                 return TDM_ERROR_BAD_MODULE;
691         }
692
693         ret = TDM_ERROR_BAD_MODULE;
694         while (n--) {
695                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
696                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
697
698                 free(namelist[n]);
699         }
700         free(namelist);
701
702         return ret;
703 }
704
705 static void
706 _tdm_display_unload_module(tdm_private_display *private_display)
707 {
708         if (private_display->module_data)
709                 private_display->module_data->deinit(private_display->bdata);
710         if (private_display->module)
711                 dlclose(private_display->module);
712
713         private_display->bdata = NULL;
714         private_display->module_data = NULL;
715         private_display->module = NULL;
716 }
717
718 EXTERN tdm_display *
719 tdm_display_init(tdm_error *error)
720 {
721         tdm_private_display *private_display = NULL;
722         const char *debug;
723         tdm_error ret;
724
725         pthread_mutex_lock(&gLock);
726
727         if (g_private_display) {
728                 g_private_display->init_count++;
729                 pthread_mutex_unlock(&gLock);
730                 if (error)
731                         *error = TDM_ERROR_NONE;
732                 return g_private_display;
733         }
734
735         debug = getenv("TDM_DEBUG");
736         if (debug && (strstr(debug, "1")))
737                 tdm_debug = 1;
738
739         private_display = calloc(1, sizeof(tdm_private_display));
740         if (!private_display) {
741                 ret = TDM_ERROR_OUT_OF_MEMORY;
742                 TDM_ERR("'private_display != NULL' failed");
743                 goto failed_alloc;
744         }
745
746         if (pthread_mutex_init(&private_display->lock, NULL)) {
747                 ret = TDM_ERROR_OPERATION_FAILED;
748                 TDM_ERR("mutex init failed: %m");
749                 goto failed_mutex_init;
750         }
751
752         ret = _tdm_display_load_module(private_display);
753         if (ret != TDM_ERROR_NONE)
754                 goto failed_load;
755
756         TDM_TRACE_BEGIN(Update_Display);
757         ret = _tdm_display_update_internal(private_display, 0);
758         TDM_TRACE_END();
759         if (ret != TDM_ERROR_NONE)
760                 goto failed_update;
761
762         TDM_TRACE_BEGIN(Bufmgr_Init);
763         ret = _tdm_display_init_bufmgr(private_display);
764         TDM_TRACE_END();
765         if (ret != TDM_ERROR_NONE)
766                 goto failed_update;
767
768         private_display->init_count = 1;
769
770         g_private_display = private_display;
771
772         if (error)
773                 *error = TDM_ERROR_NONE;
774
775         pthread_mutex_unlock(&gLock);
776
777         return (tdm_display *)private_display;
778
779 failed_update:
780         _tdm_display_unload_module(private_display);
781 failed_load:
782         pthread_mutex_destroy(&private_display->lock);
783 failed_mutex_init:
784         free(private_display);
785 failed_alloc:
786         tdm_debug = 0;
787         if (error)
788                 *error = ret;
789         pthread_mutex_unlock(&gLock);
790         return NULL;
791 }
792
793 EXTERN void
794 tdm_display_deinit(tdm_display *dpy)
795 {
796         tdm_private_display *private_display = dpy;
797
798         if (!private_display)
799                 return;
800
801         pthread_mutex_lock(&gLock);
802
803         private_display->init_count--;
804         if (private_display->init_count > 0) {
805                 pthread_mutex_unlock(&gLock);
806                 return;
807         }
808
809         pthread_mutex_lock(&private_display->lock);
810
811         if (private_display->bufmgr)
812                 tbm_bufmgr_deinit(private_display->bufmgr);
813
814         _tdm_display_destroy_private_display(private_display);
815         _tdm_display_unload_module(private_display);
816
817         pthread_mutex_unlock(&private_display->lock);
818
819         pthread_mutex_destroy(&private_display->lock);
820         free(private_display);
821         g_private_display = NULL;
822         tdm_debug = 0;
823
824         pthread_mutex_unlock(&gLock);
825 }
826