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);
199 if (private_display->outputs) {
200 free(private_display->outputs);
201 private_display->outputs = NULL;
204 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
205 tdm_pp_destroy_internal(p);
207 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
208 _tdm_display_destroy_private_output(o);
210 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
211 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
213 private_display->capabilities = 0;
214 private_display->caps_display.max_layer_count = -1;
218 _tdm_display_update_caps_pp(tdm_private_display *private_display,
221 tdm_func_display *func_display = &private_display->func_display;
223 int bufsize = sizeof(buf);
225 int *len_buf = &bufsize;
229 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
230 return TDM_ERROR_NONE;
232 if (!func_display->display_get_pp_capability) {
233 TDM_ERR("no display_get_pp_capability()");
234 return TDM_ERROR_BAD_MODULE;
237 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
238 if (ret != TDM_ERROR_NONE) {
239 TDM_ERR("display_get_pp_capability() failed");
240 return TDM_ERROR_BAD_MODULE;
243 TDM_DBG("pp capabilities: %x", caps->capabilities);
245 for (i = 0; i < caps->format_count; i++)
246 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
247 TDM_DBG("pp formats: %s", buf);
248 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
249 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
250 TDM_DBG("pp align: %d", caps->preferred_align);
252 return TDM_ERROR_NONE;
256 _tdm_display_update_caps_capture(tdm_private_display *private_display,
257 tdm_caps_capture *caps)
259 tdm_func_display *func_display = &private_display->func_display;
261 int bufsize = sizeof(buf);
263 int *len_buf = &bufsize;
267 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
268 return TDM_ERROR_NONE;
270 if (!func_display->display_get_capture_capability) {
271 TDM_ERR("no display_get_capture_capability()");
272 return TDM_ERROR_BAD_MODULE;
275 ret = func_display->display_get_capture_capability(private_display->bdata,
277 if (ret != TDM_ERROR_NONE) {
278 TDM_ERR("display_get_capture_capability() failed");
279 return TDM_ERROR_BAD_MODULE;
283 for (i = 0; i < caps->format_count; i++)
284 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
285 TDM_DBG("capture formats: %s", buf);
287 return TDM_ERROR_NONE;
291 _tdm_display_update_caps_layer(tdm_private_display *private_display,
292 tdm_layer *layer_backend, tdm_caps_layer *caps)
294 tdm_func_layer *func_layer = &private_display->func_layer;
296 int bufsize = sizeof(buf);
298 int *len_buf = &bufsize;
302 if (!func_layer->layer_get_capability) {
303 TDM_ERR("no layer_get_capability()");
304 return TDM_ERROR_BAD_MODULE;
307 ret = func_layer->layer_get_capability(layer_backend, caps);
308 if (ret != TDM_ERROR_NONE) {
309 TDM_ERR("layer_get_capability() failed");
310 return TDM_ERROR_BAD_MODULE;
313 TDM_DBG("layer capabilities: %x", caps->capabilities);
314 TDM_DBG("layer zpos : %d", caps->zpos);
316 for (i = 0; i < caps->format_count; i++)
317 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
318 TDM_DBG("layer formats: %s", buf);
319 for (i = 0; i < caps->prop_count; i++)
320 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
322 return TDM_ERROR_NONE;
326 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
327 tdm_output *output_backend, tdm_caps_output *caps)
329 tdm_func_output *func_output = &private_display->func_output;
330 char temp[TDM_NAME_LEN];
334 if (!func_output->output_get_capability) {
335 TDM_ERR("no output_get_capability()");
336 return TDM_ERROR_BAD_MODULE;
339 ret = func_output->output_get_capability(output_backend, caps);
340 if (ret != TDM_ERROR_NONE) {
341 TDM_ERR("output_get_capability() failed");
342 return TDM_ERROR_BAD_MODULE;
345 /* FIXME: Use model for tdm client to distinguish amoung outputs */
346 snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
347 snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
349 TDM_DBG("output maker: %s", caps->maker);
350 TDM_DBG("output model: %s", caps->model);
351 TDM_DBG("output name: %s", caps->name);
352 TDM_DBG("output status: %d", caps->status);
353 TDM_DBG("output type : %d", caps->type);
354 for (i = 0; i < caps->prop_count; i++)
355 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
356 for (i = 0; i < caps->mode_count; i++) {
357 TDM_DBG("output modes: name(%s), clock(%d) vrefresh(%d), flags(%x), type(%d)",
358 caps->modes[i].name, caps->modes[i].clock, caps->modes[i].vrefresh,
359 caps->modes[i].flags, caps->modes[i].type);
360 TDM_DBG("\t\t %d, %d, %d, %d, %d",
361 caps->modes[i].hdisplay, caps->modes[i].hsync_start, caps->modes[i].hsync_end,
362 caps->modes[i].htotal, caps->modes[i].hskew);
363 TDM_DBG("\t\t %d, %d, %d, %d, %d",
364 caps->modes[i].vdisplay, caps->modes[i].vsync_start, caps->modes[i].vsync_end,
365 caps->modes[i].vtotal, caps->modes[i].vscan);
367 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
368 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
369 TDM_DBG("output align: %d", caps->preferred_align);
371 return TDM_ERROR_NONE;
375 _tdm_display_update_layer(tdm_private_display *private_display,
376 tdm_private_output *private_output,
377 tdm_layer *layer_backend)
379 tdm_private_layer *private_layer;
382 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
383 if (!private_layer) {
384 private_layer = calloc(1, sizeof(tdm_private_layer));
385 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
387 LIST_ADD(&private_layer->link, &private_output->layer_list);
388 private_layer->private_display = private_display;
389 private_layer->private_output = private_output;
390 private_layer->layer_backend = layer_backend;
392 LIST_INITHEAD(&private_layer->capture_list);
394 private_layer->usable = 1;
396 _tdm_display_destroy_caps_layer(&private_layer->caps);
398 ret = _tdm_display_update_caps_layer(private_display, layer_backend,
399 &private_layer->caps);
400 if (ret != TDM_ERROR_NONE)
403 return TDM_ERROR_NONE;
405 _tdm_display_destroy_private_layer(private_layer);
410 tdm_display_update_output(tdm_private_display *private_display,
411 tdm_output *output_backend, int pipe)
413 tdm_func_output *func_output = &private_display->func_output;
414 tdm_private_output *private_output = NULL;
415 tdm_layer **layers = NULL;
416 int layer_count = 0, i;
419 private_output = _tdm_display_find_private_output(private_display,
421 if (!private_output) {
422 private_output = calloc(1, sizeof(tdm_private_output));
423 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
425 private_output->stamp = tdm_helper_get_time_in_millis();
426 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
427 private_output->stamp++;
429 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
431 private_output->private_display = private_display;
432 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
433 private_output->output_backend = output_backend;
434 private_output->pipe = pipe;
436 LIST_INITHEAD(&private_output->layer_list);
437 LIST_INITHEAD(&private_output->capture_list);
438 LIST_INITHEAD(&private_output->vblank_handler_list);
439 LIST_INITHEAD(&private_output->commit_handler_list);
440 LIST_INITHEAD(&private_output->change_handler_list_main);
441 LIST_INITHEAD(&private_output->change_handler_list_sub);
443 if (func_output->output_set_status_handler) {
444 func_output->output_set_status_handler(private_output->output_backend,
445 tdm_output_cb_status,
447 private_output->regist_change_cb = 1;
451 _tdm_display_destroy_caps_output(&private_output->caps);
453 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
454 &private_output->caps);
455 if (ret != TDM_ERROR_NONE)
458 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
459 if (ret != TDM_ERROR_NONE)
462 for (i = 0; i < layer_count; i++) {
463 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
464 if (ret != TDM_ERROR_NONE)
470 return TDM_ERROR_NONE;
472 _tdm_display_destroy_private_output(private_output);
478 _tdm_display_set_main_first(tdm_output **outputs, int index)
480 tdm_output *output_tmp = NULL;
485 output_tmp = outputs[0];
486 outputs[0] = outputs[index];
487 outputs[index] = output_tmp;
493 _tdm_display_get_ordered_outputs(tdm_private_display *private_display, int *count)
495 tdm_func_display *func_display = &private_display->func_display;
496 tdm_output **outputs = NULL;
497 tdm_output **new_outputs = NULL;
498 tdm_output *output_dsi = NULL;
499 tdm_output *output_lvds = NULL;
500 tdm_output *output_hdmia = NULL;
501 tdm_output *output_hdmib = NULL;
502 int i, output_count = 0, output_connected_count = 0;
503 int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
506 /* don't change list order if not init time */
507 if (private_display->outputs)
508 return private_display->outputs;
510 outputs = func_display->display_get_outputs(private_display->bdata,
511 &output_count, &ret);
512 if (ret != TDM_ERROR_NONE)
513 goto failed_get_outputs;
515 *count = output_count;
517 if (output_count == 0)
518 goto failed_get_outputs;
519 else if (output_count == 1) {
520 private_display->outputs = outputs;
524 /* count connected outputs */
525 for (i = 0; i < output_count; i++) {
526 tdm_func_output *func_output = &private_display->func_output;
527 tdm_caps_output caps;
528 memset(&caps, 0, sizeof(tdm_caps_output));
530 if (!func_output->output_get_capability) {
531 TDM_ERR("no output_get_capability()");
532 goto failed_get_outputs;
535 ret = func_output->output_get_capability(outputs[i], &caps);
536 if (ret != TDM_ERROR_NONE) {
537 TDM_ERR("output_get_capability() failed");
538 goto failed_get_outputs;
541 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
542 output_connected_count++;
545 case TDM_OUTPUT_TYPE_DSI:
546 output_dsi = outputs[i];
549 case TDM_OUTPUT_TYPE_LVDS:
550 output_lvds = outputs[i];
553 case TDM_OUTPUT_TYPE_HDMIA:
554 output_hdmia = outputs[i];
557 case TDM_OUTPUT_TYPE_HDMIB:
558 output_hdmib = outputs[i];
567 /* ordering : main output is first */
568 /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
569 * But hdmi is possible, so set hdmi to main display.
570 * If connected only one output, it is main output.
571 * If connected outputs over 2, has priority like below.
572 * (dsi > lvds > hdmi > else)
574 if (output_connected_count == 0) {
575 /* hdmi > dsi > lvds > else */
576 if (output_hdmia != NULL)
577 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
578 else if (output_hdmib != NULL)
579 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
580 else if (output_dsi != NULL)
581 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
582 else if (output_lvds != NULL)
583 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
585 new_outputs = outputs;
586 } else { /* (output_connected_count > 1) */
587 /* dsi > lvds > hdmi > else */
588 if (output_dsi != NULL)
589 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
590 else if (output_lvds != NULL)
591 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
592 else if (output_hdmia != NULL)
593 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
594 else if (output_hdmib != NULL)
595 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
597 new_outputs = outputs;
600 private_display->outputs = new_outputs;
611 _tdm_display_update_internal(tdm_private_display *private_display,
614 tdm_output **outputs = NULL;
615 int output_count = 0, i;
618 LIST_INITHEAD(&private_display->output_list);
619 LIST_INITHEAD(&private_display->pp_list);
620 LIST_INITHEAD(&private_display->capture_list);
623 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
624 if (ret != TDM_ERROR_NONE)
627 ret = _tdm_display_update_caps_capture(private_display,
628 &private_display->caps_capture);
629 if (ret != TDM_ERROR_NONE)
633 outputs = _tdm_display_get_ordered_outputs(private_display, &output_count);
637 for (i = 0; i < output_count; i++) {
638 ret = tdm_display_update_output(private_display, outputs[i], i);
639 if (ret != TDM_ERROR_NONE)
643 return TDM_ERROR_NONE;
646 _tdm_display_destroy_private_display(private_display);
651 tdm_display_update(tdm_display *dpy)
653 tdm_private_display *private_display;
656 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
658 private_display = dpy;
659 _pthread_mutex_lock(&private_display->lock);
661 ret = _tdm_display_update_internal(private_display, 1);
663 _pthread_mutex_unlock(&private_display->lock);
668 #define SUFFIX_MODULE ".so"
669 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
672 int tdm_debug_buffer;
673 int tdm_debug_thread;
676 static tdm_private_display *g_private_display;
677 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
680 _tdm_display_check_module(tdm_backend_module *module)
686 TDM_INFO("TDM ABI version : %d.%d",
687 TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
689 name = module->name ? module->name : "unknown";
690 vendor = module->vendor ? module->vendor : "unknown";
691 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
692 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
694 TDM_INFO("TDM module name: %s", name);
695 TDM_INFO("'%s' vendor: %s", name, vendor);
696 TDM_INFO("'%s' version: %d.%d", name, major, minor);
698 if (major != TDM_MAJOR_VERSION) {
699 TDM_ERR("'%s' major version mismatch, %d != %d",
700 name, major, TDM_MAJOR_VERSION);
701 return TDM_ERROR_BAD_MODULE;
704 if (minor > TDM_MINOR_VERSION) {
705 TDM_ERR("'%s' minor version(%d) is newer than %d",
706 name, minor, TDM_MINOR_VERSION);
707 return TDM_ERROR_BAD_MODULE;
711 TDM_ERR("'%s' doesn't have init function", name);
712 return TDM_ERROR_BAD_MODULE;
715 if (!module->deinit) {
716 TDM_ERR("'%s' doesn't have deinit function", name);
717 return TDM_ERROR_BAD_MODULE;
720 return TDM_ERROR_NONE;
724 _tdm_display_check_backend_functions(tdm_private_display *private_display)
726 tdm_func_display *func_display = &private_display->func_display;
727 tdm_func_output *func_output = &private_display->func_output;
728 tdm_func_layer *func_layer = &private_display->func_layer;
731 /* below functions should be implemented in backend side */
733 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
734 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
735 TDM_ERROR_BAD_MODULE);
736 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
737 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
738 TDM_ERROR_BAD_MODULE);
739 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
740 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
742 ret = func_display->display_get_capabilitiy(private_display->bdata,
743 &private_display->caps_display);
744 if (ret != TDM_ERROR_NONE) {
745 TDM_ERR("display_get_capabilitiy() failed");
746 return TDM_ERROR_BAD_MODULE;
749 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
750 tdm_func_pp *func_pp = &private_display->func_pp;
751 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
752 TDM_ERROR_BAD_MODULE);
753 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
754 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
755 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
756 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
759 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
760 tdm_func_capture *func_capture = &private_display->func_capture;
761 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
762 TDM_ERROR_BAD_MODULE);
763 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
764 TDM_ERROR_BAD_MODULE);
765 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
766 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
767 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
768 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
769 TDM_ERROR_BAD_MODULE);
772 return TDM_ERROR_NONE;
776 _tdm_display_load_module_with_file(tdm_private_display *private_display,
779 char path[PATH_MAX] = {0,};
780 tdm_backend_module *module_data;
784 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
786 TDM_TRACE_BEGIN(Load_Backend);
788 module = dlopen(path, RTLD_LAZY);
790 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
792 return TDM_ERROR_BAD_MODULE;
795 module_data = dlsym(module, "tdm_backend_module_data");
797 TDM_ERR("'%s' doesn't have data object", file);
798 ret = TDM_ERROR_BAD_MODULE;
803 private_display->module_data = module_data;
804 private_display->module = module;
806 /* check if version, init() and deinit() are valid or not */
807 ret = _tdm_display_check_module(module_data);
808 if (ret != TDM_ERROR_NONE)
813 /* We don't care if backend_data is NULL or not. It's up to backend. */
814 TDM_TRACE_BEGIN(Init_Backend);
815 private_display->bdata = module_data->init((tdm_display *)private_display,
818 if (ret != TDM_ERROR_NONE) {
819 TDM_ERR("'%s' init failed", file);
823 ret = _tdm_display_check_backend_functions(private_display);
824 if (ret != TDM_ERROR_NONE) {
825 module_data->deinit(private_display->bdata);
826 private_display->bdata = NULL;
830 TDM_INFO("Success to load module(%s)", file);
832 return TDM_ERROR_NONE;
835 private_display->module_data = NULL;
836 private_display->module = NULL;
841 _tdm_display_load_module(tdm_private_display *private_display)
843 const char *module_name;
844 struct dirent **namelist;
848 module_name = getenv("TDM_MODULE");
850 module_name = DEFAULT_MODULE;
852 /* load bufmgr priv from default lib */
853 ret = _tdm_display_load_module_with_file(private_display, module_name);
854 if (ret == TDM_ERROR_NONE)
855 return TDM_ERROR_NONE;
857 /* load bufmgr priv from configured path */
858 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
860 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
861 return TDM_ERROR_BAD_MODULE;
864 ret = TDM_ERROR_BAD_MODULE;
866 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
867 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
877 _tdm_display_unload_module(tdm_private_display *private_display)
879 if (private_display->module_data)
880 private_display->module_data->deinit(private_display->bdata);
881 if (private_display->module)
882 dlclose(private_display->module);
884 private_display->bdata = NULL;
885 private_display->module_data = NULL;
886 private_display->module = NULL;
890 tdm_display_init(tdm_error *error)
892 tdm_private_display *private_display = NULL;
896 _pthread_mutex_lock(&gLock);
898 if (g_private_display) {
899 g_private_display->init_count++;
900 _pthread_mutex_unlock(&gLock);
902 *error = TDM_ERROR_NONE;
903 return g_private_display;
906 debug = getenv("TDM_DEBUG");
907 if (debug && (strstr(debug, "1")))
910 debug = getenv("TDM_DEBUG_BUFFER");
911 if (debug && (strstr(debug, "1")))
912 tdm_debug_buffer = 1;
914 debug = getenv("TDM_DEBUG_THREAD");
915 if (debug && (strstr(debug, "1")))
916 tdm_debug_thread = 1;
918 debug = getenv("TDM_DEBUG_MUTEX");
919 if (debug && (strstr(debug, "1")))
922 private_display = calloc(1, sizeof(tdm_private_display));
923 if (!private_display) {
924 ret = TDM_ERROR_OUT_OF_MEMORY;
925 TDM_ERR("'private_display != NULL' failed");
929 if (pthread_mutex_init(&private_display->lock, NULL)) {
930 ret = TDM_ERROR_OPERATION_FAILED;
931 TDM_ERR("mutex init failed: %m");
932 goto failed_mutex_init;
935 _pthread_mutex_lock(&private_display->lock);
937 ret = tdm_event_loop_init(private_display);
938 if (ret != TDM_ERROR_NONE)
941 ret = _tdm_display_load_module(private_display);
942 if (ret != TDM_ERROR_NONE)
946 int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
947 if (tdm_drm_fd >= 0) {
948 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
950 if (!private_display->bufmgr) {
951 TDM_ERR("tbm_bufmgr_init failed");
954 TDM_INFO("tbm_bufmgr_init successed");
959 TDM_TRACE_BEGIN(Update_Display);
960 ret = _tdm_display_update_internal(private_display, 0);
962 if (ret != TDM_ERROR_NONE)
965 tdm_event_loop_create_backend_source(private_display);
967 private_display->init_count = 1;
969 g_private_display = private_display;
972 *error = TDM_ERROR_NONE;
974 _pthread_mutex_unlock(&private_display->lock);
975 _pthread_mutex_unlock(&gLock);
977 return (tdm_display *)private_display;
980 _tdm_display_unload_module(private_display);
982 tdm_event_loop_deinit(private_display);
984 _pthread_mutex_unlock(&private_display->lock);
985 pthread_mutex_destroy(&private_display->lock);
987 free(private_display);
990 tdm_debug_buffer = 0;
993 _pthread_mutex_unlock(&gLock);
998 tdm_display_deinit(tdm_display *dpy)
1000 tdm_private_display *private_display = dpy;
1002 if (!private_display)
1005 _pthread_mutex_lock(&gLock);
1007 private_display->init_count--;
1008 if (private_display->init_count > 0) {
1009 _pthread_mutex_unlock(&gLock);
1013 _pthread_mutex_lock(&private_display->lock);
1015 tdm_event_loop_deinit(private_display);
1017 _tdm_display_destroy_private_display(private_display);
1018 _tdm_display_unload_module(private_display);
1021 if (private_display->bufmgr)
1022 tbm_bufmgr_deinit(private_display->bufmgr);
1025 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1027 _pthread_mutex_unlock(&private_display->lock);
1029 pthread_mutex_destroy(&private_display->lock);
1030 free(private_display);
1031 g_private_display = NULL;
1033 tdm_debug_buffer = 0;
1035 _pthread_mutex_unlock(&gLock);
1041 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1043 tdm_backend_module *module = private_display->module_data;
1045 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1048 if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)