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,
443 private_output->regist_change_cb = 1;
447 _tdm_display_destroy_caps_output(&private_output->caps);
449 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
450 &private_output->caps);
451 if (ret != TDM_ERROR_NONE)
454 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
455 if (ret != TDM_ERROR_NONE)
458 for (i = 0; i < layer_count; i++) {
459 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
460 if (ret != TDM_ERROR_NONE)
466 return TDM_ERROR_NONE;
468 _tdm_display_destroy_private_output(private_output);
474 _tdm_display_set_main_first(tdm_output **outputs, int index)
476 tdm_output *output_tmp = NULL;
481 output_tmp = outputs[0];
482 outputs[0] = outputs[index];
483 outputs[index] = output_tmp;
489 _tdm_display_get_ordered_outputs(tdm_private_display *private_display,
490 int *count, int init)
492 tdm_func_display *func_display = &private_display->func_display;
493 tdm_output **outputs = NULL;
494 tdm_output **new_outputs = NULL;
495 tdm_output *output_dsi = NULL;
496 tdm_output *output_lvds = NULL;
497 tdm_output *output_hdmia = NULL;
498 tdm_output *output_hdmib = NULL;
499 int i, output_count = 0, output_connected_count = 0;
500 int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
503 outputs = func_display->display_get_outputs(private_display->bdata,
504 &output_count, &ret);
505 if (ret != TDM_ERROR_NONE)
506 goto failed_get_outputs;
508 *count = output_count;
510 if (output_count == 0)
511 goto failed_get_outputs;
512 else if (output_count == 1)
515 /* don't change list order if not init time */
519 /* count connected outputs */
520 for (i = 0; i < output_count; i++) {
521 tdm_func_output *func_output = &private_display->func_output;
522 tdm_caps_output caps;
523 memset(&caps, 0, sizeof(tdm_caps_output));
525 if (!func_output->output_get_capability) {
526 TDM_ERR("no output_get_capability()");
530 ret = func_output->output_get_capability(outputs[i], &caps);
531 if (ret != TDM_ERROR_NONE) {
532 TDM_ERR("output_get_capability() failed");
536 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
537 output_connected_count++;
540 case TDM_OUTPUT_TYPE_DSI:
541 output_dsi = outputs[i];
544 case TDM_OUTPUT_TYPE_LVDS:
545 output_lvds = outputs[i];
548 case TDM_OUTPUT_TYPE_HDMIA:
549 output_hdmia = outputs[i];
552 case TDM_OUTPUT_TYPE_HDMIB:
553 output_hdmib = outputs[i];
562 /* ordering : main output is first */
563 /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
564 * But hdmi is possible, so set hdmi to main display.
565 * If connected only one output, it is main output.
566 * If connected outputs over 2, has priority like below.
567 * (dsi > lvds > hdmi > else)
569 if (output_connected_count == 0) {
570 /* hdmi > dsi > lvds > else */
571 if (output_hdmia != NULL)
572 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
573 else if (output_hdmib != NULL)
574 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
575 else if (output_dsi != NULL)
576 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
577 else if (output_lvds != NULL)
578 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
580 new_outputs = outputs;
581 } else { /* (output_connected_count > 1) */
582 /* dsi > lvds > hdmi > else */
583 if (output_dsi != NULL)
584 new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
585 else if (output_lvds != NULL)
586 new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
587 else if (output_hdmia != NULL)
588 new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
589 else if (output_hdmib != NULL)
590 new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
592 new_outputs = outputs;
603 _tdm_display_update_internal(tdm_private_display *private_display,
606 tdm_output **outputs = NULL;
607 int output_count = 0, i;
610 LIST_INITHEAD(&private_display->output_list);
611 LIST_INITHEAD(&private_display->pp_list);
612 LIST_INITHEAD(&private_display->capture_list);
615 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
616 if (ret != TDM_ERROR_NONE)
619 ret = _tdm_display_update_caps_capture(private_display,
620 &private_display->caps_capture);
621 if (ret != TDM_ERROR_NONE)
625 outputs = _tdm_display_get_ordered_outputs(private_display, &output_count, only_display);
629 for (i = 0; i < output_count; i++) {
630 ret = tdm_display_update_output(private_display, outputs[i], i);
631 if (ret != TDM_ERROR_NONE)
637 return TDM_ERROR_NONE;
640 _tdm_display_destroy_private_display(private_display);
646 tdm_display_update(tdm_display *dpy)
648 tdm_private_display *private_display;
651 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
653 private_display = dpy;
654 _pthread_mutex_lock(&private_display->lock);
656 ret = _tdm_display_update_internal(private_display, 1);
658 _pthread_mutex_unlock(&private_display->lock);
663 #define SUFFIX_MODULE ".so"
664 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
667 int tdm_debug_buffer;
668 int tdm_debug_thread;
671 static tdm_private_display *g_private_display;
672 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
675 _tdm_display_check_module(tdm_backend_module *module)
681 TDM_INFO("TDM ABI version : %d.%d",
682 TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
684 name = module->name ? module->name : "unknown";
685 vendor = module->vendor ? module->vendor : "unknown";
686 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
687 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
689 TDM_INFO("TDM module name: %s", name);
690 TDM_INFO("'%s' vendor: %s", name, vendor);
691 TDM_INFO("'%s' version: %d.%d", name, major, minor);
693 if (major != TDM_MAJOR_VERSION) {
694 TDM_ERR("'%s' major version mismatch, %d != %d",
695 name, major, TDM_MAJOR_VERSION);
696 return TDM_ERROR_BAD_MODULE;
699 if (minor > TDM_MINOR_VERSION) {
700 TDM_ERR("'%s' minor version(%d) is newer than %d",
701 name, minor, TDM_MINOR_VERSION);
702 return TDM_ERROR_BAD_MODULE;
706 TDM_ERR("'%s' doesn't have init function", name);
707 return TDM_ERROR_BAD_MODULE;
710 if (!module->deinit) {
711 TDM_ERR("'%s' doesn't have deinit function", name);
712 return TDM_ERROR_BAD_MODULE;
715 return TDM_ERROR_NONE;
719 _tdm_display_check_backend_functions(tdm_private_display *private_display)
721 tdm_func_display *func_display = &private_display->func_display;
722 tdm_func_output *func_output = &private_display->func_output;
723 tdm_func_layer *func_layer = &private_display->func_layer;
726 /* below functions should be implemented in backend side */
728 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
729 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
730 TDM_ERROR_BAD_MODULE);
731 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
732 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
733 TDM_ERROR_BAD_MODULE);
734 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
735 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
737 ret = func_display->display_get_capabilitiy(private_display->bdata,
738 &private_display->caps_display);
739 if (ret != TDM_ERROR_NONE) {
740 TDM_ERR("display_get_capabilitiy() failed");
741 return TDM_ERROR_BAD_MODULE;
744 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
745 tdm_func_pp *func_pp = &private_display->func_pp;
746 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
747 TDM_ERROR_BAD_MODULE);
748 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
749 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
750 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
751 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
754 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
755 tdm_func_capture *func_capture = &private_display->func_capture;
756 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
757 TDM_ERROR_BAD_MODULE);
758 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
759 TDM_ERROR_BAD_MODULE);
760 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
761 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
762 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
763 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
764 TDM_ERROR_BAD_MODULE);
767 return TDM_ERROR_NONE;
771 _tdm_display_load_module_with_file(tdm_private_display *private_display,
774 char path[PATH_MAX] = {0,};
775 tdm_backend_module *module_data;
779 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
781 TDM_TRACE_BEGIN(Load_Backend);
783 module = dlopen(path, RTLD_LAZY);
785 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
787 return TDM_ERROR_BAD_MODULE;
790 module_data = dlsym(module, "tdm_backend_module_data");
792 TDM_ERR("'%s' doesn't have data object", file);
793 ret = TDM_ERROR_BAD_MODULE;
798 private_display->module_data = module_data;
799 private_display->module = module;
801 /* check if version, init() and deinit() are valid or not */
802 ret = _tdm_display_check_module(module_data);
803 if (ret != TDM_ERROR_NONE)
808 /* We don't care if backend_data is NULL or not. It's up to backend. */
809 TDM_TRACE_BEGIN(Init_Backend);
810 private_display->bdata = module_data->init((tdm_display *)private_display,
813 if (ret != TDM_ERROR_NONE) {
814 TDM_ERR("'%s' init failed", file);
818 ret = _tdm_display_check_backend_functions(private_display);
819 if (ret != TDM_ERROR_NONE) {
820 module_data->deinit(private_display->bdata);
821 private_display->bdata = NULL;
825 TDM_INFO("Success to load module(%s)", file);
827 return TDM_ERROR_NONE;
830 private_display->module_data = NULL;
831 private_display->module = NULL;
836 _tdm_display_load_module(tdm_private_display *private_display)
838 const char *module_name;
839 struct dirent **namelist;
843 module_name = getenv("TDM_MODULE");
845 module_name = DEFAULT_MODULE;
847 /* load bufmgr priv from default lib */
848 ret = _tdm_display_load_module_with_file(private_display, module_name);
849 if (ret == TDM_ERROR_NONE)
850 return TDM_ERROR_NONE;
852 /* load bufmgr priv from configured path */
853 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
855 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
856 return TDM_ERROR_BAD_MODULE;
859 ret = TDM_ERROR_BAD_MODULE;
861 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
862 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
872 _tdm_display_unload_module(tdm_private_display *private_display)
874 if (private_display->module_data)
875 private_display->module_data->deinit(private_display->bdata);
876 if (private_display->module)
877 dlclose(private_display->module);
879 private_display->bdata = NULL;
880 private_display->module_data = NULL;
881 private_display->module = NULL;
885 tdm_display_init(tdm_error *error)
887 tdm_private_display *private_display = NULL;
891 _pthread_mutex_lock(&gLock);
893 if (g_private_display) {
894 g_private_display->init_count++;
895 _pthread_mutex_unlock(&gLock);
897 *error = TDM_ERROR_NONE;
898 return g_private_display;
901 debug = getenv("TDM_DEBUG");
902 if (debug && (strstr(debug, "1")))
905 debug = getenv("TDM_DEBUG_BUFFER");
906 if (debug && (strstr(debug, "1")))
907 tdm_debug_buffer = 1;
909 debug = getenv("TDM_DEBUG_THREAD");
910 if (debug && (strstr(debug, "1")))
911 tdm_debug_thread = 1;
913 debug = getenv("TDM_DEBUG_MUTEX");
914 if (debug && (strstr(debug, "1")))
917 private_display = calloc(1, sizeof(tdm_private_display));
918 if (!private_display) {
919 ret = TDM_ERROR_OUT_OF_MEMORY;
920 TDM_ERR("'private_display != NULL' failed");
924 if (pthread_mutex_init(&private_display->lock, NULL)) {
925 ret = TDM_ERROR_OPERATION_FAILED;
926 TDM_ERR("mutex init failed: %m");
927 goto failed_mutex_init;
930 _pthread_mutex_lock(&private_display->lock);
932 ret = tdm_event_loop_init(private_display);
933 if (ret != TDM_ERROR_NONE)
936 ret = _tdm_display_load_module(private_display);
937 if (ret != TDM_ERROR_NONE)
941 int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
942 if (tdm_drm_fd >= 0) {
943 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
945 if (!private_display->bufmgr) {
946 TDM_ERR("tbm_bufmgr_init failed");
949 TDM_INFO("tbm_bufmgr_init successed");
954 TDM_TRACE_BEGIN(Update_Display);
955 ret = _tdm_display_update_internal(private_display, 0);
957 if (ret != TDM_ERROR_NONE)
960 tdm_event_loop_create_backend_source(private_display);
962 private_display->init_count = 1;
964 g_private_display = private_display;
967 *error = TDM_ERROR_NONE;
969 _pthread_mutex_unlock(&private_display->lock);
970 _pthread_mutex_unlock(&gLock);
972 return (tdm_display *)private_display;
975 _tdm_display_unload_module(private_display);
977 tdm_event_loop_deinit(private_display);
979 _pthread_mutex_unlock(&private_display->lock);
980 pthread_mutex_destroy(&private_display->lock);
982 free(private_display);
985 tdm_debug_buffer = 0;
988 _pthread_mutex_unlock(&gLock);
993 tdm_display_deinit(tdm_display *dpy)
995 tdm_private_display *private_display = dpy;
997 if (!private_display)
1000 _pthread_mutex_lock(&gLock);
1002 private_display->init_count--;
1003 if (private_display->init_count > 0) {
1004 _pthread_mutex_unlock(&gLock);
1008 _pthread_mutex_lock(&private_display->lock);
1010 tdm_event_loop_deinit(private_display);
1012 _tdm_display_destroy_private_display(private_display);
1013 _tdm_display_unload_module(private_display);
1016 if (private_display->bufmgr)
1017 tbm_bufmgr_deinit(private_display->bufmgr);
1020 tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1022 _pthread_mutex_unlock(&private_display->lock);
1024 pthread_mutex_destroy(&private_display->lock);
1025 free(private_display);
1026 g_private_display = NULL;
1028 tdm_debug_buffer = 0;
1030 _pthread_mutex_unlock(&gLock);
1036 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1038 tdm_backend_module *module = private_display->module_data;
1040 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1043 if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)