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"
43 #include "tdm_helper.h"
45 static tdm_private_layer *
46 _tdm_display_find_private_layer(tdm_private_output *private_output,
47 tdm_layer *layer_backend)
49 tdm_private_layer *private_layer = NULL;
51 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
52 if (private_layer->layer_backend == layer_backend)
59 static tdm_private_output *
60 _tdm_display_find_private_output(tdm_private_display *private_display,
61 tdm_output *output_backend)
63 tdm_private_output *private_output = NULL;
65 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
66 if (private_output->output_backend == output_backend)
67 return private_output;
74 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
76 free(caps_pp->formats);
77 memset(caps_pp, 0, sizeof(tdm_caps_pp));
81 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
83 free(caps_capture->formats);
84 memset(caps_capture, 0, sizeof(tdm_caps_capture));
88 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
90 free(caps_layer->formats);
91 free(caps_layer->props);
92 memset(caps_layer, 0, sizeof(tdm_caps_layer));
96 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
98 free(caps_output->modes);
99 free(caps_output->props);
100 memset(caps_output, 0, sizeof(tdm_caps_output));
104 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
106 tdm_private_capture *c = NULL, *cc = NULL;
108 LIST_DEL(&private_layer->link);
110 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
111 tdm_capture_destroy_internal(c);
113 _tdm_display_destroy_caps_layer(&private_layer->caps);
119 _tdm_display_destroy_private_output(tdm_private_output *private_output)
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;
127 LIST_DEL(&private_output->link);
129 free(private_output->layers_ptr);
131 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
136 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
141 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
146 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
147 tdm_capture_destroy_internal(c);
149 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
150 _tdm_display_destroy_private_layer(l);
152 _tdm_display_destroy_caps_output(&private_output->caps);
154 free(private_output);
158 _tdm_display_destroy_private_display(tdm_private_display *private_display)
160 tdm_private_output *o = NULL, *oo = NULL;
161 tdm_private_pp *p = NULL, *pp = NULL;
163 free(private_display->outputs_ptr);
165 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
166 tdm_pp_destroy_internal(p);
168 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
169 _tdm_display_destroy_private_output(o);
171 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
172 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
174 private_display->capabilities = 0;
175 private_display->caps_display.max_layer_count = -1;
179 _tdm_display_update_caps_pp(tdm_private_display *private_display,
182 tdm_func_display *func_display = &private_display->func_display;
184 int bufsize = sizeof(buf);
186 int *len_buf = &bufsize;
190 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
191 return TDM_ERROR_NONE;
193 if (!func_display->display_get_pp_capability) {
194 TDM_ERR("no display_get_pp_capability()");
195 return TDM_ERROR_BAD_MODULE;
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;
204 TDM_DBG("pp capabilities: %x", caps->capabilities);
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);
213 return TDM_ERROR_NONE;
217 _tdm_display_update_caps_capture(tdm_private_display *private_display,
218 tdm_caps_capture *caps)
220 tdm_func_display *func_display = &private_display->func_display;
222 int bufsize = sizeof(buf);
224 int *len_buf = &bufsize;
228 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
229 return TDM_ERROR_NONE;
231 if (!func_display->display_get_capture_capability) {
232 TDM_ERR("no display_get_capture_capability()");
233 return TDM_ERROR_BAD_MODULE;
236 ret = func_display->display_get_capture_capability(private_display->bdata,
238 if (ret != TDM_ERROR_NONE) {
239 TDM_ERR("display_get_capture_capability() failed");
240 return TDM_ERROR_BAD_MODULE;
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);
248 return TDM_ERROR_NONE;
252 _tdm_display_update_caps_layer(tdm_private_display *private_display,
253 tdm_layer *layer_backend, tdm_caps_layer *caps)
255 tdm_func_layer *func_layer = &private_display->func_layer;
257 int bufsize = sizeof(buf);
259 int *len_buf = &bufsize;
263 if (!func_layer->layer_get_capability) {
264 TDM_ERR("no layer_get_capability()");
265 return TDM_ERROR_BAD_MODULE;
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;
274 TDM_DBG("layer capabilities: %x", caps->capabilities);
275 TDM_DBG("layer zpos : %d", caps->zpos);
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);
283 return TDM_ERROR_NONE;
287 _tdm_display_update_caps_output(tdm_private_display *private_display,
288 tdm_output *output_backend, tdm_caps_output *caps)
290 tdm_func_output *func_output = &private_display->func_output;
294 if (!func_output->output_get_capability) {
295 TDM_ERR("no output_get_capability()");
296 return TDM_ERROR_BAD_MODULE;
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;
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);
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);
327 return TDM_ERROR_NONE;
331 _tdm_display_update_layer(tdm_private_display *private_display,
332 tdm_private_output *private_output,
333 tdm_layer *layer_backend)
335 tdm_private_layer *private_layer;
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);
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;
348 LIST_INITHEAD(&private_layer->capture_list);
350 private_layer->usable = 1;
352 _tdm_display_destroy_caps_layer(&private_layer->caps);
354 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
355 &private_layer->caps);
356 if (ret != TDM_ERROR_NONE)
359 return TDM_ERROR_NONE;
361 _tdm_display_destroy_private_layer(private_layer);
366 _tdm_output_cb_status(tdm_output *output, tdm_output_conn_status status,
369 tdm_private_output *private_output = user_data;
372 TDM_RETURN_IF_FAIL(private_output);
375 tdm_output_call_change_handler_internal(private_output,
376 TDM_OUTPUT_CHANGE_CONNECTION,
381 _tdm_display_update_output(tdm_private_display *private_display,
382 tdm_output *output_backend, int pipe)
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;
390 private_output = _tdm_display_find_private_output(private_display,
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);
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;
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);
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,
412 if (ret != TDM_ERROR_NONE)
416 _tdm_display_destroy_caps_output(&private_output->caps);
418 ret = _tdm_display_update_caps_output(private_display, output_backend,
419 &private_output->caps);
420 if (ret != TDM_ERROR_NONE)
423 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
424 if (ret != TDM_ERROR_NONE)
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)
435 return TDM_ERROR_NONE;
437 _tdm_display_destroy_private_output(private_output);
443 _tdm_display_update_internal(tdm_private_display *private_display,
446 tdm_func_display *func_display = &private_display->func_display;
447 tdm_output **outputs = NULL;
448 int output_count = 0, i;
451 LIST_INITHEAD(&private_display->output_list);
452 LIST_INITHEAD(&private_display->pp_list);
455 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
456 if (ret != TDM_ERROR_NONE)
459 ret = _tdm_display_update_caps_capture(private_display,
460 &private_display->caps_capture);
461 if (ret != TDM_ERROR_NONE)
465 outputs = func_display->display_get_outputs(private_display->bdata,
466 &output_count, &ret);
467 if (ret != TDM_ERROR_NONE)
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)
478 return TDM_ERROR_NONE;
481 _tdm_display_destroy_private_display(private_display);
487 tdm_display_update(tdm_display *dpy)
489 tdm_private_display *private_display;
492 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
494 private_display = dpy;
495 _pthread_mutex_lock(&private_display->lock);
497 ret = _tdm_display_update_internal(private_display, 1);
499 _pthread_mutex_unlock(&private_display->lock);
504 #define SUFFIX_MODULE ".so"
505 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
508 int tdm_debug_buffer;
511 static tdm_private_display *g_private_display;
512 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
515 _tdm_display_check_module(tdm_backend_module *module)
522 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
523 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
525 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
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);
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);
536 if (major != abimaj) {
537 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
538 return TDM_ERROR_BAD_MODULE;
541 if (minor > abimin) {
542 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
543 return TDM_ERROR_BAD_MODULE;
547 TDM_ERR("'%s' doesn't have init function", name);
548 return TDM_ERROR_BAD_MODULE;
551 if (!module->deinit) {
552 TDM_ERR("'%s' doesn't have deinit function", name);
553 return TDM_ERROR_BAD_MODULE;
556 return TDM_ERROR_NONE;
560 _tdm_display_check_backend_functions(tdm_private_display *private_display)
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;
567 /* below functions should be implemented in backend side */
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);
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;
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);
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);
608 return TDM_ERROR_NONE;
612 _tdm_display_load_module_with_file(tdm_private_display *private_display,
615 char path[PATH_MAX] = {0,};
616 tdm_backend_module *module_data;
620 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
622 TDM_TRACE_BEGIN(Load_Backend);
624 module = dlopen(path, RTLD_LAZY);
626 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
628 return TDM_ERROR_BAD_MODULE;
631 module_data = dlsym(module, "tdm_backend_module_data");
633 TDM_ERR("'%s' doesn't have data object", file);
634 ret = TDM_ERROR_BAD_MODULE;
639 private_display->module_data = module_data;
640 private_display->module = module;
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)
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,
654 if (ret != TDM_ERROR_NONE) {
655 TDM_ERR("'%s' init failed", file);
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;
666 TDM_INFO("Success to load module(%s)", file);
668 return TDM_ERROR_NONE;
671 private_display->module_data = NULL;
672 private_display->module = NULL;
677 _tdm_display_load_module(tdm_private_display *private_display)
679 const char *module_name;
680 struct dirent **namelist;
684 module_name = getenv("TDM_MODULE");
686 module_name = DEFAULT_MODULE;
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;
693 /* load bufmgr priv from configured path */
694 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
696 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
697 return TDM_ERROR_BAD_MODULE;
700 ret = TDM_ERROR_BAD_MODULE;
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);
713 _tdm_display_unload_module(tdm_private_display *private_display)
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);
720 private_display->bdata = NULL;
721 private_display->module_data = NULL;
722 private_display->module = NULL;
726 tdm_display_init(tdm_error *error)
728 tdm_private_display *private_display = NULL;
732 _pthread_mutex_lock(&gLock);
734 if (g_private_display) {
735 g_private_display->init_count++;
736 _pthread_mutex_unlock(&gLock);
738 *error = TDM_ERROR_NONE;
739 return g_private_display;
742 debug = getenv("TDM_DEBUG");
743 if (debug && (strstr(debug, "1")))
746 debug = getenv("TDM_DEBUG_BUFFER");
747 if (debug && (strstr(debug, "1")))
748 tdm_debug_buffer = 1;
750 debug = getenv("TDM_DEBUG_MUTEX");
751 if (debug && (strstr(debug, "1")))
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");
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;
767 ret = tdm_event_init(private_display);
768 if (ret != TDM_ERROR_NONE)
771 ret = _tdm_display_load_module(private_display);
772 if (ret != TDM_ERROR_NONE)
775 TDM_TRACE_BEGIN(Update_Display);
776 ret = _tdm_display_update_internal(private_display, 0);
778 if (ret != TDM_ERROR_NONE)
781 tdm_event_create_main_source(private_display);
783 private_display->init_count = 1;
785 g_private_display = private_display;
788 *error = TDM_ERROR_NONE;
790 _pthread_mutex_unlock(&gLock);
792 return (tdm_display *)private_display;
795 _tdm_display_unload_module(private_display);
797 pthread_mutex_destroy(&private_display->lock);
799 free(private_display);
802 tdm_debug_buffer = 0;
805 _pthread_mutex_unlock(&gLock);
810 tdm_display_deinit(tdm_display *dpy)
812 tdm_private_display *private_display = dpy;
814 if (!private_display)
817 _pthread_mutex_lock(&gLock);
819 private_display->init_count--;
820 if (private_display->init_count > 0) {
821 _pthread_mutex_unlock(&gLock);
825 _pthread_mutex_lock(&private_display->lock);
827 _tdm_display_destroy_private_display(private_display);
828 _tdm_display_unload_module(private_display);
829 tdm_event_deinit(private_display);
831 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
833 _pthread_mutex_unlock(&private_display->lock);
835 pthread_mutex_destroy(&private_display->lock);
836 free(private_display);
837 g_private_display = NULL;
839 tdm_debug_buffer = 0;
841 _pthread_mutex_unlock(&gLock);