virtual: support tdm_client output_set_mode
[platform/core/uifw/libtdm.git] / src / tdm_output.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 <boram1288.park@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_private.h"
41
42 #define COUNT_MAX   10
43
44 #define OUTPUT_FUNC_ENTRY() \
45         tdm_private_display *private_display; \
46         tdm_private_output *private_output; \
47         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
48         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); \
49         private_output = (tdm_private_output*)output; \
50         private_display = private_output->private_display
51
52 #define OUTPUT_FUNC_ENTRY_ERROR() \
53         tdm_private_display *private_display; \
54         tdm_private_output *private_output; \
55         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
56         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
57         private_output = (tdm_private_output*)output; \
58         private_display = private_output->private_display
59
60 #define OUTPUT_FUNC_ENTRY_VOID() \
61         tdm_private_display *private_display; \
62         tdm_private_output *private_output; \
63         TDM_RETURN_IF_FAIL(tdm_output_is_valid(output)); \
64         private_output = (tdm_private_output*)output; \
65         private_display = private_output->private_display
66
67 static void
68 _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay);
69
70 static tdm_error
71 _tdm_output_vblank_timeout_cb(void *user_data)
72 {
73         tdm_private_output *private_output = user_data;
74         tdm_private_output_vblank_handler *v = NULL;
75
76         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OPERATION_FAILED);
77
78         private_output->vblank_timeout_timer_expired++;
79
80         TDM_ERR("TDM output(%d) vblank TIMEOUT!! (%d time%s)",
81                         private_output->pipe,
82                         private_output->vblank_timeout_timer_expired,
83                         (private_output->vblank_timeout_timer_expired > 1) ? "s" : "");
84
85         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
86                 TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
87                                 v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
88         }
89
90         return TDM_ERROR_NONE;
91 }
92
93 INTERN void
94 tdm_output_vblank_print_wait_information(tdm_private_output *private_output, void *user_data)
95 {
96         tdm_private_output_vblank_handler *v = NULL;
97
98         TDM_RETURN_IF_FAIL(private_output != NULL);
99         TDM_RETURN_IF_FAIL(user_data != NULL);
100
101         TDM_ERR("TDM output(%d) vblank user_data(%p) info!!", private_output->pipe, user_data);
102
103         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
104                 if (v->user_data != user_data)
105                         continue;
106                 TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
107                                 v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
108         }
109 }
110
111 static void
112 _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay)
113 {
114         tdm_error ret;
115
116         if (!private_output->vblank_timeout_timer) {
117                 private_output->vblank_timeout_timer =
118                         tdm_event_loop_add_timer_handler(private_output->private_display,
119                                                                                          _tdm_output_vblank_timeout_cb,
120                                                                                          private_output,
121                                                                                          &ret);
122                 if (!private_output->vblank_timeout_timer) {
123                         TDM_ERR("output(%d) couldn't add timer", private_output->pipe);
124                         return;
125                 }
126                 TDM_INFO("output(%d) create vblank timeout timer", private_output->pipe);
127                 private_output->vblank_timeout_timer_expired = 0;
128         }
129
130         ret = tdm_event_loop_source_timer_update(private_output->vblank_timeout_timer, ms_delay);
131         if (ret != TDM_ERROR_NONE) {
132                 TDM_ERR("output(%d) couldn't update timer", private_output->pipe);
133                 return;
134         }
135 }
136
137 INTERN tdm_error
138 tdm_output_init(tdm_private_display *private_display)
139 {
140         tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_DESTROY, tdm_display_find_output_stamp);
141         tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_COMMIT, tdm_display_find_output_stamp);
142         tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_VBLANK, tdm_display_find_output_stamp);
143         tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_STATUS, tdm_display_find_output_stamp);
144         tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_DPMS, tdm_display_find_output_stamp);
145
146         return TDM_ERROR_NONE;
147 }
148
149 INTERN tdm_error
150 tdm_output_call_thread_cb_destroy(tdm_private_output *private_output)
151 {
152         tdm_thread_cb_output_destroy output_destroy;
153         tdm_error ret;
154
155         memset(&output_destroy, 0, sizeof output_destroy);
156         output_destroy.base.type = TDM_THREAD_CB_OUTPUT_DESTROY;
157         output_destroy.base.length = sizeof output_destroy;
158         output_destroy.base.object_stamp = private_output->stamp;
159         output_destroy.base.data = NULL;
160         output_destroy.base.sync = 1;
161
162         ret = tdm_thread_cb_call(private_output, &output_destroy.base, 1);
163         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
164
165         return TDM_ERROR_NONE;
166 }
167
168 INTERN void
169 tdm_output_thread_cb_destroy(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
170 {
171         tdm_private_output *private_output = object;
172         tdm_private_output_destroy_handler *destroy_handler = user_data;
173
174         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
175
176         assert(destroy_handler->owner_tid == syscall(SYS_gettid));
177
178         _pthread_mutex_unlock(&private_display->lock);
179         destroy_handler->func(private_output, destroy_handler->user_data);
180         _pthread_mutex_lock(&private_display->lock);
181 }
182
183 EXTERN tdm_error
184 tdm_output_add_destroy_handler(tdm_output *output,
185                                                            tdm_output_destroy_handler func,
186                                                            void *user_data)
187 {
188         tdm_private_output_destroy_handler *destroy_handler = NULL;
189         OUTPUT_FUNC_ENTRY();
190
191         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
192
193         _pthread_mutex_lock(&private_display->lock);
194
195         LIST_FOR_EACH_ENTRY(destroy_handler, &private_output->destroy_handler_list, link) {
196                 if (destroy_handler->func == func && destroy_handler->user_data == user_data) {
197                         TDM_ERR("can't add twice");
198                         _pthread_mutex_unlock(&private_display->lock);
199                         return TDM_ERROR_BAD_REQUEST;
200                 }
201         }
202
203         destroy_handler = calloc(1, sizeof(tdm_private_output_destroy_handler));
204         if (!destroy_handler) {
205                 TDM_ERR("failed: alloc memory");
206                 _pthread_mutex_unlock(&private_display->lock);
207                 return TDM_ERROR_OUT_OF_MEMORY;
208         }
209
210         ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_DESTROY, NULL, tdm_output_thread_cb_destroy, destroy_handler);
211         if (ret != TDM_ERROR_NONE) {
212                 TDM_ERR("tdm_thread_cb_add failed");
213                 free(destroy_handler);
214                 _pthread_mutex_unlock(&private_display->lock);
215                 return TDM_ERROR_OPERATION_FAILED;
216         }
217
218         destroy_handler->private_output = private_output;
219         destroy_handler->func = func;
220         destroy_handler->user_data = user_data;
221         destroy_handler->owner_tid = syscall(SYS_gettid);
222
223         LIST_ADDTAIL(&destroy_handler->link, &private_output->destroy_handler_list);
224
225         _pthread_mutex_unlock(&private_display->lock);
226
227         return ret;
228 }
229
230
231 EXTERN void
232 tdm_output_remove_destroy_handler(tdm_output *output,
233                                                                   tdm_output_destroy_handler func,
234                                                                   void *user_data)
235 {
236         tdm_private_display *private_display;
237         tdm_private_output *private_output;
238         tdm_private_output_destroy_handler *destroy_handler = NULL, *hh = NULL;
239
240         TDM_RETURN_IF_FAIL(output != NULL);
241         TDM_RETURN_IF_FAIL(func != NULL);
242
243         private_output = (tdm_private_output*)output;
244         private_display = private_output->private_display;
245
246         _pthread_mutex_lock(&private_display->lock);
247
248         LIST_FOR_EACH_ENTRY_SAFE(destroy_handler, hh, &private_output->destroy_handler_list, link) {
249                 if (destroy_handler->func != func || destroy_handler->user_data != user_data)
250                         continue;
251
252                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_DESTROY, NULL, tdm_output_thread_cb_destroy, destroy_handler);
253
254                 LIST_DEL(&destroy_handler->link);
255                 free(destroy_handler);
256
257                 _pthread_mutex_unlock(&private_display->lock);
258
259                 return;
260         }
261
262         _pthread_mutex_unlock(&private_display->lock);
263 }
264
265 EXTERN tdm_module *
266 tdm_output_get_backend_module(tdm_output *output, tdm_error *error)
267 {
268         tdm_private_module *private_module;
269
270         OUTPUT_FUNC_ENTRY_ERROR();
271
272         _pthread_mutex_lock(&private_display->lock);
273
274         private_module = private_output->private_module;
275
276         if (error)
277                 *error = TDM_ERROR_NONE;
278
279         _pthread_mutex_unlock(&private_display->lock);
280
281         return private_module;
282 }
283
284 EXTERN tdm_error
285 tdm_output_get_model_info(tdm_output *output, const char **maker,
286                                                   const char **model, const char **name)
287 {
288         OUTPUT_FUNC_ENTRY();
289
290         _pthread_mutex_lock(&private_display->lock);
291
292         if (maker)
293                 *maker = private_output->caps.maker;
294         if (model)
295                 *model = private_output->caps.model;
296         if (name)
297                 *name = private_output->caps.name;
298
299         _pthread_mutex_unlock(&private_display->lock);
300
301         return ret;
302 }
303
304 EXTERN tdm_error
305 tdm_output_get_capabilities(tdm_output *output, tdm_output_capability *capabilities)
306 {
307         OUTPUT_FUNC_ENTRY();
308
309         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
310
311         _pthread_mutex_lock(&private_display->lock);
312
313         *capabilities = private_output->caps.capabilities;
314
315         _pthread_mutex_unlock(&private_display->lock);
316
317         return ret;
318 }
319
320 EXTERN tdm_error
321 tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status)
322 {
323         OUTPUT_FUNC_ENTRY();
324
325         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
326
327         _pthread_mutex_lock(&private_display->lock);
328
329         *status = private_output->caps.status;
330
331         _pthread_mutex_unlock(&private_display->lock);
332
333         return ret;
334 }
335
336 INTERN void
337 tdm_output_thread_cb_change(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
338 {
339         tdm_private_output *private_output = object;
340         tdm_private_output_change_handler *change_handler = user_data;
341         tdm_output_change_type type = TDM_OUTPUT_CHANGE_CONNECTION;
342         tdm_value value = {.u32 = 0 };
343
344         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
345
346         assert(change_handler->owner_tid == syscall(SYS_gettid));
347
348         if (cb_base->type == TDM_THREAD_CB_OUTPUT_STATUS) {
349                 tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status *)cb_base;
350                 type = TDM_OUTPUT_CHANGE_CONNECTION;
351                 value.u32 = output_status->status;
352         } else if (cb_base->type == TDM_THREAD_CB_OUTPUT_DPMS) {
353                 tdm_thread_cb_output_dpms *output_dpms = (tdm_thread_cb_output_dpms *)cb_base;
354                 type = TDM_OUTPUT_CHANGE_DPMS;
355                 value.u32 = output_dpms->dpms;
356         } else {
357                 TDM_NEVER_GET_HERE();
358                 return;
359         }
360
361         _pthread_mutex_unlock(&private_display->lock);
362         change_handler->func(private_output, type, value, change_handler->user_data);
363         _pthread_mutex_lock(&private_display->lock);
364
365 }
366
367 static tdm_error
368 _tdm_output_call_thread_cb_status(tdm_private_output *private_output, tdm_output_conn_status status)
369 {
370         tdm_thread_cb_output_status output_status;
371         pid_t caller_tid = syscall(SYS_gettid);
372         tdm_error ret;
373
374         memset(&output_status, 0, sizeof output_status);
375         output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS;
376         output_status.base.length = sizeof output_status;
377         output_status.base.object_stamp = private_output->stamp;
378         output_status.base.data = NULL;
379         if (tdm_thread_in_display_thread(caller_tid))
380                 output_status.base.sync = 0;
381         else
382                 output_status.base.sync = 1;
383         output_status.status = status;
384
385         ret = tdm_thread_cb_call(private_output, &output_status.base, 1);
386         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
387
388         return TDM_ERROR_NONE;
389 }
390
391 static tdm_error
392 _tdm_output_call_thread_cb_dpms(tdm_private_output *private_output, tdm_output_dpms dpms)
393 {
394         tdm_thread_cb_output_dpms output_dpms;
395         tdm_error ret;
396
397         memset(&output_dpms, 0, sizeof output_dpms);
398         output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS;
399         output_dpms.base.length = sizeof output_dpms;
400         output_dpms.base.object_stamp = private_output->stamp;
401         output_dpms.base.data = NULL;
402         output_dpms.base.sync = 0;
403         output_dpms.dpms = dpms;
404
405         ret = tdm_thread_cb_call(private_output, &output_dpms.base, 1);
406         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
407
408         return TDM_ERROR_NONE;
409 }
410
411 INTERN void
412 tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, void *user_data)
413 {
414         tdm_private_output *private_output = user_data;
415         tdm_error ret;
416
417         TDM_RETURN_IF_FAIL(private_output);
418
419         TDM_INFO("output(%d) %s", private_output->pipe, tdm_status_str(status));
420
421         if ((private_output->caps.status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED && status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
422                 (private_output->caps.status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED && status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)) {
423                 ret = tdm_display_update_output(private_output->private_module, output_backend);
424                 TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
425         } else {
426                 private_output->caps.status = status;
427         }
428
429         ret = _tdm_output_call_thread_cb_status(private_output, status);
430         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
431 }
432
433 INTERN void
434 tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data)
435 {
436         tdm_private_output *private_output = user_data;
437         tdm_error ret;
438
439         TDM_INFO("output(%d) %s", private_output->pipe, tdm_status_str(dpms));
440
441         private_output->current_dpms_value = dpms;
442         private_output->waiting_dpms_change = 0;
443         TDM_INFO("output(%d) dpms async '%s' done", private_output->pipe, tdm_dpms_str(dpms));
444
445         ret = _tdm_output_call_thread_cb_dpms(private_output, dpms);
446         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
447 }
448
449 EXTERN tdm_error
450 tdm_output_add_change_handler(tdm_output *output,
451                                                           tdm_output_change_handler func,
452                                                           void *user_data)
453 {
454         tdm_private_output_change_handler *change_handler = NULL;
455         OUTPUT_FUNC_ENTRY();
456
457         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
458
459         _pthread_mutex_lock(&private_display->lock);
460
461         LIST_FOR_EACH_ENTRY(change_handler, &private_output->change_handler_list, link) {
462                 if (change_handler->func == func && change_handler->user_data == user_data) {
463                         TDM_ERR("can't add twice");
464                         _pthread_mutex_unlock(&private_display->lock);
465                         return TDM_ERROR_BAD_REQUEST;
466                 }
467         }
468
469         change_handler = calloc(1, sizeof(tdm_private_output_change_handler));
470         if (!change_handler) {
471                 /* LCOV_EXCL_START */
472                 TDM_ERR("failed: alloc memory");
473                 _pthread_mutex_unlock(&private_display->lock);
474                 return TDM_ERROR_OUT_OF_MEMORY;
475                 /* LCOV_EXCL_STOP */
476         }
477
478         ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_DPMS, NULL, tdm_output_thread_cb_change, change_handler);
479         if (ret != TDM_ERROR_NONE) {
480                 /* LCOV_EXCL_START */
481                 TDM_ERR("tdm_thread_cb_add failed");
482                 free(change_handler);
483                 _pthread_mutex_unlock(&private_display->lock);
484                 return TDM_ERROR_OPERATION_FAILED;
485                 /* LCOV_EXCL_STOP */
486         }
487
488         ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_STATUS, NULL, tdm_output_thread_cb_change, change_handler);
489         if (ret != TDM_ERROR_NONE) {
490                 /* LCOV_EXCL_START */
491                 TDM_ERR("tdm_thread_cb_add failed");
492                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_DPMS, NULL, tdm_output_thread_cb_change, change_handler);
493                 free(change_handler);
494                 _pthread_mutex_unlock(&private_display->lock);
495                 return TDM_ERROR_OPERATION_FAILED;
496                 /* LCOV_EXCL_STOP */
497         }
498
499         change_handler->private_output = private_output;
500         change_handler->func = func;
501         change_handler->user_data = user_data;
502         change_handler->owner_tid = syscall(SYS_gettid);
503
504         LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list);
505
506         _pthread_mutex_unlock(&private_display->lock);
507
508         return ret;
509 }
510
511 EXTERN tdm_error
512 tdm_output_add_mode_change_request_handler(tdm_output *output,
513                                                                                    tdm_output_mode_change_request_handler func,
514                                                                                    void *user_data)
515 {
516         tdm_private_display *private_display;
517         tdm_private_output *private_output;
518         tdm_private_output_mode_change_handler *mode_change_handler = NULL;
519
520         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
521         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
522
523         private_output = (tdm_private_output*)output;
524         private_display = private_output->private_display;
525
526         _pthread_mutex_lock(&private_display->lock);
527
528         LIST_FOR_EACH_ENTRY(mode_change_handler, &private_output->mode_change_request_handler_list, link) {
529                 if (mode_change_handler->func == func && mode_change_handler->user_data == user_data) {
530                         TDM_ERR("can't add twice");
531                         _pthread_mutex_unlock(&private_display->lock);
532                         return TDM_ERROR_BAD_REQUEST;
533                 }
534         }
535
536         mode_change_handler = calloc(1, sizeof(tdm_private_output_change_handler));
537         if (!mode_change_handler) {
538                 /* LCOV_EXCL_START */
539                 TDM_ERR("failed: alloc memory");
540                 _pthread_mutex_unlock(&private_display->lock);
541                 return TDM_ERROR_OUT_OF_MEMORY;
542                 /* LCOV_EXCL_STOP */
543         }
544
545         mode_change_handler->private_output = private_output;
546         mode_change_handler->func = func;
547         mode_change_handler->user_data = user_data;
548
549         LIST_ADDTAIL(&mode_change_handler->link, &private_output->mode_change_request_handler_list);
550
551         _pthread_mutex_unlock(&private_display->lock);
552
553         return TDM_ERROR_NONE;
554 }
555
556 EXTERN tdm_error
557 tdm_output_remove_mode_change_request_handler(tdm_output *output,
558                                                                                           tdm_output_mode_change_request_handler func,
559                                                                                           void *user_data)
560 {
561         tdm_private_display *private_display;
562         tdm_private_output *private_output;
563         tdm_private_output_mode_change_handler *mode_change_handler = NULL, *hh = NULL;
564
565         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
566         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
567
568         private_output = (tdm_private_output*)output;
569         private_display = private_output->private_display;
570
571         _pthread_mutex_lock(&private_display->lock);
572
573         LIST_FOR_EACH_ENTRY_SAFE(mode_change_handler, hh, &private_output->mode_change_request_handler_list, link) {
574                 if (mode_change_handler->func != func || mode_change_handler->user_data != user_data)
575                         continue;
576
577                 LIST_DEL(&mode_change_handler->link);
578                 free(mode_change_handler);
579
580                 _pthread_mutex_unlock(&private_display->lock);
581
582                 return TDM_ERROR_NONE;
583         }
584
585         _pthread_mutex_unlock(&private_display->lock);
586
587         return TDM_ERROR_INVALID_PARAMETER;
588 }
589
590 EXTERN void
591 tdm_output_remove_change_handler(tdm_output *output,
592                                                                  tdm_output_change_handler func,
593                                                                  void *user_data)
594 {
595         tdm_private_display *private_display;
596         tdm_private_output *private_output;
597         tdm_private_output_change_handler *change_handler = NULL, *hh = NULL;
598
599         TDM_RETURN_IF_FAIL(output != NULL);
600         TDM_RETURN_IF_FAIL(func != NULL);
601
602         private_output = (tdm_private_output*)output;
603         private_display = private_output->private_display;
604
605         _pthread_mutex_lock(&private_display->lock);
606
607         LIST_FOR_EACH_ENTRY_SAFE(change_handler, hh, &private_output->change_handler_list, link) {
608                 if (change_handler->func != func || change_handler->user_data != user_data)
609                         continue;
610
611                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_DPMS, NULL, tdm_output_thread_cb_change, change_handler);
612                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_STATUS, NULL, tdm_output_thread_cb_change, change_handler);
613
614                 LIST_DEL(&change_handler->link);
615                 free(change_handler);
616
617                 _pthread_mutex_unlock(&private_display->lock);
618
619                 return;
620         }
621
622         _pthread_mutex_unlock(&private_display->lock);
623 }
624
625 EXTERN tdm_error
626 tdm_output_get_output_type(tdm_output *output, tdm_output_type *type)
627 {
628         OUTPUT_FUNC_ENTRY();
629
630         TDM_RETURN_VAL_IF_FAIL(type != NULL, TDM_ERROR_INVALID_PARAMETER);
631
632         _pthread_mutex_lock(&private_display->lock);
633
634         *type = private_output->caps.type;
635
636         _pthread_mutex_unlock(&private_display->lock);
637
638         return ret;
639 }
640
641 EXTERN tdm_error
642 tdm_output_get_layer_count(tdm_output *output, int *count)
643 {
644         tdm_private_layer *private_layer = NULL;
645
646         OUTPUT_FUNC_ENTRY();
647
648         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
649
650         _pthread_mutex_lock(&private_display->lock);
651
652         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
653                 TDM_ERR("output(%p) support HWC. Use HWC functions", private_output);
654                 *count = 0;
655                 _pthread_mutex_unlock(&private_display->lock);
656                 return TDM_ERROR_BAD_REQUEST;
657         }
658
659         *count = 0;
660         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
661                 (*count)++;
662         if (*count == 0) {
663                 _pthread_mutex_unlock(&private_display->lock);
664                 return TDM_ERROR_NONE;
665         }
666
667         _pthread_mutex_unlock(&private_display->lock);
668
669         return ret;
670 }
671
672
673 EXTERN tdm_layer *
674 tdm_output_get_layer(tdm_output *output, int index, tdm_error *error)
675 {
676         tdm_private_layer *private_layer = NULL;
677
678         OUTPUT_FUNC_ENTRY_ERROR();
679
680         _pthread_mutex_lock(&private_display->lock);
681
682         if (error)
683                 *error = TDM_ERROR_NONE;
684
685         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
686                 _pthread_mutex_unlock(&private_display->lock);
687                 TDM_ERR("output(%p) support HWC. Use HWC functions", private_output);
688                 if (error)
689                         *error = TDM_ERROR_BAD_REQUEST;
690                 return NULL;
691         }
692
693         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
694                 if (private_layer->index == index) {
695                         _pthread_mutex_unlock(&private_display->lock);
696                         return private_layer;
697                 }
698         }
699
700         _pthread_mutex_unlock(&private_display->lock);
701
702         return NULL;
703 }
704
705 EXTERN tdm_error
706 tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props,
707                                                                         int *count)
708 {
709         OUTPUT_FUNC_ENTRY();
710
711         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
712         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
713
714         _pthread_mutex_lock(&private_display->lock);
715
716         *props = (const tdm_prop *)private_output->caps.props;
717         *count = private_output->caps.prop_count;
718
719         _pthread_mutex_unlock(&private_display->lock);
720
721         return ret;
722 }
723
724 EXTERN tdm_error
725 tdm_output_get_available_modes(tdm_output *output,
726                                                            const tdm_output_mode **modes, int *count)
727 {
728         OUTPUT_FUNC_ENTRY();
729
730         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
731         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
732
733         _pthread_mutex_lock(&private_display->lock);
734
735         *modes = (const tdm_output_mode *)private_output->caps.modes;
736         *count = private_output->caps.mode_count;
737
738         _pthread_mutex_unlock(&private_display->lock);
739
740         return ret;
741 }
742
743 EXTERN tdm_error
744 tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h,
745                                                           int *max_w, int *max_h, int *preferred_align)
746 {
747         OUTPUT_FUNC_ENTRY();
748
749         _pthread_mutex_lock(&private_display->lock);
750
751         if (min_w)
752                 *min_w = TDM_FRONT_VALUE(private_output->caps.min_w);
753         if (min_h)
754                 *min_h = TDM_FRONT_VALUE(private_output->caps.min_h);
755         if (max_w)
756                 *max_w = TDM_FRONT_VALUE(private_output->caps.max_w);
757         if (max_h)
758                 *max_h = TDM_FRONT_VALUE(private_output->caps.max_h);
759         if (preferred_align)
760                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align);
761
762         _pthread_mutex_unlock(&private_display->lock);
763
764         return ret;
765 }
766
767 EXTERN tdm_error
768 tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h,
769                                                                          int *max_w, int *max_h, int *preferred_align)
770 {
771         OUTPUT_FUNC_ENTRY();
772
773         _pthread_mutex_lock(&private_display->lock);
774
775         if (!tdm_module_check_abi(private_output->private_module, 1, 5)) {
776                 _pthread_mutex_unlock(&private_display->lock);
777                 return TDM_ERROR_BAD_REQUEST;
778         }
779
780         if (min_w)
781                 *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w);
782         if (min_h)
783                 *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h);
784         if (max_w)
785                 *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w);
786         if (max_h)
787                 *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h);
788         if (preferred_align)
789                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align);
790
791         _pthread_mutex_unlock(&private_display->lock);
792
793         return ret;
794 }
795
796 EXTERN tdm_error
797 tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth,
798                                                          unsigned int *mmHeight)
799 {
800         OUTPUT_FUNC_ENTRY();
801
802         _pthread_mutex_lock(&private_display->lock);
803
804         if (mmWidth)
805                 *mmWidth = private_output->caps.mmWidth;
806         if (mmHeight)
807                 *mmHeight = private_output->caps.mmHeight;
808
809         _pthread_mutex_unlock(&private_display->lock);
810
811         return ret;
812 }
813
814 EXTERN tdm_error
815 tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel)
816 {
817         OUTPUT_FUNC_ENTRY();
818         TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER);
819
820         _pthread_mutex_lock(&private_display->lock);
821
822         *subpixel = private_output->caps.subpixel;
823
824         _pthread_mutex_unlock(&private_display->lock);
825
826         return ret;
827 }
828
829 EXTERN tdm_error
830 tdm_output_get_pipe(tdm_output *output, unsigned int *pipe)
831 {
832         OUTPUT_FUNC_ENTRY();
833         TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER);
834
835         _pthread_mutex_lock(&private_display->lock);
836
837         *pipe = private_output->pipe;
838
839         _pthread_mutex_unlock(&private_display->lock);
840
841         return ret;
842 }
843
844 EXTERN tdm_error
845 tdm_output_get_primary_index(tdm_output *output, int *index)
846 {
847         tdm_private_layer *private_layer = NULL;
848
849         OUTPUT_FUNC_ENTRY();
850         TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER);
851
852         _pthread_mutex_lock(&private_display->lock);
853
854         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
855                 if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) {
856                         *index = private_layer->index;
857                         break;
858                 }
859         }
860
861         _pthread_mutex_unlock(&private_display->lock);
862
863         return ret;
864 }
865
866 EXTERN tdm_error
867 tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
868 {
869         tdm_private_module *private_module;
870         tdm_func_output *func_output;
871         OUTPUT_FUNC_ENTRY();
872
873         _pthread_mutex_lock(&private_display->lock);
874
875         private_module = private_output->private_module;
876         func_output = &private_module->func_output;
877
878         if (!func_output->output_set_property) {
879                 /* LCOV_EXCL_START */
880                 _pthread_mutex_unlock(&private_display->lock);
881                 TDM_WRN("not implemented!!");
882                 return TDM_ERROR_NOT_IMPLEMENTED;
883                 /* LCOV_EXCL_STOP */
884         }
885
886         ret = func_output->output_set_property(private_output->output_backend, id,
887                                                                                    value);
888
889         _pthread_mutex_unlock(&private_display->lock);
890
891         return ret;
892 }
893
894 EXTERN tdm_error
895 tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
896 {
897         tdm_private_module *private_module;
898         tdm_func_output *func_output;
899         OUTPUT_FUNC_ENTRY();
900
901         TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER);
902
903         _pthread_mutex_lock(&private_display->lock);
904
905         private_module = private_output->private_module;
906         func_output = &private_module->func_output;
907
908         if (!func_output->output_get_property) {
909                 /* LCOV_EXCL_START */
910                 _pthread_mutex_unlock(&private_display->lock);
911                 TDM_WRN("not implemented!!");
912                 return TDM_ERROR_NOT_IMPLEMENTED;
913                 /* LCOV_EXCL_STOP */
914         }
915
916         ret = func_output->output_get_property(private_output->output_backend, id,
917                                                                                    value);
918
919         _pthread_mutex_unlock(&private_display->lock);
920
921         return ret;
922 }
923
924 static void
925 _tdm_output_thread_cb_vblank(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
926 {
927         tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank *)cb_base;
928         tdm_private_output_vblank_handler *vblank_handler = output_vblank->base.data;
929         tdm_private_output_vblank_handler *v = NULL, *vv = NULL;
930         tdm_private_output *private_output = object;
931         struct list_head clone_list;
932         int interval, sync;
933         pid_t tid = syscall(SYS_gettid);
934
935         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
936
937         assert(vblank_handler->owner_tid == tid);
938
939         vblank_handler->sent_to_frontend = 0;
940
941         _tdm_output_vblank_timeout_update(private_output, 0);
942
943         tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_VBLANK, vblank_handler, _tdm_output_thread_cb_vblank, NULL);
944
945         interval = vblank_handler->interval;
946         sync = vblank_handler->sync;
947
948         LIST_INITHEAD(&clone_list);
949
950         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
951                 if (v->interval != interval || v->sync != sync || v->owner_tid != tid)
952                         continue;
953
954                 LIST_DEL(&v->link);
955                 LIST_ADDTAIL(&v->link, &clone_list);
956         }
957
958         if (tdm_debug_module & TDM_DEBUG_COMMIT)
959                 TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe);
960
961         _pthread_mutex_unlock(&private_display->lock);
962         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) {
963                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
964                         TDM_INFO("handler(%p)", v);
965
966                 LIST_DEL(&v->link);
967
968                 if (v->func)
969                         v->func(v->private_output,
970                                         output_vblank->sequence,
971                                         output_vblank->tv_sec,
972                                         output_vblank->tv_usec,
973                                         v->user_data);
974
975                 free(v);
976         }
977         _pthread_mutex_lock(&private_display->lock);
978
979         if (tdm_debug_module & TDM_DEBUG_COMMIT)
980                 TDM_INFO("-----------------------------------------...");
981 }
982
983 static void
984 _tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
985                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
986 {
987         tdm_private_output_vblank_handler *vblank_handler = user_data;
988         tdm_thread_cb_output_vblank output_vblank;
989         tdm_error ret;
990
991         memset(&output_vblank, 0, sizeof output_vblank);
992         output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
993         output_vblank.base.length = sizeof output_vblank;
994         output_vblank.base.object_stamp = vblank_handler->private_output->stamp;
995         output_vblank.base.data = vblank_handler;
996         output_vblank.base.sync = 0;
997         output_vblank.sequence = sequence;
998         output_vblank.tv_sec = tv_sec;
999         output_vblank.tv_usec = tv_usec;
1000
1001         vblank_handler->sent_to_frontend = 1;
1002
1003         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1004                 TDM_INFO("output(%d) wait_vblank: handler(%p)", vblank_handler->private_output->pipe, vblank_handler);
1005
1006         ret = tdm_thread_cb_call(vblank_handler->private_output, &output_vblank.base, 1);
1007         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1008 }
1009
1010 static void
1011 _tdm_output_thread_cb_commit(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
1012 {
1013         tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit *)cb_base;
1014         tdm_private_output_commit_handler *output_commit_handler = output_commit->base.data;
1015         tdm_private_output *private_output = object;
1016         tdm_private_layer *private_layer = NULL;
1017
1018         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1019
1020         if (!output_commit_handler)
1021                 return;
1022
1023         assert(output_commit_handler->owner_tid == syscall(SYS_gettid));
1024
1025         tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_COMMIT, output_commit_handler, _tdm_output_thread_cb_commit, NULL);
1026
1027         LIST_DEL(&output_commit_handler->link);
1028
1029         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
1030                 TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe);
1031                 TDM_INFO("handler(%p)", output_commit_handler);
1032         }
1033
1034         if (private_output->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
1035                 /* In case of layer commit, the below will be handled in the layer commit callback */
1036                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1037                         if (private_layer->committed_buffer)
1038                                 tdm_layer_committed(private_layer, &private_layer->committed_buffer);
1039                 }
1040         }
1041
1042         if (output_commit_handler->func) {
1043                 _pthread_mutex_unlock(&private_display->lock);
1044                 output_commit_handler->func(private_output,
1045                                                                         output_commit->sequence,
1046                                                                         output_commit->tv_sec,
1047                                                                         output_commit->tv_usec,
1048                                                                         output_commit_handler->user_data);
1049                 _pthread_mutex_lock(&private_display->lock);
1050         }
1051
1052         free(output_commit_handler);
1053
1054         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1055                 TDM_INFO("-----------------------------------------...");
1056 }
1057
1058 static void
1059 _tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
1060                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
1061 {
1062         tdm_private_output_commit_handler *output_commit_handler = user_data;
1063         tdm_private_output *private_output;
1064         tdm_thread_cb_output_commit output_commit;
1065         tdm_error ret;
1066
1067         if (output_commit_handler)
1068                 private_output = output_commit_handler->private_output;
1069         else
1070                 private_output = tdm_display_find_private_output(tdm_display_get(), output_backend);
1071
1072         memset(&output_commit, 0, sizeof output_commit);
1073         output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
1074         output_commit.base.length = sizeof output_commit;
1075         output_commit.base.object_stamp = private_output->stamp;
1076         output_commit.base.data = output_commit_handler;
1077         output_commit.base.sync = 0;
1078         output_commit.sequence = sequence;
1079         output_commit.tv_sec = tv_sec;
1080         output_commit.tv_usec = tv_usec;
1081
1082         ret = tdm_thread_cb_call(private_output, &output_commit.base, 1);
1083         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1084 }
1085
1086 /* add_front: To distinguish between the user vblank handlers and the layer
1087  *            commit vblank handlers. The layer commit handlers will be called
1088  *            before calling the user vblank handlers.
1089  */
1090 static tdm_error
1091 _tdm_output_wait_vblank(tdm_private_output *private_output, int interval, int sync,
1092                                                 tdm_output_vblank_handler func, void *user_data,
1093                                                 unsigned int add_front)
1094 {
1095         tdm_private_module *private_module;
1096         tdm_func_output *func_output;
1097         tdm_private_output_vblank_handler *vblank_handler = NULL, *v = NULL;
1098         unsigned int skip_request = 0;
1099         pid_t tid = syscall(SYS_gettid);
1100         tdm_error ret = TDM_ERROR_NONE;
1101
1102         private_module = private_output->private_module;
1103         func_output = &private_module->func_output;
1104
1105         /* interval SHOULD be at least 1 */
1106         if (interval <= 0)
1107                 interval = 1;
1108
1109         if (!func_output->output_wait_vblank) {
1110                 /* LCOV_EXCL_START */
1111                 TDM_WRN("not implemented!!");
1112                 return TDM_ERROR_NOT_IMPLEMENTED;
1113                 /* LCOV_EXCL_STOP */
1114         }
1115
1116         if (!private_output->regist_vblank_cb) {
1117                 private_output->regist_vblank_cb = 1;
1118                 ret = func_output->output_set_vblank_handler(private_output->output_backend,
1119                                 _tdm_output_cb_vblank);
1120         }
1121
1122         vblank_handler = calloc(1, sizeof(tdm_private_output_vblank_handler));
1123         if (!vblank_handler) {
1124                 /* LCOV_EXCL_START */
1125                 TDM_ERR("failed: alloc memory");
1126                 return TDM_ERROR_OUT_OF_MEMORY;
1127                 /* LCOV_EXCL_STOP */
1128         }
1129
1130         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1131                 TDM_INFO("output(%d) wait_vblank: handler(%p)", private_output->pipe, vblank_handler);
1132
1133         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
1134                 if (v->interval == interval && v->sync == sync && v->owner_tid == tid) {
1135                         skip_request = 1;
1136                         break;
1137                 }
1138         }
1139
1140         if (add_front)
1141                 LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list);
1142         else
1143                 LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list);
1144
1145         vblank_handler->private_output = private_output;
1146         vblank_handler->interval = interval;
1147         vblank_handler->sync = sync;
1148         vblank_handler->func = func;
1149         vblank_handler->user_data = user_data;
1150         vblank_handler->owner_tid = tid;
1151
1152         /* If there is the previous request, we can skip to call output_wait_vblank() */
1153         if (!skip_request) {
1154                 ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_VBLANK, vblank_handler, _tdm_output_thread_cb_vblank, NULL);
1155                 if (ret != TDM_ERROR_NONE) {
1156                         TDM_ERR("tdm_thread_cb_add failed");
1157                         goto wait_failed;
1158                 }
1159
1160                 ret = func_output->output_wait_vblank(private_output->output_backend, interval,
1161                                                                                           sync, vblank_handler);
1162                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
1163
1164                 _tdm_output_vblank_timeout_update(private_output, 1000);
1165
1166                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
1167                         TDM_INFO("output(%d) backend wait_vblank", private_output->pipe);
1168         }
1169
1170         return ret;
1171
1172 wait_failed:
1173         /* LCOV_EXCL_START */
1174         if (vblank_handler) {
1175                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_VBLANK, vblank_handler, _tdm_output_thread_cb_vblank, NULL);
1176                 LIST_DEL(&vblank_handler->link);
1177                 free(vblank_handler);
1178         }
1179         return ret;
1180         /* LCOV_EXCL_STOP */
1181 }
1182
1183 EXTERN tdm_error
1184 tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
1185                                            tdm_output_vblank_handler func, void *user_data)
1186 {
1187         OUTPUT_FUNC_ENTRY();
1188         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1189
1190         _pthread_mutex_lock(&private_display->lock);
1191
1192         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
1193                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
1194                                 tdm_dpms_str(private_output->current_dpms_value));
1195                 _pthread_mutex_unlock(&private_display->lock);
1196                 return TDM_ERROR_DPMS_OFF;
1197         }
1198
1199         ret = _tdm_output_wait_vblank(private_output, interval, sync, func, user_data, 0);
1200
1201         _pthread_mutex_unlock(&private_display->lock);
1202
1203         return ret;
1204 }
1205
1206 /* LCOV_EXCL_START */
1207 EXTERN tdm_error
1208 tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync,
1209                                                                  tdm_output_vblank_handler func, void *user_data)
1210 {
1211         OUTPUT_FUNC_ENTRY();
1212
1213         _pthread_mutex_lock(&private_display->lock);
1214
1215         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
1216                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
1217                                 tdm_dpms_str(private_output->current_dpms_value));
1218                 _pthread_mutex_unlock(&private_display->lock);
1219                 return TDM_ERROR_DPMS_OFF;
1220         }
1221
1222         ret = _tdm_output_wait_vblank(private_output, interval, sync, func, user_data, 1);
1223
1224         _pthread_mutex_unlock(&private_display->lock);
1225
1226         return ret;
1227 }
1228 /* LCOV_EXCL_STOP */
1229
1230 INTERN void
1231 tdm_output_remove_vblank_handler_internal(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
1232 {
1233         tdm_private_output *private_output = (tdm_private_output*)output;
1234         tdm_private_output_vblank_handler *v = NULL;
1235
1236         TDM_RETURN_IF_FAIL(private_output != NULL);
1237         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1238
1239         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
1240                 if (v->func == func && v->user_data == user_data) {
1241                         /* only set func & user_data to NULL. It will be freed when an event occurs */
1242                         v->func = NULL;
1243                         v->user_data = NULL;
1244                         break;
1245                 }
1246         }
1247 }
1248
1249 INTERN void
1250 tdm_output_remove_commit_handler_internal(tdm_output *output, tdm_output_commit_handler func, void *user_data)
1251 {
1252         tdm_private_output *private_output = (tdm_private_output*)output;
1253         tdm_private_output_commit_handler *c = NULL;
1254
1255         TDM_RETURN_IF_FAIL(private_output != NULL);
1256         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1257
1258         LIST_FOR_EACH_ENTRY(c, &private_output->output_commit_handler_list, link) {
1259                 if (c->func == func && c->user_data == user_data) {
1260                         /* only set func & user_data to NULL. It will be freed when an event occurs */
1261                         c->func = NULL;
1262                         c->user_data = NULL;
1263                         break;
1264                 }
1265         }
1266 }
1267
1268 EXTERN tdm_error
1269 tdm_output_remove_vblank_handler(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
1270 {
1271         OUTPUT_FUNC_ENTRY();
1272
1273         _pthread_mutex_lock(&private_display->lock);
1274
1275         tdm_output_remove_vblank_handler_internal(output, func, user_data);
1276
1277         _pthread_mutex_unlock(&private_display->lock);
1278
1279         return ret;
1280 }
1281
1282 EXTERN tdm_error
1283 tdm_output_remove_commit_handler(tdm_output *output, tdm_output_commit_handler func, void *user_data)
1284 {
1285         OUTPUT_FUNC_ENTRY();
1286
1287         _pthread_mutex_lock(&private_display->lock);
1288
1289         tdm_output_remove_commit_handler_internal(output, func, user_data);
1290
1291         _pthread_mutex_unlock(&private_display->lock);
1292
1293         return ret;
1294 }
1295
1296 INTERN void
1297 tdm_output_call_mode_set_request(tdm_output *output, unsigned int index)
1298 {
1299         tdm_private_output *private_output = (tdm_private_output*)output;
1300         tdm_private_output_mode_change_handler *mode_change_handler = NULL;
1301
1302         TDM_RETURN_IF_FAIL(private_output != NULL);
1303         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1304
1305         if (LIST_IS_EMPTY(&private_output->mode_change_request_handler_list))
1306                 return;
1307
1308         LIST_FOR_EACH_ENTRY(mode_change_handler, &private_output->mode_change_request_handler_list, link) {
1309                 mode_change_handler->func(mode_change_handler->private_output, index, mode_change_handler->user_data);
1310         }
1311 }
1312
1313 tdm_error
1314 _tdm_output_commit_virtual(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data)
1315 {
1316         tdm_private_output *private_output;
1317         tdm_private_output_commit_handler *output_commit_handler = NULL;
1318         tdm_private_layer *private_layer = NULL;
1319         tdm_private_display *private_display;
1320         tbm_surface_h buffer;
1321         tdm_error ret = TDM_ERROR_NONE;
1322
1323         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1324
1325         private_output = (tdm_private_output*)output;
1326         private_display = private_output->private_display;
1327
1328         if (!LIST_IS_EMPTY(&private_output->output_commit_handler_list)) {
1329                 /* support only 1 commit */
1330                 TDM_ERR("voutput canot commit while commiting");
1331                 return TDM_ERROR_OPERATION_FAILED;
1332         }
1333
1334         output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler));
1335         if (!output_commit_handler) {
1336                 /* LCOV_EXCL_START */
1337                 TDM_ERR("failed: alloc memory");
1338                 return TDM_ERROR_OUT_OF_MEMORY;
1339                 /* LCOV_EXCL_STOP */
1340         }
1341
1342         LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list);
1343         output_commit_handler->private_output = private_output;
1344         output_commit_handler->func = func;
1345         output_commit_handler->user_data = user_data;
1346         output_commit_handler->owner_tid = syscall(SYS_gettid);
1347
1348         /* voutput use only 1 layer */
1349         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1350                 if (private_layer) break;
1351         }
1352         TDM_GOTO_IF_FAIL(private_layer, commit_failed);
1353
1354         buffer = private_layer->commiting_buffer;
1355         TDM_GOTO_IF_FAIL(buffer != NULL, commit_failed);
1356
1357         _pthread_mutex_unlock(&private_display->lock);
1358         ret = tdm_output_attach_buffer(private_output, buffer);
1359         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1360         ret = tdm_output_commit_buffer(private_output);
1361         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1362         _pthread_mutex_lock(&private_display->lock);
1363
1364         return ret;
1365
1366 commit_failed:
1367         /* LCOV_EXCL_START */
1368         if (output_commit_handler) {
1369                 LIST_DEL(&output_commit_handler->link);
1370                 free(output_commit_handler);
1371         }
1372         return ret;
1373 /* LCOV_EXCL_STOP */
1374 }
1375
1376 INTERN tdm_error
1377 tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data)
1378 {
1379         tdm_private_display *private_display;
1380         tdm_private_output *private_output;
1381         tdm_private_module *private_module;
1382         tdm_func_output *func_output;
1383         tdm_private_output_commit_handler *output_commit_handler = NULL;
1384         tdm_private_layer *private_layer = NULL;
1385         tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
1386         tdm_error ret = TDM_ERROR_NONE;
1387
1388         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1389
1390         private_output = (tdm_private_output*)output;
1391         private_module = private_output->private_module;
1392         private_display = private_module->private_display;
1393         func_output = &private_module->func_output;
1394
1395         if (private_module == private_display->virtual_module)
1396                 return _tdm_output_commit_virtual(output, sync, func, user_data);
1397
1398         if (!func_output->output_commit) {
1399                 /* LCOV_EXCL_START */
1400                 TDM_WRN("not implemented!!");
1401                 return TDM_ERROR_NOT_IMPLEMENTED;
1402                 /* LCOV_EXCL_STOP */
1403         }
1404
1405         ret = tdm_output_get_dpms_internal(output, &dpms_value);
1406         TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1407
1408         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) {
1409                 if (!private_output->regist_commit_cb) {
1410                         private_output->regist_commit_cb = 1;
1411                         ret = func_output->output_set_commit_handler(private_output->output_backend, _tdm_output_cb_commit);
1412                         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1413                 }
1414
1415                 output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler));
1416                 if (!output_commit_handler) {
1417                         /* LCOV_EXCL_START */
1418                         TDM_ERR("failed: alloc memory");
1419                         return TDM_ERROR_OUT_OF_MEMORY;
1420                         /* LCOV_EXCL_STOP */
1421                 }
1422
1423                 ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_COMMIT, output_commit_handler, _tdm_output_thread_cb_commit, NULL);
1424                 if (ret != TDM_ERROR_NONE) {
1425                         TDM_ERR("tdm_thread_cb_add failed");
1426                         free(output_commit_handler);
1427                         return ret;
1428                 }
1429
1430                 LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list);
1431                 output_commit_handler->private_output = private_output;
1432                 output_commit_handler->func = func;
1433                 output_commit_handler->user_data = user_data;
1434                 output_commit_handler->owner_tid = syscall(SYS_gettid);
1435
1436                 ret = func_output->output_commit(private_output->output_backend, sync,
1437                                 output_commit_handler);
1438                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1439
1440                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
1441                         TDM_INFO("output(%d) backend commit: handle(%p) func(%p) user_data(%p)",
1442                                         private_output->pipe, output_commit_handler, func, user_data);
1443         }
1444
1445         /* Even if DPMS is off, committed_buffer should be changed because it will be referred
1446          * for tdm_layer_committed() function.
1447          */
1448         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1449                 if (!private_layer->waiting_buffer)
1450                         continue;
1451
1452                 if (private_layer->committed_buffer) {
1453                         tdm_layer_free_buffer(private_layer, private_layer->committed_buffer);
1454                         private_layer->committed_buffer = NULL;
1455                         if (tdm_debug_module & TDM_DEBUG_BUFFER)
1456                                 TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)",
1457                                                  private_layer, private_layer->waiting_buffer->buffer,
1458                                                  private_layer->committed_buffer);
1459                 }
1460
1461                 private_layer->committed_buffer = private_layer->waiting_buffer;
1462                 private_layer->waiting_buffer = NULL;
1463                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
1464                         TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)",
1465                                          private_layer, private_layer->waiting_buffer,
1466                                          private_layer->committed_buffer->buffer);
1467         }
1468
1469         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) {
1470                 TDM_WRN("dpms %s. Directly call commit handler instead of commit.", tdm_dpms_str(dpms_value));
1471                 if (func)
1472                         func(output, 0, 0, 0, user_data);
1473         }
1474
1475         return ret;
1476
1477 commit_failed:
1478         /* LCOV_EXCL_START */
1479         if (output_commit_handler) {
1480                 tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_COMMIT, output_commit_handler, _tdm_output_thread_cb_commit, NULL);
1481                 LIST_DEL(&output_commit_handler->link);
1482                 free(output_commit_handler);
1483         }
1484         return ret;
1485         /* LCOV_EXCL_STOP */
1486 }
1487
1488 EXTERN tdm_error
1489 tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
1490                                   void *user_data)
1491 {
1492         tdm_private_layer *private_layer = NULL;
1493
1494         OUTPUT_FUNC_ENTRY();
1495
1496         _pthread_mutex_lock(&private_display->lock);
1497
1498         if (private_output->commit_type == TDM_COMMIT_TYPE_NONE)
1499                 private_output->commit_type = TDM_COMMIT_TYPE_OUTPUT;
1500         else if (private_output->commit_type == TDM_COMMIT_TYPE_LAYER) {
1501                 TDM_ERR("Can't supported. Use tdm_layer_commit");
1502                 _pthread_mutex_unlock(&private_display->lock);
1503                 return TDM_ERROR_BAD_REQUEST;
1504         }
1505
1506         if (private_output->commit_per_vblank) {
1507                 TDM_ERR("Use tdm_layer_commit");
1508                 _pthread_mutex_unlock(&private_display->lock);
1509                 return TDM_ERROR_BAD_REQUEST;
1510         }
1511
1512         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
1513                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
1514                                 tdm_dpms_str(private_output->current_dpms_value));
1515                 _pthread_mutex_unlock(&private_display->lock);
1516                 return TDM_ERROR_DPMS_OFF;
1517         }
1518
1519         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1520                 TDM_INFO("output(%d) commit", private_output->pipe);
1521
1522         /* apply the pending data of all layers */
1523         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1524                 tdm_layer_commit_pending_data(private_layer);
1525         }
1526
1527         ret = tdm_output_commit_internal(output, sync, func, user_data);
1528
1529         _pthread_mutex_unlock(&private_display->lock);
1530
1531         return ret;
1532 }
1533
1534 EXTERN tdm_error
1535 tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1536 {
1537         tdm_private_module *private_module;
1538         tdm_func_output *func_output;
1539         OUTPUT_FUNC_ENTRY();
1540
1541         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1542
1543         _pthread_mutex_lock(&private_display->lock);
1544
1545         private_module = private_output->private_module;
1546         func_output = &private_module->func_output;
1547
1548         if (!func_output->output_set_mode) {
1549                 /* LCOV_EXCL_START */
1550                 _pthread_mutex_unlock(&private_display->lock);
1551                 TDM_WRN("not implemented!!");
1552                 return TDM_ERROR_NOT_IMPLEMENTED;
1553                 /* LCOV_EXCL_STOP */
1554         }
1555
1556         ret = func_output->output_set_mode(private_output->output_backend, mode);
1557         if (ret == TDM_ERROR_NONE) {
1558                 private_output->current_mode = mode;
1559                 private_output->need_set_target_info = 1;
1560                 TDM_INFO("mode: %dx%d %dhz", mode->hdisplay, mode->vdisplay, mode->vrefresh);
1561         }
1562
1563         _pthread_mutex_unlock(&private_display->lock);
1564
1565         return ret;
1566 }
1567
1568 EXTERN tdm_error
1569 tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1570 {
1571         OUTPUT_FUNC_ENTRY();
1572
1573         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1574
1575         _pthread_mutex_lock(&private_display->lock);
1576
1577         *mode = private_output->current_mode;
1578
1579         _pthread_mutex_unlock(&private_display->lock);
1580
1581         return ret;
1582 }
1583
1584 EXTERN tdm_error
1585 tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1586 {
1587         tdm_private_module *private_module;
1588         tdm_func_output *func_output;
1589         OUTPUT_FUNC_ENTRY();
1590
1591         if (dpms_value > TDM_OUTPUT_DPMS_OFF) {
1592                 if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) {
1593                         TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value);
1594                         return TDM_ERROR_BAD_REQUEST;
1595                 }
1596
1597                 if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) {
1598                         TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'",
1599                                         private_output->pipe, tdm_dpms_str(dpms_value));
1600                         return TDM_ERROR_BAD_REQUEST;
1601                 }
1602         }
1603
1604         _pthread_mutex_lock(&private_display->lock);
1605
1606         if (private_output->waiting_dpms_change) {
1607                 TDM_ERR("DPMS is not changed yet. Can't be changed twice");
1608                 _pthread_mutex_unlock(&private_display->lock);
1609                 return TDM_ERROR_BAD_REQUEST;
1610         }
1611
1612         private_module = private_output->private_module;
1613         func_output = &private_module->func_output;
1614
1615         TDM_INFO("output(%d) dpms '%s'", private_output->pipe, tdm_dpms_str(dpms_value));
1616
1617         if (func_output->output_set_dpms)
1618                 ret = func_output->output_set_dpms(private_output->output_backend, dpms_value);
1619         else {
1620                 /* LCOV_EXCL_START */
1621                 ret = TDM_ERROR_NONE;
1622                 TDM_WRN("not implemented!!");
1623                 goto done;
1624                 /* LCOV_EXCL_STOP */
1625         }
1626
1627 done:
1628         if (ret == TDM_ERROR_NONE) {
1629                 if (private_output->current_dpms_value != dpms_value) {
1630                         private_output->current_dpms_value = dpms_value;
1631                         _tdm_output_call_thread_cb_dpms(private_output, dpms_value);
1632                 }
1633                 TDM_INFO("output(%d) dpms '%s' done", private_output->pipe, tdm_dpms_str(dpms_value));
1634         } else {
1635                 tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF;
1636
1637                 /* update current_dpms_value forcely */
1638                 tdm_output_get_dpms_internal(output, &temp);
1639
1640                 TDM_ERR("output(%d) set_dpms failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp));
1641         }
1642
1643         _pthread_mutex_unlock(&private_display->lock);
1644
1645         return ret;
1646 }
1647
1648 /* LCOV_EXCL_START */
1649 EXTERN tdm_error
1650 tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value)
1651 {
1652         tdm_private_module *private_module;
1653         tdm_func_output *func_output;
1654         OUTPUT_FUNC_ENTRY();
1655
1656         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_ASYNC_DPMS)) {
1657                 TDM_ERR("output doesn't support the asynchronous DPMS control!");
1658                 return TDM_ERROR_BAD_REQUEST;
1659         }
1660
1661         if (dpms_value > TDM_OUTPUT_DPMS_OFF) {
1662                 if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) {
1663                         TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value);
1664                         return TDM_ERROR_BAD_REQUEST;
1665                 }
1666
1667                 if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) {
1668                         TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'",
1669                                         private_output->pipe, tdm_dpms_str(dpms_value));
1670                         return TDM_ERROR_BAD_REQUEST;
1671                 }
1672         }
1673
1674         _pthread_mutex_lock(&private_display->lock);
1675
1676         if (private_output->waiting_dpms_change) {
1677                 TDM_ERR("DPMS is not changed yet. Can't be changed twice");
1678                 _pthread_mutex_unlock(&private_display->lock);
1679                 return TDM_ERROR_BAD_REQUEST;
1680         }
1681
1682         private_module = private_output->private_module;
1683         func_output = &private_module->func_output;
1684         if (!func_output->output_set_dpms_handler) {
1685                 TDM_WRN("not implemented: output_set_dpms_handler");
1686                 _pthread_mutex_unlock(&private_display->lock);
1687                 return TDM_ERROR_NOT_IMPLEMENTED;
1688         }
1689
1690         if (!func_output->output_set_dpms_async) {
1691                 TDM_WRN("not implemented: output_set_dpms_async");
1692                 _pthread_mutex_unlock(&private_display->lock);
1693                 return TDM_ERROR_NOT_IMPLEMENTED;
1694         }
1695
1696         if (!private_output->regist_dpms_cb) {
1697                 private_output->regist_dpms_cb = 1;
1698                 ret = func_output->output_set_dpms_handler(private_output->output_backend,
1699                                 tdm_output_cb_dpms, private_output);
1700                 if (ret != TDM_ERROR_NONE) {
1701                         _pthread_mutex_unlock(&private_display->lock);
1702                         TDM_ERR("Can't set the dpms handler!!");
1703                         return ret;
1704                 }
1705         }
1706
1707         TDM_INFO("output(%d) dpms async '%s'", private_output->pipe, tdm_dpms_str(dpms_value));
1708
1709         ret = func_output->output_set_dpms_async(private_output->output_backend, dpms_value);
1710
1711         if (ret == TDM_ERROR_NONE) {
1712                 private_output->waiting_dpms_change = 1;
1713                 TDM_INFO("output(%d) dpms async '%s' waiting", private_output->pipe, tdm_dpms_str(dpms_value));
1714         } else {
1715                 tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF;
1716
1717                 /* update current_dpms_value forcely */
1718                 tdm_output_get_dpms_internal(output, &temp);
1719
1720                 TDM_ERR("output(%d) set_dpms_async failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp));
1721         }
1722
1723         _pthread_mutex_unlock(&private_display->lock);
1724
1725         return ret;
1726 }
1727 /* LCOV_EXCL_STOP */
1728
1729 INTERN tdm_error
1730 tdm_output_get_dpms_internal(tdm_output *output, tdm_output_dpms *dpms_value)
1731 {
1732         tdm_private_output *private_output;
1733         tdm_private_module *private_module;
1734         tdm_func_output *func_output;
1735         tdm_error ret = TDM_ERROR_NONE;
1736
1737         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1738
1739         private_output = (tdm_private_output*)output;
1740
1741         /* TODO: this is ugly. But before calling backend's output_get_dpms(), we have
1742          * to check if all backends's DPMS operation has no problem. In future, we'd
1743          * better use new env instead of using commit_per_vblank variable to distinguish
1744          * whether we use the stored value or backend's output_get_dpms.
1745          */
1746         if (!private_output->commit_per_vblank) {
1747                 *dpms_value = private_output->current_dpms_value;
1748                 return TDM_ERROR_NONE;
1749         }
1750
1751         private_module = private_output->private_module;
1752         func_output = &private_module->func_output;
1753
1754         if (!func_output->output_get_dpms) {
1755                 /* LCOV_EXCL_START */
1756                 *dpms_value = private_output->current_dpms_value;
1757                 TDM_WRN("not implemented!!");
1758                 return TDM_ERROR_NONE;
1759                 /* LCOV_EXCL_STOP */
1760         }
1761
1762         ret = func_output->output_get_dpms(private_output->output_backend, dpms_value);
1763         if (ret != TDM_ERROR_NONE) {
1764                 /* LCOV_EXCL_START */
1765                 TDM_ERR("output_get_dpms failed");
1766                 *dpms_value = TDM_OUTPUT_DPMS_OFF;
1767                 /* LCOV_EXCL_STOP */
1768         }
1769
1770         /* checking with backend's value */
1771         if (*dpms_value != private_output->current_dpms_value) {
1772                 TDM_ERR("output(%d) dpms changed suddenly: %s -> %s",
1773                                 private_output->pipe, tdm_dpms_str(private_output->current_dpms_value),
1774                                 tdm_dpms_str(*dpms_value));
1775                 private_output->current_dpms_value = *dpms_value;
1776                 _tdm_output_call_thread_cb_dpms(private_output, *dpms_value);
1777         }
1778
1779         return ret;
1780 }
1781
1782 EXTERN tdm_error
1783 tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1784 {
1785         OUTPUT_FUNC_ENTRY();
1786
1787         TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER);
1788
1789         _pthread_mutex_lock(&private_display->lock);
1790
1791         ret = tdm_output_get_dpms_internal(output, dpms_value);
1792
1793         _pthread_mutex_unlock(&private_display->lock);
1794
1795         return ret;
1796 }
1797
1798 EXTERN tdm_error
1799 tdm_output_has_capture_capability(tdm_output *output, unsigned int *has_capability)
1800 {
1801         tdm_private_module *private_module;
1802
1803         OUTPUT_FUNC_ENTRY();
1804
1805         TDM_RETURN_VAL_IF_FAIL(has_capability != NULL, TDM_ERROR_INVALID_PARAMETER);
1806
1807         _pthread_mutex_lock(&private_display->lock);
1808
1809         private_module = private_output->private_module;
1810
1811         if (!(private_module->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
1812                 *has_capability = 0;
1813         else if (!(private_module->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT))
1814                 *has_capability = 0;
1815         else
1816                 *has_capability = 1;
1817
1818         _pthread_mutex_unlock(&private_display->lock);
1819
1820         return ret;
1821 }
1822
1823 EXTERN tdm_capture *
1824 tdm_output_create_capture(tdm_output *output, tdm_error *error)
1825 {
1826         tdm_capture *capture = NULL;
1827
1828         OUTPUT_FUNC_ENTRY_ERROR();
1829
1830         _pthread_mutex_lock(&private_display->lock);
1831
1832         capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error);
1833
1834         _pthread_mutex_unlock(&private_display->lock);
1835
1836         return capture;
1837 }
1838
1839 EXTERN tdm_hwc *
1840 tdm_output_get_hwc(tdm_output *output, tdm_error *error)
1841 {
1842         tdm_private_hwc *private_hwc = NULL;
1843
1844         OUTPUT_FUNC_ENTRY_ERROR();
1845
1846         _pthread_mutex_lock(&private_display->lock);
1847
1848         private_hwc = private_output->private_hwc;
1849         if (!private_hwc) {
1850                 if (error)
1851                         *error = TDM_ERROR_BAD_REQUEST;
1852                 _pthread_mutex_unlock(&private_display->lock);
1853                 return NULL;
1854         }
1855
1856         if (error)
1857                 *error = TDM_ERROR_NONE;
1858
1859         _pthread_mutex_unlock(&private_display->lock);
1860
1861         return private_hwc;
1862 }
1863
1864 INTERN tdm_error
1865 tdm_output_choose_commit_per_vblank_mode(tdm_private_output *private_output, int mode)
1866 {
1867         if (!private_output)
1868                 return TDM_ERROR_INVALID_PARAMETER;
1869
1870         if (mode < 0 || mode > 2)
1871                 return TDM_ERROR_INVALID_PARAMETER;
1872
1873         private_output->commit_per_vblank = mode;
1874
1875         if (private_output->commit_per_vblank == 0)
1876                 TDM_INFO("commit per vblank: disable");
1877         else if (private_output->commit_per_vblank == 1)
1878                 TDM_INFO("commit per vblank: enable (1 layer)");
1879         else if (private_output->commit_per_vblank == 2)
1880                 TDM_INFO("commit per vblank: enable (previous commit)");
1881
1882         return TDM_ERROR_NONE;
1883 }
1884
1885 INTERN tdm_error
1886 tdm_output_set_available_mode(tdm_output *output, const tdm_output_mode *modes, int count)
1887 {
1888         tdm_private_module *private_module = NULL;
1889         tdm_func_output *func_output = NULL;
1890
1891         OUTPUT_FUNC_ENTRY();
1892
1893         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
1894         TDM_RETURN_VAL_IF_FAIL(count != 0, TDM_ERROR_INVALID_PARAMETER);
1895
1896         private_module = private_output->private_module;
1897         TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
1898
1899         _pthread_mutex_lock(&private_display->lock);
1900
1901         func_output = &private_module->func_output;
1902         if (func_output->output_set_available_mode)
1903                 ret = func_output->output_set_available_mode(private_output->output_backend, modes, count);
1904
1905         _pthread_mutex_unlock(&private_display->lock);
1906
1907         return ret;
1908 }
1909
1910 INTERN tdm_error
1911 tdm_output_set_physical_size(tdm_output *output,  unsigned int mmwidth, unsigned int mmheight)
1912 {
1913         tdm_private_module *private_module = NULL;
1914         tdm_func_output *func_output = NULL;
1915
1916         OUTPUT_FUNC_ENTRY();
1917
1918         TDM_RETURN_VAL_IF_FAIL(mmwidth != 0, TDM_ERROR_INVALID_PARAMETER);
1919         TDM_RETURN_VAL_IF_FAIL(mmheight != 0, TDM_ERROR_INVALID_PARAMETER);
1920
1921         private_module = private_output->private_module;
1922         TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
1923
1924         _pthread_mutex_lock(&private_display->lock);
1925
1926         func_output = &private_module->func_output;
1927         if (func_output->output_set_physical_size)
1928                 ret = func_output->output_set_physical_size(private_output->output_backend, mmwidth, mmheight);
1929
1930         _pthread_mutex_unlock(&private_display->lock);
1931
1932         return ret;
1933 }
1934
1935 INTERN tdm_error
1936 tdm_output_set_connect(tdm_output *output)
1937 {
1938         tdm_private_module *private_module = NULL;
1939         tdm_func_output *func_output = NULL;
1940
1941         OUTPUT_FUNC_ENTRY();
1942
1943         private_module = private_output->private_module;
1944         TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
1945
1946         _pthread_mutex_lock(&private_display->lock);
1947
1948         func_output = &private_module->func_output;
1949         if (func_output->output_set_connect)
1950                 ret = func_output->output_set_connect(private_output->output_backend);
1951
1952         _pthread_mutex_unlock(&private_display->lock);
1953
1954         return ret;
1955 }
1956
1957 INTERN tdm_error
1958 tdm_output_set_disconnect(tdm_output *output)
1959 {
1960         tdm_private_module *private_module = NULL;
1961         tdm_func_output *func_output = NULL;
1962
1963         OUTPUT_FUNC_ENTRY();
1964
1965         private_module = private_output->private_module;
1966         TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE);
1967
1968         _pthread_mutex_lock(&private_display->lock);
1969
1970         func_output = &private_module->func_output;
1971         if (func_output->output_set_disconnect)
1972                 ret = func_output->output_set_disconnect(private_output->output_backend);
1973
1974         _pthread_mutex_unlock(&private_display->lock);
1975
1976         return ret;
1977 }
1978
1979 INTERN tdm_error
1980 tdm_output_commit_done(tdm_output *output, tbm_surface_h buffer)
1981 {
1982         tdm_private_layer *private_layer = NULL;
1983         tdm_private_output_commit_handler *output_commit_handler = NULL;
1984         static int sequence = 0;
1985         tdm_private_output *private_output;
1986         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); \
1987         private_output = (tdm_private_output*)output;
1988
1989         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1990                 if (private_layer) break;
1991         }
1992
1993         private_layer->commiting_buffer = NULL;
1994
1995         LIST_FOR_EACH_ENTRY(output_commit_handler, &private_output->output_commit_handler_list, link) {
1996                 if (output_commit_handler) break;
1997         }
1998         TDM_RETURN_VAL_IF_FAIL(output_commit_handler, TDM_ERROR_INVALID_PARAMETER);
1999
2000         LIST_DEL(&output_commit_handler->link);
2001
2002         output_commit_handler->func(private_output,
2003                                                                 sequence++,
2004                                                                 0, 0,
2005                                                                 output_commit_handler->user_data);
2006         free(output_commit_handler);
2007
2008         return TDM_ERROR_NONE;
2009 }
2010 /* LCOV_EXCL_STOP */