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