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 pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER;
48 static tdm_private_layer *
49 _tdm_display_find_private_layer(tdm_private_output *private_output,
50 tdm_layer *layer_backend)
52 tdm_private_layer *private_layer = NULL;
54 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
55 if (private_layer->layer_backend == layer_backend)
62 static tdm_private_output *
63 _tdm_display_find_private_output(tdm_private_display *private_display,
64 tdm_output *output_backend)
66 tdm_private_output *private_output = NULL;
68 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
69 if (private_output->output_backend == output_backend)
70 return private_output;
76 INTERN tdm_private_output *
77 tdm_display_find_output_stamp(tdm_private_display *private_display,
80 tdm_private_output *private_output = NULL;
82 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
83 if (private_output->stamp == stamp)
84 return private_output;
91 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
94 free(caps_pp->formats);
96 memset(caps_pp, 0, sizeof(tdm_caps_pp));
100 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
102 if (caps_capture->formats)
103 free(caps_capture->formats);
105 memset(caps_capture, 0, sizeof(tdm_caps_capture));
109 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
111 if (caps_layer->formats)
112 free(caps_layer->formats);
114 if (caps_layer->props)
115 free(caps_layer->props);
117 memset(caps_layer, 0, sizeof(tdm_caps_layer));
121 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
123 if (caps_output->modes)
124 free(caps_output->modes);
126 if (caps_output->props)
127 free(caps_output->props);
129 memset(caps_output, 0, sizeof(tdm_caps_output));
133 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
135 tdm_private_capture *c = NULL, *cc = NULL;
137 LIST_DEL(&private_layer->link);
139 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
140 tdm_capture_destroy_internal(c);
142 _tdm_display_destroy_caps_layer(&private_layer->caps);
148 _tdm_display_destroy_private_output(tdm_private_output *private_output)
150 tdm_private_layer *l = NULL, *ll = NULL;
151 tdm_private_capture *c = NULL, *cc = NULL;
152 tdm_private_vblank_handler *v = NULL, *vv = NULL;
153 tdm_private_commit_handler *m = NULL, *mm = NULL;
154 tdm_private_change_handler *h = NULL, *hh = NULL;
156 LIST_DEL(&private_output->link);
158 free(private_output->layers_ptr);
160 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
165 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
170 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
175 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
180 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
181 tdm_capture_destroy_internal(c);
183 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
184 _tdm_display_destroy_private_layer(l);
186 _tdm_display_destroy_caps_output(&private_output->caps);
188 private_output->stamp = 0;
189 free(private_output);
193 _tdm_display_destroy_private_display(tdm_private_display *private_display)
195 tdm_private_output *o = NULL, *oo = NULL;
196 tdm_private_pp *p = NULL, *pp = NULL;
198 free(private_display->outputs_ptr);
200 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
201 tdm_pp_destroy_internal(p);
203 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
204 _tdm_display_destroy_private_output(o);
206 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
207 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
209 private_display->capabilities = 0;
210 private_display->caps_display.max_layer_count = -1;
214 _tdm_display_update_caps_pp(tdm_private_display *private_display,
217 tdm_func_display *func_display = &private_display->func_display;
219 int bufsize = sizeof(buf);
221 int *len_buf = &bufsize;
225 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
226 return TDM_ERROR_NONE;
228 if (!func_display->display_get_pp_capability) {
229 TDM_ERR("no display_get_pp_capability()");
230 return TDM_ERROR_BAD_MODULE;
233 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
234 if (ret != TDM_ERROR_NONE) {
235 TDM_ERR("display_get_pp_capability() failed");
236 return TDM_ERROR_BAD_MODULE;
239 TDM_DBG("pp capabilities: %x", caps->capabilities);
241 for (i = 0; i < caps->format_count; i++)
242 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
243 TDM_DBG("pp formats: %s", buf);
244 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
245 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
246 TDM_DBG("pp align: %d", caps->preferred_align);
248 return TDM_ERROR_NONE;
252 _tdm_display_update_caps_capture(tdm_private_display *private_display,
253 tdm_caps_capture *caps)
255 tdm_func_display *func_display = &private_display->func_display;
257 int bufsize = sizeof(buf);
259 int *len_buf = &bufsize;
263 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
264 return TDM_ERROR_NONE;
266 if (!func_display->display_get_capture_capability) {
267 TDM_ERR("no display_get_capture_capability()");
268 return TDM_ERROR_BAD_MODULE;
271 ret = func_display->display_get_capture_capability(private_display->bdata,
273 if (ret != TDM_ERROR_NONE) {
274 TDM_ERR("display_get_capture_capability() failed");
275 return TDM_ERROR_BAD_MODULE;
279 for (i = 0; i < caps->format_count; i++)
280 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
281 TDM_DBG("capture formats: %s", buf);
283 return TDM_ERROR_NONE;
287 _tdm_display_update_caps_layer(tdm_private_display *private_display,
288 tdm_layer *layer_backend, tdm_caps_layer *caps)
290 tdm_func_layer *func_layer = &private_display->func_layer;
292 int bufsize = sizeof(buf);
294 int *len_buf = &bufsize;
298 if (!func_layer->layer_get_capability) {
299 TDM_ERR("no layer_get_capability()");
300 return TDM_ERROR_BAD_MODULE;
303 ret = func_layer->layer_get_capability(layer_backend, caps);
304 if (ret != TDM_ERROR_NONE) {
305 TDM_ERR("layer_get_capability() failed");
306 return TDM_ERROR_BAD_MODULE;
309 TDM_DBG("layer capabilities: %x", caps->capabilities);
310 TDM_DBG("layer zpos : %d", caps->zpos);
312 for (i = 0; i < caps->format_count; i++)
313 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
314 TDM_DBG("layer formats: %s", buf);
315 for (i = 0; i < caps->prop_count; i++)
316 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
318 return TDM_ERROR_NONE;
322 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
323 tdm_output *output_backend, tdm_caps_output *caps)
325 tdm_func_output *func_output = &private_display->func_output;
326 char temp[TDM_NAME_LEN];
330 if (!func_output->output_get_capability) {
331 TDM_ERR("no output_get_capability()");
332 return TDM_ERROR_BAD_MODULE;
335 ret = func_output->output_get_capability(output_backend, caps);
336 if (ret != TDM_ERROR_NONE) {
337 TDM_ERR("output_get_capability() failed");
338 return TDM_ERROR_BAD_MODULE;
341 /* FIXME: Use model for tdm client to distinguish amoung outputs */
342 snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
343 snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
345 TDM_DBG("output maker: %s", caps->maker);
346 TDM_DBG("output model: %s", caps->model);
347 TDM_DBG("output name: %s", caps->name);
348 TDM_DBG("output status: %d", caps->status);
349 TDM_DBG("output type : %d", caps->type);
350 for (i = 0; i < caps->prop_count; i++)
351 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
352 for (i = 0; i < caps->mode_count; i++) {
353 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
354 caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
355 caps->modes[i].flags, caps->modes[i].type);
356 TDM_DBG("\t\t %d, %d, %d, %d, %d",
357 caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
358 caps->modes[i].htotal, caps->modes[i].hskew);
359 TDM_DBG("\t\t %d, %d, %d, %d, %d",
360 caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
361 caps->modes[i].vtotal, caps->modes[i].vscan);
363 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
364 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
365 TDM_DBG("output align: %d", caps->preferred_align);
367 return TDM_ERROR_NONE;
371 _tdm_display_update_layer(tdm_private_display *private_display,
372 tdm_private_output *private_output,
373 tdm_layer *layer_backend)
375 tdm_private_layer *private_layer;
378 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
379 if (!private_layer) {
380 private_layer = calloc(1, sizeof(tdm_private_layer));
381 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
383 LIST_ADD(&private_layer->link, &private_output->layer_list);
384 private_layer->private_display = private_display;
385 private_layer->private_output = private_output;
386 private_layer->layer_backend = layer_backend;
388 LIST_INITHEAD(&private_layer->capture_list);
390 private_layer->usable = 1;
392 _tdm_display_destroy_caps_layer(&private_layer->caps);
394 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
395 &private_layer->caps);
396 if (ret != TDM_ERROR_NONE)
399 return TDM_ERROR_NONE;
401 _tdm_display_destroy_private_layer(private_layer);
406 _tdm_display_update_output(tdm_private_display *private_display,
407 tdm_output *output_backend, int pipe)
409 tdm_func_output *func_output = &private_display->func_output;
410 tdm_private_output *private_output = NULL;
411 tdm_layer **layers = NULL;
412 int layer_count = 0, i;
415 private_output = _tdm_display_find_private_output(private_display,
417 if (!private_output) {
418 private_output = calloc(1, sizeof(tdm_private_output));
419 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
421 private_output->stamp = tdm_helper_get_time_in_millis();
422 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
423 private_output->stamp++;
425 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
427 private_output->private_display = private_display;
428 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
429 private_output->output_backend = output_backend;
430 private_output->pipe = pipe;
432 LIST_INITHEAD(&private_output->layer_list);
433 LIST_INITHEAD(&private_output->capture_list);
434 LIST_INITHEAD(&private_output->vblank_handler_list);
435 LIST_INITHEAD(&private_output->commit_handler_list);
436 LIST_INITHEAD(&private_output->change_handler_list_main);
437 LIST_INITHEAD(&private_output->change_handler_list_sub);
439 if (func_output->output_set_status_handler)
440 func_output->output_set_status_handler(private_output->output_backend,
441 tdm_output_cb_status,
445 _tdm_display_destroy_caps_output(&private_output->caps);
447 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
448 &private_output->caps);
449 if (ret != TDM_ERROR_NONE)
452 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
453 if (ret != TDM_ERROR_NONE)
456 for (i = 0; i < layer_count; i++) {
457 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
458 if (ret != TDM_ERROR_NONE)
464 return TDM_ERROR_NONE;
466 _tdm_display_destroy_private_output(private_output);
472 _tdm_display_set_main_first(tdm_output **outputs, int index)
474 tdm_output *output_tmp = NULL;
479 output_tmp = outputs[0];
480 outputs[0] = outputs[index];
481 outputs[index] = output_tmp;
487 _tdm_display_get_ordered_outputs(tdm_private_display *private_display,
488 int *count, int init)
490 tdm_func_display *func_display = &private_display->func_display;
491 tdm_output **outputs = NULL;
492 tdm_output **new_outputs = NULL;
493 tdm_output *output_dsi = NULL;
494 tdm_output *output_lvds = NULL;
495 tdm_output *output_hdmia = NULL;
496 tdm_output *output_hdmib = NULL;
497 int i, output_count = 0, output_connected_count = 0;
498 int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
501 outputs = func_display->display_get_outputs(private_display->bdata,
502 &output_count, &ret);
503 if (ret != TDM_ERROR_NONE)
504 goto failed_get_outputs;
506 *count = output_count;
508 if (output_count == 0)
509 goto failed_get_outputs;
510 else if (output_count == 1)
513 /* don't change list order if not init time */
517 /* count connected outputs */
518 for (i = 0; i < output_count; i++) {
519 tdm_func_output *func_output = &private_display->func_output;
520 tdm_caps_output caps;
521 memset(&caps, 0, sizeof(tdm_caps_output));
523 if (!func_output->output_get_capability) {
524 TDM_ERR("no output_get_capability()");
528 ret = func_output->output_get_capability(outputs[i], &caps);
529 if (ret != TDM_ERROR_NONE) {
530 TDM_ERR("output_get_capability() failed");
534 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
535 output_connected_count++;
538 case TDM_OUTPUT_TYPE_DSI:
539 output_dsi = outputs[i];
542 case TDM_OUTPUT_TYPE_LVDS:
543 output_lvds = outputs[i];
546 case TDM_OUTPUT_TYPE_HDMIA:
547 output_hdmia = outputs[i];
550 case TDM_OUTPUT_TYPE_HDMIB:
551 output_hdmib = outputs[i];
560 /* ordering : main output is first */
561 /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
562 * But hdmi is possible, so set hdmi to main display.
563 * If connected only one output, it is main output.
564 * If connected outputs over 2, has priority like below.
565 * (dsi > lvds > hdmi > else)
567 if (output_connected_count == 0) {
568 /* hdmi > dsi > lvds > else */
569 if (output_hdmia != NULL)
570 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
571 else if (output_hdmib != NULL)
572 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
573 else if (output_dsi != NULL)
574 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
575 else if (output_lvds != NULL)
576 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
578 new_outputs = outputs;
579 } else { /* (output_connected_count > 1) */
580 /* dsi > lvds > hdmi > else */
581 if (output_dsi != NULL)
582 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
583 else if (output_lvds != NULL)
584 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
585 else if (output_hdmia != NULL)
586 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
587 else if (output_hdmib != NULL)
588 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
590 new_outputs = outputs;
601 _tdm_display_update_internal(tdm_private_display *private_display,
604 tdm_output **outputs = NULL;
605 int output_count = 0, i;
608 LIST_INITHEAD(&private_display->output_list);
609 LIST_INITHEAD(&private_display->pp_list);
610 LIST_INITHEAD(&private_display->capture_list);
613 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
614 if (ret != TDM_ERROR_NONE)
617 ret = _tdm_display_update_caps_capture(private_display,
618 &private_display->caps_capture);
619 if (ret != TDM_ERROR_NONE)
623 outputs = _tdm_display_get_ordered_outputs(private_display, &output_count, only_display);
627 for (i = 0; i < output_count; i++) {
628 ret = _tdm_display_update_output(private_display, outputs[i], i);
629 if (ret != TDM_ERROR_NONE)
635 return TDM_ERROR_NONE;
638 _tdm_display_destroy_private_display(private_display);
644 tdm_display_update(tdm_display *dpy)
646 tdm_private_display *private_display;
649 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
651 private_display = dpy;
652 _pthread_mutex_lock(&private_display->lock);
654 ret = _tdm_display_update_internal(private_display, 1);
656 _pthread_mutex_unlock(&private_display->lock);
661 #define SUFFIX_MODULE ".so"
662 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
665 int tdm_debug_buffer;
666 int tdm_debug_thread;
669 static tdm_private_display *g_private_display;
670 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
673 _tdm_display_check_module(tdm_backend_module *module)
679 TDM_INFO("TDM ABI version : %d.%d",
680 TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
682 name = module->name ? module->name : "unknown";
683 vendor = module->vendor ? module->vendor : "unknown";
684 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
685 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
687 TDM_INFO("TDM module name: %s", name);
688 TDM_INFO("'%s' vendor: %s", name, vendor);
689 TDM_INFO("'%s' version: %d.%d", name, major, minor);
691 if (major != TDM_MAJOR_VERSION) {
692 TDM_ERR("'%s' major version mismatch, %d != %d",
693 name, major, TDM_MAJOR_VERSION);
694 return TDM_ERROR_BAD_MODULE;
697 if (minor > TDM_MINOR_VERSION) {
698 TDM_ERR("'%s' minor version(%d) is newer than %d",
699 name, minor, TDM_MINOR_VERSION);
700 return TDM_ERROR_BAD_MODULE;
704 TDM_ERR("'%s' doesn't have init function", name);
705 return TDM_ERROR_BAD_MODULE;
708 if (!module->deinit) {
709 TDM_ERR("'%s' doesn't have deinit function", name);
710 return TDM_ERROR_BAD_MODULE;
713 return TDM_ERROR_NONE;
717 _tdm_display_check_backend_functions(tdm_private_display *private_display)
719 tdm_func_display *func_display = &private_display->func_display;
720 tdm_func_output *func_output = &private_display->func_output;
721 tdm_func_layer *func_layer = &private_display->func_layer;
724 /* below functions should be implemented in backend side */
726 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
727 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
728 TDM_ERROR_BAD_MODULE);
729 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
730 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
731 TDM_ERROR_BAD_MODULE);
732 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
733 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
735 ret = func_display->display_get_capabilitiy(private_display->bdata,
736 &private_display->caps_display);
737 if (ret != TDM_ERROR_NONE) {
738 TDM_ERR("display_get_capabilitiy() failed");
739 return TDM_ERROR_BAD_MODULE;
742 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
743 tdm_func_pp *func_pp = &private_display->func_pp;
744 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
745 TDM_ERROR_BAD_MODULE);
746 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
747 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
748 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
749 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
752 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
753 tdm_func_capture *func_capture = &private_display->func_capture;
754 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
755 TDM_ERROR_BAD_MODULE);
756 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
757 TDM_ERROR_BAD_MODULE);
758 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
759 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
760 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
761 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
762 TDM_ERROR_BAD_MODULE);
765 return TDM_ERROR_NONE;
769 _tdm_display_load_module_with_file(tdm_private_display *private_display,
772 char path[PATH_MAX] = {0,};
773 tdm_backend_module *module_data;
777 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
779 TDM_TRACE_BEGIN(Load_Backend);
781 module = dlopen(path, RTLD_LAZY);
783 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
785 return TDM_ERROR_BAD_MODULE;
788 module_data = dlsym(module, "tdm_backend_module_data");
790 TDM_ERR("'%s' doesn't have data object", file);
791 ret = TDM_ERROR_BAD_MODULE;
796 private_display->module_data = module_data;
797 private_display->module = module;
799 /* check if version, init() and deinit() are valid or not */
800 ret = _tdm_display_check_module(module_data);
801 if (ret != TDM_ERROR_NONE)
806 /* We don't care if backend_data is NULL or not. It's up to backend. */
807 TDM_TRACE_BEGIN(Init_Backend);
808 private_display->bdata = module_data->init((tdm_display *)private_display,
811 if (ret != TDM_ERROR_NONE) {
812 TDM_ERR("'%s' init failed", file);
816 ret = _tdm_display_check_backend_functions(private_display);
817 if (ret != TDM_ERROR_NONE) {
818 module_data->deinit(private_display->bdata);
819 private_display->bdata = NULL;
823 TDM_INFO("Success to load module(%s)", file);
825 return TDM_ERROR_NONE;
828 private_display->module_data = NULL;
829 private_display->module = NULL;
834 _tdm_display_load_module(tdm_private_display *private_display)
836 const char *module_name;
837 struct dirent **namelist;
841 module_name = getenv("TDM_MODULE");
843 module_name = DEFAULT_MODULE;
845 /* load bufmgr priv from default lib */
846 ret = _tdm_display_load_module_with_file(private_display, module_name);
847 if (ret == TDM_ERROR_NONE)
848 return TDM_ERROR_NONE;
850 /* load bufmgr priv from configured path */
851 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
853 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
854 return TDM_ERROR_BAD_MODULE;
857 ret = TDM_ERROR_BAD_MODULE;
859 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
860 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
870 _tdm_display_unload_module(tdm_private_display *private_display)
872 if (private_display->module_data)
873 private_display->module_data->deinit(private_display->bdata);
874 if (private_display->module)
875 dlclose(private_display->module);
877 private_display->bdata = NULL;
878 private_display->module_data = NULL;
879 private_display->module = NULL;
883 tdm_display_init(tdm_error *error)
885 tdm_private_display *private_display = NULL;
889 _pthread_mutex_lock(&gLock);
891 if (g_private_display) {
892 g_private_display->init_count++;
893 _pthread_mutex_unlock(&gLock);
895 *error = TDM_ERROR_NONE;
896 return g_private_display;
899 debug = getenv("TDM_DEBUG");
900 if (debug && (strstr(debug, "1")))
903 debug = getenv("TDM_DEBUG_BUFFER");
904 if (debug && (strstr(debug, "1")))
905 tdm_debug_buffer = 1;
907 debug = getenv("TDM_DEBUG_THREAD");
908 if (debug && (strstr(debug, "1")))
909 tdm_debug_thread = 1;
911 debug = getenv("TDM_DEBUG_MUTEX");
912 if (debug && (strstr(debug, "1")))
915 private_display = calloc(1, sizeof(tdm_private_display));
916 if (!private_display) {
917 ret = TDM_ERROR_OUT_OF_MEMORY;
918 TDM_ERR("'private_display != NULL' failed");
922 if (pthread_mutex_init(&private_display->lock, NULL)) {
923 ret = TDM_ERROR_OPERATION_FAILED;
924 TDM_ERR("mutex init failed: %m");
925 goto failed_mutex_init;
928 _pthread_mutex_lock(&private_display->lock);
930 ret = tdm_event_loop_init(private_display);
931 if (ret != TDM_ERROR_NONE)
934 ret = _tdm_display_load_module(private_display);
935 if (ret != TDM_ERROR_NONE)
939 int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
940 if (tdm_drm_fd >= 0) {
941 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
943 if (!private_display->bufmgr) {
944 TDM_ERR("tbm_bufmgr_init failed");
947 TDM_INFO("tbm_bufmgr_init successed");
952 TDM_TRACE_BEGIN(Update_Display);
953 ret = _tdm_display_update_internal(private_display, 0);
955 if (ret != TDM_ERROR_NONE)
958 tdm_event_loop_create_backend_source(private_display);
960 private_display->init_count = 1;
962 g_private_display = private_display;
965 *error = TDM_ERROR_NONE;
967 _pthread_mutex_unlock(&private_display->lock);
968 _pthread_mutex_unlock(&gLock);
970 return (tdm_display *)private_display;
973 _tdm_display_unload_module(private_display);
975 tdm_event_loop_deinit(private_display);
977 _pthread_mutex_unlock(&private_display->lock);
978 pthread_mutex_destroy(&private_display->lock);
980 free(private_display);
983 tdm_debug_buffer = 0;
986 _pthread_mutex_unlock(&gLock);
991 tdm_display_deinit(tdm_display *dpy)
993 tdm_private_display *private_display = dpy;
995 if (!private_display)
998 _pthread_mutex_lock(&gLock);
1000 private_display->init_count--;
1001 if (private_display->init_count > 0) {
1002 _pthread_mutex_unlock(&gLock);
1006 _pthread_mutex_lock(&private_display->lock);
1008 tdm_event_loop_deinit(private_display);
1010 _tdm_display_destroy_private_display(private_display);
1011 _tdm_display_unload_module(private_display);
1014 if (private_display->bufmgr)
1015 tbm_bufmgr_deinit(private_display->bufmgr);
1018 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1020 _pthread_mutex_unlock(&private_display->lock);
1022 pthread_mutex_destroy(&private_display->lock);
1023 free(private_display);
1024 g_private_display = NULL;
1026 tdm_debug_buffer = 0;
1028 _pthread_mutex_unlock(&gLock);
1034 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1036 tdm_backend_module *module = private_display->module_data;
1038 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1041 if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)