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)
680 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
681 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
683 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
685 name = module->name ? module->name : "unknown";
686 vendor = module->vendor ? module->vendor : "unknown";
687 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
688 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
690 TDM_INFO("TDM module name: %s", name);
691 TDM_INFO("'%s' vendor: %s", name, vendor);
692 TDM_INFO("'%s' version: %d.%d", name, major, minor);
694 if (major != abimaj) {
695 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
696 return TDM_ERROR_BAD_MODULE;
699 if (minor > abimin) {
700 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
701 return TDM_ERROR_BAD_MODULE;
705 TDM_ERR("'%s' doesn't have init function", name);
706 return TDM_ERROR_BAD_MODULE;
709 if (!module->deinit) {
710 TDM_ERR("'%s' doesn't have deinit function", name);
711 return TDM_ERROR_BAD_MODULE;
714 return TDM_ERROR_NONE;
718 _tdm_display_check_backend_functions(tdm_private_display *private_display)
720 tdm_func_display *func_display = &private_display->func_display;
721 tdm_func_output *func_output = &private_display->func_output;
722 tdm_func_layer *func_layer = &private_display->func_layer;
725 /* below functions should be implemented in backend side */
727 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
728 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
729 TDM_ERROR_BAD_MODULE);
730 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
731 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
732 TDM_ERROR_BAD_MODULE);
733 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
734 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
736 ret = func_display->display_get_capabilitiy(private_display->bdata,
737 &private_display->caps_display);
738 if (ret != TDM_ERROR_NONE) {
739 TDM_ERR("display_get_capabilitiy() failed");
740 return TDM_ERROR_BAD_MODULE;
743 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
744 tdm_func_pp *func_pp = &private_display->func_pp;
745 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
746 TDM_ERROR_BAD_MODULE);
747 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
748 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
749 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
750 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
753 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
754 tdm_func_capture *func_capture = &private_display->func_capture;
755 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
756 TDM_ERROR_BAD_MODULE);
757 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
758 TDM_ERROR_BAD_MODULE);
759 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
760 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
761 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
762 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
763 TDM_ERROR_BAD_MODULE);
766 return TDM_ERROR_NONE;
770 _tdm_display_load_module_with_file(tdm_private_display *private_display,
773 char path[PATH_MAX] = {0,};
774 tdm_backend_module *module_data;
778 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
780 TDM_TRACE_BEGIN(Load_Backend);
782 module = dlopen(path, RTLD_LAZY);
784 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
786 return TDM_ERROR_BAD_MODULE;
789 module_data = dlsym(module, "tdm_backend_module_data");
791 TDM_ERR("'%s' doesn't have data object", file);
792 ret = TDM_ERROR_BAD_MODULE;
797 private_display->module_data = module_data;
798 private_display->module = module;
800 /* check if version, init() and deinit() are valid or not */
801 ret = _tdm_display_check_module(module_data);
802 if (ret != TDM_ERROR_NONE)
807 /* We don't care if backend_data is NULL or not. It's up to backend. */
808 TDM_TRACE_BEGIN(Init_Backend);
809 private_display->bdata = module_data->init((tdm_display *)private_display,
812 if (ret != TDM_ERROR_NONE) {
813 TDM_ERR("'%s' init failed", file);
817 ret = _tdm_display_check_backend_functions(private_display);
818 if (ret != TDM_ERROR_NONE) {
819 module_data->deinit(private_display->bdata);
820 private_display->bdata = NULL;
824 TDM_INFO("Success to load module(%s)", file);
826 return TDM_ERROR_NONE;
829 private_display->module_data = NULL;
830 private_display->module = NULL;
835 _tdm_display_load_module(tdm_private_display *private_display)
837 const char *module_name;
838 struct dirent **namelist;
842 module_name = getenv("TDM_MODULE");
844 module_name = DEFAULT_MODULE;
846 /* load bufmgr priv from default lib */
847 ret = _tdm_display_load_module_with_file(private_display, module_name);
848 if (ret == TDM_ERROR_NONE)
849 return TDM_ERROR_NONE;
851 /* load bufmgr priv from configured path */
852 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
854 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
855 return TDM_ERROR_BAD_MODULE;
858 ret = TDM_ERROR_BAD_MODULE;
860 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
861 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
871 _tdm_display_unload_module(tdm_private_display *private_display)
873 if (private_display->module_data)
874 private_display->module_data->deinit(private_display->bdata);
875 if (private_display->module)
876 dlclose(private_display->module);
878 private_display->bdata = NULL;
879 private_display->module_data = NULL;
880 private_display->module = NULL;
884 tdm_display_init(tdm_error *error)
886 tdm_private_display *private_display = NULL;
890 _pthread_mutex_lock(&gLock);
892 if (g_private_display) {
893 g_private_display->init_count++;
894 _pthread_mutex_unlock(&gLock);
896 *error = TDM_ERROR_NONE;
897 return g_private_display;
900 debug = getenv("TDM_DEBUG");
901 if (debug && (strstr(debug, "1")))
904 debug = getenv("TDM_DEBUG_BUFFER");
905 if (debug && (strstr(debug, "1")))
906 tdm_debug_buffer = 1;
908 debug = getenv("TDM_DEBUG_THREAD");
909 if (debug && (strstr(debug, "1")))
910 tdm_debug_thread = 1;
912 debug = getenv("TDM_DEBUG_MUTEX");
913 if (debug && (strstr(debug, "1")))
916 private_display = calloc(1, sizeof(tdm_private_display));
917 if (!private_display) {
918 ret = TDM_ERROR_OUT_OF_MEMORY;
919 TDM_ERR("'private_display != NULL' failed");
923 if (pthread_mutex_init(&private_display->lock, NULL)) {
924 ret = TDM_ERROR_OPERATION_FAILED;
925 TDM_ERR("mutex init failed: %m");
926 goto failed_mutex_init;
929 _pthread_mutex_lock(&private_display->lock);
931 ret = tdm_event_loop_init(private_display);
932 if (ret != TDM_ERROR_NONE)
935 ret = _tdm_display_load_module(private_display);
936 if (ret != TDM_ERROR_NONE)
940 int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
941 if (tdm_drm_fd >= 0) {
942 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
944 if (!private_display->bufmgr) {
945 TDM_ERR("tbm_bufmgr_init failed");
948 TDM_INFO("tbm_bufmgr_init successed");
953 TDM_TRACE_BEGIN(Update_Display);
954 ret = _tdm_display_update_internal(private_display, 0);
956 if (ret != TDM_ERROR_NONE)
959 tdm_event_loop_create_backend_source(private_display);
961 private_display->init_count = 1;
963 g_private_display = private_display;
966 *error = TDM_ERROR_NONE;
968 _pthread_mutex_unlock(&private_display->lock);
969 _pthread_mutex_unlock(&gLock);
971 return (tdm_display *)private_display;
974 _tdm_display_unload_module(private_display);
976 tdm_event_loop_deinit(private_display);
978 _pthread_mutex_unlock(&private_display->lock);
979 pthread_mutex_destroy(&private_display->lock);
981 free(private_display);
984 tdm_debug_buffer = 0;
987 _pthread_mutex_unlock(&gLock);
992 tdm_display_deinit(tdm_display *dpy)
994 tdm_private_display *private_display = dpy;
996 if (!private_display)
999 _pthread_mutex_lock(&gLock);
1001 private_display->init_count--;
1002 if (private_display->init_count > 0) {
1003 _pthread_mutex_unlock(&gLock);
1007 _pthread_mutex_lock(&private_display->lock);
1009 tdm_event_loop_deinit(private_display);
1011 _tdm_display_destroy_private_display(private_display);
1012 _tdm_display_unload_module(private_display);
1015 if (private_display->bufmgr)
1016 tbm_bufmgr_deinit(private_display->bufmgr);
1019 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1021 _pthread_mutex_unlock(&private_display->lock);
1023 pthread_mutex_destroy(&private_display->lock);
1024 free(private_display);
1025 g_private_display = NULL;
1027 tdm_debug_buffer = 0;
1029 _pthread_mutex_unlock(&gLock);
1035 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1037 tdm_backend_module *module = private_display->module_data;
1039 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1042 if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)