unref buffer when destroyed
[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 int tdm_debug_buffer;
504
505 static tdm_private_display *g_private_display;
506 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
507
508 static tdm_error
509 _tdm_display_check_module(tdm_backend_module *module)
510 {
511         const char *name;
512         const char *vendor;
513         int major, minor;
514         int abimaj, abimin;
515
516         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
517         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
518
519         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
520
521         name = module->name ? module->name : "unknown";
522         vendor = module->vendor ? module->vendor : "unknown";
523         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
524         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
525
526         TDM_INFO("TDM module name: %s", name);
527         TDM_INFO("'%s' vendor: %s", name, vendor);
528         TDM_INFO("'%s' version: %d.%d", name, major, minor);
529
530         if (major != abimaj) {
531                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
532                 return TDM_ERROR_BAD_MODULE;
533         }
534
535         if (minor > abimin) {
536                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
537                 return TDM_ERROR_BAD_MODULE;
538         }
539
540         if (!module->init) {
541                 TDM_ERR("'%s' doesn't have init function", name);
542                 return TDM_ERROR_BAD_MODULE;
543         }
544
545         if (!module->deinit) {
546                 TDM_ERR("'%s' doesn't have deinit function", name);
547                 return TDM_ERROR_BAD_MODULE;
548         }
549
550         return TDM_ERROR_NONE;
551 }
552
553 static tdm_error
554 _tdm_display_check_backend_functions(tdm_private_display *private_display)
555 {
556         tdm_func_display *func_display = &private_display->func_display;
557         tdm_func_output *func_output = &private_display->func_output;
558         tdm_func_layer *func_layer = &private_display->func_layer;
559         tdm_error ret;
560
561         /* below functions should be implemented in backend side */
562
563         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
564         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
565                                TDM_ERROR_BAD_MODULE);
566         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
567         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
568                                TDM_ERROR_BAD_MODULE);
569         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
570         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
571
572         ret = func_display->display_get_capabilitiy(private_display->bdata,
573                         &private_display->caps_display);
574         if (ret != TDM_ERROR_NONE) {
575                 TDM_ERR("display_get_capabilitiy() failed");
576                 return TDM_ERROR_BAD_MODULE;
577         }
578
579         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
580                 tdm_func_pp *func_pp = &private_display->func_pp;
581                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
582                                        TDM_ERROR_BAD_MODULE);
583                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
584                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
585                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
586                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
587         }
588
589         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
590                 tdm_func_capture *func_capture = &private_display->func_capture;
591                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
592                                        TDM_ERROR_BAD_MODULE);
593                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
594                                        TDM_ERROR_BAD_MODULE);
595                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
596                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
597                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
598                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
599                                        TDM_ERROR_BAD_MODULE);
600         }
601
602         return TDM_ERROR_NONE;
603 }
604
605 static tdm_error
606 _tdm_display_load_module_with_file(tdm_private_display *private_display,
607                                    const char *file)
608 {
609         char path[PATH_MAX] = {0,};
610         tdm_backend_module *module_data;
611         void *module;
612         tdm_error ret;
613
614         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
615
616         TDM_TRACE_BEGIN(Load_Backend);
617
618         module = dlopen(path, RTLD_LAZY);
619         if (!module) {
620                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
621                 TDM_TRACE_END();
622                 return TDM_ERROR_BAD_MODULE;
623         }
624
625         module_data = dlsym(module, "tdm_backend_module_data");
626         if (!module_data) {
627                 TDM_ERR("'%s' doesn't have data object", file);
628                 ret = TDM_ERROR_BAD_MODULE;
629                 TDM_TRACE_END();
630                 goto failed_load;
631         }
632
633         private_display->module_data = module_data;
634         private_display->module = module;
635
636         /* check if version, init() and deinit() are valid or not */
637         ret = _tdm_display_check_module(module_data);
638         if (ret != TDM_ERROR_NONE)
639                 goto failed_load;
640
641         TDM_TRACE_END();
642
643         /* We don't care if backend_data is NULL or not. It's up to backend. */
644         TDM_TRACE_BEGIN(Init_Backend);
645         private_display->bdata = module_data->init((tdm_display *)private_display,
646                                  &ret);
647         TDM_TRACE_END();
648         if (ret != TDM_ERROR_NONE) {
649                 TDM_ERR("'%s' init failed", file);
650                 goto failed_load;
651         }
652
653         ret = _tdm_display_check_backend_functions(private_display);
654         if (ret != TDM_ERROR_NONE) {
655                 module_data->deinit(private_display->bdata);
656                 private_display->bdata = NULL;
657                 goto failed_load;
658         }
659
660         TDM_INFO("Success to load module(%s)", file);
661
662         return TDM_ERROR_NONE;
663 failed_load:
664         dlclose(module);
665         private_display->module_data = NULL;
666         private_display->module = NULL;
667         return ret;
668 }
669
670 static tdm_error
671 _tdm_display_load_module(tdm_private_display *private_display)
672 {
673         const char *module_name;
674         struct dirent **namelist;
675         int n;
676         tdm_error ret = 0;
677
678         module_name = getenv("TDM_MODULE");
679         if (!module_name)
680                 module_name = DEFAULT_MODULE;
681
682         /* load bufmgr priv from default lib */
683         ret = _tdm_display_load_module_with_file(private_display, module_name);
684         if (ret == TDM_ERROR_NONE)
685                 return TDM_ERROR_NONE;
686
687         /* load bufmgr priv from configured path */
688         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
689         if (n < 0) {
690                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
691                 return TDM_ERROR_BAD_MODULE;
692         }
693
694         ret = TDM_ERROR_BAD_MODULE;
695         while (n--) {
696                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
697                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
698
699                 free(namelist[n]);
700         }
701         free(namelist);
702
703         return ret;
704 }
705
706 static void
707 _tdm_display_unload_module(tdm_private_display *private_display)
708 {
709         if (private_display->module_data)
710                 private_display->module_data->deinit(private_display->bdata);
711         if (private_display->module)
712                 dlclose(private_display->module);
713
714         private_display->bdata = NULL;
715         private_display->module_data = NULL;
716         private_display->module = NULL;
717 }
718
719 EXTERN tdm_display *
720 tdm_display_init(tdm_error *error)
721 {
722         tdm_private_display *private_display = NULL;
723         const char *debug;
724         tdm_error ret;
725
726         pthread_mutex_lock(&gLock);
727
728         if (g_private_display) {
729                 g_private_display->init_count++;
730                 pthread_mutex_unlock(&gLock);
731                 if (error)
732                         *error = TDM_ERROR_NONE;
733                 return g_private_display;
734         }
735
736         debug = getenv("TDM_DEBUG");
737         if (debug && (strstr(debug, "1")))
738                 tdm_debug = 1;
739
740         debug = getenv("TDM_DEBUG_BUFFER");
741         if (debug && (strstr(debug, "1")))
742                 tdm_debug_buffer = 1;
743
744         private_display = calloc(1, sizeof(tdm_private_display));
745         if (!private_display) {
746                 ret = TDM_ERROR_OUT_OF_MEMORY;
747                 TDM_ERR("'private_display != NULL' failed");
748                 goto failed_alloc;
749         }
750
751         if (pthread_mutex_init(&private_display->lock, NULL)) {
752                 ret = TDM_ERROR_OPERATION_FAILED;
753                 TDM_ERR("mutex init failed: %m");
754                 goto failed_mutex_init;
755         }
756
757         ret = _tdm_display_load_module(private_display);
758         if (ret != TDM_ERROR_NONE)
759                 goto failed_load;
760
761         TDM_TRACE_BEGIN(Update_Display);
762         ret = _tdm_display_update_internal(private_display, 0);
763         TDM_TRACE_END();
764         if (ret != TDM_ERROR_NONE)
765                 goto failed_update;
766
767         TDM_TRACE_BEGIN(Bufmgr_Init);
768         ret = _tdm_display_init_bufmgr(private_display);
769         TDM_TRACE_END();
770         if (ret != TDM_ERROR_NONE)
771                 goto failed_update;
772
773         private_display->init_count = 1;
774
775         g_private_display = private_display;
776
777         if (error)
778                 *error = TDM_ERROR_NONE;
779
780         pthread_mutex_unlock(&gLock);
781
782         return (tdm_display *)private_display;
783
784 failed_update:
785         _tdm_display_unload_module(private_display);
786 failed_load:
787         pthread_mutex_destroy(&private_display->lock);
788 failed_mutex_init:
789         free(private_display);
790 failed_alloc:
791         tdm_debug = 0;
792         tdm_debug_buffer = 0;
793         if (error)
794                 *error = ret;
795         pthread_mutex_unlock(&gLock);
796         return NULL;
797 }
798
799 EXTERN void
800 tdm_display_deinit(tdm_display *dpy)
801 {
802         tdm_private_display *private_display = dpy;
803
804         if (!private_display)
805                 return;
806
807         pthread_mutex_lock(&gLock);
808
809         private_display->init_count--;
810         if (private_display->init_count > 0) {
811                 pthread_mutex_unlock(&gLock);
812                 return;
813         }
814
815         pthread_mutex_lock(&private_display->lock);
816
817         if (private_display->bufmgr)
818                 tbm_bufmgr_deinit(private_display->bufmgr);
819
820         _tdm_display_destroy_private_display(private_display);
821         _tdm_display_unload_module(private_display);
822
823         pthread_mutex_unlock(&private_display->lock);
824
825         pthread_mutex_destroy(&private_display->lock);
826         free(private_display);
827         g_private_display = NULL;
828         tdm_debug = 0;
829         tdm_debug_buffer = 0;
830
831         pthread_mutex_unlock(&gLock);
832 }
833