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;
126 LIST_DEL(&private_output->link);
128 free(private_output->layers_ptr);
130 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
135 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
140 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
141 tdm_capture_destroy_internal(c);
143 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
144 _tdm_display_destroy_private_layer(l);
146 _tdm_display_destroy_caps_output(&private_output->caps);
148 free(private_output);
152 _tdm_display_destroy_private_display(tdm_private_display *private_display)
154 tdm_private_output *o = NULL, *oo = NULL;
155 tdm_private_pp *p = NULL, *pp = NULL;
157 free(private_display->outputs_ptr);
159 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
160 tdm_pp_destroy_internal(p);
162 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
163 _tdm_display_destroy_private_output(o);
165 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
166 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
168 private_display->capabilities = 0;
169 private_display->caps_display.max_layer_count = -1;
173 _tdm_display_update_caps_pp(tdm_private_display *private_display,
176 tdm_func_display *func_display = &private_display->func_display;
178 int bufsize = sizeof(buf);
180 int *len_buf = &bufsize;
184 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
185 return TDM_ERROR_NONE;
187 if (!func_display->display_get_pp_capability) {
188 TDM_ERR("no display_get_pp_capability()");
189 return TDM_ERROR_BAD_MODULE;
192 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
193 if (ret != TDM_ERROR_NONE) {
194 TDM_ERR("display_get_pp_capability() failed");
195 return TDM_ERROR_BAD_MODULE;
198 TDM_DBG("pp capabilities: %x", caps->capabilities);
200 for (i = 0; i < caps->format_count; i++)
201 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
202 TDM_DBG("pp formats: %s", buf);
203 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
204 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
205 TDM_DBG("pp align: %d", caps->preferred_align);
207 return TDM_ERROR_NONE;
211 _tdm_display_update_caps_capture(tdm_private_display *private_display,
212 tdm_caps_capture *caps)
214 tdm_func_display *func_display = &private_display->func_display;
216 int bufsize = sizeof(buf);
218 int *len_buf = &bufsize;
222 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
223 return TDM_ERROR_NONE;
225 if (!func_display->display_get_capture_capability) {
226 TDM_ERR("no display_get_capture_capability()");
227 return TDM_ERROR_BAD_MODULE;
230 ret = func_display->display_get_capture_capability(private_display->bdata,
232 if (ret != TDM_ERROR_NONE) {
233 TDM_ERR("display_get_capture_capability() failed");
234 return TDM_ERROR_BAD_MODULE;
238 for (i = 0; i < caps->format_count; i++)
239 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
240 TDM_DBG("capture formats: %s", buf);
242 return TDM_ERROR_NONE;
246 _tdm_display_update_caps_layer(tdm_private_display *private_display,
247 tdm_layer *layer_backend, tdm_caps_layer *caps)
249 tdm_func_layer *func_layer = &private_display->func_layer;
251 int bufsize = sizeof(buf);
253 int *len_buf = &bufsize;
257 if (!func_layer->layer_get_capability) {
258 TDM_ERR("no layer_get_capability()");
259 return TDM_ERROR_BAD_MODULE;
262 ret = func_layer->layer_get_capability(layer_backend, caps);
263 if (ret != TDM_ERROR_NONE) {
264 TDM_ERR("layer_get_capability() failed");
265 return TDM_ERROR_BAD_MODULE;
268 TDM_DBG("layer capabilities: %x", caps->capabilities);
269 TDM_DBG("layer zpos : %d", caps->zpos);
271 for (i = 0; i < caps->format_count; i++)
272 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
273 TDM_DBG("layer formats: %s", buf);
274 for (i = 0; i < caps->prop_count; i++)
275 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
277 return TDM_ERROR_NONE;
281 _tdm_display_update_caps_output(tdm_private_display *private_display,
282 tdm_output *output_backend, tdm_caps_output *caps)
284 tdm_func_output *func_output = &private_display->func_output;
288 if (!func_output->output_get_capability) {
289 TDM_ERR("no output_get_capability()");
290 return TDM_ERROR_BAD_MODULE;
293 ret = func_output->output_get_capability(output_backend, caps);
294 if (ret != TDM_ERROR_NONE) {
295 TDM_ERR("output_get_capability() failed");
296 return TDM_ERROR_BAD_MODULE;
299 TDM_DBG("output maker: %s", caps->maker);
300 TDM_DBG("output model: %s", caps->model);
301 TDM_DBG("output name: %s", caps->name);
302 TDM_DBG("output status: %d", caps->status);
303 TDM_DBG("output type : %d", caps->type);
304 for (i = 0; i < caps->prop_count; i++)
305 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
306 for (i = 0; i < caps->mode_count; i++) {
307 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
308 caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
309 caps->modes[i].flags, caps->modes[i].type);
310 TDM_DBG("\t\t %d, %d, %d, %d, %d",
311 caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
312 caps->modes[i].htotal, caps->modes[i].hskew);
313 TDM_DBG("\t\t %d, %d, %d, %d, %d",
314 caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
315 caps->modes[i].vtotal, caps->modes[i].vscan);
317 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
318 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
319 TDM_DBG("output align: %d", caps->preferred_align);
321 return TDM_ERROR_NONE;
325 _tdm_display_update_layer(tdm_private_display *private_display,
326 tdm_private_output *private_output,
327 tdm_layer *layer_backend)
329 tdm_private_layer *private_layer;
332 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
333 if (!private_layer) {
334 private_layer = calloc(1, sizeof(tdm_private_layer));
335 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
337 LIST_ADD(&private_layer->link, &private_output->layer_list);
338 private_layer->private_display = private_display;
339 private_layer->private_output = private_output;
340 private_layer->layer_backend = layer_backend;
342 LIST_INITHEAD(&private_layer->capture_list);
344 private_layer->usable = 1;
346 _tdm_display_destroy_caps_layer(&private_layer->caps);
348 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
349 &private_layer->caps);
350 if (ret != TDM_ERROR_NONE)
353 return TDM_ERROR_NONE;
355 _tdm_display_destroy_private_layer(private_layer);
360 _tdm_display_update_output(tdm_private_display *private_display,
361 tdm_output *output_backend, int pipe)
363 tdm_func_output *func_output = &private_display->func_output;
364 tdm_private_output *private_output = NULL;
365 tdm_layer **layers = NULL;
366 int layer_count = 0, i;
369 private_output = _tdm_display_find_private_output(private_display,
371 if (!private_output) {
372 private_output = calloc(1, sizeof(tdm_private_output));
373 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
375 LIST_ADD(&private_output->link, &private_display->output_list);
376 private_output->private_display = private_display;
377 private_output->output_backend = output_backend;
378 private_output->pipe = pipe;
380 LIST_INITHEAD(&private_output->layer_list);
381 LIST_INITHEAD(&private_output->capture_list);
382 LIST_INITHEAD(&private_output->vblank_handler_list);
383 LIST_INITHEAD(&private_output->commit_handler_list);
385 _tdm_display_destroy_caps_output(&private_output->caps);
387 ret = _tdm_display_update_caps_output(private_display, output_backend,
388 &private_output->caps);
389 if (ret != TDM_ERROR_NONE)
392 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
393 if (ret != TDM_ERROR_NONE)
396 for (i = 0; i < layer_count; i++) {
397 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
398 if (ret != TDM_ERROR_NONE)
404 return TDM_ERROR_NONE;
406 _tdm_display_destroy_private_output(private_output);
412 _tdm_display_update_internal(tdm_private_display *private_display,
415 tdm_func_display *func_display = &private_display->func_display;
416 tdm_output **outputs = NULL;
417 int output_count = 0, i;
420 LIST_INITHEAD(&private_display->output_list);
421 LIST_INITHEAD(&private_display->pp_list);
424 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
425 if (ret != TDM_ERROR_NONE)
428 ret = _tdm_display_update_caps_capture(private_display,
429 &private_display->caps_capture);
430 if (ret != TDM_ERROR_NONE)
434 outputs = func_display->display_get_outputs(private_display->bdata,
435 &output_count, &ret);
436 if (ret != TDM_ERROR_NONE)
439 for (i = 0; i < output_count; i++) {
440 ret = _tdm_display_update_output(private_display, outputs[i], i);
441 if (ret != TDM_ERROR_NONE)
447 return TDM_ERROR_NONE;
450 _tdm_display_destroy_private_display(private_display);
456 tdm_display_update(tdm_display *dpy)
458 tdm_private_display *private_display;
461 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
463 private_display = dpy;
464 pthread_mutex_lock(&private_display->lock);
466 ret = _tdm_display_update_internal(private_display, 1);
468 pthread_mutex_unlock(&private_display->lock);
473 #define SUFFIX_MODULE ".so"
474 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
477 int tdm_debug_buffer;
479 static tdm_private_display *g_private_display;
480 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
483 _tdm_display_check_module(tdm_backend_module *module)
490 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
491 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
493 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
495 name = module->name ? module->name : "unknown";
496 vendor = module->vendor ? module->vendor : "unknown";
497 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
498 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
500 TDM_INFO("TDM module name: %s", name);
501 TDM_INFO("'%s' vendor: %s", name, vendor);
502 TDM_INFO("'%s' version: %d.%d", name, major, minor);
504 if (major != abimaj) {
505 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
506 return TDM_ERROR_BAD_MODULE;
509 if (minor > abimin) {
510 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
511 return TDM_ERROR_BAD_MODULE;
515 TDM_ERR("'%s' doesn't have init function", name);
516 return TDM_ERROR_BAD_MODULE;
519 if (!module->deinit) {
520 TDM_ERR("'%s' doesn't have deinit function", name);
521 return TDM_ERROR_BAD_MODULE;
524 return TDM_ERROR_NONE;
528 _tdm_display_check_backend_functions(tdm_private_display *private_display)
530 tdm_func_display *func_display = &private_display->func_display;
531 tdm_func_output *func_output = &private_display->func_output;
532 tdm_func_layer *func_layer = &private_display->func_layer;
535 /* below functions should be implemented in backend side */
537 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
538 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
539 TDM_ERROR_BAD_MODULE);
540 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
541 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
542 TDM_ERROR_BAD_MODULE);
543 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
544 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
546 ret = func_display->display_get_capabilitiy(private_display->bdata,
547 &private_display->caps_display);
548 if (ret != TDM_ERROR_NONE) {
549 TDM_ERR("display_get_capabilitiy() failed");
550 return TDM_ERROR_BAD_MODULE;
553 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
554 tdm_func_pp *func_pp = &private_display->func_pp;
555 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
556 TDM_ERROR_BAD_MODULE);
557 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
558 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
559 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
560 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
563 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
564 tdm_func_capture *func_capture = &private_display->func_capture;
565 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
566 TDM_ERROR_BAD_MODULE);
567 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
568 TDM_ERROR_BAD_MODULE);
569 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
570 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
571 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
572 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
573 TDM_ERROR_BAD_MODULE);
576 return TDM_ERROR_NONE;
580 _tdm_display_load_module_with_file(tdm_private_display *private_display,
583 char path[PATH_MAX] = {0,};
584 tdm_backend_module *module_data;
588 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
590 TDM_TRACE_BEGIN(Load_Backend);
592 module = dlopen(path, RTLD_LAZY);
594 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
596 return TDM_ERROR_BAD_MODULE;
599 module_data = dlsym(module, "tdm_backend_module_data");
601 TDM_ERR("'%s' doesn't have data object", file);
602 ret = TDM_ERROR_BAD_MODULE;
607 private_display->module_data = module_data;
608 private_display->module = module;
610 /* check if version, init() and deinit() are valid or not */
611 ret = _tdm_display_check_module(module_data);
612 if (ret != TDM_ERROR_NONE)
617 /* We don't care if backend_data is NULL or not. It's up to backend. */
618 TDM_TRACE_BEGIN(Init_Backend);
619 private_display->bdata = module_data->init((tdm_display *)private_display,
622 if (ret != TDM_ERROR_NONE) {
623 TDM_ERR("'%s' init failed", file);
627 ret = _tdm_display_check_backend_functions(private_display);
628 if (ret != TDM_ERROR_NONE) {
629 module_data->deinit(private_display->bdata);
630 private_display->bdata = NULL;
634 TDM_INFO("Success to load module(%s)", file);
636 return TDM_ERROR_NONE;
639 private_display->module_data = NULL;
640 private_display->module = NULL;
645 _tdm_display_load_module(tdm_private_display *private_display)
647 const char *module_name;
648 struct dirent **namelist;
652 module_name = getenv("TDM_MODULE");
654 module_name = DEFAULT_MODULE;
656 /* load bufmgr priv from default lib */
657 ret = _tdm_display_load_module_with_file(private_display, module_name);
658 if (ret == TDM_ERROR_NONE)
659 return TDM_ERROR_NONE;
661 /* load bufmgr priv from configured path */
662 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
664 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
665 return TDM_ERROR_BAD_MODULE;
668 ret = TDM_ERROR_BAD_MODULE;
670 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
671 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
681 _tdm_display_unload_module(tdm_private_display *private_display)
683 if (private_display->module_data)
684 private_display->module_data->deinit(private_display->bdata);
685 if (private_display->module)
686 dlclose(private_display->module);
688 private_display->bdata = NULL;
689 private_display->module_data = NULL;
690 private_display->module = NULL;
694 tdm_display_init(tdm_error *error)
696 tdm_private_display *private_display = NULL;
700 pthread_mutex_lock(&gLock);
702 if (g_private_display) {
703 g_private_display->init_count++;
704 pthread_mutex_unlock(&gLock);
706 *error = TDM_ERROR_NONE;
707 return g_private_display;
710 debug = getenv("TDM_DEBUG");
711 if (debug && (strstr(debug, "1")))
714 debug = getenv("TDM_DEBUG_BUFFER");
715 if (debug && (strstr(debug, "1")))
716 tdm_debug_buffer = 1;
718 private_display = calloc(1, sizeof(tdm_private_display));
719 if (!private_display) {
720 ret = TDM_ERROR_OUT_OF_MEMORY;
721 TDM_ERR("'private_display != NULL' failed");
725 if (pthread_mutex_init(&private_display->lock, NULL)) {
726 ret = TDM_ERROR_OPERATION_FAILED;
727 TDM_ERR("mutex init failed: %m");
728 goto failed_mutex_init;
731 ret = _tdm_display_load_module(private_display);
732 if (ret != TDM_ERROR_NONE)
735 TDM_TRACE_BEGIN(Update_Display);
736 ret = _tdm_display_update_internal(private_display, 0);
738 if (ret != TDM_ERROR_NONE)
741 private_display->init_count = 1;
743 g_private_display = private_display;
746 *error = TDM_ERROR_NONE;
748 pthread_mutex_unlock(&gLock);
750 return (tdm_display *)private_display;
753 _tdm_display_unload_module(private_display);
755 pthread_mutex_destroy(&private_display->lock);
757 free(private_display);
760 tdm_debug_buffer = 0;
763 pthread_mutex_unlock(&gLock);
768 tdm_display_deinit(tdm_display *dpy)
770 tdm_private_display *private_display = dpy;
772 if (!private_display)
775 pthread_mutex_lock(&gLock);
777 private_display->init_count--;
778 if (private_display->init_count > 0) {
779 pthread_mutex_unlock(&gLock);
783 pthread_mutex_lock(&private_display->lock);
785 _tdm_display_destroy_private_display(private_display);
786 _tdm_display_unload_module(private_display);
788 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
790 pthread_mutex_unlock(&private_display->lock);
792 pthread_mutex_destroy(&private_display->lock);
793 free(private_display);
794 g_private_display = NULL;
796 tdm_debug_buffer = 0;
798 pthread_mutex_unlock(&gLock);