init variable
[platform/core/uifw/libtdm.git] / src / tdm.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
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>
13
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:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
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.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44
45 pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER;
46 int tdm_mutex_locked;
47
48 static tdm_private_layer *
49 _tdm_display_find_private_layer(tdm_private_output *private_output,
50                                 tdm_layer *layer_backend)
51 {
52         tdm_private_layer *private_layer = NULL;
53
54         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
55                 if (private_layer->layer_backend == layer_backend)
56                         return private_layer;
57         }
58
59         return NULL;
60 }
61
62 static tdm_private_output *
63 _tdm_display_find_private_output(tdm_private_display *private_display,
64                                  tdm_output *output_backend)
65 {
66         tdm_private_output *private_output = NULL;
67
68         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
69                 if (private_output->output_backend == output_backend)
70                         return private_output;
71         }
72
73         return NULL;
74 }
75
76 INTERN tdm_private_output *
77 tdm_display_find_output_stamp(tdm_private_display *private_display,
78                               unsigned long stamp)
79 {
80         tdm_private_output *private_output = NULL;
81
82         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
83                 if (private_output->stamp == stamp)
84                         return private_output;
85         }
86
87         return NULL;
88 }
89
90 static void
91 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
92 {
93         free(caps_pp->formats);
94         memset(caps_pp, 0, sizeof(tdm_caps_pp));
95 }
96
97 static void
98 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
99 {
100         free(caps_capture->formats);
101         memset(caps_capture, 0, sizeof(tdm_caps_capture));
102 }
103
104 static void
105 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
106 {
107         free(caps_layer->formats);
108         free(caps_layer->props);
109         memset(caps_layer, 0, sizeof(tdm_caps_layer));
110 }
111
112 static void
113 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
114 {
115         free(caps_output->modes);
116         free(caps_output->props);
117         memset(caps_output, 0, sizeof(tdm_caps_output));
118 }
119
120 static void
121 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
122 {
123         tdm_private_capture *c = NULL, *cc = NULL;
124
125         LIST_DEL(&private_layer->link);
126
127         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
128         tdm_capture_destroy_internal(c);
129
130         _tdm_display_destroy_caps_layer(&private_layer->caps);
131
132         free(private_layer);
133 }
134
135 static void
136 _tdm_display_destroy_private_output(tdm_private_output *private_output)
137 {
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;
143
144         LIST_DEL(&private_output->link);
145
146         free(private_output->layers_ptr);
147
148         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
149                 LIST_DEL(&v->link);
150                 free(v);
151         }
152
153         LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
154                 LIST_DEL(&m->link);
155                 free(m);
156         }
157
158         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
159                 LIST_DEL(&h->link);
160                 free(h);
161         }
162
163         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
164                 LIST_DEL(&h->link);
165                 free(h);
166         }
167
168         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
169         tdm_capture_destroy_internal(c);
170
171         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
172         _tdm_display_destroy_private_layer(l);
173
174         _tdm_display_destroy_caps_output(&private_output->caps);
175
176         private_output->stamp = 0;
177         free(private_output);
178 }
179
180 static void
181 _tdm_display_destroy_private_display(tdm_private_display *private_display)
182 {
183         tdm_private_output *o = NULL, *oo = NULL;
184         tdm_private_pp *p = NULL, *pp = NULL;
185
186         free(private_display->outputs_ptr);
187
188         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
189         tdm_pp_destroy_internal(p);
190
191         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
192         _tdm_display_destroy_private_output(o);
193
194         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
195         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
196
197         private_display->capabilities = 0;
198         private_display->caps_display.max_layer_count = -1;
199 }
200
201 static tdm_error
202 _tdm_display_update_caps_pp(tdm_private_display *private_display,
203                             tdm_caps_pp *caps)
204 {
205         tdm_func_display *func_display = &private_display->func_display;
206         char buf[1024];
207         int bufsize = sizeof(buf);
208         char *str_buf = buf;
209         int *len_buf = &bufsize;
210         int i;
211         tdm_error ret;
212
213         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
214                 return TDM_ERROR_NONE;
215
216         if (!func_display->display_get_pp_capability) {
217                 TDM_ERR("no display_get_pp_capability()");
218                 return TDM_ERROR_BAD_MODULE;
219         }
220
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;
225         }
226
227         TDM_DBG("pp capabilities: %x", caps->capabilities);
228         buf[0] = '\0';
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);
235
236         return TDM_ERROR_NONE;
237 }
238
239 static tdm_error
240 _tdm_display_update_caps_capture(tdm_private_display *private_display,
241                                  tdm_caps_capture *caps)
242 {
243         tdm_func_display *func_display = &private_display->func_display;
244         char buf[1024];
245         int bufsize = sizeof(buf);
246         char *str_buf = buf;
247         int *len_buf = &bufsize;
248         int i;
249         tdm_error ret;
250
251         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
252                 return TDM_ERROR_NONE;
253
254         if (!func_display->display_get_capture_capability) {
255                 TDM_ERR("no display_get_capture_capability()");
256                 return TDM_ERROR_BAD_MODULE;
257         }
258
259         ret = func_display->display_get_capture_capability(private_display->bdata,
260                         caps);
261         if (ret != TDM_ERROR_NONE) {
262                 TDM_ERR("display_get_capture_capability() failed");
263                 return TDM_ERROR_BAD_MODULE;
264         }
265
266         buf[0] = '\0';
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);
270
271         return TDM_ERROR_NONE;
272 }
273
274 static tdm_error
275 _tdm_display_update_caps_layer(tdm_private_display *private_display,
276                                tdm_layer *layer_backend, tdm_caps_layer *caps)
277 {
278         tdm_func_layer *func_layer = &private_display->func_layer;
279         char buf[1024];
280         int bufsize = sizeof(buf);
281         char *str_buf = buf;
282         int *len_buf = &bufsize;
283         int i;
284         tdm_error ret;
285
286         if (!func_layer->layer_get_capability) {
287                 TDM_ERR("no layer_get_capability()");
288                 return TDM_ERROR_BAD_MODULE;
289         }
290
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;
295         }
296
297         TDM_DBG("layer capabilities: %x", caps->capabilities);
298         TDM_DBG("layer zpos : %d", caps->zpos);
299         buf[0] = '\0';
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);
305
306         return TDM_ERROR_NONE;
307 }
308
309 static tdm_error
310 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
311                                 tdm_output *output_backend, tdm_caps_output *caps)
312 {
313         tdm_func_output *func_output = &private_display->func_output;
314         char temp[TDM_NAME_LEN];
315         int i;
316         tdm_error ret;
317
318         if (!func_output->output_get_capability) {
319                 TDM_ERR("no output_get_capability()");
320                 return TDM_ERROR_BAD_MODULE;
321         }
322
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;
327         }
328
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);
332
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);
350         }
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);
354
355         return TDM_ERROR_NONE;
356 }
357
358 static tdm_error
359 _tdm_display_update_layer(tdm_private_display *private_display,
360                           tdm_private_output *private_output,
361                           tdm_layer *layer_backend)
362 {
363         tdm_private_layer *private_layer;
364         tdm_error ret;
365
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);
370
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;
375
376                 LIST_INITHEAD(&private_layer->capture_list);
377
378                 private_layer->usable = 1;
379         } else
380                 _tdm_display_destroy_caps_layer(&private_layer->caps);
381
382         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
383                                              &private_layer->caps);
384         if (ret != TDM_ERROR_NONE)
385                 goto failed_update;
386
387         return TDM_ERROR_NONE;
388 failed_update:
389         _tdm_display_destroy_private_layer(private_layer);
390         return ret;
391 }
392
393 static tdm_error
394 _tdm_display_update_output(tdm_private_display *private_display,
395                            tdm_output *output_backend, int pipe)
396 {
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;
401         tdm_error ret;
402
403         private_output = _tdm_display_find_private_output(private_display,
404                          output_backend);
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);
408
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++;
412
413                 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
414
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;
419
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);
426
427                 if (func_output->output_set_status_handler)
428                         func_output->output_set_status_handler(private_output->output_backend,
429                                                                tdm_output_cb_status,
430                                                                private_output);
431
432         } else
433                 _tdm_display_destroy_caps_output(&private_output->caps);
434
435         ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
436                                               &private_output->caps);
437         if (ret != TDM_ERROR_NONE)
438                 return ret;
439
440         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
441         if (ret != TDM_ERROR_NONE)
442                 goto failed_update;
443
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)
447                         goto failed_update;
448         }
449
450         free(layers);
451
452         return TDM_ERROR_NONE;
453 failed_update:
454         _tdm_display_destroy_private_output(private_output);
455         free(layers);
456         return ret;
457 }
458
459 static tdm_output **
460 _tdm_display_set_main_first(tdm_output **outputs, int index)
461 {
462         tdm_output *output_tmp = NULL;
463
464         if (index == 0)
465                 return outputs;
466
467         output_tmp = outputs[0];
468         outputs[0] = outputs[index];
469         outputs[index] = output_tmp;
470
471         return outputs;
472 }
473
474 static tdm_output **
475 _tdm_display_get_ordered_outputs(tdm_private_display *private_display,
476                            int *count, int init)
477 {
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;
487         tdm_error ret;
488
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;
493
494         *count = output_count;
495
496         if (output_count == 0)
497                 goto failed_get_outputs;
498         else if (output_count == 1)
499                 return outputs;
500
501         /* don't change list order if not init time */
502         if (init != 0)
503                 return outputs;
504
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));
510
511                 if (!func_output->output_get_capability) {
512                         TDM_ERR("no output_get_capability()");
513                         return outputs;
514                 }
515
516                 ret = func_output->output_get_capability(outputs[i], &caps);
517                 if (ret != TDM_ERROR_NONE) {
518                         TDM_ERR("output_get_capability() failed");
519                         return outputs;
520                 }
521
522                 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
523                         output_connected_count++;
524
525                         switch (caps.type) {
526                         case TDM_OUTPUT_TYPE_DSI:
527                                 output_dsi = outputs[i];
528                                 index_dsi = i;
529                                 break;
530                         case TDM_OUTPUT_TYPE_LVDS:
531                                 output_lvds = outputs[i];
532                                 index_lvds = i;
533                                 break;
534                         case TDM_OUTPUT_TYPE_HDMIA:
535                                 output_hdmia = outputs[i];
536                                 index_hdmia = i;
537                                 break;
538                         case TDM_OUTPUT_TYPE_HDMIB:
539                                 output_hdmib = outputs[i];
540                                 index_hdmib = i;
541                                 break;
542                         default :
543                                 break;
544                         }
545                 }
546         }
547
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)
554           */
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);
565                 else
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);
577                 else
578                         new_outputs = outputs;
579         }
580
581         return new_outputs;
582
583 failed_get_outputs:
584         *count = 0;
585         return NULL;
586 }
587
588 static tdm_error
589 _tdm_display_update_internal(tdm_private_display *private_display,
590                              int only_display)
591 {
592         tdm_output **outputs = NULL;
593         int output_count = 0, i;
594         tdm_error ret;
595
596         LIST_INITHEAD(&private_display->output_list);
597         LIST_INITHEAD(&private_display->pp_list);
598         LIST_INITHEAD(&private_display->capture_list);
599
600         if (!only_display) {
601                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
602                 if (ret != TDM_ERROR_NONE)
603                         goto failed_update;
604
605                 ret = _tdm_display_update_caps_capture(private_display,
606                                                        &private_display->caps_capture);
607                 if (ret != TDM_ERROR_NONE)
608                         goto failed_update;
609         }
610
611         outputs = _tdm_display_get_ordered_outputs(private_display, &output_count, only_display);
612         if (!outputs)
613                 goto failed_update;
614
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)
618                         goto failed_update;
619         }
620
621         free(outputs);
622
623         return TDM_ERROR_NONE;
624
625 failed_update:
626         _tdm_display_destroy_private_display(private_display);
627         free(outputs);
628         return ret;
629 }
630
631 EXTERN tdm_error
632 tdm_display_update(tdm_display *dpy)
633 {
634         tdm_private_display *private_display;
635         tdm_error ret;
636
637         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
638
639         private_display = dpy;
640         _pthread_mutex_lock(&private_display->lock);
641
642         ret = _tdm_display_update_internal(private_display, 1);
643
644         _pthread_mutex_unlock(&private_display->lock);
645
646         return ret;
647 }
648
649 #define SUFFIX_MODULE    ".so"
650 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
651
652 int tdm_debug;
653 int tdm_debug_buffer;
654 int tdm_debug_thread;
655 int tdm_debug_mutex;
656
657 static tdm_private_display *g_private_display;
658 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
659
660 static tdm_error
661 _tdm_display_check_module(tdm_backend_module *module)
662 {
663         const char *name;
664         const char *vendor;
665         int major, minor;
666         int abimaj, abimin;
667
668         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
669         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
670
671         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
672
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);
677
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);
681
682         if (major != abimaj) {
683                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
684                 return TDM_ERROR_BAD_MODULE;
685         }
686
687         if (minor > abimin) {
688                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
689                 return TDM_ERROR_BAD_MODULE;
690         }
691
692         if (!module->init) {
693                 TDM_ERR("'%s' doesn't have init function", name);
694                 return TDM_ERROR_BAD_MODULE;
695         }
696
697         if (!module->deinit) {
698                 TDM_ERR("'%s' doesn't have deinit function", name);
699                 return TDM_ERROR_BAD_MODULE;
700         }
701
702         return TDM_ERROR_NONE;
703 }
704
705 static tdm_error
706 _tdm_display_check_backend_functions(tdm_private_display *private_display)
707 {
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;
711         tdm_error ret;
712
713         /* below functions should be implemented in backend side */
714
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);
723
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;
729         }
730
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);
739         }
740
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);
752         }
753
754         return TDM_ERROR_NONE;
755 }
756
757 static tdm_error
758 _tdm_display_load_module_with_file(tdm_private_display *private_display,
759                                    const char *file)
760 {
761         char path[PATH_MAX] = {0,};
762         tdm_backend_module *module_data;
763         void *module;
764         tdm_error ret;
765
766         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
767
768         TDM_TRACE_BEGIN(Load_Backend);
769
770         module = dlopen(path, RTLD_LAZY);
771         if (!module) {
772                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
773                 TDM_TRACE_END();
774                 return TDM_ERROR_BAD_MODULE;
775         }
776
777         module_data = dlsym(module, "tdm_backend_module_data");
778         if (!module_data) {
779                 TDM_ERR("'%s' doesn't have data object", file);
780                 ret = TDM_ERROR_BAD_MODULE;
781                 TDM_TRACE_END();
782                 goto failed_load;
783         }
784
785         private_display->module_data = module_data;
786         private_display->module = module;
787
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)
791                 goto failed_load;
792
793         TDM_TRACE_END();
794
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,
798                                  &ret);
799         TDM_TRACE_END();
800         if (ret != TDM_ERROR_NONE) {
801                 TDM_ERR("'%s' init failed", file);
802                 goto failed_load;
803         }
804
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;
809                 goto failed_load;
810         }
811
812         TDM_INFO("Success to load module(%s)", file);
813
814         return TDM_ERROR_NONE;
815 failed_load:
816         dlclose(module);
817         private_display->module_data = NULL;
818         private_display->module = NULL;
819         return ret;
820 }
821
822 static tdm_error
823 _tdm_display_load_module(tdm_private_display *private_display)
824 {
825         const char *module_name;
826         struct dirent **namelist;
827         int n;
828         tdm_error ret = 0;
829
830         module_name = getenv("TDM_MODULE");
831         if (!module_name)
832                 module_name = DEFAULT_MODULE;
833
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;
838
839         /* load bufmgr priv from configured path */
840         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
841         if (n < 0) {
842                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
843                 return TDM_ERROR_BAD_MODULE;
844         }
845
846         ret = TDM_ERROR_BAD_MODULE;
847         while (n--) {
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);
850
851                 free(namelist[n]);
852         }
853         free(namelist);
854
855         return ret;
856 }
857
858 static void
859 _tdm_display_unload_module(tdm_private_display *private_display)
860 {
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);
865
866         private_display->bdata = NULL;
867         private_display->module_data = NULL;
868         private_display->module = NULL;
869 }
870
871 EXTERN tdm_display *
872 tdm_display_init(tdm_error *error)
873 {
874         tdm_private_display *private_display = NULL;
875         const char *debug;
876         tdm_error ret;
877
878         _pthread_mutex_lock(&gLock);
879
880         if (g_private_display) {
881                 g_private_display->init_count++;
882                 _pthread_mutex_unlock(&gLock);
883                 if (error)
884                         *error = TDM_ERROR_NONE;
885                 return g_private_display;
886         }
887
888         debug = getenv("TDM_DEBUG");
889         if (debug && (strstr(debug, "1")))
890                 tdm_debug = 1;
891
892         debug = getenv("TDM_DEBUG_BUFFER");
893         if (debug && (strstr(debug, "1")))
894                 tdm_debug_buffer = 1;
895
896         debug = getenv("TDM_DEBUG_THREAD");
897         if (debug && (strstr(debug, "1")))
898                 tdm_debug_thread = 1;
899
900         debug = getenv("TDM_DEBUG_MUTEX");
901         if (debug && (strstr(debug, "1")))
902                 tdm_debug_mutex = 1;
903
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");
908                 goto failed_alloc;
909         }
910
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;
915         }
916
917         _pthread_mutex_lock(&private_display->lock);
918
919         ret = tdm_event_loop_init(private_display);
920         if (ret != TDM_ERROR_NONE)
921                 goto failed_event;
922
923         ret = _tdm_display_load_module(private_display);
924         if (ret != TDM_ERROR_NONE)
925                 goto failed_load;
926
927 #ifdef INIT_BUFMGR
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);
931                 close(tdm_drm_fd);
932                 if (!private_display->bufmgr) {
933                         TDM_ERR("tbm_bufmgr_init failed");
934                         goto failed_update;
935                 } else {
936                         TDM_INFO("tbm_bufmgr_init successed");
937                 }
938         }
939 #endif
940
941         TDM_TRACE_BEGIN(Update_Display);
942         ret = _tdm_display_update_internal(private_display, 0);
943         TDM_TRACE_END();
944         if (ret != TDM_ERROR_NONE)
945                 goto failed_update;
946
947         tdm_event_loop_create_backend_source(private_display);
948
949         private_display->init_count = 1;
950
951         g_private_display = private_display;
952
953         if (error)
954                 *error = TDM_ERROR_NONE;
955
956         _pthread_mutex_unlock(&private_display->lock);
957         _pthread_mutex_unlock(&gLock);
958
959         return (tdm_display *)private_display;
960
961 failed_update:
962         _tdm_display_unload_module(private_display);
963 failed_load:
964         tdm_event_loop_deinit(private_display);
965 failed_event:
966         _pthread_mutex_unlock(&private_display->lock);
967         pthread_mutex_destroy(&private_display->lock);
968 failed_mutex_init:
969         free(private_display);
970 failed_alloc:
971         tdm_debug = 0;
972         tdm_debug_buffer = 0;
973         if (error)
974                 *error = ret;
975         _pthread_mutex_unlock(&gLock);
976         return NULL;
977 }
978
979 EXTERN void
980 tdm_display_deinit(tdm_display *dpy)
981 {
982         tdm_private_display *private_display = dpy;
983
984         if (!private_display)
985                 return;
986
987         _pthread_mutex_lock(&gLock);
988
989         private_display->init_count--;
990         if (private_display->init_count > 0) {
991                 _pthread_mutex_unlock(&gLock);
992                 return;
993         }
994
995         _pthread_mutex_lock(&private_display->lock);
996
997         tdm_event_loop_deinit(private_display);
998
999         _tdm_display_destroy_private_display(private_display);
1000         _tdm_display_unload_module(private_display);
1001
1002 #ifdef INIT_BUFMGR
1003         if (private_display->bufmgr)
1004                 tbm_bufmgr_deinit(private_display->bufmgr);
1005 #endif
1006
1007         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1008
1009         _pthread_mutex_unlock(&private_display->lock);
1010
1011         pthread_mutex_destroy(&private_display->lock);
1012         free(private_display);
1013         g_private_display = NULL;
1014         tdm_debug = 0;
1015         tdm_debug_buffer = 0;
1016
1017         _pthread_mutex_unlock(&gLock);
1018
1019         TDM_INFO("done");
1020 }
1021