1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
44 static tdm_private_layer *
45 _tdm_display_find_private_layer(tdm_private_output *private_output,
46 tdm_layer *layer_backend)
48 tdm_private_layer *private_layer = NULL;
50 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
51 if (private_layer->layer_backend == layer_backend)
58 static tdm_private_output *
59 _tdm_display_find_private_output(tdm_private_display *private_display,
60 tdm_output *output_backend)
62 tdm_private_output *private_output = NULL;
64 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
65 if (private_output->output_backend == output_backend)
66 return private_output;
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
75 free(caps_pp->formats);
76 memset(caps_pp, 0, sizeof(tdm_caps_pp));
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
82 free(caps_capture->formats);
83 memset(caps_capture, 0, sizeof(tdm_caps_capture));
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
89 free(caps_layer->formats);
90 free(caps_layer->props);
91 memset(caps_layer, 0, sizeof(tdm_caps_layer));
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
97 free(caps_output->modes);
98 free(caps_output->props);
99 memset(caps_output, 0, sizeof(tdm_caps_output));
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
105 tdm_private_capture *c = NULL, *cc = NULL;
107 LIST_DEL(&private_layer->link);
109 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110 tdm_capture_destroy_internal(c);
112 _tdm_display_destroy_caps_layer(&private_layer->caps);
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
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;
125 LIST_DEL(&private_output->link);
127 free(private_output->layers_ptr);
129 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
134 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
139 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
140 tdm_capture_destroy_internal(c);
142 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
143 _tdm_display_destroy_private_layer(l);
145 _tdm_display_destroy_caps_output(&private_output->caps);
147 free(private_output);
151 _tdm_display_destroy_private_display(tdm_private_display *private_display)
153 tdm_private_output *o = NULL, *oo = NULL;
154 tdm_private_pp *p = NULL, *pp = NULL;
156 free(private_display->outputs_ptr);
158 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
159 tdm_pp_destroy_internal(p);
161 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
162 _tdm_display_destroy_private_output(o);
164 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
165 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
167 private_display->capabilities = 0;
168 private_display->caps_display.max_layer_count = -1;
172 _tdm_display_update_caps_pp(tdm_private_display *private_display,
175 tdm_func_display *func_display = &private_display->func_display;
177 int bufsize = sizeof(buf);
179 int *len_buf = &bufsize;
183 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
184 return TDM_ERROR_NONE;
186 if (!func_display->display_get_pp_capability) {
187 TDM_ERR("no display_get_pp_capability()");
188 return TDM_ERROR_BAD_MODULE;
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;
197 TDM_DBG("pp capabilities: %x", caps->capabilities);
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);
206 return TDM_ERROR_NONE;
210 _tdm_display_update_caps_capture(tdm_private_display *private_display,
211 tdm_caps_capture *caps)
213 tdm_func_display *func_display = &private_display->func_display;
215 int bufsize = sizeof(buf);
217 int *len_buf = &bufsize;
221 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
222 return TDM_ERROR_NONE;
224 if (!func_display->display_get_capture_capability) {
225 TDM_ERR("no display_get_capture_capability()");
226 return TDM_ERROR_BAD_MODULE;
229 ret = func_display->display_get_capture_capability(private_display->bdata,
231 if (ret != TDM_ERROR_NONE) {
232 TDM_ERR("display_get_capture_capability() failed");
233 return TDM_ERROR_BAD_MODULE;
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);
241 return TDM_ERROR_NONE;
245 _tdm_display_update_caps_layer(tdm_private_display *private_display,
246 tdm_layer *layer_backend, tdm_caps_layer *caps)
248 tdm_func_layer *func_layer = &private_display->func_layer;
250 int bufsize = sizeof(buf);
252 int *len_buf = &bufsize;
256 if (!func_layer->layer_get_capability) {
257 TDM_ERR("no layer_get_capability()");
258 return TDM_ERROR_BAD_MODULE;
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;
267 TDM_DBG("layer capabilities: %x", caps->capabilities);
268 TDM_DBG("layer zpos : %d", caps->zpos);
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);
276 return TDM_ERROR_NONE;
280 _tdm_display_update_caps_output(tdm_private_display *private_display,
281 tdm_output *output_backend, tdm_caps_output *caps)
283 tdm_func_output *func_output = &private_display->func_output;
287 if (!func_output->output_get_capability) {
288 TDM_ERR("no output_get_capability()");
289 return TDM_ERROR_BAD_MODULE;
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;
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);
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);
320 return TDM_ERROR_NONE;
324 _tdm_display_update_layer(tdm_private_display *private_display,
325 tdm_private_output *private_output,
326 tdm_layer *layer_backend)
328 tdm_private_layer *private_layer;
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);
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;
341 LIST_INITHEAD(&private_layer->capture_list);
343 private_layer->usable = 1;
345 _tdm_display_destroy_caps_layer(&private_layer->caps);
347 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
348 &private_layer->caps);
349 if (ret != TDM_ERROR_NONE)
352 return TDM_ERROR_NONE;
354 _tdm_display_destroy_private_layer(private_layer);
359 _tdm_display_update_output(tdm_private_display *private_display,
360 tdm_output *output_backend, int pipe)
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;
368 private_output = _tdm_display_find_private_output(private_display,
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);
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;
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);
384 _tdm_display_destroy_caps_output(&private_output->caps);
386 ret = _tdm_display_update_caps_output(private_display, output_backend,
387 &private_output->caps);
388 if (ret != TDM_ERROR_NONE)
391 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
392 if (ret != TDM_ERROR_NONE)
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)
403 return TDM_ERROR_NONE;
405 _tdm_display_destroy_private_output(private_output);
411 _tdm_display_update_internal(tdm_private_display *private_display,
414 tdm_func_display *func_display = &private_display->func_display;
415 tdm_output **outputs = NULL;
416 int output_count = 0, i;
419 LIST_INITHEAD(&private_display->output_list);
420 LIST_INITHEAD(&private_display->pp_list);
423 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
424 if (ret != TDM_ERROR_NONE)
427 ret = _tdm_display_update_caps_capture(private_display,
428 &private_display->caps_capture);
429 if (ret != TDM_ERROR_NONE)
433 outputs = func_display->display_get_outputs(private_display->bdata,
434 &output_count, &ret);
435 if (ret != TDM_ERROR_NONE)
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)
446 return TDM_ERROR_NONE;
449 _tdm_display_destroy_private_display(private_display);
455 _tdm_display_init_bufmgr(tdm_private_display *private_display)
457 tdm_func_display *func_display = &private_display->func_display;
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");
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;
475 TDM_INFO("init TBM bufmgr: fd(%d)", buffer_fd);
477 return TDM_ERROR_NONE;
482 tdm_display_update(tdm_display *dpy)
484 tdm_private_display *private_display;
487 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
489 private_display = dpy;
490 pthread_mutex_lock(&private_display->lock);
492 ret = _tdm_display_update_internal(private_display, 1);
494 pthread_mutex_unlock(&private_display->lock);
499 #define SUFFIX_MODULE ".so"
500 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
503 int tdm_debug_buffer;
505 static tdm_private_display *g_private_display;
506 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
509 _tdm_display_check_module(tdm_backend_module *module)
516 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
517 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
519 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
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);
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);
530 if (major != abimaj) {
531 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
532 return TDM_ERROR_BAD_MODULE;
535 if (minor > abimin) {
536 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
537 return TDM_ERROR_BAD_MODULE;
541 TDM_ERR("'%s' doesn't have init function", name);
542 return TDM_ERROR_BAD_MODULE;
545 if (!module->deinit) {
546 TDM_ERR("'%s' doesn't have deinit function", name);
547 return TDM_ERROR_BAD_MODULE;
550 return TDM_ERROR_NONE;
554 _tdm_display_check_backend_functions(tdm_private_display *private_display)
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;
561 /* below functions should be implemented in backend side */
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);
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;
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);
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);
602 return TDM_ERROR_NONE;
606 _tdm_display_load_module_with_file(tdm_private_display *private_display,
609 char path[PATH_MAX] = {0,};
610 tdm_backend_module *module_data;
614 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
616 TDM_TRACE_BEGIN(Load_Backend);
618 module = dlopen(path, RTLD_LAZY);
620 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
622 return TDM_ERROR_BAD_MODULE;
625 module_data = dlsym(module, "tdm_backend_module_data");
627 TDM_ERR("'%s' doesn't have data object", file);
628 ret = TDM_ERROR_BAD_MODULE;
633 private_display->module_data = module_data;
634 private_display->module = module;
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)
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,
648 if (ret != TDM_ERROR_NONE) {
649 TDM_ERR("'%s' init failed", file);
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;
660 TDM_INFO("Success to load module(%s)", file);
662 return TDM_ERROR_NONE;
665 private_display->module_data = NULL;
666 private_display->module = NULL;
671 _tdm_display_load_module(tdm_private_display *private_display)
673 const char *module_name;
674 struct dirent **namelist;
678 module_name = getenv("TDM_MODULE");
680 module_name = DEFAULT_MODULE;
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;
687 /* load bufmgr priv from configured path */
688 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
690 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
691 return TDM_ERROR_BAD_MODULE;
694 ret = TDM_ERROR_BAD_MODULE;
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);
707 _tdm_display_unload_module(tdm_private_display *private_display)
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);
714 private_display->bdata = NULL;
715 private_display->module_data = NULL;
716 private_display->module = NULL;
720 tdm_display_init(tdm_error *error)
722 tdm_private_display *private_display = NULL;
726 pthread_mutex_lock(&gLock);
728 if (g_private_display) {
729 g_private_display->init_count++;
730 pthread_mutex_unlock(&gLock);
732 *error = TDM_ERROR_NONE;
733 return g_private_display;
736 debug = getenv("TDM_DEBUG");
737 if (debug && (strstr(debug, "1")))
740 debug = getenv("TDM_DEBUG_BUFFER");
741 if (debug && (strstr(debug, "1")))
742 tdm_debug_buffer = 1;
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");
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;
757 ret = _tdm_display_load_module(private_display);
758 if (ret != TDM_ERROR_NONE)
761 TDM_TRACE_BEGIN(Update_Display);
762 ret = _tdm_display_update_internal(private_display, 0);
764 if (ret != TDM_ERROR_NONE)
767 TDM_TRACE_BEGIN(Bufmgr_Init);
768 ret = _tdm_display_init_bufmgr(private_display);
770 if (ret != TDM_ERROR_NONE)
773 private_display->init_count = 1;
775 g_private_display = private_display;
778 *error = TDM_ERROR_NONE;
780 pthread_mutex_unlock(&gLock);
782 return (tdm_display *)private_display;
785 _tdm_display_unload_module(private_display);
787 pthread_mutex_destroy(&private_display->lock);
789 free(private_display);
792 tdm_debug_buffer = 0;
795 pthread_mutex_unlock(&gLock);
800 tdm_display_deinit(tdm_display *dpy)
802 tdm_private_display *private_display = dpy;
804 if (!private_display)
807 pthread_mutex_lock(&gLock);
809 private_display->init_count--;
810 if (private_display->init_count > 0) {
811 pthread_mutex_unlock(&gLock);
815 pthread_mutex_lock(&private_display->lock);
817 if (private_display->bufmgr)
818 tbm_bufmgr_deinit(private_display->bufmgr);
820 _tdm_display_destroy_private_display(private_display);
821 _tdm_display_unload_module(private_display);
823 pthread_mutex_unlock(&private_display->lock);
825 pthread_mutex_destroy(&private_display->lock);
826 free(private_display);
827 g_private_display = NULL;
829 tdm_debug_buffer = 0;
831 pthread_mutex_unlock(&gLock);