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