reuse ordered output
[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         if (caps_pp->formats)
94                 free(caps_pp->formats);
95
96         memset(caps_pp, 0, sizeof(tdm_caps_pp));
97 }
98
99 static void
100 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
101 {
102         if (caps_capture->formats)
103                 free(caps_capture->formats);
104
105         memset(caps_capture, 0, sizeof(tdm_caps_capture));
106 }
107
108 static void
109 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
110 {
111         if (caps_layer->formats)
112                 free(caps_layer->formats);
113
114         if (caps_layer->props)
115                 free(caps_layer->props);
116
117         memset(caps_layer, 0, sizeof(tdm_caps_layer));
118 }
119
120 static void
121 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
122 {
123         if (caps_output->modes)
124                 free(caps_output->modes);
125
126         if (caps_output->props)
127                 free(caps_output->props);
128
129         memset(caps_output, 0, sizeof(tdm_caps_output));
130 }
131
132 static void
133 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
134 {
135         tdm_private_capture *c = NULL, *cc = NULL;
136
137         LIST_DEL(&private_layer->link);
138
139         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
140         tdm_capture_destroy_internal(c);
141
142         _tdm_display_destroy_caps_layer(&private_layer->caps);
143
144         free(private_layer);
145 }
146
147 static void
148 _tdm_display_destroy_private_output(tdm_private_output *private_output)
149 {
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;
155
156         LIST_DEL(&private_output->link);
157
158         free(private_output->layers_ptr);
159
160         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
161                 LIST_DEL(&v->link);
162                 free(v);
163         }
164
165         LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) {
166                 LIST_DEL(&m->link);
167                 free(m);
168         }
169
170         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
171                 LIST_DEL(&h->link);
172                 free(h);
173         }
174
175         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
176                 LIST_DEL(&h->link);
177                 free(h);
178         }
179
180         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
181         tdm_capture_destroy_internal(c);
182
183         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
184         _tdm_display_destroy_private_layer(l);
185
186         _tdm_display_destroy_caps_output(&private_output->caps);
187
188         private_output->stamp = 0;
189         free(private_output);
190 }
191
192 static void
193 _tdm_display_destroy_private_display(tdm_private_display *private_display)
194 {
195         tdm_private_output *o = NULL, *oo = NULL;
196         tdm_private_pp *p = NULL, *pp = NULL;
197
198         free(private_display->outputs_ptr);
199         if (private_display->outputs) {
200                 free(private_display->outputs);
201                 private_display->outputs = NULL;
202         }
203
204         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
205         tdm_pp_destroy_internal(p);
206
207         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
208         _tdm_display_destroy_private_output(o);
209
210         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
211         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
212
213         private_display->capabilities = 0;
214         private_display->caps_display.max_layer_count = -1;
215 }
216
217 static tdm_error
218 _tdm_display_update_caps_pp(tdm_private_display *private_display,
219                             tdm_caps_pp *caps)
220 {
221         tdm_func_display *func_display = &private_display->func_display;
222         char buf[1024];
223         int bufsize = sizeof(buf);
224         char *str_buf = buf;
225         int *len_buf = &bufsize;
226         int i;
227         tdm_error ret;
228
229         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
230                 return TDM_ERROR_NONE;
231
232         if (!func_display->display_get_pp_capability) {
233                 TDM_ERR("no display_get_pp_capability()");
234                 return TDM_ERROR_BAD_MODULE;
235         }
236
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;
241         }
242
243         TDM_DBG("pp capabilities: %x", caps->capabilities);
244         buf[0] = '\0';
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);
251
252         return TDM_ERROR_NONE;
253 }
254
255 static tdm_error
256 _tdm_display_update_caps_capture(tdm_private_display *private_display,
257                                  tdm_caps_capture *caps)
258 {
259         tdm_func_display *func_display = &private_display->func_display;
260         char buf[1024];
261         int bufsize = sizeof(buf);
262         char *str_buf = buf;
263         int *len_buf = &bufsize;
264         int i;
265         tdm_error ret;
266
267         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
268                 return TDM_ERROR_NONE;
269
270         if (!func_display->display_get_capture_capability) {
271                 TDM_ERR("no display_get_capture_capability()");
272                 return TDM_ERROR_BAD_MODULE;
273         }
274
275         ret = func_display->display_get_capture_capability(private_display->bdata,
276                         caps);
277         if (ret != TDM_ERROR_NONE) {
278                 TDM_ERR("display_get_capture_capability() failed");
279                 return TDM_ERROR_BAD_MODULE;
280         }
281
282         buf[0] = '\0';
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);
286
287         return TDM_ERROR_NONE;
288 }
289
290 static tdm_error
291 _tdm_display_update_caps_layer(tdm_private_display *private_display,
292                                tdm_layer *layer_backend, tdm_caps_layer *caps)
293 {
294         tdm_func_layer *func_layer = &private_display->func_layer;
295         char buf[1024];
296         int bufsize = sizeof(buf);
297         char *str_buf = buf;
298         int *len_buf = &bufsize;
299         int i;
300         tdm_error ret;
301
302         if (!func_layer->layer_get_capability) {
303                 TDM_ERR("no layer_get_capability()");
304                 return TDM_ERROR_BAD_MODULE;
305         }
306
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;
311         }
312
313         TDM_DBG("layer capabilities: %x", caps->capabilities);
314         TDM_DBG("layer zpos : %d", caps->zpos);
315         buf[0] = '\0';
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);
321
322         return TDM_ERROR_NONE;
323 }
324
325 static tdm_error
326 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
327                                 tdm_output *output_backend, tdm_caps_output *caps)
328 {
329         tdm_func_output *func_output = &private_display->func_output;
330         char temp[TDM_NAME_LEN];
331         int i;
332         tdm_error ret;
333
334         if (!func_output->output_get_capability) {
335                 TDM_ERR("no output_get_capability()");
336                 return TDM_ERROR_BAD_MODULE;
337         }
338
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;
343         }
344
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);
348
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);
366         }
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);
370
371         return TDM_ERROR_NONE;
372 }
373
374 static tdm_error
375 _tdm_display_update_layer(tdm_private_display *private_display,
376                           tdm_private_output *private_output,
377                           tdm_layer *layer_backend)
378 {
379         tdm_private_layer *private_layer;
380         tdm_error ret;
381
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);
386
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;
391
392                 LIST_INITHEAD(&private_layer->capture_list);
393
394                 private_layer->usable = 1;
395         } else
396                 _tdm_display_destroy_caps_layer(&private_layer->caps);
397
398         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
399                                              &private_layer->caps);
400         if (ret != TDM_ERROR_NONE)
401                 goto failed_update;
402
403         return TDM_ERROR_NONE;
404 failed_update:
405         _tdm_display_destroy_private_layer(private_layer);
406         return ret;
407 }
408
409 INTERN tdm_error
410 tdm_display_update_output(tdm_private_display *private_display,
411                            tdm_output *output_backend, int pipe)
412 {
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;
417         tdm_error ret;
418
419         private_output = _tdm_display_find_private_output(private_display,
420                          output_backend);
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);
424
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++;
428
429                 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
430
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;
435
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);
442
443                 if (func_output->output_set_status_handler) {
444                         func_output->output_set_status_handler(private_output->output_backend,
445                                                                tdm_output_cb_status,
446                                                                private_output);
447                         private_output->regist_change_cb = 1;
448                 }
449
450         } else
451                 _tdm_display_destroy_caps_output(&private_output->caps);
452
453         ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
454                                               &private_output->caps);
455         if (ret != TDM_ERROR_NONE)
456                 return ret;
457
458         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
459         if (ret != TDM_ERROR_NONE)
460                 goto failed_update;
461
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)
465                         goto failed_update;
466         }
467
468         free(layers);
469
470         return TDM_ERROR_NONE;
471 failed_update:
472         _tdm_display_destroy_private_output(private_output);
473         free(layers);
474         return ret;
475 }
476
477 static tdm_output **
478 _tdm_display_set_main_first(tdm_output **outputs, int index)
479 {
480         tdm_output *output_tmp = NULL;
481
482         if (index == 0)
483                 return outputs;
484
485         output_tmp = outputs[0];
486         outputs[0] = outputs[index];
487         outputs[index] = output_tmp;
488
489         return outputs;
490 }
491
492 static tdm_output **
493 _tdm_display_get_ordered_outputs(tdm_private_display *private_display, int *count)
494 {
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;
504         tdm_error ret;
505
506         /* don't change list order if not init time */
507         if (private_display->outputs)
508                 return private_display->outputs;
509
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;
514
515         *count = output_count;
516
517         if (output_count == 0)
518                 goto failed_get_outputs;
519         else if (output_count == 1) {
520                 private_display->outputs = outputs;
521                 return outputs;
522         }
523
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));
529
530                 if (!func_output->output_get_capability) {
531                         TDM_ERR("no output_get_capability()");
532                         goto failed_get_outputs;
533                 }
534
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;
539                 }
540
541                 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
542                         output_connected_count++;
543
544                         switch (caps.type) {
545                         case TDM_OUTPUT_TYPE_DSI:
546                                 output_dsi = outputs[i];
547                                 index_dsi = i;
548                                 break;
549                         case TDM_OUTPUT_TYPE_LVDS:
550                                 output_lvds = outputs[i];
551                                 index_lvds = i;
552                                 break;
553                         case TDM_OUTPUT_TYPE_HDMIA:
554                                 output_hdmia = outputs[i];
555                                 index_hdmia = i;
556                                 break;
557                         case TDM_OUTPUT_TYPE_HDMIB:
558                                 output_hdmib = outputs[i];
559                                 index_hdmib = i;
560                                 break;
561                         default :
562                                 break;
563                         }
564                 }
565         }
566
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)
573           */
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);
584                 else
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);
596                 else
597                         new_outputs = outputs;
598         }
599
600         private_display->outputs = new_outputs;
601
602         return new_outputs;
603
604 failed_get_outputs:
605         free(outputs);
606         *count = 0;
607         return NULL;
608 }
609
610 static tdm_error
611 _tdm_display_update_internal(tdm_private_display *private_display,
612                              int only_display)
613 {
614         tdm_output **outputs = NULL;
615         int output_count = 0, i;
616         tdm_error ret;
617
618         LIST_INITHEAD(&private_display->output_list);
619         LIST_INITHEAD(&private_display->pp_list);
620         LIST_INITHEAD(&private_display->capture_list);
621
622         if (!only_display) {
623                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
624                 if (ret != TDM_ERROR_NONE)
625                         goto failed_update;
626
627                 ret = _tdm_display_update_caps_capture(private_display,
628                                                        &private_display->caps_capture);
629                 if (ret != TDM_ERROR_NONE)
630                         goto failed_update;
631         }
632
633         outputs = _tdm_display_get_ordered_outputs(private_display, &output_count);
634         if (!outputs)
635                 goto failed_update;
636
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)
640                         goto failed_update;
641         }
642
643         return TDM_ERROR_NONE;
644
645 failed_update:
646         _tdm_display_destroy_private_display(private_display);
647         return ret;
648 }
649
650 EXTERN tdm_error
651 tdm_display_update(tdm_display *dpy)
652 {
653         tdm_private_display *private_display;
654         tdm_error ret;
655
656         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
657
658         private_display = dpy;
659         _pthread_mutex_lock(&private_display->lock);
660
661         ret = _tdm_display_update_internal(private_display, 1);
662
663         _pthread_mutex_unlock(&private_display->lock);
664
665         return ret;
666 }
667
668 #define SUFFIX_MODULE    ".so"
669 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
670
671 int tdm_debug;
672 int tdm_debug_buffer;
673 int tdm_debug_thread;
674 int tdm_debug_mutex;
675
676 static tdm_private_display *g_private_display;
677 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
678
679 static tdm_error
680 _tdm_display_check_module(tdm_backend_module *module)
681 {
682         const char *name;
683         const char *vendor;
684         int major, minor;
685
686         TDM_INFO("TDM ABI version : %d.%d",
687                  TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
688
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);
693
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);
697
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;
702         }
703
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;
708         }
709
710         if (!module->init) {
711                 TDM_ERR("'%s' doesn't have init function", name);
712                 return TDM_ERROR_BAD_MODULE;
713         }
714
715         if (!module->deinit) {
716                 TDM_ERR("'%s' doesn't have deinit function", name);
717                 return TDM_ERROR_BAD_MODULE;
718         }
719
720         return TDM_ERROR_NONE;
721 }
722
723 static tdm_error
724 _tdm_display_check_backend_functions(tdm_private_display *private_display)
725 {
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;
729         tdm_error ret;
730
731         /* below functions should be implemented in backend side */
732
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);
741
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;
747         }
748
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);
757         }
758
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);
770         }
771
772         return TDM_ERROR_NONE;
773 }
774
775 static tdm_error
776 _tdm_display_load_module_with_file(tdm_private_display *private_display,
777                                    const char *file)
778 {
779         char path[PATH_MAX] = {0,};
780         tdm_backend_module *module_data;
781         void *module;
782         tdm_error ret;
783
784         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
785
786         TDM_TRACE_BEGIN(Load_Backend);
787
788         module = dlopen(path, RTLD_LAZY);
789         if (!module) {
790                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
791                 TDM_TRACE_END();
792                 return TDM_ERROR_BAD_MODULE;
793         }
794
795         module_data = dlsym(module, "tdm_backend_module_data");
796         if (!module_data) {
797                 TDM_ERR("'%s' doesn't have data object", file);
798                 ret = TDM_ERROR_BAD_MODULE;
799                 TDM_TRACE_END();
800                 goto failed_load;
801         }
802
803         private_display->module_data = module_data;
804         private_display->module = module;
805
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)
809                 goto failed_load;
810
811         TDM_TRACE_END();
812
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,
816                                  &ret);
817         TDM_TRACE_END();
818         if (ret != TDM_ERROR_NONE) {
819                 TDM_ERR("'%s' init failed", file);
820                 goto failed_load;
821         }
822
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;
827                 goto failed_load;
828         }
829
830         TDM_INFO("Success to load module(%s)", file);
831
832         return TDM_ERROR_NONE;
833 failed_load:
834         dlclose(module);
835         private_display->module_data = NULL;
836         private_display->module = NULL;
837         return ret;
838 }
839
840 static tdm_error
841 _tdm_display_load_module(tdm_private_display *private_display)
842 {
843         const char *module_name;
844         struct dirent **namelist;
845         int n;
846         tdm_error ret = 0;
847
848         module_name = getenv("TDM_MODULE");
849         if (!module_name)
850                 module_name = DEFAULT_MODULE;
851
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;
856
857         /* load bufmgr priv from configured path */
858         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
859         if (n < 0) {
860                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
861                 return TDM_ERROR_BAD_MODULE;
862         }
863
864         ret = TDM_ERROR_BAD_MODULE;
865         while (n--) {
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);
868
869                 free(namelist[n]);
870         }
871         free(namelist);
872
873         return ret;
874 }
875
876 static void
877 _tdm_display_unload_module(tdm_private_display *private_display)
878 {
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);
883
884         private_display->bdata = NULL;
885         private_display->module_data = NULL;
886         private_display->module = NULL;
887 }
888
889 EXTERN tdm_display *
890 tdm_display_init(tdm_error *error)
891 {
892         tdm_private_display *private_display = NULL;
893         const char *debug;
894         tdm_error ret;
895
896         _pthread_mutex_lock(&gLock);
897
898         if (g_private_display) {
899                 g_private_display->init_count++;
900                 _pthread_mutex_unlock(&gLock);
901                 if (error)
902                         *error = TDM_ERROR_NONE;
903                 return g_private_display;
904         }
905
906         debug = getenv("TDM_DEBUG");
907         if (debug && (strstr(debug, "1")))
908                 tdm_debug = 1;
909
910         debug = getenv("TDM_DEBUG_BUFFER");
911         if (debug && (strstr(debug, "1")))
912                 tdm_debug_buffer = 1;
913
914         debug = getenv("TDM_DEBUG_THREAD");
915         if (debug && (strstr(debug, "1")))
916                 tdm_debug_thread = 1;
917
918         debug = getenv("TDM_DEBUG_MUTEX");
919         if (debug && (strstr(debug, "1")))
920                 tdm_debug_mutex = 1;
921
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");
926                 goto failed_alloc;
927         }
928
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;
933         }
934
935         _pthread_mutex_lock(&private_display->lock);
936
937         ret = tdm_event_loop_init(private_display);
938         if (ret != TDM_ERROR_NONE)
939                 goto failed_event;
940
941         ret = _tdm_display_load_module(private_display);
942         if (ret != TDM_ERROR_NONE)
943                 goto failed_load;
944
945 #ifdef INIT_BUFMGR
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);
949                 close(tdm_drm_fd);
950                 if (!private_display->bufmgr) {
951                         TDM_ERR("tbm_bufmgr_init failed");
952                         goto failed_update;
953                 } else {
954                         TDM_INFO("tbm_bufmgr_init successed");
955                 }
956         }
957 #endif
958
959         TDM_TRACE_BEGIN(Update_Display);
960         ret = _tdm_display_update_internal(private_display, 0);
961         TDM_TRACE_END();
962         if (ret != TDM_ERROR_NONE)
963                 goto failed_update;
964
965         tdm_event_loop_create_backend_source(private_display);
966
967         private_display->init_count = 1;
968
969         g_private_display = private_display;
970
971         if (error)
972                 *error = TDM_ERROR_NONE;
973
974         _pthread_mutex_unlock(&private_display->lock);
975         _pthread_mutex_unlock(&gLock);
976
977         return (tdm_display *)private_display;
978
979 failed_update:
980         _tdm_display_unload_module(private_display);
981 failed_load:
982         tdm_event_loop_deinit(private_display);
983 failed_event:
984         _pthread_mutex_unlock(&private_display->lock);
985         pthread_mutex_destroy(&private_display->lock);
986 failed_mutex_init:
987         free(private_display);
988 failed_alloc:
989         tdm_debug = 0;
990         tdm_debug_buffer = 0;
991         if (error)
992                 *error = ret;
993         _pthread_mutex_unlock(&gLock);
994         return NULL;
995 }
996
997 EXTERN void
998 tdm_display_deinit(tdm_display *dpy)
999 {
1000         tdm_private_display *private_display = dpy;
1001
1002         if (!private_display)
1003                 return;
1004
1005         _pthread_mutex_lock(&gLock);
1006
1007         private_display->init_count--;
1008         if (private_display->init_count > 0) {
1009                 _pthread_mutex_unlock(&gLock);
1010                 return;
1011         }
1012
1013         _pthread_mutex_lock(&private_display->lock);
1014
1015         tdm_event_loop_deinit(private_display);
1016
1017         _tdm_display_destroy_private_display(private_display);
1018         _tdm_display_unload_module(private_display);
1019
1020 #ifdef INIT_BUFMGR
1021         if (private_display->bufmgr)
1022                 tbm_bufmgr_deinit(private_display->bufmgr);
1023 #endif
1024
1025         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1026
1027         _pthread_mutex_unlock(&private_display->lock);
1028
1029         pthread_mutex_destroy(&private_display->lock);
1030         free(private_display);
1031         g_private_display = NULL;
1032         tdm_debug = 0;
1033         tdm_debug_buffer = 0;
1034
1035         _pthread_mutex_unlock(&gLock);
1036
1037         TDM_INFO("done");
1038 }
1039
1040 INTERN int
1041 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1042 {
1043         tdm_backend_module *module = private_display->module_data;
1044
1045         if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1046                 return 0;
1047
1048         if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1049                 return 0;
1050
1051         return 1;
1052 }
1053