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)
93 free(caps_pp->formats);
94 memset(caps_pp, 0, sizeof(tdm_caps_pp));
98 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
100 free(caps_capture->formats);
101 memset(caps_capture, 0, sizeof(tdm_caps_capture));
105 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
107 free(caps_layer->formats);
108 free(caps_layer->props);
109 memset(caps_layer, 0, sizeof(tdm_caps_layer));
113 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
115 free(caps_output->modes);
116 free(caps_output->props);
117 memset(caps_output, 0, sizeof(tdm_caps_output));
121 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
123 tdm_private_capture *c = NULL, *cc = NULL;
125 LIST_DEL(&private_layer->link);
127 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
128 tdm_capture_destroy_internal(c);
130 _tdm_display_destroy_caps_layer(&private_layer->caps);
136 _tdm_display_destroy_private_output(tdm_private_output *private_output)
138 tdm_private_layer *l = NULL, *ll = NULL;
139 tdm_private_capture *c = NULL, *cc = NULL;
140 tdm_private_vblank_handler *v = NULL, *vv = NULL;
141 tdm_private_commit_handler *m = NULL, *mm = NULL;
142 tdm_private_change_handler *h = NULL, *hh = NULL;
144 LIST_DEL(&private_output->link);
146 free(private_output->layers_ptr);
148 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
153 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
158 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
163 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
168 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
169 tdm_capture_destroy_internal(c);
171 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
172 _tdm_display_destroy_private_layer(l);
174 _tdm_display_destroy_caps_output(&private_output->caps);
176 private_output->stamp = 0;
177 free(private_output);
181 _tdm_display_destroy_private_display(tdm_private_display *private_display)
183 tdm_private_output *o = NULL, *oo = NULL;
184 tdm_private_pp *p = NULL, *pp = NULL;
186 free(private_display->outputs_ptr);
188 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
189 tdm_pp_destroy_internal(p);
191 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
192 _tdm_display_destroy_private_output(o);
194 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
195 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
197 private_display->capabilities = 0;
198 private_display->caps_display.max_layer_count = -1;
202 _tdm_display_update_caps_pp(tdm_private_display *private_display,
205 tdm_func_display *func_display = &private_display->func_display;
207 int bufsize = sizeof(buf);
209 int *len_buf = &bufsize;
213 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
214 return TDM_ERROR_NONE;
216 if (!func_display->display_get_pp_capability) {
217 TDM_ERR("no display_get_pp_capability()");
218 return TDM_ERROR_BAD_MODULE;
221 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
222 if (ret != TDM_ERROR_NONE) {
223 TDM_ERR("display_get_pp_capability() failed");
224 return TDM_ERROR_BAD_MODULE;
227 TDM_DBG("pp capabilities: %x", caps->capabilities);
229 for (i = 0; i < caps->format_count; i++)
230 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
231 TDM_DBG("pp formats: %s", buf);
232 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
233 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
234 TDM_DBG("pp align: %d", caps->preferred_align);
236 return TDM_ERROR_NONE;
240 _tdm_display_update_caps_capture(tdm_private_display *private_display,
241 tdm_caps_capture *caps)
243 tdm_func_display *func_display = &private_display->func_display;
245 int bufsize = sizeof(buf);
247 int *len_buf = &bufsize;
251 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
252 return TDM_ERROR_NONE;
254 if (!func_display->display_get_capture_capability) {
255 TDM_ERR("no display_get_capture_capability()");
256 return TDM_ERROR_BAD_MODULE;
259 ret = func_display->display_get_capture_capability(private_display->bdata,
261 if (ret != TDM_ERROR_NONE) {
262 TDM_ERR("display_get_capture_capability() failed");
263 return TDM_ERROR_BAD_MODULE;
267 for (i = 0; i < caps->format_count; i++)
268 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
269 TDM_DBG("capture formats: %s", buf);
271 return TDM_ERROR_NONE;
275 _tdm_display_update_caps_layer(tdm_private_display *private_display,
276 tdm_layer *layer_backend, tdm_caps_layer *caps)
278 tdm_func_layer *func_layer = &private_display->func_layer;
280 int bufsize = sizeof(buf);
282 int *len_buf = &bufsize;
286 if (!func_layer->layer_get_capability) {
287 TDM_ERR("no layer_get_capability()");
288 return TDM_ERROR_BAD_MODULE;
291 ret = func_layer->layer_get_capability(layer_backend, caps);
292 if (ret != TDM_ERROR_NONE) {
293 TDM_ERR("layer_get_capability() failed");
294 return TDM_ERROR_BAD_MODULE;
297 TDM_DBG("layer capabilities: %x", caps->capabilities);
298 TDM_DBG("layer zpos : %d", caps->zpos);
300 for (i = 0; i < caps->format_count; i++)
301 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
302 TDM_DBG("layer formats: %s", buf);
303 for (i = 0; i < caps->prop_count; i++)
304 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
306 return TDM_ERROR_NONE;
310 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
311 tdm_output *output_backend, tdm_caps_output *caps)
313 tdm_func_output *func_output = &private_display->func_output;
314 char temp[TDM_NAME_LEN];
318 if (!func_output->output_get_capability) {
319 TDM_ERR("no output_get_capability()");
320 return TDM_ERROR_BAD_MODULE;
323 ret = func_output->output_get_capability(output_backend, caps);
324 if (ret != TDM_ERROR_NONE) {
325 TDM_ERR("output_get_capability() failed");
326 return TDM_ERROR_BAD_MODULE;
329 /* FIXME: Use model for tdm client to distinguish amoung outputs */
330 snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
331 snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
333 TDM_DBG("output maker: %s", caps->maker);
334 TDM_DBG("output model: %s", caps->model);
335 TDM_DBG("output name: %s", caps->name);
336 TDM_DBG("output status: %d", caps->status);
337 TDM_DBG("output type : %d", caps->type);
338 for (i = 0; i < caps->prop_count; i++)
339 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
340 for (i = 0; i < caps->mode_count; i++) {
341 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
342 caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
343 caps->modes[i].flags, caps->modes[i].type);
344 TDM_DBG("\t\t %d, %d, %d, %d, %d",
345 caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
346 caps->modes[i].htotal, caps->modes[i].hskew);
347 TDM_DBG("\t\t %d, %d, %d, %d, %d",
348 caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
349 caps->modes[i].vtotal, caps->modes[i].vscan);
351 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
352 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
353 TDM_DBG("output align: %d", caps->preferred_align);
355 return TDM_ERROR_NONE;
359 _tdm_display_update_layer(tdm_private_display *private_display,
360 tdm_private_output *private_output,
361 tdm_layer *layer_backend)
363 tdm_private_layer *private_layer;
366 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
367 if (!private_layer) {
368 private_layer = calloc(1, sizeof(tdm_private_layer));
369 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
371 LIST_ADD(&private_layer->link, &private_output->layer_list);
372 private_layer->private_display = private_display;
373 private_layer->private_output = private_output;
374 private_layer->layer_backend = layer_backend;
376 LIST_INITHEAD(&private_layer->capture_list);
378 private_layer->usable = 1;
380 _tdm_display_destroy_caps_layer(&private_layer->caps);
382 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
383 &private_layer->caps);
384 if (ret != TDM_ERROR_NONE)
387 return TDM_ERROR_NONE;
389 _tdm_display_destroy_private_layer(private_layer);
394 _tdm_display_update_output(tdm_private_display *private_display,
395 tdm_output *output_backend, int pipe)
397 tdm_func_output *func_output = &private_display->func_output;
398 tdm_private_output *private_output = NULL;
399 tdm_layer **layers = NULL;
400 int layer_count = 0, i;
403 private_output = _tdm_display_find_private_output(private_display,
405 if (!private_output) {
406 private_output = calloc(1, sizeof(tdm_private_output));
407 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
409 private_output->stamp = tdm_helper_get_time_in_millis();
410 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
411 private_output->stamp++;
413 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
415 private_output->private_display = private_display;
416 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
417 private_output->output_backend = output_backend;
418 private_output->pipe = pipe;
420 LIST_INITHEAD(&private_output->layer_list);
421 LIST_INITHEAD(&private_output->capture_list);
422 LIST_INITHEAD(&private_output->vblank_handler_list);
423 LIST_INITHEAD(&private_output->commit_handler_list);
424 LIST_INITHEAD(&private_output->change_handler_list_main);
425 LIST_INITHEAD(&private_output->change_handler_list_sub);
427 if (func_output->output_set_status_handler)
428 func_output->output_set_status_handler(private_output->output_backend,
429 tdm_output_cb_status,
433 _tdm_display_destroy_caps_output(&private_output->caps);
435 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
436 &private_output->caps);
437 if (ret != TDM_ERROR_NONE)
440 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
441 if (ret != TDM_ERROR_NONE)
444 for (i = 0; i < layer_count; i++) {
445 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
446 if (ret != TDM_ERROR_NONE)
452 return TDM_ERROR_NONE;
454 _tdm_display_destroy_private_output(private_output);
460 _tdm_display_set_main_first(tdm_output **outputs, int index)
462 tdm_output *output_tmp = NULL;
467 output_tmp = outputs[0];
468 outputs[0] = outputs[index];
469 outputs[index] = output_tmp;
475 _tdm_display_get_ordered_outputs(tdm_private_display *private_display,
476 int *count, int init)
478 tdm_func_display *func_display = &private_display->func_display;
479 tdm_output **outputs = NULL;
480 tdm_output **new_outputs = NULL;
481 tdm_output *output_dsi = NULL;
482 tdm_output *output_lvds = NULL;
483 tdm_output *output_hdmia = NULL;
484 tdm_output *output_hdmib = NULL;
485 int i, output_count = 0, output_connected_count = 0;
486 int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
489 outputs = func_display->display_get_outputs(private_display->bdata,
490 &output_count, &ret);
491 if (ret != TDM_ERROR_NONE)
492 goto failed_get_outputs;
494 *count = output_count;
496 if (output_count == 0)
497 goto failed_get_outputs;
498 else if (output_count == 1)
501 /* don't change list order if not init time */
505 /* count connected outputs */
506 for (i = 0; i < output_count; i++) {
507 tdm_func_output *func_output = &private_display->func_output;
508 tdm_caps_output caps;
509 memset(&caps, 0, sizeof(tdm_caps_output));
511 if (!func_output->output_get_capability) {
512 TDM_ERR("no output_get_capability()");
516 ret = func_output->output_get_capability(outputs[i], &caps);
517 if (ret != TDM_ERROR_NONE) {
518 TDM_ERR("output_get_capability() failed");
522 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
523 output_connected_count++;
526 case TDM_OUTPUT_TYPE_DSI:
527 output_dsi = outputs[i];
530 case TDM_OUTPUT_TYPE_LVDS:
531 output_lvds = outputs[i];
534 case TDM_OUTPUT_TYPE_HDMIA:
535 output_hdmia = outputs[i];
538 case TDM_OUTPUT_TYPE_HDMIB:
539 output_hdmib = outputs[i];
548 /* ordering : main output is first */
549 /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
550 * But hdmi is possible, so set hdmi to main display.
551 * If connected only one output, it is main output.
552 * If connected outputs over 2, has priority like below.
553 * (dsi > lvds > hdmi > else)
555 if (output_connected_count == 0) {
556 /* hdmi > dsi > lvds > else */
557 if (output_hdmia != NULL)
558 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
559 else if (output_hdmib != NULL)
560 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
561 else if (output_dsi != NULL)
562 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
563 else if (output_lvds != NULL)
564 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
566 new_outputs = outputs;
567 } else { /* (output_connected_count > 1) */
568 /* dsi > lvds > hdmi > else */
569 if (output_dsi != NULL)
570 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
571 else if (output_lvds != NULL)
572 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
573 else if (output_hdmia != NULL)
574 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
575 else if (output_hdmib != NULL)
576 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
578 new_outputs = outputs;
589 _tdm_display_update_internal(tdm_private_display *private_display,
592 tdm_output **outputs = NULL;
593 int output_count = 0, i;
596 LIST_INITHEAD(&private_display->output_list);
597 LIST_INITHEAD(&private_display->pp_list);
598 LIST_INITHEAD(&private_display->capture_list);
601 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
602 if (ret != TDM_ERROR_NONE)
605 ret = _tdm_display_update_caps_capture(private_display,
606 &private_display->caps_capture);
607 if (ret != TDM_ERROR_NONE)
611 outputs = _tdm_display_get_ordered_outputs(private_display, &output_count, only_display);
615 for (i = 0; i < output_count; i++) {
616 ret = _tdm_display_update_output(private_display, outputs[i], i);
617 if (ret != TDM_ERROR_NONE)
623 return TDM_ERROR_NONE;
626 _tdm_display_destroy_private_display(private_display);
632 tdm_display_update(tdm_display *dpy)
634 tdm_private_display *private_display;
637 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
639 private_display = dpy;
640 _pthread_mutex_lock(&private_display->lock);
642 ret = _tdm_display_update_internal(private_display, 1);
644 _pthread_mutex_unlock(&private_display->lock);
649 #define SUFFIX_MODULE ".so"
650 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
653 int tdm_debug_buffer;
654 int tdm_debug_thread;
657 static tdm_private_display *g_private_display;
658 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
661 _tdm_display_check_module(tdm_backend_module *module)
668 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
669 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
671 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
673 name = module->name ? module->name : "unknown";
674 vendor = module->vendor ? module->vendor : "unknown";
675 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
676 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
678 TDM_INFO("TDM module name: %s", name);
679 TDM_INFO("'%s' vendor: %s", name, vendor);
680 TDM_INFO("'%s' version: %d.%d", name, major, minor);
682 if (major != abimaj) {
683 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
684 return TDM_ERROR_BAD_MODULE;
687 if (minor > abimin) {
688 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
689 return TDM_ERROR_BAD_MODULE;
693 TDM_ERR("'%s' doesn't have init function", name);
694 return TDM_ERROR_BAD_MODULE;
697 if (!module->deinit) {
698 TDM_ERR("'%s' doesn't have deinit function", name);
699 return TDM_ERROR_BAD_MODULE;
702 return TDM_ERROR_NONE;
706 _tdm_display_check_backend_functions(tdm_private_display *private_display)
708 tdm_func_display *func_display = &private_display->func_display;
709 tdm_func_output *func_output = &private_display->func_output;
710 tdm_func_layer *func_layer = &private_display->func_layer;
713 /* below functions should be implemented in backend side */
715 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
716 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
717 TDM_ERROR_BAD_MODULE);
718 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
719 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
720 TDM_ERROR_BAD_MODULE);
721 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
722 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
724 ret = func_display->display_get_capabilitiy(private_display->bdata,
725 &private_display->caps_display);
726 if (ret != TDM_ERROR_NONE) {
727 TDM_ERR("display_get_capabilitiy() failed");
728 return TDM_ERROR_BAD_MODULE;
731 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
732 tdm_func_pp *func_pp = &private_display->func_pp;
733 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
734 TDM_ERROR_BAD_MODULE);
735 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
736 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
737 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
738 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
741 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
742 tdm_func_capture *func_capture = &private_display->func_capture;
743 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
744 TDM_ERROR_BAD_MODULE);
745 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
746 TDM_ERROR_BAD_MODULE);
747 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
748 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
749 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
750 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
751 TDM_ERROR_BAD_MODULE);
754 return TDM_ERROR_NONE;
758 _tdm_display_load_module_with_file(tdm_private_display *private_display,
761 char path[PATH_MAX] = {0,};
762 tdm_backend_module *module_data;
766 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
768 TDM_TRACE_BEGIN(Load_Backend);
770 module = dlopen(path, RTLD_LAZY);
772 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
774 return TDM_ERROR_BAD_MODULE;
777 module_data = dlsym(module, "tdm_backend_module_data");
779 TDM_ERR("'%s' doesn't have data object", file);
780 ret = TDM_ERROR_BAD_MODULE;
785 private_display->module_data = module_data;
786 private_display->module = module;
788 /* check if version, init() and deinit() are valid or not */
789 ret = _tdm_display_check_module(module_data);
790 if (ret != TDM_ERROR_NONE)
795 /* We don't care if backend_data is NULL or not. It's up to backend. */
796 TDM_TRACE_BEGIN(Init_Backend);
797 private_display->bdata = module_data->init((tdm_display *)private_display,
800 if (ret != TDM_ERROR_NONE) {
801 TDM_ERR("'%s' init failed", file);
805 ret = _tdm_display_check_backend_functions(private_display);
806 if (ret != TDM_ERROR_NONE) {
807 module_data->deinit(private_display->bdata);
808 private_display->bdata = NULL;
812 TDM_INFO("Success to load module(%s)", file);
814 return TDM_ERROR_NONE;
817 private_display->module_data = NULL;
818 private_display->module = NULL;
823 _tdm_display_load_module(tdm_private_display *private_display)
825 const char *module_name;
826 struct dirent **namelist;
830 module_name = getenv("TDM_MODULE");
832 module_name = DEFAULT_MODULE;
834 /* load bufmgr priv from default lib */
835 ret = _tdm_display_load_module_with_file(private_display, module_name);
836 if (ret == TDM_ERROR_NONE)
837 return TDM_ERROR_NONE;
839 /* load bufmgr priv from configured path */
840 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
842 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
843 return TDM_ERROR_BAD_MODULE;
846 ret = TDM_ERROR_BAD_MODULE;
848 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
849 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
859 _tdm_display_unload_module(tdm_private_display *private_display)
861 if (private_display->module_data)
862 private_display->module_data->deinit(private_display->bdata);
863 if (private_display->module)
864 dlclose(private_display->module);
866 private_display->bdata = NULL;
867 private_display->module_data = NULL;
868 private_display->module = NULL;
872 tdm_display_init(tdm_error *error)
874 tdm_private_display *private_display = NULL;
878 _pthread_mutex_lock(&gLock);
880 if (g_private_display) {
881 g_private_display->init_count++;
882 _pthread_mutex_unlock(&gLock);
884 *error = TDM_ERROR_NONE;
885 return g_private_display;
888 debug = getenv("TDM_DEBUG");
889 if (debug && (strstr(debug, "1")))
892 debug = getenv("TDM_DEBUG_BUFFER");
893 if (debug && (strstr(debug, "1")))
894 tdm_debug_buffer = 1;
896 debug = getenv("TDM_DEBUG_THREAD");
897 if (debug && (strstr(debug, "1")))
898 tdm_debug_thread = 1;
900 debug = getenv("TDM_DEBUG_MUTEX");
901 if (debug && (strstr(debug, "1")))
904 private_display = calloc(1, sizeof(tdm_private_display));
905 if (!private_display) {
906 ret = TDM_ERROR_OUT_OF_MEMORY;
907 TDM_ERR("'private_display != NULL' failed");
911 if (pthread_mutex_init(&private_display->lock, NULL)) {
912 ret = TDM_ERROR_OPERATION_FAILED;
913 TDM_ERR("mutex init failed: %m");
914 goto failed_mutex_init;
917 _pthread_mutex_lock(&private_display->lock);
919 ret = tdm_event_loop_init(private_display);
920 if (ret != TDM_ERROR_NONE)
923 ret = _tdm_display_load_module(private_display);
924 if (ret != TDM_ERROR_NONE)
928 int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
929 if (tdm_drm_fd >= 0) {
930 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
932 if (!private_display->bufmgr) {
933 TDM_ERR("tbm_bufmgr_init failed");
936 TDM_INFO("tbm_bufmgr_init successed");
941 TDM_TRACE_BEGIN(Update_Display);
942 ret = _tdm_display_update_internal(private_display, 0);
944 if (ret != TDM_ERROR_NONE)
947 tdm_event_loop_create_backend_source(private_display);
949 private_display->init_count = 1;
951 g_private_display = private_display;
954 *error = TDM_ERROR_NONE;
956 _pthread_mutex_unlock(&private_display->lock);
957 _pthread_mutex_unlock(&gLock);
959 return (tdm_display *)private_display;
962 _tdm_display_unload_module(private_display);
964 tdm_event_loop_deinit(private_display);
966 _pthread_mutex_unlock(&private_display->lock);
967 pthread_mutex_destroy(&private_display->lock);
969 free(private_display);
972 tdm_debug_buffer = 0;
975 _pthread_mutex_unlock(&gLock);
980 tdm_display_deinit(tdm_display *dpy)
982 tdm_private_display *private_display = dpy;
984 if (!private_display)
987 _pthread_mutex_lock(&gLock);
989 private_display->init_count--;
990 if (private_display->init_count > 0) {
991 _pthread_mutex_unlock(&gLock);
995 _pthread_mutex_lock(&private_display->lock);
997 tdm_event_loop_deinit(private_display);
999 _tdm_display_destroy_private_display(private_display);
1000 _tdm_display_unload_module(private_display);
1003 if (private_display->bufmgr)
1004 tbm_bufmgr_deinit(private_display->bufmgr);
1007 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1009 _pthread_mutex_unlock(&private_display->lock);
1011 pthread_mutex_destroy(&private_display->lock);
1012 free(private_display);
1013 g_private_display = NULL;
1015 tdm_debug_buffer = 0;
1017 _pthread_mutex_unlock(&gLock);