add tdm_display_check_module_abi function
[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         int abimaj, abimin;
679
680         abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
681         abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
682
683         TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
684
685         name = module->name ? module->name : "unknown";
686         vendor = module->vendor ? module->vendor : "unknown";
687         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
688         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
689
690         TDM_INFO("TDM module name: %s", name);
691         TDM_INFO("'%s' vendor: %s", name, vendor);
692         TDM_INFO("'%s' version: %d.%d", name, major, minor);
693
694         if (major != abimaj) {
695                 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
696                 return TDM_ERROR_BAD_MODULE;
697         }
698
699         if (minor > abimin) {
700                 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
701                 return TDM_ERROR_BAD_MODULE;
702         }
703
704         if (!module->init) {
705                 TDM_ERR("'%s' doesn't have init function", name);
706                 return TDM_ERROR_BAD_MODULE;
707         }
708
709         if (!module->deinit) {
710                 TDM_ERR("'%s' doesn't have deinit function", name);
711                 return TDM_ERROR_BAD_MODULE;
712         }
713
714         return TDM_ERROR_NONE;
715 }
716
717 static tdm_error
718 _tdm_display_check_backend_functions(tdm_private_display *private_display)
719 {
720         tdm_func_display *func_display = &private_display->func_display;
721         tdm_func_output *func_output = &private_display->func_output;
722         tdm_func_layer *func_layer = &private_display->func_layer;
723         tdm_error ret;
724
725         /* below functions should be implemented in backend side */
726
727         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
728         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy,
729                                TDM_ERROR_BAD_MODULE);
730         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
731         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability,
732                                TDM_ERROR_BAD_MODULE);
733         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
734         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
735
736         ret = func_display->display_get_capabilitiy(private_display->bdata,
737                         &private_display->caps_display);
738         if (ret != TDM_ERROR_NONE) {
739                 TDM_ERR("display_get_capabilitiy() failed");
740                 return TDM_ERROR_BAD_MODULE;
741         }
742
743         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
744                 tdm_func_pp *func_pp = &private_display->func_pp;
745                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability,
746                                        TDM_ERROR_BAD_MODULE);
747                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
748                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
749                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
750                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
751         }
752
753         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
754                 tdm_func_capture *func_capture = &private_display->func_capture;
755                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability,
756                                        TDM_ERROR_BAD_MODULE);
757                 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture,
758                                        TDM_ERROR_BAD_MODULE);
759                 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
760                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
761                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
762                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler,
763                                        TDM_ERROR_BAD_MODULE);
764         }
765
766         return TDM_ERROR_NONE;
767 }
768
769 static tdm_error
770 _tdm_display_load_module_with_file(tdm_private_display *private_display,
771                                    const char *file)
772 {
773         char path[PATH_MAX] = {0,};
774         tdm_backend_module *module_data;
775         void *module;
776         tdm_error ret;
777
778         snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
779
780         TDM_TRACE_BEGIN(Load_Backend);
781
782         module = dlopen(path, RTLD_LAZY);
783         if (!module) {
784                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
785                 TDM_TRACE_END();
786                 return TDM_ERROR_BAD_MODULE;
787         }
788
789         module_data = dlsym(module, "tdm_backend_module_data");
790         if (!module_data) {
791                 TDM_ERR("'%s' doesn't have data object", file);
792                 ret = TDM_ERROR_BAD_MODULE;
793                 TDM_TRACE_END();
794                 goto failed_load;
795         }
796
797         private_display->module_data = module_data;
798         private_display->module = module;
799
800         /* check if version, init() and deinit() are valid or not */
801         ret = _tdm_display_check_module(module_data);
802         if (ret != TDM_ERROR_NONE)
803                 goto failed_load;
804
805         TDM_TRACE_END();
806
807         /* We don't care if backend_data is NULL or not. It's up to backend. */
808         TDM_TRACE_BEGIN(Init_Backend);
809         private_display->bdata = module_data->init((tdm_display *)private_display,
810                                  &ret);
811         TDM_TRACE_END();
812         if (ret != TDM_ERROR_NONE) {
813                 TDM_ERR("'%s' init failed", file);
814                 goto failed_load;
815         }
816
817         ret = _tdm_display_check_backend_functions(private_display);
818         if (ret != TDM_ERROR_NONE) {
819                 module_data->deinit(private_display->bdata);
820                 private_display->bdata = NULL;
821                 goto failed_load;
822         }
823
824         TDM_INFO("Success to load module(%s)", file);
825
826         return TDM_ERROR_NONE;
827 failed_load:
828         dlclose(module);
829         private_display->module_data = NULL;
830         private_display->module = NULL;
831         return ret;
832 }
833
834 static tdm_error
835 _tdm_display_load_module(tdm_private_display *private_display)
836 {
837         const char *module_name;
838         struct dirent **namelist;
839         int n;
840         tdm_error ret = 0;
841
842         module_name = getenv("TDM_MODULE");
843         if (!module_name)
844                 module_name = DEFAULT_MODULE;
845
846         /* load bufmgr priv from default lib */
847         ret = _tdm_display_load_module_with_file(private_display, module_name);
848         if (ret == TDM_ERROR_NONE)
849                 return TDM_ERROR_NONE;
850
851         /* load bufmgr priv from configured path */
852         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
853         if (n < 0) {
854                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
855                 return TDM_ERROR_BAD_MODULE;
856         }
857
858         ret = TDM_ERROR_BAD_MODULE;
859         while (n--) {
860                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
861                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
862
863                 free(namelist[n]);
864         }
865         free(namelist);
866
867         return ret;
868 }
869
870 static void
871 _tdm_display_unload_module(tdm_private_display *private_display)
872 {
873         if (private_display->module_data)
874                 private_display->module_data->deinit(private_display->bdata);
875         if (private_display->module)
876                 dlclose(private_display->module);
877
878         private_display->bdata = NULL;
879         private_display->module_data = NULL;
880         private_display->module = NULL;
881 }
882
883 EXTERN tdm_display *
884 tdm_display_init(tdm_error *error)
885 {
886         tdm_private_display *private_display = NULL;
887         const char *debug;
888         tdm_error ret;
889
890         _pthread_mutex_lock(&gLock);
891
892         if (g_private_display) {
893                 g_private_display->init_count++;
894                 _pthread_mutex_unlock(&gLock);
895                 if (error)
896                         *error = TDM_ERROR_NONE;
897                 return g_private_display;
898         }
899
900         debug = getenv("TDM_DEBUG");
901         if (debug && (strstr(debug, "1")))
902                 tdm_debug = 1;
903
904         debug = getenv("TDM_DEBUG_BUFFER");
905         if (debug && (strstr(debug, "1")))
906                 tdm_debug_buffer = 1;
907
908         debug = getenv("TDM_DEBUG_THREAD");
909         if (debug && (strstr(debug, "1")))
910                 tdm_debug_thread = 1;
911
912         debug = getenv("TDM_DEBUG_MUTEX");
913         if (debug && (strstr(debug, "1")))
914                 tdm_debug_mutex = 1;
915
916         private_display = calloc(1, sizeof(tdm_private_display));
917         if (!private_display) {
918                 ret = TDM_ERROR_OUT_OF_MEMORY;
919                 TDM_ERR("'private_display != NULL' failed");
920                 goto failed_alloc;
921         }
922
923         if (pthread_mutex_init(&private_display->lock, NULL)) {
924                 ret = TDM_ERROR_OPERATION_FAILED;
925                 TDM_ERR("mutex init failed: %m");
926                 goto failed_mutex_init;
927         }
928
929         _pthread_mutex_lock(&private_display->lock);
930
931         ret = tdm_event_loop_init(private_display);
932         if (ret != TDM_ERROR_NONE)
933                 goto failed_event;
934
935         ret = _tdm_display_load_module(private_display);
936         if (ret != TDM_ERROR_NONE)
937                 goto failed_load;
938
939 #ifdef INIT_BUFMGR
940         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
941         if (tdm_drm_fd >= 0) {
942                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
943                 close(tdm_drm_fd);
944                 if (!private_display->bufmgr) {
945                         TDM_ERR("tbm_bufmgr_init failed");
946                         goto failed_update;
947                 } else {
948                         TDM_INFO("tbm_bufmgr_init successed");
949                 }
950         }
951 #endif
952
953         TDM_TRACE_BEGIN(Update_Display);
954         ret = _tdm_display_update_internal(private_display, 0);
955         TDM_TRACE_END();
956         if (ret != TDM_ERROR_NONE)
957                 goto failed_update;
958
959         tdm_event_loop_create_backend_source(private_display);
960
961         private_display->init_count = 1;
962
963         g_private_display = private_display;
964
965         if (error)
966                 *error = TDM_ERROR_NONE;
967
968         _pthread_mutex_unlock(&private_display->lock);
969         _pthread_mutex_unlock(&gLock);
970
971         return (tdm_display *)private_display;
972
973 failed_update:
974         _tdm_display_unload_module(private_display);
975 failed_load:
976         tdm_event_loop_deinit(private_display);
977 failed_event:
978         _pthread_mutex_unlock(&private_display->lock);
979         pthread_mutex_destroy(&private_display->lock);
980 failed_mutex_init:
981         free(private_display);
982 failed_alloc:
983         tdm_debug = 0;
984         tdm_debug_buffer = 0;
985         if (error)
986                 *error = ret;
987         _pthread_mutex_unlock(&gLock);
988         return NULL;
989 }
990
991 EXTERN void
992 tdm_display_deinit(tdm_display *dpy)
993 {
994         tdm_private_display *private_display = dpy;
995
996         if (!private_display)
997                 return;
998
999         _pthread_mutex_lock(&gLock);
1000
1001         private_display->init_count--;
1002         if (private_display->init_count > 0) {
1003                 _pthread_mutex_unlock(&gLock);
1004                 return;
1005         }
1006
1007         _pthread_mutex_lock(&private_display->lock);
1008
1009         tdm_event_loop_deinit(private_display);
1010
1011         _tdm_display_destroy_private_display(private_display);
1012         _tdm_display_unload_module(private_display);
1013
1014 #ifdef INIT_BUFMGR
1015         if (private_display->bufmgr)
1016                 tbm_bufmgr_deinit(private_display->bufmgr);
1017 #endif
1018
1019         tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
1020
1021         _pthread_mutex_unlock(&private_display->lock);
1022
1023         pthread_mutex_destroy(&private_display->lock);
1024         free(private_display);
1025         g_private_display = NULL;
1026         tdm_debug = 0;
1027         tdm_debug_buffer = 0;
1028
1029         _pthread_mutex_unlock(&gLock);
1030
1031         TDM_INFO("done");
1032 }
1033
1034 INTERN int
1035 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1036 {
1037         tdm_backend_module *module = private_display->module_data;
1038
1039         if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1040                 return 0;
1041
1042         if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1043                 return 0;
1044
1045         return 1;
1046 }
1047