get version in configuration time
[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
200         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
201         tdm_pp_destroy_internal(p);
202
203         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
204         _tdm_display_destroy_private_output(o);
205
206         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
207         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
208
209         private_display->capabilities = 0;
210         private_display->caps_display.max_layer_count = -1;
211 }
212
213 static tdm_error
214 _tdm_display_update_caps_pp(tdm_private_display *private_display,
215                             tdm_caps_pp *caps)
216 {
217         tdm_func_display *func_display = &private_display->func_display;
218         char buf[1024];
219         int bufsize = sizeof(buf);
220         char *str_buf = buf;
221         int *len_buf = &bufsize;
222         int i;
223         tdm_error ret;
224
225         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
226                 return TDM_ERROR_NONE;
227
228         if (!func_display->display_get_pp_capability) {
229                 TDM_ERR("no display_get_pp_capability()");
230                 return TDM_ERROR_BAD_MODULE;
231         }
232
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;
237         }
238
239         TDM_DBG("pp capabilities: %x", caps->capabilities);
240         buf[0] = '\0';
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);
247
248         return TDM_ERROR_NONE;
249 }
250
251 static tdm_error
252 _tdm_display_update_caps_capture(tdm_private_display *private_display,
253                                  tdm_caps_capture *caps)
254 {
255         tdm_func_display *func_display = &private_display->func_display;
256         char buf[1024];
257         int bufsize = sizeof(buf);
258         char *str_buf = buf;
259         int *len_buf = &bufsize;
260         int i;
261         tdm_error ret;
262
263         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
264                 return TDM_ERROR_NONE;
265
266         if (!func_display->display_get_capture_capability) {
267                 TDM_ERR("no display_get_capture_capability()");
268                 return TDM_ERROR_BAD_MODULE;
269         }
270
271         ret = func_display->display_get_capture_capability(private_display->bdata,
272                         caps);
273         if (ret != TDM_ERROR_NONE) {
274                 TDM_ERR("display_get_capture_capability() failed");
275                 return TDM_ERROR_BAD_MODULE;
276         }
277
278         buf[0] = '\0';
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);
282
283         return TDM_ERROR_NONE;
284 }
285
286 static tdm_error
287 _tdm_display_update_caps_layer(tdm_private_display *private_display,
288                                tdm_layer *layer_backend, tdm_caps_layer *caps)
289 {
290         tdm_func_layer *func_layer = &private_display->func_layer;
291         char buf[1024];
292         int bufsize = sizeof(buf);
293         char *str_buf = buf;
294         int *len_buf = &bufsize;
295         int i;
296         tdm_error ret;
297
298         if (!func_layer->layer_get_capability) {
299                 TDM_ERR("no layer_get_capability()");
300                 return TDM_ERROR_BAD_MODULE;
301         }
302
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;
307         }
308
309         TDM_DBG("layer capabilities: %x", caps->capabilities);
310         TDM_DBG("layer zpos : %d", caps->zpos);
311         buf[0] = '\0';
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);
317
318         return TDM_ERROR_NONE;
319 }
320
321 static tdm_error
322 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
323                                 tdm_output *output_backend, tdm_caps_output *caps)
324 {
325         tdm_func_output *func_output = &private_display->func_output;
326         char temp[TDM_NAME_LEN];
327         int i;
328         tdm_error ret;
329
330         if (!func_output->output_get_capability) {
331                 TDM_ERR("no output_get_capability()");
332                 return TDM_ERROR_BAD_MODULE;
333         }
334
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;
339         }
340
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);
344
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);
362         }
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);
366
367         return TDM_ERROR_NONE;
368 }
369
370 static tdm_error
371 _tdm_display_update_layer(tdm_private_display *private_display,
372                           tdm_private_output *private_output,
373                           tdm_layer *layer_backend)
374 {
375         tdm_private_layer *private_layer;
376         tdm_error ret;
377
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);
382
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;
387
388                 LIST_INITHEAD(&private_layer->capture_list);
389
390                 private_layer->usable = 1;
391         } else
392                 _tdm_display_destroy_caps_layer(&private_layer->caps);
393
394         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
395                                              &private_layer->caps);
396         if (ret != TDM_ERROR_NONE)
397                 goto failed_update;
398
399         return TDM_ERROR_NONE;
400 failed_update:
401         _tdm_display_destroy_private_layer(private_layer);
402         return ret;
403 }
404
405 static tdm_error
406 _tdm_display_update_output(tdm_private_display *private_display,
407                            tdm_output *output_backend, int pipe)
408 {
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;
413         tdm_error ret;
414
415         private_output = _tdm_display_find_private_output(private_display,
416                          output_backend);
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);
420
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++;
424
425                 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
426
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;
431
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);
438
439                 if (func_output->output_set_status_handler)
440                         func_output->output_set_status_handler(private_output->output_backend,
441                                                                tdm_output_cb_status,
442                                                                private_output);
443
444         } else
445                 _tdm_display_destroy_caps_output(&private_output->caps);
446
447         ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
448                                               &private_output->caps);
449         if (ret != TDM_ERROR_NONE)
450                 return ret;
451
452         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
453         if (ret != TDM_ERROR_NONE)
454                 goto failed_update;
455
456         for (i = 0; i < layer_count; i++) {
457                 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
458                 if (ret != TDM_ERROR_NONE)
459                         goto failed_update;
460         }
461
462         free(layers);
463
464         return TDM_ERROR_NONE;
465 failed_update:
466         _tdm_display_destroy_private_output(private_output);
467         free(layers);
468         return ret;
469 }
470
471 static tdm_output **
472 _tdm_display_set_main_first(tdm_output **outputs, int index)
473 {
474         tdm_output *output_tmp = NULL;
475
476         if (index == 0)
477                 return outputs;
478
479         output_tmp = outputs[0];
480         outputs[0] = outputs[index];
481         outputs[index] = output_tmp;
482
483         return outputs;
484 }
485
486 static tdm_output **
487 _tdm_display_get_ordered_outputs(tdm_private_display *private_display,
488                            int *count, int init)
489 {
490         tdm_func_display *func_display = &private_display->func_display;
491         tdm_output **outputs = NULL;
492         tdm_output **new_outputs = NULL;
493         tdm_output *output_dsi = NULL;
494         tdm_output *output_lvds = NULL;
495         tdm_output *output_hdmia = NULL;
496         tdm_output *output_hdmib = NULL;
497         int i, output_count = 0, output_connected_count = 0;
498         int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
499         tdm_error ret;
500
501         outputs = func_display->display_get_outputs(private_display->bdata,
502                         &output_count, &ret);
503         if (ret != TDM_ERROR_NONE)
504                 goto failed_get_outputs;
505
506         *count = output_count;
507
508         if (output_count == 0)
509                 goto failed_get_outputs;
510         else if (output_count == 1)
511                 return outputs;
512
513         /* don't change list order if not init time */
514         if (init != 0)
515                 return outputs;
516
517         /* count connected outputs */
518         for (i = 0; i < output_count; i++) {
519                 tdm_func_output *func_output = &private_display->func_output;
520                 tdm_caps_output caps;
521                 memset(&caps, 0, sizeof(tdm_caps_output));
522
523                 if (!func_output->output_get_capability) {
524                         TDM_ERR("no output_get_capability()");
525                         return outputs;
526                 }
527
528                 ret = func_output->output_get_capability(outputs[i], &caps);
529                 if (ret != TDM_ERROR_NONE) {
530                         TDM_ERR("output_get_capability() failed");
531                         return outputs;
532                 }
533
534                 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
535                         output_connected_count++;
536
537                         switch (caps.type) {
538                         case TDM_OUTPUT_TYPE_DSI:
539                                 output_dsi = outputs[i];
540                                 index_dsi = i;
541                                 break;
542                         case TDM_OUTPUT_TYPE_LVDS:
543                                 output_lvds = outputs[i];
544                                 index_lvds = i;
545                                 break;
546                         case TDM_OUTPUT_TYPE_HDMIA:
547                                 output_hdmia = outputs[i];
548                                 index_hdmia = i;
549                                 break;
550                         case TDM_OUTPUT_TYPE_HDMIB:
551                                 output_hdmib = outputs[i];
552                                 index_hdmib = i;
553                                 break;
554                         default :
555                                 break;
556                         }
557                 }
558         }
559
560         /* ordering : main output is first */
561         /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
562           * But hdmi is possible, so set hdmi to main display.
563           * If connected only one output, it is main output.
564           * If connected outputs over 2, has priority like below.
565           * (dsi > lvds > hdmi > else)
566           */
567         if (output_connected_count == 0) {
568                 /* hdmi > dsi > lvds > else */
569                 if (output_hdmia != NULL)
570                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
571                 else if (output_hdmib != NULL)
572                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
573                 else if (output_dsi != NULL)
574                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
575                 else if (output_lvds != NULL)
576                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
577                 else
578                         new_outputs = outputs;
579         } else { /* (output_connected_count > 1) */
580                 /* dsi > lvds > hdmi > else */
581                 if (output_dsi != NULL)
582                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
583                 else if (output_lvds != NULL)
584                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
585                 else if (output_hdmia != NULL)
586                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
587                 else if (output_hdmib != NULL)
588                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
589                 else
590                         new_outputs = outputs;
591         }
592
593         return new_outputs;
594
595 failed_get_outputs:
596         *count = 0;
597         return NULL;
598 }
599
600 static tdm_error
601 _tdm_display_update_internal(tdm_private_display *private_display,
602                              int only_display)
603 {
604         tdm_output **outputs = NULL;
605         int output_count = 0, i;
606         tdm_error ret;
607
608         LIST_INITHEAD(&private_display->output_list);
609         LIST_INITHEAD(&private_display->pp_list);
610         LIST_INITHEAD(&private_display->capture_list);
611
612         if (!only_display) {
613                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
614                 if (ret != TDM_ERROR_NONE)
615                         goto failed_update;
616
617                 ret = _tdm_display_update_caps_capture(private_display,
618                                                        &private_display->caps_capture);
619                 if (ret != TDM_ERROR_NONE)
620                         goto failed_update;
621         }
622
623         outputs = _tdm_display_get_ordered_outputs(private_display, &output_count, only_display);
624         if (!outputs)
625                 goto failed_update;
626
627         for (i = 0; i < output_count; i++) {
628                 ret = _tdm_display_update_output(private_display, outputs[i], i);
629                 if (ret != TDM_ERROR_NONE)
630                         goto failed_update;
631         }
632
633         free(outputs);
634
635         return TDM_ERROR_NONE;
636
637 failed_update:
638         _tdm_display_destroy_private_display(private_display);
639         free(outputs);
640         return ret;
641 }
642
643 EXTERN tdm_error
644 tdm_display_update(tdm_display *dpy)
645 {
646         tdm_private_display *private_display;
647         tdm_error ret;
648
649         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
650
651         private_display = dpy;
652         _pthread_mutex_lock(&private_display->lock);
653
654         ret = _tdm_display_update_internal(private_display, 1);
655
656         _pthread_mutex_unlock(&private_display->lock);
657
658         return ret;
659 }
660
661 #define SUFFIX_MODULE    ".so"
662 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
663
664 int tdm_debug;
665 int tdm_debug_buffer;
666 int tdm_debug_thread;
667 int tdm_debug_mutex;
668
669 static tdm_private_display *g_private_display;
670 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
671
672 static tdm_error
673 _tdm_display_check_module(tdm_backend_module *module)
674 {
675         const char *name;
676         const char *vendor;
677         int major, minor;
678
679         TDM_INFO("TDM ABI version : %d.%d",
680                  TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
681
682         name = module->name ? module->name : "unknown";
683         vendor = module->vendor ? module->vendor : "unknown";
684         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
685         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
686
687         TDM_INFO("TDM module name: %s", name);
688         TDM_INFO("'%s' vendor: %s", name, vendor);
689         TDM_INFO("'%s' version: %d.%d", name, major, minor);
690
691         if (major != TDM_MAJOR_VERSION) {
692                 TDM_ERR("'%s' major version mismatch, %d != %d",
693                         name, major, TDM_MAJOR_VERSION);
694                 return TDM_ERROR_BAD_MODULE;
695         }
696
697         if (minor > TDM_MINOR_VERSION) {
698                 TDM_ERR("'%s' minor version(%d) is newer than %d",
699                         name, minor, TDM_MINOR_VERSION);
700                 return TDM_ERROR_BAD_MODULE;
701         }
702
703         if (!module->init) {
704                 TDM_ERR("'%s' doesn't have init function", name);
705                 return TDM_ERROR_BAD_MODULE;
706         }
707
708         if (!module->deinit) {
709                 TDM_ERR("'%s' doesn't have deinit function", name);
710                 return TDM_ERROR_BAD_MODULE;
711         }
712
713         return TDM_ERROR_NONE;
714 }
715
716 static tdm_error
717 _tdm_display_check_backend_functions(tdm_private_display *private_display)
718 {
719         tdm_func_display *func_display = &private_display->func_display;
720         tdm_func_output *func_output = &private_display->func_output;
721         tdm_func_layer *func_layer = &private_display->func_layer;
722         tdm_error ret;
723
724         /* below functions should be implemented in backend side */
725
726         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
727         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
728                                TDM_ERROR_BAD_MODULE);
729         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
730         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
731                                TDM_ERROR_BAD_MODULE);
732         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
733         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
734
735         ret = func_display->display_get_capabilitiy(private_display->bdata,
736                         &private_display->caps_display);
737         if (ret != TDM_ERROR_NONE) {
738                 TDM_ERR("display_get_capabilitiy() failed");
739                 return TDM_ERROR_BAD_MODULE;
740         }
741
742         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
743                 tdm_func_pp *func_pp = &private_display->func_pp;
744                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
745                                        TDM_ERROR_BAD_MODULE);
746                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
747                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
748                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
749                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
750         }
751
752         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
753                 tdm_func_capture *func_capture = &private_display->func_capture;
754                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
755                                        TDM_ERROR_BAD_MODULE);
756                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
757                                        TDM_ERROR_BAD_MODULE);
758                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
759                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
760                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
761                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
762                                        TDM_ERROR_BAD_MODULE);
763         }
764
765         return TDM_ERROR_NONE;
766 }
767
768 static tdm_error
769 _tdm_display_load_module_with_file(tdm_private_display *private_display,
770                                    const char *file)
771 {
772         char path[PATH_MAX] = {0,};
773         tdm_backend_module *module_data;
774         void *module;
775         tdm_error ret;
776
777         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
778
779         TDM_TRACE_BEGIN(Load_Backend);
780
781         module = dlopen(path, RTLD_LAZY);
782         if (!module) {
783                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
784                 TDM_TRACE_END();
785                 return TDM_ERROR_BAD_MODULE;
786         }
787
788         module_data = dlsym(module, "tdm_backend_module_data");
789         if (!module_data) {
790                 TDM_ERR("'%s' doesn't have data object", file);
791                 ret = TDM_ERROR_BAD_MODULE;
792                 TDM_TRACE_END();
793                 goto failed_load;
794         }
795
796         private_display->module_data = module_data;
797         private_display->module = module;
798
799         /* check if version, init() and deinit() are valid or not */
800         ret = _tdm_display_check_module(module_data);
801         if (ret != TDM_ERROR_NONE)
802                 goto failed_load;
803
804         TDM_TRACE_END();
805
806         /* We don't care if backend_data is NULL or not. It's up to backend. */
807         TDM_TRACE_BEGIN(Init_Backend);
808         private_display->bdata = module_data->init((tdm_display *)private_display,
809                                  &ret);
810         TDM_TRACE_END();
811         if (ret != TDM_ERROR_NONE) {
812                 TDM_ERR("'%s' init failed", file);
813                 goto failed_load;
814         }
815
816         ret = _tdm_display_check_backend_functions(private_display);
817         if (ret != TDM_ERROR_NONE) {
818                 module_data->deinit(private_display->bdata);
819                 private_display->bdata = NULL;
820                 goto failed_load;
821         }
822
823         TDM_INFO("Success to load module(%s)", file);
824
825         return TDM_ERROR_NONE;
826 failed_load:
827         dlclose(module);
828         private_display->module_data = NULL;
829         private_display->module = NULL;
830         return ret;
831 }
832
833 static tdm_error
834 _tdm_display_load_module(tdm_private_display *private_display)
835 {
836         const char *module_name;
837         struct dirent **namelist;
838         int n;
839         tdm_error ret = 0;
840
841         module_name = getenv("TDM_MODULE");
842         if (!module_name)
843                 module_name = DEFAULT_MODULE;
844
845         /* load bufmgr priv from default lib */
846         ret = _tdm_display_load_module_with_file(private_display, module_name);
847         if (ret == TDM_ERROR_NONE)
848                 return TDM_ERROR_NONE;
849
850         /* load bufmgr priv from configured path */
851         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
852         if (n < 0) {
853                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
854                 return TDM_ERROR_BAD_MODULE;
855         }
856
857         ret = TDM_ERROR_BAD_MODULE;
858         while (n--) {
859                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
860                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
861
862                 free(namelist[n]);
863         }
864         free(namelist);
865
866         return ret;
867 }
868
869 static void
870 _tdm_display_unload_module(tdm_private_display *private_display)
871 {
872         if (private_display->module_data)
873                 private_display->module_data->deinit(private_display->bdata);
874         if (private_display->module)
875                 dlclose(private_display->module);
876
877         private_display->bdata = NULL;
878         private_display->module_data = NULL;
879         private_display->module = NULL;
880 }
881
882 EXTERN tdm_display *
883 tdm_display_init(tdm_error *error)
884 {
885         tdm_private_display *private_display = NULL;
886         const char *debug;
887         tdm_error ret;
888
889         _pthread_mutex_lock(&gLock);
890
891         if (g_private_display) {
892                 g_private_display->init_count++;
893                 _pthread_mutex_unlock(&gLock);
894                 if (error)
895                         *error = TDM_ERROR_NONE;
896                 return g_private_display;
897         }
898
899         debug = getenv("TDM_DEBUG");
900         if (debug && (strstr(debug, "1")))
901                 tdm_debug = 1;
902
903         debug = getenv("TDM_DEBUG_BUFFER");
904         if (debug && (strstr(debug, "1")))
905                 tdm_debug_buffer = 1;
906
907         debug = getenv("TDM_DEBUG_THREAD");
908         if (debug && (strstr(debug, "1")))
909                 tdm_debug_thread = 1;
910
911         debug = getenv("TDM_DEBUG_MUTEX");
912         if (debug && (strstr(debug, "1")))
913                 tdm_debug_mutex = 1;
914
915         private_display = calloc(1, sizeof(tdm_private_display));
916         if (!private_display) {
917                 ret = TDM_ERROR_OUT_OF_MEMORY;
918                 TDM_ERR("'private_display != NULL' failed");
919                 goto failed_alloc;
920         }
921
922         if (pthread_mutex_init(&private_display->lock, NULL)) {
923                 ret = TDM_ERROR_OPERATION_FAILED;
924                 TDM_ERR("mutex init failed: %m");
925                 goto failed_mutex_init;
926         }
927
928         _pthread_mutex_lock(&private_display->lock);
929
930         ret = tdm_event_loop_init(private_display);
931         if (ret != TDM_ERROR_NONE)
932                 goto failed_event;
933
934         ret = _tdm_display_load_module(private_display);
935         if (ret != TDM_ERROR_NONE)
936                 goto failed_load;
937
938 #ifdef INIT_BUFMGR
939         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
940         if (tdm_drm_fd >= 0) {
941                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
942                 close(tdm_drm_fd);
943                 if (!private_display->bufmgr) {
944                         TDM_ERR("tbm_bufmgr_init failed");
945                         goto failed_update;
946                 } else {
947                         TDM_INFO("tbm_bufmgr_init successed");
948                 }
949         }
950 #endif
951
952         TDM_TRACE_BEGIN(Update_Display);
953         ret = _tdm_display_update_internal(private_display, 0);
954         TDM_TRACE_END();
955         if (ret != TDM_ERROR_NONE)
956                 goto failed_update;
957
958         tdm_event_loop_create_backend_source(private_display);
959
960         private_display->init_count = 1;
961
962         g_private_display = private_display;
963
964         if (error)
965                 *error = TDM_ERROR_NONE;
966
967         _pthread_mutex_unlock(&private_display->lock);
968         _pthread_mutex_unlock(&gLock);
969
970         return (tdm_display *)private_display;
971
972 failed_update:
973         _tdm_display_unload_module(private_display);
974 failed_load:
975         tdm_event_loop_deinit(private_display);
976 failed_event:
977         _pthread_mutex_unlock(&private_display->lock);
978         pthread_mutex_destroy(&private_display->lock);
979 failed_mutex_init:
980         free(private_display);
981 failed_alloc:
982         tdm_debug = 0;
983         tdm_debug_buffer = 0;
984         if (error)
985                 *error = ret;
986         _pthread_mutex_unlock(&gLock);
987         return NULL;
988 }
989
990 EXTERN void
991 tdm_display_deinit(tdm_display *dpy)
992 {
993         tdm_private_display *private_display = dpy;
994
995         if (!private_display)
996                 return;
997
998         _pthread_mutex_lock(&gLock);
999
1000         private_display->init_count--;
1001         if (private_display->init_count > 0) {
1002                 _pthread_mutex_unlock(&gLock);
1003                 return;
1004         }
1005
1006         _pthread_mutex_lock(&private_display->lock);
1007
1008         tdm_event_loop_deinit(private_display);
1009
1010         _tdm_display_destroy_private_display(private_display);
1011         _tdm_display_unload_module(private_display);
1012
1013 #ifdef INIT_BUFMGR
1014         if (private_display->bufmgr)
1015                 tbm_bufmgr_deinit(private_display->bufmgr);
1016 #endif
1017
1018         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1019
1020         _pthread_mutex_unlock(&private_display->lock);
1021
1022         pthread_mutex_destroy(&private_display->lock);
1023         free(private_display);
1024         g_private_display = NULL;
1025         tdm_debug = 0;
1026         tdm_debug_buffer = 0;
1027
1028         _pthread_mutex_unlock(&gLock);
1029
1030         TDM_INFO("done");
1031 }
1032
1033 INTERN int
1034 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1035 {
1036         tdm_backend_module *module = private_display->module_data;
1037
1038         if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1039                 return 0;
1040
1041         if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1042                 return 0;
1043
1044         return 1;
1045 }
1046