Merge branch 'tizen' into sandbox/cyeon/devel
[platform/core/uifw/libtdm.git] / client / tdm_client.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 #define WL_HIDE_DEPRECATED
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <time.h>
46 #include <strings.h>
47 #include <poll.h>
48
49 #include <tdm-client-protocol.h>
50
51 #include "tdm_client.h"
52 #include "tdm_log.h"
53 #include "tdm_macro.h"
54 #include "tdm_list.h"
55 #include "tdm.h"
56 #include "tdm_private.h"
57 #include <tbm_surface_internal.h>
58
59 #define TDM_ARRAY_NTH_DATA(array, type, n) (((type*)((array)->data)) + n)
60
61 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
62 typedef struct _tdm_private_client_voutput tdm_private_client_voutput;
63
64 typedef struct _tdm_private_client {
65         pthread_mutex_t lock;
66
67         struct wl_display *display;
68         struct wl_event_queue *queue;
69         struct wl_registry *registry;
70         struct wl_tdm *tdm;
71         struct list_head output_list;
72         struct list_head voutput_list;
73
74         unsigned int enable_ttrace;
75         unsigned int stamp;
76
77         tdm_private_client_vblank *temp_vblank;
78 } tdm_private_client;
79
80 typedef struct _tdm_private_client_output {
81         struct list_head link;
82
83         tdm_private_client *private_client;
84
85         char name[TDM_NAME_LEN];
86         struct wl_tdm_output *output;
87         int width;
88         int height;
89         int refresh;
90         tdm_output_conn_status connection;
91         tdm_output_dpms dpms;
92         struct list_head vblank_list;
93         struct list_head change_handler_list;
94
95         unsigned int req_id;
96         unsigned int watch_output_changes;
97
98         tdm_private_client_voutput *voutput;
99 } tdm_private_client_output;
100
101 typedef struct _tdm_private_client_buffer {
102         struct list_head link;
103         struct wl_buffer *wl_buffer;
104 } tdm_private_client_buffer;
105
106 struct _tdm_private_client_voutput {
107         struct list_head link;
108         struct wl_tdm_voutput *wl_voutput;
109         struct list_head commit_handler_list;
110
111         struct {
112                 int count;
113                 tdm_client_output_mode *modes;
114         } available_modes;
115
116         unsigned int mmwidth;
117         unsigned int mmheight;
118
119         uint32_t msg;
120
121         struct list_head buffer_list;
122         tbm_bufmgr bufmgr;
123         tdm_private_client_buffer *attach_buffer;
124
125         tdm_private_client *private_client;
126         tdm_private_client_output *private_output;
127         char name[TDM_NAME_LEN];
128         int get_output;
129 };
130
131 struct _tdm_private_client_vblank {
132         tdm_private_client_output *private_output;
133
134         struct wl_tdm_vblank *vblank;
135         struct list_head wait_list;
136
137         char name[TDM_NAME_LEN];
138         unsigned int sync;
139         unsigned int fps;
140         int offset;
141         unsigned int enable_fake;
142         unsigned int enable_ttrace;
143
144         unsigned int started;
145         unsigned int stamp;
146
147         double req_time;
148         double last_time;
149
150         struct list_head link;
151 };
152
153 typedef struct _tdm_client_output_handler_info {
154         tdm_private_client_output *private_output;
155
156         tdm_client_output_change_handler func;
157         void *user_data;
158
159         struct list_head link;
160         struct list_head call_link;
161 } tdm_client_output_handler_info;
162
163 typedef struct _tdm_client_wait_info {
164         tdm_private_client_vblank *private_vblank;
165
166         tdm_client_vblank_handler func;
167         void *user_data;
168
169         unsigned int req_id;
170         double req_time;
171         int need_free;
172
173         struct list_head link;
174         struct list_head call_link;
175 } tdm_client_wait_info;
176
177 typedef struct _tdm_client_voutput_commit_handler_info {
178         tdm_private_client_voutput *private_voutput;
179
180         tdm_client_voutput_commit_handler func;
181         void *user_data;
182
183         struct list_head link;
184         struct list_head call_link;
185 } tdm_client_voutput_commit_handler_info;
186
187 static unsigned int
188 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
189 {
190         uint32_t ec, id;
191         const struct wl_interface *intf;
192         int err;
193
194         err = wl_display_get_error(private_client->display);
195         if (!err)
196                 return false;
197
198         if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
199                 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
200                 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
201                                 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
202         } else {
203                 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
204         }
205
206         return true;
207 }
208
209 #define CHECK_WL_PROTOCOL_ERROR(pc)  _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
210
211 static void
212 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
213 {
214         tdm_private_client_vblank *private_vblank = data;
215         tdm_private_client *private_client;
216
217         TDM_RETURN_IF_FAIL(private_vblank != NULL);
218
219         private_vblank->stamp = stamp;
220
221         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
222         private_client = private_vblank->private_output->private_client;
223
224         private_client->stamp = stamp;
225 }
226
227 /* LCOV_EXCL_START */
228 static int
229 _tdm_client_vblank_wait_list_validation_check(tdm_private_client_vblank *private_vblank)
230 {
231         if (private_vblank->wait_list.next == NULL || private_vblank->wait_list.prev == NULL) {
232                 TDM_ERR("vblank(%p) wait_list broken. prev(%p), next(%p) pid(%d)",
233                         private_vblank, private_vblank->wait_list.prev, private_vblank->wait_list.next, getpid());
234         }
235
236         return 0;
237 }
238
239 static void
240 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
241                                                    uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
242                                                    uint32_t tv_usec, uint32_t error)
243 {
244         tdm_private_client_vblank *private_vblank = data;
245         tdm_private_client *private_client;
246         tdm_client_wait_info *w = NULL, *wait_info = NULL;
247
248         TDM_RETURN_IF_FAIL(private_vblank != NULL);
249
250         private_client = private_vblank->private_output->private_client;
251
252         private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
253
254         TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
255                         private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
256
257         _tdm_client_vblank_wait_list_validation_check(private_vblank);
258
259         LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
260                 if (w->req_id != req_id)
261                         continue;
262
263                 wait_info = w;
264                 break;
265         }
266
267         if (!wait_info) {
268                 TDM_ERR("no wait infomation for req_id(%d)", req_id);
269                 return;
270         }
271
272         if (private_vblank->enable_ttrace)
273                 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
274
275         if (wait_info->req_time >= private_vblank->last_time)
276                 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
277
278         if (wait_info->need_free)
279                 LIST_DEL(&wait_info->link);
280
281         if (wait_info->func) {
282                 pthread_mutex_unlock(&private_client->lock);
283                 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
284                 pthread_mutex_lock(&private_client->lock);
285         }
286
287         if (wait_info->need_free)
288                 free(w);
289         else
290                 wait_info->need_free = 1;
291 }
292 /* LCOV_EXCL_STOP */
293
294 /* LCOV_EXCL_START */
295 static void
296 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
297 {
298         tdm_private_client_vblank *private_vblank = data;
299         tdm_private_client *private_client;
300
301         TDM_RETURN_IF_FAIL(private_vblank != NULL);
302
303         private_vblank->enable_ttrace = enable;
304
305         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
306         private_client = private_vblank->private_output->private_client;
307
308         private_client->enable_ttrace = enable;
309 }
310 /* LCOV_EXCL_STOP */
311
312 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
313         _tdm_client_vblank_cb_stamp,
314         _tdm_client_vblank_cb_done,
315         _tdm_client_vblank_cb_ttrace,
316 };
317
318 static void
319 _tdm_client_output_destroy(tdm_private_client_output *private_output)
320 {
321         tdm_private_client_vblank *v = NULL, *vv = NULL;
322         tdm_client_output_handler_info *h = NULL, *hh = NULL;
323
324         LIST_DEL(&private_output->link);
325
326         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
327                 TDM_ERR("vblanks SHOULD be destroyed first!");
328                 LIST_DEL(&v->link);
329                 v->private_output = NULL;
330         }
331
332         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
333                 LIST_DEL(&h->link);
334                 free(h);
335         }
336
337         wl_tdm_output_destroy(private_output->output);
338
339         free(private_output);
340 }
341
342 static void
343 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
344                                                    uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
345 {
346         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
347
348         TDM_RETURN_IF_FAIL(private_output != NULL);
349
350         private_output->width = width;
351         private_output->height = height;
352         private_output->refresh = refresh;
353
354         if (error != TDM_ERROR_NONE)
355                 TDM_INFO("mode event error: %d", error);
356
357         TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
358                         private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
359                         width, height, refresh);
360 }
361
362 static void
363 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
364 {
365         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
366         tdm_private_client *private_client;
367         tdm_client_output_handler_info *h = NULL, *hh = NULL;
368         tdm_value v;
369         struct list_head call_list;
370
371         TDM_RETURN_IF_FAIL(private_output != NULL);
372
373         private_client = private_output->private_client;
374
375         if (private_output->connection == value && value != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
376                 return;
377
378         private_output->connection = value;
379
380         if (error != TDM_ERROR_NONE)
381                 TDM_INFO("connection event error: %d", error);
382
383         TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
384                         private_output,
385                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
386                         value);
387
388         LIST_INITHEAD(&call_list);
389
390         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
391                 LIST_ADDTAIL(&h->call_link, &call_list);
392         }
393
394         v.u32 = value;
395         pthread_mutex_unlock(&private_client->lock);
396         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
397                 if (h->func)
398                         h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
399         }
400         pthread_mutex_lock(&private_client->lock);
401 }
402
403 static void
404 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
405 {
406         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
407         tdm_private_client *private_client;
408         tdm_client_output_handler_info *h = NULL, *hh = NULL;
409         tdm_value v;
410         struct list_head call_list;
411
412         TDM_RETURN_IF_FAIL(private_output != NULL);
413
414         private_client = private_output->private_client;
415
416         /* If value is extended value, we handle it as DPMS on in client side
417          * The extended DPMS value is valid only in server side.
418          * Or, need to export to client side also?
419          */
420         if (value > TDM_OUTPUT_DPMS_OFF)
421                 value = TDM_OUTPUT_DPMS_ON;
422
423         if (private_output->dpms == value)
424                 return;
425
426         private_output->dpms = value;
427
428         if (error != TDM_ERROR_NONE)
429                 TDM_INFO("dpms event error: %d", error);
430
431         TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
432                         private_output,
433                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
434                         value);
435
436         LIST_INITHEAD(&call_list);
437
438         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
439                 LIST_ADDTAIL(&h->call_link, &call_list);
440         }
441
442         v.u32 = value;
443         pthread_mutex_unlock(&private_client->lock);
444         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
445                 if (h->func)
446                         h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
447         }
448         pthread_mutex_lock(&private_client->lock);
449 }
450
451 static const struct wl_tdm_output_listener tdm_client_output_listener = {
452         _tdm_client_output_cb_mode,
453         _tdm_client_output_cb_connection,
454         _tdm_client_output_cb_dpms,
455 };
456
457 static void
458 _tdm_client_cb_global(void *data, struct wl_registry *registry,
459                                           uint32_t name, const char *interface,
460                                           uint32_t version)
461 {
462         tdm_private_client *private_client = data;
463
464         if (strncmp(interface, "wl_tdm", 6) == 0) {
465                 private_client->tdm =
466                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
467                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
468
469                 wl_display_flush(private_client->display);
470         }
471 }
472
473 /* LCOV_EXCL_START */
474 static void
475 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
476 {
477 }
478 /* LCOV_EXCL_STOP */
479
480 static const struct wl_registry_listener tdm_client_registry_listener = {
481         _tdm_client_cb_global,
482         _tdm_client_cb_global_remove
483 };
484
485 tdm_client*
486 tdm_client_create(tdm_error *error)
487 {
488         tdm_private_client *private_client;
489
490         private_client = calloc(1, sizeof *private_client);
491         if (!private_client) {
492                 /* LCOV_EXCL_START */
493
494                 TDM_ERR("alloc failed");
495                 if (error)
496                         *error = TDM_ERROR_OUT_OF_MEMORY;
497                 return NULL;
498
499                 /* LCOV_EXCL_STOP */
500         }
501
502         if (pthread_mutex_init(&private_client->lock, NULL)) {
503                 TDM_ERR("mutex init failed: %m");
504                 free(private_client);
505                 if (error)
506                         *error = TDM_ERROR_OUT_OF_MEMORY;
507                 return NULL;
508         }
509
510         LIST_INITHEAD(&private_client->output_list);
511         LIST_INITHEAD(&private_client->voutput_list);
512
513         private_client->display = wl_display_connect("tdm-socket");
514         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
515
516         private_client->queue = wl_display_create_queue(private_client->display);
517         TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
518
519         private_client->registry = wl_display_get_registry(private_client->display);
520         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
521
522         wl_registry_add_listener(private_client->registry,
523                                                          &tdm_client_registry_listener, private_client);
524         wl_display_roundtrip(private_client->display);
525
526         if (CHECK_WL_PROTOCOL_ERROR(private_client))
527                 goto create_failed;
528
529         /* check global objects */
530         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
531
532         if (error)
533                 *error = TDM_ERROR_NONE;
534
535         return (tdm_client*)private_client;
536 create_failed:
537         tdm_client_destroy((tdm_client*)private_client);
538         if (error)
539                 *error = TDM_ERROR_OPERATION_FAILED;
540         return NULL;
541 }
542
543 void
544 tdm_client_destroy(tdm_client *client)
545 {
546         tdm_private_client *private_client = (tdm_private_client*)client;
547         tdm_private_client_output *o = NULL, *oo = NULL;
548         tdm_private_client_voutput *vo = NULL, *voo = NULL;
549
550         if (!private_client)
551                 return;
552
553         pthread_mutex_lock(&private_client->lock);
554
555         if (private_client->temp_vblank) {
556                 pthread_mutex_unlock(&private_client->lock);
557                 tdm_client_vblank_destroy(private_client->temp_vblank);
558                 pthread_mutex_lock(&private_client->lock);
559         }
560
561         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
562                 _tdm_client_output_destroy(o);
563         }
564
565         LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_client->voutput_list, link) {
566                 tdm_client_voutput_destroy(vo);
567         }
568
569         if (private_client->tdm)
570                 wl_tdm_destroy(private_client->tdm);
571         if (private_client->registry)
572                 wl_registry_destroy(private_client->registry);
573         if (private_client->queue)
574                 wl_event_queue_destroy(private_client->queue);
575         if (private_client->display)
576                 wl_display_disconnect(private_client->display);
577
578         pthread_mutex_unlock(&private_client->lock);
579         pthread_mutex_destroy(&private_client->lock);
580
581         free(private_client);
582 }
583
584 tdm_error
585 tdm_client_get_fd(tdm_client *client, int *fd)
586 {
587         tdm_private_client *private_client;
588
589         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
590         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
591
592         private_client = (tdm_private_client*)client;
593
594         pthread_mutex_lock(&private_client->lock);
595
596         *fd = wl_display_get_fd(private_client->display);
597
598         pthread_mutex_unlock(&private_client->lock);
599
600         if (*fd < 0)
601                 return TDM_ERROR_OPERATION_FAILED;
602
603         return TDM_ERROR_NONE;
604 }
605
606 tdm_error
607 tdm_client_handle_events(tdm_client *client)
608 {
609         tdm_private_client *private_client;
610
611         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
612
613         /* LCOV_EXCL_START */
614         private_client = (tdm_private_client*)client;
615
616         pthread_mutex_lock(&private_client->lock);
617
618         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
619                 pthread_mutex_unlock(&private_client->lock);
620                 return TDM_ERROR_PROTOCOL_ERROR;
621         }
622
623         if (private_client->enable_ttrace)
624                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
625
626         wl_display_dispatch(private_client->display);
627
628         if (private_client->enable_ttrace)
629                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
630
631         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
632                 pthread_mutex_unlock(&private_client->lock);
633                 return TDM_ERROR_PROTOCOL_ERROR;
634         }
635
636         pthread_mutex_unlock(&private_client->lock);
637
638         return TDM_ERROR_NONE;
639         /* LCOV_EXCL_STOP */
640 }
641
642 static int
643 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
644 {
645         int ret;
646         struct pollfd pfd[1];
647
648         pfd[0].fd = wl_display_get_fd(display);
649         pfd[0].events = events;
650         do {
651                 ret = poll(pfd, 1, timeout);
652         } while (ret == -1 && errno == EINTR);
653
654         return ret;
655 }
656
657 static tdm_error
658 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
659 {
660         int ret;
661         struct wl_display *display = private_client->display;
662
663         if (wl_display_prepare_read(display) == -1) {
664                 if (wl_display_dispatch_pending(display) > 0)
665                         return TDM_ERROR_NONE;
666                 else
667                         return TDM_ERROR_OPERATION_FAILED;
668         }
669
670         while (true) {
671                 ret = wl_display_flush(display);
672
673                 if (ret != -1 || errno != EAGAIN)
674                         break;
675
676                 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
677                         wl_display_cancel_read(display);
678                         TDM_ERR("_tdm_client_poll failed");
679                         return TDM_ERROR_OPERATION_FAILED;
680                 }
681         }
682
683         /* Don't stop if flushing hits an EPIPE; continue so we can read any
684          * protocol error that may have triggered it. */
685         if (ret < 0 && errno != EPIPE) {
686                 TDM_ERR("ret(%d) errno(%d)", ret, errno);
687                 wl_display_cancel_read(display);
688                 return TDM_ERROR_OPERATION_FAILED;
689         }
690
691         ret = _tdm_client_poll(display, POLLIN, timeout);
692         if (ret <= 0) {
693                 wl_display_cancel_read(display);
694                 if (ret == 0) {
695                         TDM_ERR("_tdm_client_poll timeout.");
696                         return TDM_ERROR_TIMEOUT;
697                 } else {
698                         TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
699                         return TDM_ERROR_OPERATION_FAILED;
700                 }
701         }
702
703         if (wl_display_read_events(display) == -1) {
704                 TDM_ERR("wl_display_read_events failed");
705                 return TDM_ERROR_OPERATION_FAILED;
706         }
707
708         ret = wl_display_dispatch_pending(display);
709
710         if (ret < 0) {
711                 TDM_ERR("_tdm_client_dispatch_timeout failed");
712                 return TDM_ERROR_OPERATION_FAILED;
713         }
714
715         return TDM_ERROR_NONE;
716 }
717
718 tdm_error
719 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
720 {
721         tdm_private_client *private_client;
722         tdm_error ret;
723         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
724
725         private_client = (tdm_private_client*)client;
726
727         pthread_mutex_lock(&private_client->lock);
728
729         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
730                 pthread_mutex_unlock(&private_client->lock);
731                 return TDM_ERROR_PROTOCOL_ERROR;
732         }
733
734         if (private_client->enable_ttrace)
735                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
736
737         ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
738
739         if (private_client->enable_ttrace)
740                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
741
742         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
743                 pthread_mutex_unlock(&private_client->lock);
744                 return TDM_ERROR_PROTOCOL_ERROR;
745         }
746
747         pthread_mutex_unlock(&private_client->lock);
748
749         return ret;
750 }
751
752 typedef struct _tdm_client_vblank_temp {
753         tdm_client_vblank_handler2 func;
754         void *user_data;
755 } tdm_client_vblank_temp;
756
757 /* LCOV_EXCL_START */
758 static void
759 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
760                                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
761 {
762         tdm_client_vblank_temp *vblank_temp = user_data;
763
764         TDM_RETURN_IF_FAIL(vblank_temp != NULL);
765         TDM_RETURN_IF_FAIL(vblank != NULL);
766
767         if (vblank_temp->func)
768                 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
769
770         free(vblank_temp);
771 }
772 /* LCOV_EXCL_STOP */
773
774 /* LCOV_EXCL_START */ /* deprecated */
775 tdm_error
776 tdm_client_wait_vblank(tdm_client *client, char *name,
777                                            int sw_timer, int interval, int sync,
778                                            tdm_client_vblank_handler2 func, void *user_data)
779 {
780         tdm_private_client *private_client = (tdm_private_client*)client;
781         tdm_client_output *output;
782         tdm_client_vblank_temp *vblank_temp;
783         tdm_error ret;
784
785         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
786         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
787         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
788
789         if (CHECK_WL_PROTOCOL_ERROR(private_client))
790                 return TDM_ERROR_PROTOCOL_ERROR;
791
792         if (!private_client->temp_vblank) {
793                 output = tdm_client_get_output(client, name, &ret);
794                 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
795
796                 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
797                 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
798         }
799
800         tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
801         tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
802
803         vblank_temp = calloc(1, sizeof *vblank_temp);
804         TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
805
806         vblank_temp->func = func;
807         vblank_temp->user_data = user_data;
808
809         return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
810 }
811 /* LCOV_EXCL_STOP */
812
813 tdm_client_output*
814 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
815 {
816         tdm_private_client *private_client;
817         tdm_private_client_output *private_output = NULL;
818         struct wl_proxy *wrapper;
819
820         if (error)
821                 *error = TDM_ERROR_NONE;
822
823         if (!client) {
824                 TDM_ERR("'!client' failed");
825                 if (error)
826                         *error = TDM_ERROR_INVALID_PARAMETER;
827                 return NULL;
828         }
829
830         private_client = (tdm_private_client*)client;
831
832         pthread_mutex_lock(&private_client->lock);
833
834         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
835                 if (error)
836                         *error = TDM_ERROR_PROTOCOL_ERROR;
837                 pthread_mutex_unlock(&private_client->lock);
838                 return NULL;
839         }
840
841         if (!name) {
842                 name = "primary";
843         } else if (!strncmp(name, "primary", 7) || !strncmp(name, "default", 7)) {
844                 TDM_DBG("get primary or default output");
845         } else {
846                 tdm_private_client_voutput *private_voutput = NULL;
847                 int find = 0;
848
849                 LIST_FOR_EACH_ENTRY(private_voutput, &private_client->voutput_list, link) {
850                         if (!strncmp(private_voutput->name, name, TDM_NAME_LEN)) {
851                                 find = 1;
852                                 break;
853                         }
854                 }
855                 if (!find) {
856                         if (error)
857                                 *error = TDM_ERROR_INVALID_PARAMETER;
858                         pthread_mutex_unlock(&private_client->lock);
859                         return NULL;
860                 }
861         }
862
863         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
864                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
865                         pthread_mutex_unlock(&private_client->lock);
866                         return (tdm_client_output*)private_output;
867                 }
868         }
869
870         wrapper = wl_proxy_create_wrapper(private_client->tdm);
871         if (!wrapper) {
872                 TDM_ERR("create output_wrapper failed");
873                 if (error)
874                         *error = TDM_ERROR_OUT_OF_MEMORY;
875                 pthread_mutex_unlock(&private_client->lock);
876                 return NULL;
877         }
878
879         wl_proxy_set_queue(wrapper, private_client->queue);
880
881         private_output = calloc(1, sizeof *private_output);
882         if (!private_output) {
883                 /* LCOV_EXCL_START */
884                 wl_proxy_wrapper_destroy(wrapper);
885                 TDM_ERR("alloc failed");
886                 if (error)
887                         *error = TDM_ERROR_OUT_OF_MEMORY;
888                 pthread_mutex_unlock(&private_client->lock);
889                 return NULL;
890
891                 /* LCOV_EXCL_STOP */
892         }
893
894         private_output->private_client = private_client;
895
896         snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
897         private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
898         wl_proxy_wrapper_destroy(wrapper);
899         if (!private_output->output) {
900                 /* LCOV_EXCL_START */
901
902                 TDM_ERR("couldn't create output resource");
903                 free(private_output);
904                 if (error)
905                         *error = TDM_ERROR_OUT_OF_MEMORY;
906                 pthread_mutex_unlock(&private_client->lock);
907                 return NULL;
908
909                 /* LCOV_EXCL_STOP */
910         }
911
912         LIST_INITHEAD(&private_output->vblank_list);
913         LIST_INITHEAD(&private_output->change_handler_list);
914
915         wl_tdm_output_add_listener(private_output->output,
916                                                            &tdm_client_output_listener, private_output);
917         wl_display_roundtrip_queue(private_client->display, private_client->queue);
918
919         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
920
921         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
922                 wl_tdm_output_destroy(private_output->output);
923                 free(private_output);
924                 if (error)
925                         *error = TDM_ERROR_PROTOCOL_ERROR;
926                 pthread_mutex_unlock(&private_client->lock);
927                 return NULL;
928         }
929
930         LIST_ADDTAIL(&private_output->link, &private_client->output_list);
931
932         pthread_mutex_unlock(&private_client->lock);
933
934         return (tdm_client_output*)private_output;
935 }
936
937 tdm_error
938 tdm_client_output_add_change_handler(tdm_client_output *output,
939                                                                          tdm_client_output_change_handler func,
940                                                                          void *user_data)
941 {
942         tdm_private_client_output *private_output;
943         tdm_private_client *private_client;
944         tdm_client_output_handler_info *h = NULL;
945
946         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
947         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
948
949         private_output = (tdm_private_client_output*)output;
950         private_client = private_output->private_client;
951
952         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
953                 if (h->func == func && h->user_data == user_data) {
954                         TDM_ERR("can't add twice");
955                         return TDM_ERROR_BAD_REQUEST;
956                 }
957         }
958
959         h = calloc(1, sizeof *h);
960         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
961
962         pthread_mutex_lock(&private_client->lock);
963
964         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
965                 free(h);
966                 pthread_mutex_unlock(&private_client->lock);
967                 return TDM_ERROR_PROTOCOL_ERROR;
968         }
969
970         if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
971                 wl_tdm_output_watch_output_changes(private_output->output, 1);
972                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
973
974                 /* TODO: this is very tricky.
975                  * If a client adds the change_handler, we might be able to guess that
976                  * the client will watch the tdm client's fd and handle tdm events in
977                  * event loop. Otherwise, we CAN'T make sure if a client has event loop
978                  * which handles tdm events.
979                  */
980                 private_output->watch_output_changes = 1;
981         }
982
983         h->private_output = private_output;
984         h->func = func;
985         h->user_data = user_data;
986         LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
987         LIST_INITHEAD(&h->call_link);
988
989         pthread_mutex_unlock(&private_client->lock);
990
991         return TDM_ERROR_NONE;
992 }
993
994 void
995 tdm_client_output_remove_change_handler(tdm_client_output *output,
996                                                                                 tdm_client_output_change_handler func,
997                                                                                 void *user_data)
998 {
999         tdm_private_client_output *private_output;
1000         tdm_private_client *private_client;
1001         tdm_client_output_handler_info *h = NULL;
1002
1003         TDM_RETURN_IF_FAIL(output != NULL);
1004         TDM_RETURN_IF_FAIL(func != NULL);
1005
1006         private_output = (tdm_private_client_output*)output;
1007         private_client = private_output->private_client;
1008
1009         pthread_mutex_lock(&private_client->lock);
1010
1011         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
1012                 if (h->func != func || h->user_data != user_data)
1013                         continue;
1014
1015                 LIST_DEL(&h->link);
1016                 free(h);
1017
1018                 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
1019                         private_output->watch_output_changes = 0;
1020                         if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
1021                                 wl_tdm_output_watch_output_changes(private_output->output, 0);
1022                                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1023                         }
1024                 }
1025
1026                 pthread_mutex_unlock(&private_client->lock);
1027
1028                 return;
1029         }
1030
1031         pthread_mutex_unlock(&private_client->lock);
1032 }
1033
1034 tdm_error
1035 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
1036 {
1037         tdm_private_client_output *private_output;
1038         tdm_private_client *private_client;
1039
1040         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1041         TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1042
1043         private_output = (tdm_private_client_output*)output;
1044         private_client = private_output->private_client;
1045
1046         pthread_mutex_lock(&private_client->lock);
1047
1048         if (private_output->watch_output_changes) {
1049                 *refresh = private_output->refresh;
1050                 pthread_mutex_unlock(&private_client->lock);
1051                 return TDM_ERROR_NONE;
1052         }
1053
1054         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1055                 pthread_mutex_unlock(&private_client->lock);
1056                 return TDM_ERROR_PROTOCOL_ERROR;
1057         }
1058
1059         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1060         wl_tdm_output_get_mode(private_output->output);
1061         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1062         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1063
1064         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1065                 pthread_mutex_unlock(&private_client->lock);
1066                 return TDM_ERROR_PROTOCOL_ERROR;
1067         }
1068
1069         *refresh = private_output->refresh;
1070
1071         pthread_mutex_unlock(&private_client->lock);
1072
1073         return TDM_ERROR_NONE;
1074 }
1075
1076 tdm_error
1077 tdm_client_output_get_mode(tdm_client_output *output, unsigned int *width, unsigned int *height)
1078 {
1079         tdm_private_client_output *private_output;
1080         tdm_private_client *private_client;
1081
1082         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1083         TDM_RETURN_VAL_IF_FAIL(width != NULL, TDM_ERROR_INVALID_PARAMETER);
1084         TDM_RETURN_VAL_IF_FAIL(height != NULL, TDM_ERROR_INVALID_PARAMETER);
1085
1086         private_output = (tdm_private_client_output*)output;
1087         private_client = private_output->private_client;
1088
1089         pthread_mutex_lock(&private_client->lock);
1090
1091         if (private_output->watch_output_changes) {
1092                 *width = private_output->width;
1093                 *height = private_output->height;
1094                 pthread_mutex_unlock(&private_client->lock);
1095                 return TDM_ERROR_NONE;
1096         }
1097
1098         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1099                 pthread_mutex_unlock(&private_client->lock);
1100                 return TDM_ERROR_PROTOCOL_ERROR;
1101         }
1102
1103         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1104         wl_tdm_output_get_mode(private_output->output);
1105         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1106         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1107
1108         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1109                 pthread_mutex_unlock(&private_client->lock);
1110                 return TDM_ERROR_PROTOCOL_ERROR;
1111         }
1112
1113         *width = private_output->width;
1114         *height = private_output->height;
1115
1116         pthread_mutex_unlock(&private_client->lock);
1117
1118         return TDM_ERROR_NONE;
1119 }
1120
1121 tdm_error
1122 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1123 {
1124         tdm_private_client_output *private_output;
1125         tdm_private_client *private_client;
1126
1127         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1128         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1129
1130         private_output = (tdm_private_client_output*)output;
1131         private_client = private_output->private_client;
1132
1133         pthread_mutex_lock(&private_client->lock);
1134
1135         if (private_output->watch_output_changes) {
1136                 *status = private_output->connection;
1137                 pthread_mutex_unlock(&private_client->lock);
1138                 return TDM_ERROR_NONE;
1139         }
1140
1141         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1142                 pthread_mutex_unlock(&private_client->lock);
1143                 return TDM_ERROR_PROTOCOL_ERROR;
1144         }
1145
1146         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1147         wl_tdm_output_get_connection(private_output->output);
1148         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1149         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1150
1151         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1152                 pthread_mutex_unlock(&private_client->lock);
1153                 return TDM_ERROR_PROTOCOL_ERROR;
1154         }
1155
1156         *status = private_output->connection;
1157
1158         pthread_mutex_unlock(&private_client->lock);
1159
1160         return TDM_ERROR_NONE;
1161 }
1162
1163 tdm_error
1164 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1165 {
1166         tdm_private_client_output *private_output;
1167         tdm_private_client *private_client;
1168
1169         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1170         TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1171
1172         private_output = (tdm_private_client_output*)output;
1173         private_client = private_output->private_client;
1174
1175         if (private_output->watch_output_changes) {
1176                 *dpms = private_output->dpms;
1177                 return TDM_ERROR_NONE;
1178         }
1179
1180         pthread_mutex_lock(&private_client->lock);
1181
1182         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1183                 pthread_mutex_unlock(&private_client->lock);
1184                 return TDM_ERROR_PROTOCOL_ERROR;
1185         }
1186
1187         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1188         wl_tdm_output_get_dpms(private_output->output);
1189         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1190         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1191
1192         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1193                 pthread_mutex_unlock(&private_client->lock);
1194                 return TDM_ERROR_PROTOCOL_ERROR;
1195         }
1196
1197         *dpms = private_output->dpms;
1198
1199         pthread_mutex_unlock(&private_client->lock);
1200
1201         return TDM_ERROR_NONE;
1202 }
1203
1204 tdm_client_vblank*
1205 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1206 {
1207         tdm_private_client *private_client;
1208         tdm_private_client_output *private_output;
1209         tdm_private_client_vblank *private_vblank;
1210         struct wl_proxy *wrapper;
1211
1212         if (error)
1213                 *error = TDM_ERROR_NONE;
1214
1215         if (!output) {
1216                 TDM_ERR("'!output' failed");
1217                 if (error)
1218                         *error = TDM_ERROR_INVALID_PARAMETER;
1219                 return NULL;
1220         }
1221
1222         private_output = (tdm_private_client_output*)output;
1223         private_client = private_output->private_client;
1224
1225         pthread_mutex_lock(&private_client->lock);
1226
1227         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1228                 if (error)
1229                         *error = TDM_ERROR_PROTOCOL_ERROR;
1230                 pthread_mutex_unlock(&private_client->lock);
1231                 return NULL;
1232         }
1233
1234         wrapper = wl_proxy_create_wrapper(private_output->output);
1235         if (!wrapper) {
1236                 TDM_ERR("create output_wrapper failed");
1237                 if (error)
1238                         *error = TDM_ERROR_OUT_OF_MEMORY;
1239                 pthread_mutex_unlock(&private_client->lock);
1240                 return NULL;
1241         }
1242
1243         wl_proxy_set_queue(wrapper, private_client->queue);
1244
1245         private_vblank = calloc(1, sizeof *private_vblank);
1246         if (!private_vblank) {
1247                 /* LCOV_EXCL_START */
1248
1249                 TDM_ERR("alloc failed");
1250                 wl_proxy_wrapper_destroy(wrapper);
1251                 if (error)
1252                         *error = TDM_ERROR_OUT_OF_MEMORY;
1253                 pthread_mutex_unlock(&private_client->lock);
1254                 return NULL;
1255
1256                 /* LCOV_EXCL_STOP */
1257         }
1258
1259         private_vblank->private_output = private_output;
1260
1261         private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1262         wl_proxy_wrapper_destroy(wrapper);
1263         if (!private_vblank->vblank) {
1264                 /* LCOV_EXCL_START */
1265
1266                 TDM_ERR("couldn't create vblank resource");
1267                 free(private_vblank);
1268                 if (error)
1269                         *error = TDM_ERROR_OUT_OF_MEMORY;
1270                 pthread_mutex_unlock(&private_client->lock);
1271                 return NULL;
1272
1273                 /* LCOV_EXCL_STOP */
1274         }
1275
1276         /* initial value */
1277         private_vblank->fps = private_output->refresh;
1278         private_vblank->offset = 0;
1279         private_vblank->enable_fake = 0;
1280
1281         LIST_INITHEAD(&private_vblank->wait_list);
1282
1283         wl_tdm_vblank_add_listener(private_vblank->vblank,
1284                                                            &tdm_client_vblank_listener, private_vblank);
1285         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1286
1287         wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1288
1289         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1290                 wl_tdm_vblank_destroy(private_vblank->vblank);
1291                 free(private_vblank);
1292                 if (error)
1293                         *error = TDM_ERROR_PROTOCOL_ERROR;
1294                 pthread_mutex_unlock(&private_client->lock);
1295                 return NULL;
1296         }
1297
1298         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1299
1300         pthread_mutex_unlock(&private_client->lock);
1301
1302         return (tdm_client_vblank*)private_vblank;
1303 }
1304
1305 void
1306 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1307 {
1308         tdm_private_client_vblank *private_vblank;
1309         tdm_private_client *private_client;
1310         tdm_client_wait_info *w = NULL, *ww = NULL;
1311
1312         TDM_RETURN_IF_FAIL(vblank != NULL);
1313
1314         private_vblank = vblank;
1315         private_client = private_vblank->private_output->private_client;
1316
1317         pthread_mutex_lock(&private_client->lock);
1318
1319         LIST_DEL(&private_vblank->link);
1320
1321         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1322                 LIST_DEL(&w->link);
1323                 free(w);
1324         }
1325
1326         wl_tdm_vblank_destroy(private_vblank->vblank);
1327
1328         free(private_vblank);
1329
1330         pthread_mutex_unlock(&private_client->lock);
1331 }
1332
1333 tdm_error
1334 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1335 {
1336         tdm_private_client_vblank *private_vblank;
1337         tdm_private_client *private_client;
1338
1339         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1340
1341         private_vblank = vblank;
1342         private_client = private_vblank->private_output->private_client;
1343
1344         pthread_mutex_lock(&private_client->lock);
1345
1346         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1347                 pthread_mutex_unlock(&private_client->lock);
1348                 return TDM_ERROR_PROTOCOL_ERROR;
1349         }
1350
1351         if (!name)
1352                 name = TDM_VBLANK_DEFAULT_NAME;
1353
1354         strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1355         private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1356
1357         wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1358
1359         pthread_mutex_unlock(&private_client->lock);
1360
1361         return TDM_ERROR_NONE;
1362 }
1363
1364 tdm_error
1365 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1366 {
1367         tdm_private_client_vblank *private_vblank;
1368         tdm_private_client *private_client;
1369
1370         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1371
1372         private_vblank = vblank;
1373         private_client = private_vblank->private_output->private_client;
1374
1375         pthread_mutex_lock(&private_client->lock);
1376         private_vblank->sync = sync;
1377         pthread_mutex_unlock(&private_client->lock);
1378
1379         return TDM_ERROR_NONE;
1380 }
1381
1382 tdm_error
1383 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1384 {
1385         tdm_private_client_vblank *private_vblank;
1386         tdm_private_client *private_client;
1387
1388         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1389         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1390
1391         private_vblank = vblank;
1392         private_client = private_vblank->private_output->private_client;
1393
1394         pthread_mutex_lock(&private_client->lock);
1395
1396         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1397                 pthread_mutex_unlock(&private_client->lock);
1398                 return TDM_ERROR_PROTOCOL_ERROR;
1399         }
1400
1401         if (private_vblank->fps == fps) {
1402                 pthread_mutex_unlock(&private_client->lock);
1403                 return TDM_ERROR_NONE;
1404         }
1405
1406         private_vblank->fps = fps;
1407
1408         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1409
1410         pthread_mutex_unlock(&private_client->lock);
1411
1412         return TDM_ERROR_NONE;
1413 }
1414
1415 tdm_error
1416 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1417 {
1418         tdm_private_client_vblank *private_vblank;
1419         tdm_private_client *private_client;
1420
1421         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1422
1423         private_vblank = vblank;
1424         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1425
1426         private_client = private_vblank->private_output->private_client;
1427
1428         pthread_mutex_lock(&private_client->lock);
1429
1430         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1431                 pthread_mutex_unlock(&private_client->lock);
1432                 return TDM_ERROR_PROTOCOL_ERROR;
1433         }
1434
1435         if (private_vblank->offset == offset_ms) {
1436                 pthread_mutex_unlock(&private_client->lock);
1437                 return TDM_ERROR_NONE;
1438         }
1439
1440         private_vblank->offset = offset_ms;
1441
1442         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1443
1444         pthread_mutex_unlock(&private_client->lock);
1445
1446         return TDM_ERROR_NONE;
1447 }
1448
1449 tdm_error
1450 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1451 {
1452         tdm_private_client_vblank *private_vblank;
1453         tdm_private_client *private_client;
1454
1455         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1456
1457         private_vblank = vblank;
1458         private_client = private_vblank->private_output->private_client;
1459
1460         pthread_mutex_lock(&private_client->lock);
1461
1462         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1463                 pthread_mutex_unlock(&private_client->lock);
1464                 return TDM_ERROR_PROTOCOL_ERROR;
1465         }
1466
1467         if (private_vblank->enable_fake == enable_fake) {
1468                 pthread_mutex_unlock(&private_client->lock);
1469                 return TDM_ERROR_NONE;
1470         }
1471
1472         private_vblank->enable_fake = enable_fake;
1473
1474         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1475
1476         pthread_mutex_unlock(&private_client->lock);
1477
1478         return TDM_ERROR_NONE;
1479 }
1480
1481 tdm_error
1482 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1483 {
1484         tdm_private_client *private_client;
1485         tdm_private_client_output *private_output;
1486         tdm_private_client_vblank *private_vblank;
1487         tdm_client_wait_info *w;
1488         struct timespec tp;
1489         unsigned int req_sec, req_usec;
1490         int ret = 0;
1491
1492         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1493         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1494         /* can't support "interval 0" and "getting current_msc" things because
1495          * there is a socket communication between TDM client and server. It's impossible
1496          * to return the current msc or sequence immediately.
1497          */
1498         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1499
1500         private_vblank = vblank;
1501         private_output = private_vblank->private_output;
1502         private_client = private_output->private_client;
1503
1504         pthread_mutex_lock(&private_client->lock);
1505
1506         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1507                 pthread_mutex_unlock(&private_client->lock);
1508                 return TDM_ERROR_PROTOCOL_ERROR;
1509         }
1510
1511         if (!private_vblank->started)
1512                 private_vblank->started = 1;
1513
1514         if (!private_vblank->enable_fake) {
1515                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1516                         TDM_ERR("output disconnected");
1517                         pthread_mutex_unlock(&private_client->lock);
1518                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1519                 }
1520                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1521                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1522                         pthread_mutex_unlock(&private_client->lock);
1523                         return TDM_ERROR_DPMS_OFF;
1524                 }
1525         }
1526
1527         w = calloc(1, sizeof *w);
1528         if (!w) {
1529                 /* LCOV_EXCL_START */
1530
1531                 TDM_ERR("alloc failed");
1532                 pthread_mutex_unlock(&private_client->lock);
1533                 return TDM_ERROR_OUT_OF_MEMORY;
1534
1535                 /* LCOV_EXCL_STOP */
1536         }
1537
1538         w->private_vblank = private_vblank;
1539         w->func = func;
1540         w->user_data = user_data;
1541
1542         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1543         LIST_INITHEAD(&w->call_link);
1544
1545         clock_gettime(CLOCK_MONOTONIC, &tp);
1546         req_sec = (unsigned int)tp.tv_sec;
1547         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1548
1549         w->req_id = ++private_output->req_id;
1550         w->req_time = TDM_TIME(req_sec, req_usec);
1551         w->need_free = (private_vblank->sync) ? 0 : 1;
1552
1553         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1554
1555         if (private_vblank->enable_ttrace)
1556                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1557
1558         TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1559                         vblank, interval, w->req_id, w->req_time);
1560
1561         private_vblank->req_time = w->req_time;
1562
1563         if (private_vblank->last_time >= w->req_time)
1564                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1565
1566         if (!private_vblank->sync) {
1567                 wl_display_flush(private_client->display);
1568                 pthread_mutex_unlock(&private_client->lock);
1569                 return TDM_ERROR_NONE;
1570         }
1571
1572         /* LCOV_EXCL_START */
1573
1574         while (ret != -1 && !w->need_free)
1575                 ret = wl_display_dispatch(private_client->display);
1576
1577         clock_gettime(CLOCK_MONOTONIC, &tp);
1578         TDM_DBG("block during %d us",
1579                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1580                         - (req_sec * 1000000 + req_usec));
1581
1582         LIST_DEL(&w->link);
1583         free(w);
1584
1585         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1586                 pthread_mutex_unlock(&private_client->lock);
1587                 return TDM_ERROR_PROTOCOL_ERROR;
1588         }
1589
1590         pthread_mutex_unlock(&private_client->lock);
1591
1592         return TDM_ERROR_NONE;
1593
1594         /* LCOV_EXCL_STOP */
1595 }
1596
1597 tdm_error
1598 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1599                                                    tdm_client_vblank_handler func, void *user_data)
1600 {
1601         tdm_private_client *private_client;
1602         tdm_private_client_output *private_output;
1603         tdm_private_client_vblank *private_vblank;
1604         tdm_client_wait_info *w;
1605         struct timespec tp;
1606         unsigned int req_sec, req_usec;
1607         int ret = 0;
1608
1609         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1610         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1611
1612         private_vblank = vblank;
1613         private_output = private_vblank->private_output;
1614         private_client = private_output->private_client;
1615
1616         pthread_mutex_lock(&private_client->lock);
1617
1618         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1619                 pthread_mutex_unlock(&private_client->lock);
1620                 return TDM_ERROR_PROTOCOL_ERROR;
1621         }
1622
1623         if (!private_vblank->started)
1624                 private_vblank->started = 1;
1625
1626         if (!private_vblank->enable_fake) {
1627                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1628                         TDM_ERR("output disconnected");
1629                         pthread_mutex_unlock(&private_client->lock);
1630                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1631                 }
1632                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1633                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1634                         pthread_mutex_unlock(&private_client->lock);
1635                         return TDM_ERROR_DPMS_OFF;
1636                 }
1637         }
1638
1639         w = calloc(1, sizeof *w);
1640         if (!w) {
1641                 /* LCOV_EXCL_START */
1642
1643                 TDM_ERR("alloc failed");
1644                 pthread_mutex_unlock(&private_client->lock);
1645                 return TDM_ERROR_OUT_OF_MEMORY;
1646
1647                 /* LCOV_EXCL_STOP */
1648         }
1649
1650         w->private_vblank = private_vblank;
1651         w->func = func;
1652         w->user_data = user_data;
1653
1654         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1655         LIST_INITHEAD(&w->call_link);
1656
1657         clock_gettime(CLOCK_MONOTONIC, &tp);
1658         req_sec = (unsigned int)tp.tv_sec;
1659         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1660
1661         w->req_id = ++private_output->req_id;
1662         w->req_time = TDM_TIME(req_sec, req_usec);
1663         w->need_free = (private_vblank->sync) ? 0 : 1;
1664
1665         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1666
1667         if (private_vblank->enable_ttrace)
1668                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1669
1670         TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1671                         vblank, sequence, w->req_id, w->req_time);
1672
1673         private_vblank->req_time = w->req_time;
1674
1675         if (private_vblank->last_time >= w->req_time)
1676                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1677
1678         if (!private_vblank->sync) {
1679                 wl_display_flush(private_client->display);
1680                 pthread_mutex_unlock(&private_client->lock);
1681                 return TDM_ERROR_NONE;
1682         }
1683
1684         /* LCOV_EXCL_START */
1685
1686         while (ret != -1 && !w->need_free)
1687                 ret = wl_display_dispatch(private_client->display);
1688
1689         clock_gettime(CLOCK_MONOTONIC, &tp);
1690         TDM_DBG("block during %d us",
1691                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1692                         - (req_sec * 1000000 + req_usec));
1693
1694         LIST_DEL(&w->link);
1695         free(w);
1696
1697         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1698                 pthread_mutex_unlock(&private_client->lock);
1699                 return TDM_ERROR_PROTOCOL_ERROR;
1700         }
1701
1702         pthread_mutex_unlock(&private_client->lock);
1703
1704         return TDM_ERROR_NONE;
1705
1706         /* LCOV_EXCL_STOP */
1707 }
1708
1709 unsigned int
1710 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1711 {
1712         tdm_private_client_vblank *private_vblank;
1713
1714         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1715
1716         private_vblank = vblank;
1717
1718         return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1719 }
1720
1721 static tbm_surface_h
1722 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1723                                                          int is_fd,
1724                                                          int32_t width,
1725                                                          int32_t height,
1726                                                          uint32_t format,
1727                                                          int32_t bpp,
1728                                                          int32_t size,
1729                                                          int32_t num_plane,
1730                                                          struct wl_array *plane_buf_idx,
1731                                                          struct wl_array *plane_offset,
1732                                                          struct wl_array *plane_stride,
1733                                                          struct wl_array *plane_size,
1734                                                          uint32_t flags,
1735                                                          int32_t num_buf,
1736                                                          uint32_t buf0,
1737                                                          uint32_t buf1,
1738                                                          uint32_t buf2)
1739 {
1740         int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1741         tbm_surface_info_s info = { 0, };
1742         tbm_bo bos[TBM_SURF_PLANE_MAX];
1743         int i, numPlane, numName;
1744         tbm_surface_h tbm_surface;
1745
1746         numPlane = tbm_surface_internal_get_num_planes(format);
1747         TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1748
1749         info.width = width;
1750         info.height = height;
1751         info.format = format;
1752         info.bpp = bpp;
1753         info.size = size;
1754         info.num_planes = numPlane;
1755
1756         /*Fill plane info*/
1757         for (i = 0; i < numPlane; i++) {
1758                 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1759                 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1760                 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1761         }
1762
1763         /*Fill buffer*/
1764         numName = num_buf;
1765         names[0] = buf0;
1766         names[1] = buf1;
1767         names[2] = buf2;
1768
1769         for (i = 0; i < numName; i++) {
1770                 if (is_fd)
1771                         bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1772                 else
1773                         bos[i] = tbm_bo_import(bufmgr, names[i]);
1774         }
1775
1776         tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1777         if (tbm_surface == NULL) {
1778                 if (is_fd) {
1779                         close(buf0);
1780                         close(buf1);
1781                         close(buf2);
1782                 }
1783                 return NULL;
1784         }
1785
1786         if (is_fd) {
1787                 close(buf0);
1788                 close(buf1);
1789                 close(buf2);
1790         }
1791
1792         for (i = 0; i < numName; i++)
1793                 tbm_bo_unref(bos[i]);
1794
1795         return tbm_surface;
1796 }
1797 static void
1798 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1799                 struct wl_tdm_voutput *wl_voutput,
1800                 struct wl_buffer *wl_buffer,
1801                 int32_t width,
1802                 int32_t height,
1803                 uint32_t format,
1804                 int32_t bpp,
1805                 int32_t size,
1806                 int32_t num_plane,
1807                 struct wl_array *plane_buf_idx,
1808                 struct wl_array *plane_offset,
1809                 struct wl_array *plane_stride,
1810                 struct wl_array *plane_size,
1811                 uint32_t flags,
1812                 int32_t num_buf,
1813                 uint32_t buf0,
1814                 uint32_t buf1,
1815                 uint32_t buf2)
1816 {
1817         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1818         tdm_private_client_buffer *buffer = NULL;
1819         tbm_surface_h tbm_surface;
1820
1821         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1822
1823         buffer = calloc(1, sizeof *buffer);
1824         TDM_RETURN_IF_FAIL(buffer != NULL);
1825
1826         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1827                               width, height, format, bpp, size,
1828                               num_plane,
1829                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1830                               0,
1831                               num_buf,
1832                               buf0, buf1, buf2);
1833         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1834
1835         tbm_surface_internal_ref(tbm_surface);
1836         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1837
1838         buffer->wl_buffer = wl_buffer;
1839
1840         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1841
1842         return;
1843
1844 fail:
1845         if (buffer)
1846                 free(buffer);
1847
1848         if (wl_buffer)
1849                 wl_buffer_destroy(wl_buffer);
1850 }
1851
1852 static void
1853 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1854                 struct wl_tdm_voutput *wl_voutput,
1855                 struct wl_buffer *wl_buffer,
1856                 int32_t width,
1857                 int32_t height,
1858                 uint32_t format,
1859                 int32_t bpp,
1860                 int32_t size,
1861                 int32_t num_plane,
1862                 struct wl_array *plane_buf_idx,
1863                 struct wl_array *plane_offset,
1864                 struct wl_array *plane_stride,
1865                 struct wl_array *plane_size,
1866                 uint32_t flags,
1867                 int32_t num_buf,
1868                 int32_t buf0,
1869                 int32_t buf1,
1870                 int32_t buf2)
1871 {
1872         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1873         tdm_private_client_buffer *buffer = NULL;
1874         tbm_surface_h tbm_surface;
1875
1876         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1877
1878         buffer = calloc(1, sizeof *buffer);
1879         TDM_RETURN_IF_FAIL(buffer != NULL);
1880
1881         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1882                               width, height, format, bpp, size,
1883                               num_plane,
1884                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1885                               0,
1886                               num_buf,
1887                               buf0, buf1, buf2);
1888         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1889
1890         tbm_surface_internal_ref(tbm_surface);
1891         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1892
1893         buffer->wl_buffer = wl_buffer;
1894
1895         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1896
1897         return;
1898
1899 fail:
1900         if (buffer)
1901                 free(buffer);
1902
1903         if (wl_buffer)
1904                 wl_buffer_destroy(wl_buffer);
1905 }
1906
1907 static void
1908 tdm_client_voutput_cb_buffer_destroy(void *data,
1909                 struct wl_tdm_voutput *wl_voutput,
1910                 struct wl_buffer *wl_buffer)
1911 {
1912         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1913         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1914         tbm_surface_h tbm_surface = NULL;
1915
1916         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1917
1918         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1919                 if (wl_buffer == cb->wl_buffer) {
1920                         LIST_DEL(&cb->link);
1921
1922                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1923                         if (tbm_surface)
1924                                 tbm_surface_internal_unref(tbm_surface);
1925
1926                         wl_buffer_set_user_data(wl_buffer, NULL);
1927                         wl_buffer_destroy(wl_buffer);
1928
1929                         free(cb);
1930
1931                         break;
1932                 }
1933         }
1934
1935         return;
1936 }
1937
1938 void
1939 tdm_client_voutput_cb_attach_buffer(void *data,
1940                 struct wl_tdm_voutput *wl_voutput,
1941                 struct wl_buffer *wl_buffer)
1942 {
1943         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1944         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1945
1946         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1947
1948         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1949                 if (wl_buffer == cb->wl_buffer) {
1950                         private_voutput->attach_buffer = cb;
1951                         break;
1952                 }
1953         }
1954
1955         return;
1956 }
1957
1958 void
1959 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
1960 {
1961         tdm_private_client_voutput *private_voutput;
1962         tdm_private_client *private_client;
1963         tbm_surface_h buffer = NULL;
1964         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
1965         struct list_head call_list;
1966
1967         private_voutput = (tdm_private_client_voutput *)data;
1968         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1969         TDM_RETURN_IF_FAIL(private_voutput->attach_buffer != NULL);
1970
1971         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
1972         TDM_RETURN_IF_FAIL(buffer != NULL);
1973
1974         tbm_surface_internal_ref(buffer);
1975
1976         private_client = private_voutput->private_client;
1977
1978         LIST_INITHEAD(&call_list);
1979
1980         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
1981                 LIST_ADDTAIL(&h->call_link, &call_list);
1982         }
1983
1984         pthread_mutex_unlock(&private_client->lock);
1985         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
1986                 if (h->func)
1987                         h->func(private_voutput, buffer, h->user_data);
1988         }
1989
1990         /* if no added commit_handler call commit done immediately */
1991         if (LIST_IS_EMPTY(&private_voutput->commit_handler_list))
1992                 tdm_client_voutput_commit_done(private_voutput);
1993
1994         pthread_mutex_lock(&private_client->lock);
1995 }
1996
1997 void
1998 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1999 {
2000         tdm_private_client_voutput *private_voutput = data;
2001
2002         private_voutput->msg = msg;
2003 }
2004
2005 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
2006         tdm_client_voutput_cb_buffer_import_with_id,
2007         tdm_client_voutput_cb_buffer_import_with_fd,
2008         tdm_client_voutput_cb_buffer_destroy,
2009         tdm_client_voutput_cb_attach_buffer,
2010         tdm_client_voutput_cb_commit,
2011         tdm_client_voutput_cb_ack_message
2012 };
2013
2014 tdm_client_voutput *
2015 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
2016 {
2017         tdm_private_client *private_client;
2018         tdm_private_client_output *private_output = NULL;
2019         tdm_private_client_voutput *private_voutput;
2020         struct wl_proxy *wrapper;
2021
2022         if (error)
2023                 *error = TDM_ERROR_NONE;
2024
2025         if (!client) {
2026                 TDM_ERR("'!client' failed");
2027                 if (error)
2028                         *error = TDM_ERROR_INVALID_PARAMETER;
2029                 return NULL;
2030         }
2031
2032         if (!name) {
2033                 TDM_ERR("'!name' failed");
2034                 if (error)
2035                         *error = TDM_ERROR_INVALID_PARAMETER;
2036                 return NULL;
2037         }
2038
2039         private_client = (tdm_private_client *)client;
2040
2041         pthread_mutex_lock(&private_client->lock);
2042
2043         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2044                 if (error)
2045                         *error = TDM_ERROR_PROTOCOL_ERROR;
2046                 pthread_mutex_unlock(&private_client->lock);
2047                 return NULL;
2048         }
2049
2050         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
2051                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
2052                         if (error)
2053                                 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
2054                         pthread_mutex_unlock(&private_client->lock);
2055                         return NULL;
2056                 }
2057         }
2058
2059         wrapper = wl_proxy_create_wrapper(private_client->tdm);
2060         if (!wrapper) {
2061                 TDM_ERR("create virtual output wrapper failed");
2062                 if (error)
2063                         *error = TDM_ERROR_OUT_OF_MEMORY;
2064                 pthread_mutex_unlock(&private_client->lock);
2065                 return NULL;
2066         }
2067
2068         wl_proxy_set_queue(wrapper, private_client->queue);
2069
2070         private_voutput = calloc(1, sizeof *private_voutput);
2071         if (!private_voutput) {
2072                 /* LOCV_EXCL_START */
2073                 wl_proxy_wrapper_destroy(wrapper);
2074                 TDM_ERR("alloc failed");
2075                 if (error)
2076                         *error = TDM_ERROR_OUT_OF_MEMORY;
2077                 pthread_mutex_unlock(&private_client->lock);
2078                 return NULL;
2079                 /* LOCV_EXCL_STOP */
2080         }
2081
2082         private_voutput->bufmgr = tbm_bufmgr_init(-1);
2083         if (private_voutput->bufmgr == NULL) {
2084                 /* LCOV_EXCL_START */
2085                 wl_proxy_wrapper_destroy(wrapper);
2086                 TDM_ERR("fail tbm_bufmgr_init");
2087                 free(private_voutput);
2088                 if (error)
2089                         *error = TDM_ERROR_OUT_OF_MEMORY;
2090                 pthread_mutex_unlock(&private_client->lock);
2091                 return NULL;
2092                 /* LCOV_EXCL_STOP */
2093         }
2094
2095         LIST_INITHEAD(&private_voutput->commit_handler_list);
2096         LIST_INITHEAD(&private_voutput->buffer_list);
2097
2098         private_voutput->private_client = private_client;
2099         strncpy(private_voutput->name, name, TDM_NAME_LEN - 1);
2100         private_voutput->name[TDM_NAME_LEN - 1] = '\0';
2101
2102         private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, name);
2103         wl_proxy_wrapper_destroy(wrapper);
2104         if (!private_voutput->wl_voutput) {
2105                 /* LCOV_EXCL_START */
2106                 TDM_ERR("couldn't create voutput resource");
2107                 free(private_voutput);
2108                 if (error)
2109                         *error = TDM_ERROR_OUT_OF_MEMORY;
2110                 pthread_mutex_unlock(&private_client->lock);
2111                 return NULL;
2112                 /* LCOV_EXCL_STOP */
2113         }
2114
2115         wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
2116                                                                 &tdm_client_voutput_lisntener, private_voutput);
2117         wl_display_roundtrip_queue(private_client->display, private_client->queue);
2118
2119         wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2120
2121         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2122                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2123                 free(private_voutput);
2124                 if (error)
2125                         *error = TDM_ERROR_PROTOCOL_ERROR;
2126                 pthread_mutex_unlock(&private_client->lock);
2127                 return NULL;
2128         }
2129
2130         if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED) {
2131                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2132                 free(private_voutput);
2133                 if (error)
2134                         *error = TDM_ERROR_PROTOCOL_ERROR;      // FIXME add new error type.
2135                 pthread_mutex_unlock(&private_client->lock);
2136                 return NULL;
2137         }
2138
2139         LIST_ADDTAIL(&private_voutput->link, &private_client->voutput_list);
2140
2141         pthread_mutex_unlock(&private_client->lock);
2142
2143         return (tdm_client_voutput *)private_voutput;
2144 }
2145
2146 void
2147 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2148 {
2149         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2150         tdm_private_client *private_client;
2151         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2152
2153         if (!private_voutput)
2154                 return;
2155         private_client = private_voutput->private_client;
2156
2157         pthread_mutex_lock(&private_client->lock);
2158
2159         if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2160                 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2161
2162                 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2163                         tbm_surface_h tbm_surface = NULL;
2164
2165                         LIST_DEL(&cb->link);
2166
2167                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2168                         if (tbm_surface)
2169                                 tbm_surface_internal_unref(tbm_surface);
2170
2171                         wl_buffer_set_user_data(cb->wl_buffer, NULL);
2172                         wl_buffer_destroy(cb->wl_buffer);
2173
2174                         free(cb);
2175                 }
2176         }
2177
2178         if (private_voutput->bufmgr)
2179                 tbm_bufmgr_deinit(private_voutput->bufmgr);
2180
2181         if (private_voutput->available_modes.modes)
2182                 free(private_voutput->available_modes.modes);
2183
2184         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2185                 LIST_DEL(&h->link);
2186                 free(h);
2187         }
2188
2189         if (private_voutput->get_output)
2190                 _tdm_client_output_destroy(private_voutput->private_output);
2191
2192         wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2193
2194         LIST_DEL(&private_voutput->link);
2195
2196         free(private_voutput);
2197
2198         pthread_mutex_unlock(&private_client->lock);
2199 }
2200
2201 tdm_error
2202 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2203 {
2204         tdm_private_client_voutput *private_voutput;
2205         tdm_private_client *private_client;
2206         tdm_error ret = TDM_ERROR_NONE;
2207
2208         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2209
2210         if ((count > 0) && (modes == NULL))
2211                 return TDM_ERROR_INVALID_PARAMETER;
2212
2213         private_voutput = (tdm_private_client_voutput *)voutput;
2214         private_client = private_voutput->private_client;
2215
2216         if (!private_voutput->private_output) {
2217                 private_voutput->private_output = tdm_client_voutput_get_client_output(private_voutput, &ret);
2218                 TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
2219         }
2220
2221         pthread_mutex_lock(&private_client->lock);
2222
2223         if (private_voutput->private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2224                 pthread_mutex_unlock(&private_client->lock);
2225                 return TDM_ERROR_BAD_REQUEST;
2226         }
2227
2228         if (private_voutput->available_modes.modes)
2229                 free(private_voutput->available_modes.modes);
2230
2231         private_voutput->available_modes.count = count;
2232
2233         if (count != 0) {
2234                 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2235                 if (private_voutput->available_modes.modes == NULL) {
2236                         private_voutput->available_modes.count = 0;
2237                         pthread_mutex_unlock(&private_client->lock);
2238                         return TDM_ERROR_OUT_OF_MEMORY;
2239                 }
2240                 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2241         }
2242
2243         pthread_mutex_unlock(&private_client->lock);
2244
2245         return TDM_ERROR_NONE;
2246 }
2247
2248 tdm_error
2249 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2250 {
2251         tdm_private_client_voutput *private_voutput;
2252         tdm_private_client *private_client;
2253         tdm_error ret = TDM_ERROR_NONE;
2254
2255         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2256         TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2257         TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2258
2259         private_voutput = (tdm_private_client_voutput *)voutput;
2260         private_client = private_voutput->private_client;
2261
2262         if (!private_voutput->private_output) {
2263                 private_voutput->private_output = tdm_client_voutput_get_client_output(private_voutput, &ret);
2264                 TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
2265         }
2266
2267         pthread_mutex_lock(&private_client->lock);
2268
2269         if (private_voutput->private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2270                 pthread_mutex_unlock(&private_client->lock);
2271                 return TDM_ERROR_BAD_REQUEST;
2272         }
2273
2274         private_voutput->mmwidth = mmWidth;
2275         private_voutput->mmheight = mmHeight;
2276
2277         pthread_mutex_unlock(&private_client->lock);
2278
2279         return TDM_ERROR_NONE;
2280 }
2281
2282 tdm_error
2283 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2284                                                                           tdm_client_voutput_commit_handler func,
2285                                                                           void *user_data)
2286 {
2287         tdm_private_client_voutput *private_voutput;
2288         tdm_private_client *private_client;
2289         tdm_client_voutput_commit_handler_info *h = NULL;
2290
2291         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2292         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2293
2294         private_voutput = (tdm_private_client_voutput *)voutput;
2295         private_client = private_voutput->private_client;
2296
2297         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2298                 if (h->func == func && h->user_data == user_data) {
2299                         TDM_ERR("can't add twice");
2300                         return TDM_ERROR_BAD_REQUEST;
2301                 }
2302         }
2303
2304         h = calloc(1, sizeof *h);
2305         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2306
2307         pthread_mutex_lock(&private_client->lock);
2308
2309         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2310                 free(h);
2311                 pthread_mutex_unlock(&private_client->lock);
2312                 return TDM_ERROR_PROTOCOL_ERROR;
2313         }
2314
2315         h->private_voutput = private_voutput;
2316         h->func = func;
2317         h->user_data = user_data;
2318         LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2319         LIST_INITHEAD(&h->call_link);
2320
2321         pthread_mutex_unlock(&private_client->lock);
2322
2323         return TDM_ERROR_NONE;
2324 }
2325
2326 void
2327 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2328                                                                                  tdm_client_voutput_commit_handler func,
2329                                                                                  void *user_data)
2330 {
2331         tdm_private_client_voutput *private_voutput;
2332         tdm_private_client *private_client;
2333         tdm_client_voutput_commit_handler_info *h = NULL;
2334
2335         TDM_RETURN_IF_FAIL(voutput != NULL);
2336         TDM_RETURN_IF_FAIL(func != NULL);
2337
2338         private_voutput = (tdm_private_client_voutput *)voutput;
2339         private_client = private_voutput->private_client;
2340
2341         pthread_mutex_lock(&private_client->lock);
2342
2343         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2344                 if (h->func != func || h->user_data != user_data)
2345                         continue;
2346
2347                 LIST_DEL(&h->link);
2348                 free(h);
2349
2350                 pthread_mutex_unlock(&private_client->lock);
2351
2352                 return;
2353         }
2354
2355         pthread_mutex_unlock(&private_client->lock);
2356 }
2357
2358 tdm_error
2359 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2360 {
2361         tdm_private_client_voutput *private_voutput;
2362         tdm_private_client *private_client;
2363         tbm_surface_h buffer = NULL;
2364
2365         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2366
2367         private_voutput = (tdm_private_client_voutput *)voutput;
2368         TDM_RETURN_VAL_IF_FAIL(private_voutput->attach_buffer != NULL, TDM_ERROR_NONE);
2369
2370         private_client = private_voutput->private_client;
2371
2372         pthread_mutex_lock(&private_client->lock);
2373
2374         buffer = (tbm_surface_h)wl_buffer_get_user_data(private_voutput->attach_buffer->wl_buffer);
2375         tbm_surface_internal_unref(buffer);
2376         private_voutput->attach_buffer = NULL;
2377         wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2378
2379         pthread_mutex_unlock(&private_client->lock);
2380
2381         return TDM_ERROR_NONE;
2382 }
2383
2384 tdm_client_output *
2385 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2386 {
2387         tdm_private_client_voutput *private_voutput;
2388         tdm_private_client_output *private_output = NULL;
2389         tdm_private_client *private_client;
2390         tdm_error ret = TDM_ERROR_NONE;
2391
2392         if (error)
2393                 *error = TDM_ERROR_NONE;
2394
2395         if (!voutput) {
2396                 TDM_ERR("'!voutput' failed");
2397                 if (error)
2398                         *error = TDM_ERROR_INVALID_PARAMETER;
2399                 return NULL;
2400         }
2401
2402         private_voutput = (tdm_private_client_voutput *)voutput;
2403         private_client = private_voutput->private_client;
2404
2405         pthread_mutex_lock(&private_client->lock);
2406
2407         if (private_voutput->get_output) {
2408                 pthread_mutex_unlock(&private_client->lock);
2409                 return private_voutput->private_output;
2410         }
2411
2412         pthread_mutex_unlock(&private_client->lock);
2413         private_output = (tdm_private_client_output *)tdm_client_get_output(private_voutput->private_client, private_voutput->name, &ret);
2414         if (!private_output) {
2415                 TDM_ERR("tdm_client_voutput_get_client_output get private_output fail");
2416                 if (error)
2417                         *error = ret;
2418                 return NULL;
2419         }
2420         pthread_mutex_lock(&private_client->lock);
2421         private_output->voutput = private_voutput;
2422         private_voutput->private_output = private_output;
2423         private_voutput->get_output = 1;
2424
2425         pthread_mutex_unlock(&private_client->lock);
2426
2427         return private_output;
2428 }
2429
2430 void
2431 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2432 {
2433         tdm_client_output_mode *modes, *mode;
2434         struct wl_array array;
2435         int i, size;
2436
2437         modes = private_voutput->available_modes.modes;
2438         size = sizeof(tdm_client_output_mode);
2439
2440         wl_array_init(&array);
2441         for (i = 0; i < private_voutput->available_modes.count; i++) {
2442                 mode = wl_array_add(&array, size);
2443                 memcpy(mode, &modes[i], size);
2444         }
2445         wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2446         wl_array_release(&array);
2447 }
2448
2449 tdm_error
2450 tdm_client_voutput_connect(tdm_client_voutput *voutput)
2451 {
2452         tdm_private_client_output *private_output = NULL;;
2453         tdm_private_client_voutput *private_voutput = NULL;
2454         tdm_private_client *private_client;
2455
2456         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2457
2458         private_voutput = (tdm_private_client_voutput *)voutput;
2459         private_client = private_voutput->private_client;
2460         private_output = private_voutput->private_output;
2461
2462         pthread_mutex_lock(&private_client->lock);
2463
2464         if (private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2465                 pthread_mutex_unlock(&private_client->lock);
2466                 return TDM_ERROR_NONE;
2467         }
2468
2469         if (!private_output->watch_output_changes)
2470                 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2471
2472         _tdm_client_voutput_send_available_modes(private_voutput);
2473
2474         wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2475
2476         wl_tdm_voutput_connect(private_voutput->wl_voutput);
2477
2478         pthread_mutex_unlock(&private_client->lock);
2479
2480         return TDM_ERROR_NONE;
2481 }
2482
2483 tdm_error
2484 tdm_client_voutput_disconnect(tdm_client_voutput *voutput)
2485 {
2486         tdm_private_client_output *private_output = NULL;
2487         tdm_private_client_voutput *private_voutput = NULL;
2488         tdm_private_client *private_client;
2489
2490         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2491
2492         private_voutput = (tdm_private_client_voutput *)voutput;
2493         private_client = private_voutput->private_client;
2494         private_output = private_voutput->private_output;
2495
2496         pthread_mutex_lock(&private_client->lock);
2497
2498         if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
2499                 pthread_mutex_unlock(&private_client->lock);
2500                 return TDM_ERROR_NONE;
2501         }
2502
2503         if (!private_output->watch_output_changes)
2504                 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2505
2506         wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2507
2508         pthread_mutex_unlock(&private_client->lock);
2509
2510         return TDM_ERROR_NONE;
2511 }
2512
2513
2514 tdm_error
2515 tdm_client_voutput_set_mode(tdm_client_voutput *voutput, int index)
2516 {
2517         tdm_private_client_output *private_output;
2518         tdm_private_client_voutput *private_voutput = NULL;
2519         tdm_private_client *private_client;
2520
2521         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2522         TDM_RETURN_VAL_IF_FAIL(index >= 0, TDM_ERROR_INVALID_PARAMETER);
2523
2524         private_voutput = (tdm_private_client_voutput *)voutput;
2525         private_client = private_voutput->private_client;
2526         private_output = private_voutput->private_output;
2527
2528         pthread_mutex_lock(&private_client->lock);
2529
2530         if (private_voutput->available_modes.count - 1 < index) {
2531                 pthread_mutex_unlock(&private_client->lock);
2532                 return TDM_ERROR_INVALID_PARAMETER;
2533         }
2534
2535         if ((private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) ||
2536                 (private_voutput->available_modes.count == 0)) {
2537                 pthread_mutex_unlock(&private_client->lock);
2538                 return TDM_ERROR_BAD_REQUEST;
2539         }
2540
2541         TDM_DBG("mode_set request : %d", index);
2542
2543         wl_tdm_voutput_set_mode(private_voutput->wl_voutput, index);
2544
2545         pthread_mutex_unlock(&private_client->lock);
2546
2547         return TDM_ERROR_NONE;
2548 }