seperate tdm_func_ouput, tdm_func_layer from tdm_func_diplay
[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_backend)
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_backend == layer_backend)
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_backend)
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_backend == output_backend)
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,
249                                tdm_layer *layer_backend, tdm_caps_layer *caps)
250 {
251     tdm_func_layer *func_layer = &private_display->func_layer;
252     char buf[1024];
253     int bufsize = sizeof(buf);
254     char *str_buf = buf;
255     int *len_buf = &bufsize;
256     int i;
257     tdm_error ret;
258
259     if (!func_layer->layer_get_capability)
260     {
261         TDM_ERR("no layer_get_capability()");
262         return TDM_ERROR_BAD_MODULE;
263     }
264
265     ret = func_layer->layer_get_capability(layer_backend, caps);
266     if (ret != TDM_ERROR_NONE)
267     {
268         TDM_ERR("layer_get_capability() failed");
269         return TDM_ERROR_BAD_MODULE;
270     }
271
272     TDM_DBG("layer capabilities: %x", caps->capabilities);
273     TDM_DBG("layer zpos : %d", caps->zpos);
274     buf[0] = '\0';
275     for (i = 0; i < caps->format_count; i++)
276         TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
277     TDM_DBG("layer formats: %s", buf);
278     for (i = 0; i < caps->prop_count; i++)
279         TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
280
281     return TDM_ERROR_NONE;
282 }
283
284 static tdm_error
285 _tdm_display_update_caps_output(tdm_private_display *private_display,
286                                 tdm_output *output_backend, tdm_caps_output *caps)
287 {
288     tdm_func_output *func_output = &private_display->func_output;
289     int i;
290     tdm_error ret;
291
292     if (!func_output->output_get_capability)
293     {
294         TDM_ERR("no output_get_capability()");
295         return TDM_ERROR_BAD_MODULE;
296     }
297
298     ret = func_output->output_get_capability(output_backend, caps);
299     if (ret != TDM_ERROR_NONE)
300     {
301         TDM_ERR("output_get_capability() failed");
302         return TDM_ERROR_BAD_MODULE;
303     }
304
305     TDM_DBG("output status: %d", caps->status);
306     TDM_DBG("output type : %d", caps->type);
307     for (i = 0; i < caps->prop_count; i++)
308         TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
309     for (i = 0; i < caps->mode_count; i++)
310         TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
311                  caps->modes[i].name, caps->modes[i].width, caps->modes[i].height,
312                  caps->modes[i].refresh, caps->modes[i].flags, caps->modes[i].type);
313     TDM_DBG("output min  : %dx%d", caps->min_w, caps->min_h);
314     TDM_DBG("output max  : %dx%d", caps->max_w, caps->max_h);
315     TDM_DBG("output align: %d", caps->preferred_align);
316
317     return TDM_ERROR_NONE;
318 }
319
320 static tdm_error
321 _tdm_display_update_layer(tdm_private_display *private_display,
322                           tdm_private_output *private_output,
323                           tdm_layer *layer_backend)
324 {
325     tdm_private_layer *private_layer;
326     tdm_error ret;
327
328     private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
329     if (!private_layer)
330     {
331         private_layer = calloc(1, sizeof(tdm_private_layer));
332         TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
333
334         LIST_ADD(&private_layer->link, &private_output->layer_list);
335         private_layer->private_display = private_display;
336         private_layer->private_output = private_output;
337         private_layer->layer_backend = layer_backend;
338
339         LIST_INITHEAD(&private_layer->capture_list);
340
341         private_layer->usable = 1;
342     }
343     else
344         _tdm_display_destroy_caps_layer(&private_layer->caps);
345
346     ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
347     if (ret != TDM_ERROR_NONE)
348         goto failed_update;
349
350     return TDM_ERROR_NONE;
351 failed_update:
352     _tdm_display_destroy_private_layer(private_layer);
353     return ret;
354 }
355
356 static tdm_error
357 _tdm_display_update_output(tdm_private_display *private_display,
358                            tdm_output *output_backend, int pipe)
359 {
360     tdm_func_output *func_output = &private_display->func_output;
361     tdm_private_output *private_output = NULL;
362     tdm_layer **layers = NULL;
363     int layer_count = 0, i;
364     tdm_error ret;
365
366     private_output = _tdm_display_find_private_output(private_display, output_backend);
367     if (!private_output)
368     {
369         private_output = calloc(1, sizeof(tdm_private_output));
370         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
371
372         LIST_ADD(&private_output->link, &private_display->output_list);
373         private_output->private_display = private_display;
374         private_output->output_backend = output_backend;
375         private_output->pipe = pipe;
376
377         LIST_INITHEAD(&private_output->layer_list);
378         LIST_INITHEAD(&private_output->capture_list);
379         LIST_INITHEAD(&private_output->vblank_handler_list);
380         LIST_INITHEAD(&private_output->commit_handler_list);
381     }
382     else
383         _tdm_display_destroy_caps_output(&private_output->caps);
384
385     ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
386     if (ret != TDM_ERROR_NONE)
387         return ret;
388
389     layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
390     if (ret != TDM_ERROR_NONE)
391         goto failed_update;
392
393     for (i = 0; i < layer_count; i++)
394     {
395         ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
396         if (ret != TDM_ERROR_NONE)
397             goto failed_update;
398     }
399
400     free(layers);
401
402     return TDM_ERROR_NONE;
403 failed_update:
404     _tdm_display_destroy_private_output(private_output);
405     free(layers);
406     return ret;
407 }
408
409 static tdm_error
410 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
411 {
412     tdm_func_display *func_display = &private_display->func_display;
413     tdm_output **outputs = NULL;
414     int output_count = 0, i;
415     tdm_error ret;
416
417     LIST_INITHEAD(&private_display->output_list);
418     LIST_INITHEAD(&private_display->pp_list);
419
420     if (!only_display)
421     {
422         ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
423         if (ret != TDM_ERROR_NONE)
424             goto failed_update;
425
426         ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
427         if (ret != TDM_ERROR_NONE)
428             goto failed_update;
429     }
430
431     outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
432     if (ret != TDM_ERROR_NONE)
433         goto failed_update;
434
435     for (i = 0; i < output_count; i++)
436     {
437         ret = _tdm_display_update_output(private_display, outputs[i], i);
438         if (ret != TDM_ERROR_NONE)
439             goto failed_update;
440     }
441
442     free(outputs);
443
444     return TDM_ERROR_NONE;
445
446 failed_update:
447     _tdm_display_destroy_private_display(private_display);
448     free(outputs);
449     return ret;
450 }
451
452
453 EXTERN tdm_error
454 tdm_display_update(tdm_display *dpy)
455 {
456     tdm_private_display *private_display;
457     tdm_error ret;
458
459     TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
460
461     private_display = dpy;
462     pthread_mutex_lock(&private_display->lock);
463
464     ret = _tdm_display_update_internal(private_display, 1);
465
466     pthread_mutex_unlock(&private_display->lock);
467
468     return ret;
469 }
470
471 #define SUFFIX_MODULE    ".so"
472 #define DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
473
474 int tdm_debug;
475
476 static tdm_private_display *g_private_display;
477 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
478
479 static tdm_error
480 _tdm_display_check_module(tdm_backend_module *module)
481 {
482     const char *name;
483     const char *vendor;
484     int major, minor;
485     int abimaj, abimin;
486
487     abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
488     abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
489
490     TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
491
492     name = module->name ? module->name : "unknown";
493     vendor = module->vendor ? module->vendor : "unknown";
494     major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
495     minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
496
497     TDM_INFO("TDM module name: %s", name);
498     TDM_INFO("'%s' vendor: %s", name, vendor);
499     TDM_INFO("'%s' version: %d.%d", name, major, minor);
500
501     if (major != abimaj)
502     {
503         TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
504         return TDM_ERROR_BAD_MODULE;
505     }
506
507     if (minor > abimin)
508     {
509         TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
510         return TDM_ERROR_BAD_MODULE;
511     }
512
513     if (!module->init)
514     {
515         TDM_ERR("'%s' doesn't have init function", name);
516         return TDM_ERROR_BAD_MODULE;
517     }
518
519     if (!module->deinit)
520     {
521         TDM_ERR("'%s' doesn't have deinit function", name);
522         return TDM_ERROR_BAD_MODULE;
523     }
524
525     return TDM_ERROR_NONE;
526 }
527
528 static tdm_error
529 _tdm_display_check_backend_functions(tdm_private_display *private_display)
530 {
531     tdm_func_display *func_display = &private_display->func_display;
532     tdm_func_output *func_output = &private_display->func_output;
533     tdm_func_layer *func_layer = &private_display->func_layer;
534     tdm_error ret;
535
536     /* below functions should be implemented in backend side */
537
538     TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
539     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
540     TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
541     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
542     TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
543     TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
544
545     ret = func_display->display_get_capabilitiy(private_display->bdata,
546                                                 &private_display->caps_display);
547     if (ret != TDM_ERROR_NONE)
548     {
549         TDM_ERR("display_get_capabilitiy() failed");
550         return TDM_ERROR_BAD_MODULE;
551     }
552
553     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
554     {
555         tdm_func_pp *func_pp = &private_display->func_pp;
556         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
557         TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
558         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
559         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
560         TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
561     }
562
563     if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
564     {
565         tdm_func_capture *func_capture = &private_display->func_capture;
566         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
567         TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
568         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
569         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
570         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
571         TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
572     }
573
574     return TDM_ERROR_NONE;
575 }
576
577 static tdm_error
578 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
579 {
580     char path[PATH_MAX] = {0,};
581     tdm_backend_module *module_data;
582     void *module;
583     tdm_error ret;
584
585     snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
586
587     module = dlopen(path, RTLD_LAZY);
588     if (!module)
589     {
590         TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
591         return TDM_ERROR_BAD_MODULE;
592     }
593
594     module_data = dlsym(module, "tdm_backend_module_data");
595     if (!module_data)
596     {
597         TDM_ERR("'%s' doesn't have data object", file);
598         ret = TDM_ERROR_BAD_MODULE;
599         goto failed_load;
600     }
601
602     /* check if version, init() and deinit() are valid or not */
603     ret = _tdm_display_check_module(module_data);
604     if (ret != TDM_ERROR_NONE)
605         goto failed_load;
606
607     /* We don't care if backend_data is NULL or not. It's up to backend. */
608     private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
609     if (ret != TDM_ERROR_NONE)
610     {
611         TDM_ERR("'%s' init failed", file);
612         goto failed_load;
613     }
614
615     ret = _tdm_display_check_backend_functions(private_display);
616     if (ret != TDM_ERROR_NONE)
617     {
618         module_data->deinit(private_display->bdata);
619         private_display->bdata = NULL;
620         goto failed_load;
621     }
622
623     private_display->module_data = module_data;
624     private_display->module = module;
625
626     TDM_INFO("Success to load module(%s)", file);
627
628     return TDM_ERROR_NONE;
629 failed_load:
630     dlclose(module);
631     return ret;
632 }
633
634 static tdm_error
635 _tdm_display_load_module(tdm_private_display *private_display)
636 {
637     const char *module_name;
638     struct dirent **namelist;
639     int n;
640     tdm_error ret = 0;
641
642     module_name = getenv("TDM_MODULE");
643     if (!module_name)
644         module_name = DEFAULT_MODULE;
645
646     /* load bufmgr priv from default lib */
647     ret = _tdm_display_load_module_with_file(private_display, module_name);
648     if (ret == TDM_ERROR_NONE)
649         return TDM_ERROR_NONE;
650
651     /* load bufmgr priv from configured path */
652     n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
653     if (n < 0)
654     {
655         TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
656         return TDM_ERROR_BAD_MODULE;
657     }
658
659     ret = TDM_ERROR_BAD_MODULE;
660     while (n--)
661     {
662         if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
663             ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
664
665         free(namelist[n]);
666     }
667     free(namelist);
668
669     return ret;
670 }
671
672 static void
673 _tdm_display_unload_module(tdm_private_display *private_display)
674 {
675     if (private_display->module_data)
676         private_display->module_data->deinit(private_display->bdata);
677     if (private_display->module)
678         dlclose(private_display->module);
679
680     private_display->bdata = NULL;
681     private_display->module_data = NULL;
682     private_display->module = NULL;
683 }
684
685 EXTERN tdm_display*
686 tdm_display_init(tdm_error *error)
687 {
688     tdm_private_display *private_display = NULL;
689     const char *debug;
690     tdm_error ret;
691
692     pthread_mutex_lock(&gLock);
693
694     if (g_private_display)
695     {
696         g_private_display->init_count++;
697         pthread_mutex_unlock(&gLock);
698         if (error)
699             *error = TDM_ERROR_NONE;
700         return g_private_display;
701     }
702
703     debug = getenv("TDM_DEBUG");
704     if (debug && (strstr(debug, "1")))
705         tdm_debug = 1;
706
707     private_display = calloc(1, sizeof(tdm_private_display));
708     if (!private_display)
709     {
710         ret = TDM_ERROR_OUT_OF_MEMORY;
711         TDM_ERR("'private_display != NULL' failed");
712         goto failed_alloc;
713     }
714
715     if (pthread_mutex_init(&private_display->lock, NULL))
716     {
717         ret = TDM_ERROR_OPERATION_FAILED;
718         TDM_ERR("mutex init failed: %m");
719         goto failed_mutex_init;
720     }
721
722     ret = _tdm_display_load_module(private_display);
723     if (ret != TDM_ERROR_NONE)
724         goto failed_load;
725
726     ret = _tdm_display_update_internal(private_display, 0);
727     if (ret != TDM_ERROR_NONE)
728         goto failed_update;
729
730     private_display->init_count = 1;
731
732     g_private_display = private_display;
733
734     if (error)
735         *error = TDM_ERROR_NONE;
736
737     pthread_mutex_unlock(&gLock);
738
739     return (tdm_display*)private_display;
740
741 failed_update:
742     _tdm_display_unload_module(private_display);
743 failed_load:
744     pthread_mutex_destroy(&private_display->lock);
745 failed_mutex_init:
746     free(private_display);
747 failed_alloc:
748     tdm_debug = 0;
749     if (error)
750         *error = ret;
751     pthread_mutex_unlock(&gLock);
752     return NULL;
753 }
754
755 EXTERN void
756 tdm_display_deinit(tdm_display *dpy)
757 {
758     tdm_private_display *private_display = dpy;
759
760     if (!private_display)
761         return;
762
763     pthread_mutex_lock(&gLock);
764
765     private_display->init_count--;
766     if (private_display->init_count > 0)
767     {
768         pthread_mutex_unlock(&gLock);
769         return;
770     }
771
772     pthread_mutex_lock(&private_display->lock);
773
774     _tdm_display_destroy_private_display(private_display);
775     _tdm_display_unload_module(private_display);
776
777     pthread_mutex_unlock(&private_display->lock);
778
779     pthread_mutex_destroy(&private_display->lock);
780     free(private_display);
781     tdm_debug = 0;
782
783     pthread_mutex_unlock(&gLock);
784 }
785