hide tdm_display_capability from backend
[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
44 static tdm_private_layer*
45 _tdm_display_find_private_layer(tdm_private_output *private_output, tdm_layer *layer)
46 {
47     tdm_private_layer *private_layer = NULL;
48
49     LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
50     {
51         if (private_layer->layer == layer)
52             return private_layer;
53     }
54
55     return NULL;
56 }
57
58 static tdm_private_output*
59 _tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output)
60 {
61     tdm_private_output *private_output = NULL;
62
63     LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
64     {
65         if (private_output->output == output)
66             return private_output;
67     }
68
69     return NULL;
70 }
71
72 static void
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
74 {
75     free(caps_pp->formats);
76     memset(caps_pp, 0, sizeof(tdm_caps_pp));
77 }
78
79 static void
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
81 {
82     free(caps_capture->formats);
83     memset(caps_capture, 0, sizeof(tdm_caps_capture));
84 }
85
86 static void
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
88 {
89     free(caps_layer->formats);
90     free(caps_layer->props);
91     memset(caps_layer, 0, sizeof(tdm_caps_layer));
92 }
93
94 static void
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
96 {
97     free(caps_output->modes);
98     free(caps_output->props);
99     memset(caps_output, 0, sizeof(tdm_caps_output));
100 }
101
102 static void
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
104 {
105     tdm_private_capture *c = NULL, *cc = NULL;
106
107     LIST_DEL(&private_layer->link);
108
109     LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110         tdm_capture_destroy_internal(c);
111
112     _tdm_display_destroy_caps_layer(&private_layer->caps);
113
114     free(private_layer);
115 }
116
117 static void
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
119 {
120     tdm_private_layer *l = NULL, *ll = NULL;
121     tdm_private_capture *c = NULL, *cc = NULL;
122     tdm_private_vblank_handler *v = NULL, *vv = NULL;
123     tdm_private_commit_handler *m = NULL, *mm = NULL;
124
125     LIST_DEL(&private_output->link);
126
127     free(private_output->layers_ptr);
128
129     LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link)
130     {
131         LIST_DEL(&v->link);
132         free(v);
133     }
134
135     LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link)
136     {
137         LIST_DEL(&m->link);
138         free(m);
139     }
140
141     LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
142         tdm_capture_destroy_internal(c);
143
144     LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
145         _tdm_display_destroy_private_layer(l);
146
147     _tdm_display_destroy_caps_output(&private_output->caps);
148
149     free(private_output);
150 }
151
152 static void
153 _tdm_display_destroy_private_display(tdm_private_display *private_display)
154 {
155     tdm_private_output *o = NULL, *oo = NULL;
156     tdm_private_pp *p = NULL, *pp = NULL;
157
158     free(private_display->outputs_ptr);
159
160     LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
161         tdm_pp_destroy_internal(p);
162
163     LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
164         _tdm_display_destroy_private_output(o);
165
166     _tdm_display_destroy_caps_pp(&private_display->caps_pp);
167     _tdm_display_destroy_caps_capture(&private_display->caps_capture);
168
169     private_display->capabilities = 0;
170     private_display->caps_display.max_layer_count = -1;
171 }
172
173 static tdm_error
174 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
175 {
176     tdm_func_display *func_display = &private_display->func_display;
177     char buf[1024];
178     int bufsize = sizeof(buf);
179     char *str_buf = buf;
180     int *len_buf = &bufsize;
181     int i;
182     tdm_error ret;
183
184     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
185         return TDM_ERROR_NONE;
186
187     if (!func_display->display_get_pp_capability)
188     {
189         TDM_ERR("no display_get_pp_capability()");
190         return TDM_ERROR_BAD_MODULE;
191     }
192
193     ret = func_display->display_get_pp_capability(private_display->bdata, caps);
194     if (ret != TDM_ERROR_NONE)
195     {
196         TDM_ERR("display_get_pp_capability() failed");
197         return TDM_ERROR_BAD_MODULE;
198     }
199
200     TDM_DBG("pp capabilities: %x", caps->capabilities);
201     buf[0] = '\0';
202     for (i = 0; i < caps->format_count; i++)
203         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
204     TDM_DBG("pp formats: %s", buf);
205     TDM_DBG("pp min  : %dx%d", caps->min_w, caps->min_h);
206     TDM_DBG("pp max  : %dx%d", caps->max_w, caps->max_h);
207     TDM_DBG("pp align: %d", caps->preferred_align);
208
209     return TDM_ERROR_NONE;
210 }
211
212 static tdm_error
213 _tdm_display_update_caps_capture(tdm_private_display *private_display, tdm_caps_capture *caps)
214 {
215     tdm_func_display *func_display = &private_display->func_display;
216     char buf[1024];
217     int bufsize = sizeof(buf);
218     char *str_buf = buf;
219     int *len_buf = &bufsize;
220     int i;
221     tdm_error ret;
222
223     if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
224         return TDM_ERROR_NONE;
225
226     if (!func_display->display_get_capture_capability)
227     {
228         TDM_ERR("no display_get_capture_capability()");
229         return TDM_ERROR_BAD_MODULE;
230     }
231
232     ret = func_display->display_get_capture_capability(private_display->bdata, caps);
233     if (ret != TDM_ERROR_NONE)
234     {
235         TDM_ERR("display_get_capture_capability() failed");
236         return TDM_ERROR_BAD_MODULE;
237     }
238
239     buf[0] = '\0';
240     for (i = 0; i < caps->format_count; i++)
241         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
242     TDM_DBG("capture formats: %s", buf);
243
244     return TDM_ERROR_NONE;
245 }
246
247 static tdm_error
248 _tdm_display_update_caps_layer(tdm_private_display *private_display, tdm_layer *layer, tdm_caps_layer *caps)
249 {
250     tdm_func_display *func_display = &private_display->func_display;
251     char buf[1024];
252     int bufsize = sizeof(buf);
253     char *str_buf = buf;
254     int *len_buf = &bufsize;
255     int i;
256     tdm_error ret;
257
258     if (!func_display->layer_get_capability)
259     {
260         TDM_ERR("no layer_get_capability()");
261         return TDM_ERROR_BAD_MODULE;
262     }
263
264     ret = func_display->layer_get_capability(layer, caps);
265     if (ret != TDM_ERROR_NONE)
266     {
267         TDM_ERR("layer_get_capability() failed");
268         return TDM_ERROR_BAD_MODULE;
269     }
270
271     TDM_DBG("layer capabilities: %x", caps->capabilities);
272     TDM_DBG("layer zpos : %d", caps->zpos);
273     buf[0] = '\0';
274     for (i = 0; i < caps->format_count; i++)
275         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
276     TDM_DBG("layer formats: %s", buf);
277     for (i = 0; i < caps->prop_count; i++)
278         TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
279
280     return TDM_ERROR_NONE;
281 }
282
283 static tdm_error
284 _tdm_display_update_caps_output(tdm_private_display *private_display, tdm_output *output, tdm_caps_output *caps)
285 {
286     tdm_func_display *func_display = &private_display->func_display;
287     int i;
288     tdm_error ret;
289
290     if (!func_display->output_get_capability)
291     {
292         TDM_ERR("no output_get_capability()");
293         return TDM_ERROR_BAD_MODULE;
294     }
295
296     ret = func_display->output_get_capability(output, caps);
297     if (ret != TDM_ERROR_NONE)
298     {
299         TDM_ERR("output_get_capability() failed");
300         return TDM_ERROR_BAD_MODULE;
301     }
302
303     TDM_DBG("output status: %d", caps->status);
304     TDM_DBG("output type : %d", caps->type);
305     for (i = 0; i < caps->prop_count; i++)
306         TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
307     for (i = 0; i < caps->mode_count; i++)
308         TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
309                  caps->modes[i]->name, caps->modes[i]->width, caps->modes[i]->height,
310                  caps->modes[i]->refresh, caps->modes[i]->flags, caps->modes[i]->type);
311     TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
312     TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
313     TDM_DBG("output align: %d", caps->preferred_align);
314
315     return TDM_ERROR_NONE;
316 }
317
318 static tdm_error
319 _tdm_display_update_layer(tdm_private_display *private_display,
320                           tdm_private_output *private_output,
321                           tdm_layer *layer)
322 {
323     tdm_private_layer *private_layer;
324     tdm_error ret;
325
326     private_layer = _tdm_display_find_private_layer(private_output, layer);
327     if (!private_layer)
328     {
329         private_layer = calloc(1, sizeof(tdm_private_layer));
330         TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
331
332         LIST_ADD(&private_layer->link, &private_output->layer_list);
333         private_layer->func_display = &private_display->func_display;
334         private_layer->private_display = private_display;
335         private_layer->private_output = private_output;
336         private_layer->layer = layer;
337
338         LIST_INITHEAD(&private_layer->capture_list);
339
340         private_layer->usable = 1;
341     }
342     else
343         _tdm_display_destroy_caps_layer(&private_layer->caps);
344
345     ret = _tdm_display_update_caps_layer(private_display, layer, &private_layer->caps);
346     if (ret != TDM_ERROR_NONE)
347         goto failed_update;
348
349     return TDM_ERROR_NONE;
350 failed_update:
351     _tdm_display_destroy_private_layer(private_layer);
352     return ret;
353 }
354
355 static tdm_error
356 _tdm_display_update_output(tdm_private_display *private_display, tdm_output *output, int pipe)
357 {
358     tdm_func_display *func_display = &private_display->func_display;
359     tdm_private_output *private_output = NULL;
360     tdm_layer **layers = NULL;
361     int layer_count = 0, i;
362     tdm_error ret;
363
364     private_output = _tdm_display_find_private_output(private_display, output);
365     if (!private_output)
366     {
367         private_output = calloc(1, sizeof(tdm_private_output));
368         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
369
370         LIST_ADD(&private_output->link, &private_display->output_list);
371         private_output->func_display = func_display;
372         private_output->private_display = private_display;
373         private_output->output = output;
374         private_output->pipe = pipe;
375
376         LIST_INITHEAD(&private_output->layer_list);
377         LIST_INITHEAD(&private_output->capture_list);
378         LIST_INITHEAD(&private_output->vblank_handler_list);
379         LIST_INITHEAD(&private_output->commit_handler_list);
380     }
381     else
382         _tdm_display_destroy_caps_output(&private_output->caps);
383
384     ret = _tdm_display_update_caps_output(private_display, output, &private_output->caps);
385     if (ret != TDM_ERROR_NONE)
386         return ret;
387
388     layers = func_display->output_get_layers(output, &layer_count, &ret);
389     if (ret != TDM_ERROR_NONE)
390         goto failed_update;
391
392     for (i = 0; i < layer_count; i++)
393     {
394         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
395         if (ret != TDM_ERROR_NONE)
396             goto failed_update;
397     }
398
399     free(layers);
400
401     return TDM_ERROR_NONE;
402 failed_update:
403     _tdm_display_destroy_private_output(private_output);
404     free(layers);
405     return ret;
406 }
407
408 static tdm_error
409 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
410 {
411     tdm_func_display *func_display = &private_display->func_display;
412     tdm_output **outputs = NULL;
413     int output_count = 0, i;
414     tdm_error ret;
415
416     LIST_INITHEAD(&private_display->output_list);
417     LIST_INITHEAD(&private_display->pp_list);
418
419     if (!only_display)
420     {
421         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
422         if (ret != TDM_ERROR_NONE)
423             goto failed_update;
424
425         ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
426         if (ret != TDM_ERROR_NONE)
427             goto failed_update;
428     }
429
430     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
431     if (ret != TDM_ERROR_NONE)
432         goto failed_update;
433
434     for (i = 0; i < output_count; i++)
435     {
436         ret = _tdm_display_update_output(private_display, outputs[i], i);
437         if (ret != TDM_ERROR_NONE)
438             goto failed_update;
439     }
440
441     free(outputs);
442
443     return TDM_ERROR_NONE;
444
445 failed_update:
446     _tdm_display_destroy_private_display(private_display);
447     free(outputs);
448     return ret;
449 }
450
451
452 EXTERN tdm_error
453 tdm_display_update(tdm_display *dpy)
454 {
455     tdm_private_display *private_display;
456     tdm_error ret;
457
458     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
459
460     private_display = dpy;
461     pthread_mutex_lock(&private_display->lock);
462
463     ret = _tdm_display_update_internal(private_display, 1);
464
465     pthread_mutex_unlock(&private_display->lock);
466
467     return ret;
468 }
469
470 #define SUFFIX_MODULE    ".so"
471 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
472
473 int tdm_debug;
474
475 static tdm_private_display *g_private_display;
476 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
477
478 static tdm_error
479 _tdm_display_check_module(tdm_backend_module *module)
480 {
481     const char *name;
482     const char *vendor;
483     int major, minor;
484     int abimaj, abimin;
485
486     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
487     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
488
489     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
490
491     name = module->name ? module->name : "unknown";
492     vendor = module->vendor ? module->vendor : "unknown";
493     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
494     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
495
496     TDM_INFO("TDM module name: %s", name);
497     TDM_INFO("'%s' vendor: %s", name, vendor);
498     TDM_INFO("'%s' version: %d.%d", name, major, minor);
499
500     if (major != abimaj)
501     {
502         TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
503         return TDM_ERROR_BAD_MODULE;
504     }
505
506     if (minor > abimin)
507     {
508         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
509         return TDM_ERROR_BAD_MODULE;
510     }
511
512     if (!module->init)
513     {
514         TDM_ERR("'%s' doesn't have init function", name);
515         return TDM_ERROR_BAD_MODULE;
516     }
517
518     if (!module->deinit)
519     {
520         TDM_ERR("'%s' doesn't have deinit function", name);
521         return TDM_ERROR_BAD_MODULE;
522     }
523
524     return TDM_ERROR_NONE;
525 }
526
527 static tdm_error
528 _tdm_display_check_backend_functions(tdm_private_display *private_display)
529 {
530     tdm_func_display *func_display = &private_display->func_display;
531     tdm_error ret;
532
533     /* below functions should be implemented in backend side */
534
535     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
536     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
537     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
538     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_capability, TDM_ERROR_BAD_MODULE);
539     TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
540     TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
541
542     ret = func_display->display_get_capabilitiy(private_display->bdata,
543                                                 &private_display->caps_display);
544     if (ret != TDM_ERROR_NONE)
545     {
546         TDM_ERR("display_get_capabilitiy() failed");
547         return TDM_ERROR_BAD_MODULE;
548     }
549
550     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
551     {
552         tdm_func_pp *func_pp = &private_display->func_pp;
553         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
554         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
555         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
556         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
557         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
558     }
559
560     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
561     {
562         tdm_func_capture *func_capture = &private_display->func_capture;
563         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
564         TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
565         TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
566         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
567         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
568         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
569     }
570
571     return TDM_ERROR_NONE;
572 }
573
574 static tdm_error
575 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
576 {
577     char path[PATH_MAX] = {0,};
578     tdm_backend_module *module_data;
579     void *module;
580     tdm_error ret;
581
582     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
583
584     module = dlopen(path, RTLD_LAZY);
585     if (!module)
586     {
587         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
588         return TDM_ERROR_BAD_MODULE;
589     }
590
591     module_data = dlsym(module, "tdm_backend_module_data");
592     if (!module_data)
593     {
594         TDM_ERR("'%s' doesn't have data object", file);
595         ret = TDM_ERROR_BAD_MODULE;
596         goto failed_load;
597     }
598
599     /* check if version, init() and deinit() are valid or not */
600     ret = _tdm_display_check_module(module_data);
601     if (ret != TDM_ERROR_NONE)
602         goto failed_load;
603
604     /* We don't care if backend_data is NULL or not. It's up to backend. */
605     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
606     if (ret != TDM_ERROR_NONE)
607     {
608         TDM_ERR("'%s' init failed", file);
609         goto failed_load;
610     }
611
612     ret = _tdm_display_check_backend_functions(private_display);
613     if (ret != TDM_ERROR_NONE)
614     {
615         module_data->deinit(private_display->bdata);
616         private_display->bdata = NULL;
617         goto failed_load;
618     }
619
620     private_display->module_data = module_data;
621     private_display->module = module;
622
623     TDM_INFO("Success to load module(%s)", file);
624
625     return TDM_ERROR_NONE;
626 failed_load:
627     dlclose(module);
628     return ret;
629 }
630
631 static tdm_error
632 _tdm_display_load_module(tdm_private_display *private_display)
633 {
634     const char *module_name;
635     struct dirent **namelist;
636     int n;
637     tdm_error ret = 0;
638
639     module_name = getenv("TDM_MODULE");
640     if (!module_name)
641         module_name = DEFAULT_MODULE;
642
643     /* load bufmgr priv from default lib */
644     ret = _tdm_display_load_module_with_file(private_display, module_name);
645     if (ret == TDM_ERROR_NONE)
646         return TDM_ERROR_NONE;
647
648     /* load bufmgr priv from configured path */
649     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
650     if (n < 0)
651     {
652         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
653         return TDM_ERROR_BAD_MODULE;
654     }
655
656     ret = TDM_ERROR_BAD_MODULE;
657     while (n--)
658     {
659         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
660             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
661
662         free(namelist[n]);
663     }
664     free(namelist);
665
666     return ret;
667 }
668
669 static void
670 _tdm_display_unload_module(tdm_private_display *private_display)
671 {
672     if (private_display->module_data)
673         private_display->module_data->deinit(private_display->bdata);
674     if (private_display->module)
675         dlclose(private_display->module);
676
677     private_display->bdata = NULL;
678     private_display->module_data = NULL;
679     private_display->module = NULL;
680 }
681
682 EXTERN tdm_display*
683 tdm_display_init(tdm_error *error)
684 {
685     tdm_private_display *private_display = NULL;
686     const char *debug;
687     tdm_error ret;
688
689     pthread_mutex_lock(&gLock);
690
691     if (g_private_display)
692     {
693         g_private_display->init_count++;
694         pthread_mutex_unlock(&gLock);
695         if (error)
696             *error = TDM_ERROR_NONE;
697         return g_private_display;
698     }
699
700     debug = getenv("TDM_DEBUG");
701     if (debug && (strstr(debug, "1")))
702         tdm_debug = 1;
703
704     private_display = calloc(1, sizeof(tdm_private_display));
705     if (!private_display)
706     {
707         ret = TDM_ERROR_OUT_OF_MEMORY;
708         TDM_ERR("'private_display != NULL' failed");
709         goto failed_alloc;
710     }
711
712     if (pthread_mutex_init(&private_display->lock, NULL))
713     {
714         ret = TDM_ERROR_OPERATION_FAILED;
715         TDM_ERR("mutex init failed: %m");
716         goto failed_mutex_init;
717     }
718
719     ret = _tdm_display_load_module(private_display);
720     if (ret != TDM_ERROR_NONE)
721         goto failed_load;
722
723     ret = _tdm_display_update_internal(private_display, 0);
724     if (ret != TDM_ERROR_NONE)
725         goto failed_update;
726
727     private_display->init_count = 1;
728
729     g_private_display = private_display;
730
731     if (error)
732         *error = TDM_ERROR_NONE;
733
734     pthread_mutex_unlock(&gLock);
735
736     return (tdm_display*)private_display;
737
738 failed_update:
739     _tdm_display_unload_module(private_display);
740 failed_load:
741     pthread_mutex_destroy(&private_display->lock);
742 failed_mutex_init:
743     free(private_display);
744 failed_alloc:
745     tdm_debug = 0;
746     if (error)
747         *error = ret;
748     pthread_mutex_unlock(&gLock);
749     return NULL;
750 }
751
752 EXTERN void
753 tdm_display_deinit(tdm_display *dpy)
754 {
755     tdm_private_display *private_display = dpy;
756
757     if (!private_display)
758         return;
759
760     pthread_mutex_lock(&gLock);
761
762     private_display->init_count--;
763     if (private_display->init_count > 0)
764     {
765         pthread_mutex_unlock(&gLock);
766         return;
767     }
768
769     pthread_mutex_lock(&private_display->lock);
770
771     _tdm_display_destroy_private_display(private_display);
772     _tdm_display_unload_module(private_display);
773
774     pthread_mutex_unlock(&private_display->lock);
775
776     pthread_mutex_destroy(&private_display->lock);
777     free(private_display);
778     tdm_debug = 0;
779
780     pthread_mutex_unlock(&gLock);
781 }
782