1 /**************************************************************************
5 * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
36 #define WL_HIDE_DEPRECATED
49 #include <tdm-client-protocol.h>
51 #include "tdm_client.h"
53 #include "tdm_macro.h"
56 #include "tdm_private.h"
57 #include <tbm_surface_internal.h>
59 #define TDM_ARRAY_NTH_DATA(array, type, n) (((type*)((array)->data)) + n)
61 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
63 typedef struct _tdm_private_client {
66 struct wl_display *display;
67 struct wl_event_queue *queue;
68 struct wl_registry *registry;
70 struct list_head output_list;
72 unsigned int enable_ttrace;
75 tdm_private_client_vblank *temp_vblank;
78 typedef struct _tdm_private_client_output {
79 tdm_private_client *private_client;
81 char name[TDM_NAME_LEN];
82 struct wl_tdm_output *output;
86 tdm_output_conn_status connection;
88 struct list_head vblank_list;
89 struct list_head change_handler_list;
92 unsigned int watch_output_changes;
94 struct list_head link;
95 } tdm_private_client_output;
97 typedef struct _tdm_private_client_buffer {
98 struct list_head link;
99 struct wl_buffer *wl_buffer;
100 } tdm_private_client_buffer;
102 typedef struct _tdm_private_client_voutput {
103 tdm_private_client_output base;
104 struct wl_tdm_voutput *wl_voutput;
105 struct list_head commit_handler_list;
110 tdm_client_output_mode *modes;
113 unsigned int mmwidth;
114 unsigned int mmheight;
118 struct list_head buffer_list;
120 tdm_private_client_buffer *commit_buffer;
121 } tdm_private_client_voutput;
123 struct _tdm_private_client_vblank {
124 tdm_private_client_output *private_output;
126 struct wl_tdm_vblank *vblank;
127 struct list_head wait_list;
129 char name[TDM_NAME_LEN];
133 unsigned int enable_fake;
134 unsigned int enable_ttrace;
136 unsigned int started;
142 struct list_head link;
145 typedef struct _tdm_client_output_handler_info {
146 tdm_private_client_output *private_output;
148 tdm_client_output_change_handler func;
151 struct list_head link;
152 struct list_head call_link;
153 } tdm_client_output_handler_info;
155 typedef struct _tdm_client_wait_info {
156 tdm_private_client_vblank *private_vblank;
158 tdm_client_vblank_handler func;
165 struct list_head link;
166 struct list_head call_link;
167 } tdm_client_wait_info;
169 typedef struct _tdm_client_voutput_commit_handler_info
171 tdm_private_client_voutput *private_voutput;
173 tdm_client_voutput_commit_handler func;
176 struct list_head link;
177 struct list_head call_link;
178 } tdm_client_voutput_commit_handler_info;
181 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
184 const struct wl_interface *intf;
187 err = wl_display_get_error(private_client->display);
191 if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
192 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
193 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
194 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
196 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
202 #define CHECK_WL_PROTOCOL_ERROR(pc) _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
205 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
207 tdm_private_client_vblank *private_vblank = data;
208 tdm_private_client *private_client;
210 TDM_RETURN_IF_FAIL(private_vblank != NULL);
212 private_vblank->stamp = stamp;
214 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
215 private_client = private_vblank->private_output->private_client;
217 private_client->stamp = stamp;
220 /* LCOV_EXCL_START */
222 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
223 uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
224 uint32_t tv_usec, uint32_t error)
226 tdm_private_client_vblank *private_vblank = data;
227 tdm_private_client *private_client;
228 tdm_client_wait_info *w = NULL, *wait_info = NULL;
230 TDM_RETURN_IF_FAIL(private_vblank != NULL);
232 private_client = private_vblank->private_output->private_client;
234 private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
236 TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
237 private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
239 LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
240 if (w->req_id != req_id)
248 TDM_ERR("no wait infomation for req_id(%d)", req_id);
252 if (private_vblank->enable_ttrace)
253 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
255 if (wait_info->req_time >= private_vblank->last_time)
256 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
258 if (wait_info->need_free)
259 LIST_DEL(&wait_info->link);
261 if (wait_info->func) {
262 pthread_mutex_unlock(&private_client->lock);
263 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
264 pthread_mutex_lock(&private_client->lock);
267 if (wait_info->need_free)
270 wait_info->need_free = 1;
274 /* LCOV_EXCL_START */
276 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
278 tdm_private_client_vblank *private_vblank = data;
279 tdm_private_client *private_client;
281 TDM_RETURN_IF_FAIL(private_vblank != NULL);
283 private_vblank->enable_ttrace = enable;
285 TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
286 private_client = private_vblank->private_output->private_client;
288 private_client->enable_ttrace = enable;
292 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
293 _tdm_client_vblank_cb_stamp,
294 _tdm_client_vblank_cb_done,
295 _tdm_client_vblank_cb_ttrace,
299 _tdm_client_output_destroy(tdm_private_client_output *private_output)
301 tdm_private_client_vblank *v = NULL, *vv = NULL;
302 tdm_client_output_handler_info *h = NULL, *hh = NULL;
304 LIST_DEL(&private_output->link);
306 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
307 TDM_ERR("vblanks SHOULD be destroyed first!");
309 v->private_output = NULL;
312 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
317 wl_tdm_output_destroy(private_output->output);
319 free(private_output);
323 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
324 uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
326 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
328 TDM_RETURN_IF_FAIL(private_output != NULL);
330 private_output->width = width;
331 private_output->height = height;
332 private_output->refresh = refresh;
334 if (error != TDM_ERROR_NONE)
335 TDM_INFO("mode event error: %d", error);
337 TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
338 private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
339 width, height, refresh);
343 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
345 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
346 tdm_private_client *private_client;
347 tdm_client_output_handler_info *h = NULL, *hh = NULL;
349 struct list_head call_list;
351 TDM_RETURN_IF_FAIL(private_output != NULL);
353 private_client = private_output->private_client;
355 if (private_output->connection == value)
358 private_output->connection = value;
360 if (error != TDM_ERROR_NONE)
361 TDM_INFO("connection event error: %d", error);
363 TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
365 wl_proxy_get_id((struct wl_proxy*)private_output->output),
368 LIST_INITHEAD(&call_list);
370 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
371 LIST_ADDTAIL(&h->call_link, &call_list);
375 pthread_mutex_unlock(&private_client->lock);
376 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
378 h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
380 pthread_mutex_lock(&private_client->lock);
384 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
386 tdm_private_client_output *private_output = (tdm_private_client_output*)data;
387 tdm_private_client *private_client;
388 tdm_client_output_handler_info *h = NULL, *hh = NULL;
390 struct list_head call_list;
392 TDM_RETURN_IF_FAIL(private_output != NULL);
394 private_client = private_output->private_client;
396 /* If value is extended value, we handle it as DPMS on in client side
397 * The extended DPMS value is valid only in server side.
398 * Or, need to export to client side also?
400 if (value > TDM_OUTPUT_DPMS_OFF)
401 value = TDM_OUTPUT_DPMS_ON;
403 if (private_output->dpms == value)
406 private_output->dpms = value;
408 if (error != TDM_ERROR_NONE)
409 TDM_INFO("dpms event error: %d", error);
411 TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
413 wl_proxy_get_id((struct wl_proxy*)private_output->output),
416 LIST_INITHEAD(&call_list);
418 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
419 LIST_ADDTAIL(&h->call_link, &call_list);
423 pthread_mutex_unlock(&private_client->lock);
424 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
426 h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
428 pthread_mutex_lock(&private_client->lock);
431 static const struct wl_tdm_output_listener tdm_client_output_listener = {
432 _tdm_client_output_cb_mode,
433 _tdm_client_output_cb_connection,
434 _tdm_client_output_cb_dpms,
438 _tdm_client_cb_global(void *data, struct wl_registry *registry,
439 uint32_t name, const char *interface,
442 tdm_private_client *private_client = data;
444 if (strncmp(interface, "wl_tdm", 6) == 0) {
445 private_client->tdm =
446 wl_registry_bind(registry, name, &wl_tdm_interface, version);
447 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
449 wl_display_flush(private_client->display);
453 /* LCOV_EXCL_START */
455 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
460 static const struct wl_registry_listener tdm_client_registry_listener = {
461 _tdm_client_cb_global,
462 _tdm_client_cb_global_remove
466 tdm_client_create(tdm_error *error)
468 tdm_private_client *private_client;
470 private_client = calloc(1, sizeof *private_client);
471 if (!private_client) {
472 /* LCOV_EXCL_START */
474 TDM_ERR("alloc failed");
476 *error = TDM_ERROR_OUT_OF_MEMORY;
482 if (pthread_mutex_init(&private_client->lock, NULL)) {
483 TDM_ERR("mutex init failed: %m");
484 free(private_client);
486 *error = TDM_ERROR_OUT_OF_MEMORY;
490 LIST_INITHEAD(&private_client->output_list);
492 private_client->display = wl_display_connect("tdm-socket");
493 TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
495 private_client->queue = wl_display_create_queue(private_client->display);
496 TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
498 private_client->registry = wl_display_get_registry(private_client->display);
499 TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
501 wl_registry_add_listener(private_client->registry,
502 &tdm_client_registry_listener, private_client);
503 wl_display_roundtrip(private_client->display);
505 if (CHECK_WL_PROTOCOL_ERROR(private_client))
508 /* check global objects */
509 TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
512 *error = TDM_ERROR_NONE;
514 return (tdm_client*)private_client;
516 tdm_client_destroy((tdm_client*)private_client);
518 *error = TDM_ERROR_OPERATION_FAILED;
523 tdm_client_destroy(tdm_client *client)
525 tdm_private_client *private_client = (tdm_private_client*)client;
526 tdm_private_client_output *o = NULL, *oo = NULL;
531 pthread_mutex_lock(&private_client->lock);
533 if (private_client->temp_vblank) {
534 pthread_mutex_unlock(&private_client->lock);
535 tdm_client_vblank_destroy(private_client->temp_vblank);
536 pthread_mutex_lock(&private_client->lock);
539 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
540 _tdm_client_output_destroy(o);
543 if (private_client->tdm)
544 wl_tdm_destroy(private_client->tdm);
545 if (private_client->registry)
546 wl_registry_destroy(private_client->registry);
547 if (private_client->queue)
548 wl_event_queue_destroy(private_client->queue);
549 if (private_client->display)
550 wl_display_disconnect(private_client->display);
552 pthread_mutex_unlock(&private_client->lock);
553 pthread_mutex_destroy(&private_client->lock);
555 free(private_client);
559 tdm_client_get_fd(tdm_client *client, int *fd)
561 tdm_private_client *private_client;
563 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
564 TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
566 private_client = (tdm_private_client*)client;
568 pthread_mutex_lock(&private_client->lock);
570 *fd = wl_display_get_fd(private_client->display);
572 pthread_mutex_unlock(&private_client->lock);
575 return TDM_ERROR_OPERATION_FAILED;
577 return TDM_ERROR_NONE;
581 tdm_client_handle_events(tdm_client *client)
583 tdm_private_client *private_client;
585 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
587 /* LCOV_EXCL_START */
588 private_client = (tdm_private_client*)client;
590 pthread_mutex_lock(&private_client->lock);
592 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
593 pthread_mutex_unlock(&private_client->lock);
594 return TDM_ERROR_PROTOCOL_ERROR;
597 if (private_client->enable_ttrace)
598 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
600 wl_display_dispatch(private_client->display);
602 if (private_client->enable_ttrace)
603 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
605 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
606 pthread_mutex_unlock(&private_client->lock);
607 return TDM_ERROR_PROTOCOL_ERROR;
610 pthread_mutex_unlock(&private_client->lock);
612 return TDM_ERROR_NONE;
617 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
620 struct pollfd pfd[1];
622 pfd[0].fd = wl_display_get_fd(display);
623 pfd[0].events = events;
625 ret = poll(pfd, 1, timeout);
626 } while (ret == -1 && errno == EINTR);
632 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
635 struct wl_display *display = private_client->display;
637 if (wl_display_prepare_read(display) == -1) {
638 if (wl_display_dispatch_pending(display) > 0)
639 return TDM_ERROR_NONE;
641 return TDM_ERROR_OPERATION_FAILED;
645 ret = wl_display_flush(display);
647 if (ret != -1 || errno != EAGAIN)
650 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
651 wl_display_cancel_read(display);
652 TDM_ERR("_tdm_client_poll failed");
653 return TDM_ERROR_OPERATION_FAILED;
657 /* Don't stop if flushing hits an EPIPE; continue so we can read any
658 * protocol error that may have triggered it. */
659 if (ret < 0 && errno != EPIPE) {
660 TDM_ERR("ret(%d) errno(%d)", ret, errno);
661 wl_display_cancel_read(display);
662 return TDM_ERROR_OPERATION_FAILED;
665 ret = _tdm_client_poll(display, POLLIN, timeout);
667 wl_display_cancel_read(display);
669 TDM_ERR("_tdm_client_poll timeout.");
670 return TDM_ERROR_TIMEOUT;
672 TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
673 return TDM_ERROR_OPERATION_FAILED;
677 if (wl_display_read_events(display) == -1) {
678 TDM_ERR("wl_display_read_events failed");
679 return TDM_ERROR_OPERATION_FAILED;
682 ret = wl_display_dispatch_pending(display);
685 TDM_ERR("_tdm_client_dispatch_timeout failed");
686 return TDM_ERROR_OPERATION_FAILED;
689 return TDM_ERROR_NONE;
693 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
695 tdm_private_client *private_client;
697 TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
699 private_client = (tdm_private_client*)client;
701 pthread_mutex_lock(&private_client->lock);
703 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
704 pthread_mutex_unlock(&private_client->lock);
705 return TDM_ERROR_PROTOCOL_ERROR;
708 if (private_client->enable_ttrace)
709 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
711 ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
713 if (private_client->enable_ttrace)
714 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
716 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
717 pthread_mutex_unlock(&private_client->lock);
718 return TDM_ERROR_PROTOCOL_ERROR;
721 pthread_mutex_unlock(&private_client->lock);
726 typedef struct _tdm_client_vblank_temp {
727 tdm_client_vblank_handler2 func;
729 } tdm_client_vblank_temp;
731 /* LCOV_EXCL_START */
733 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
734 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
736 tdm_client_vblank_temp *vblank_temp = user_data;
738 TDM_RETURN_IF_FAIL(vblank_temp != NULL);
739 TDM_RETURN_IF_FAIL(vblank != NULL);
741 if (vblank_temp->func)
742 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
748 /* LCOV_EXCL_START */ /* deprecated */
750 tdm_client_wait_vblank(tdm_client *client, char *name,
751 int sw_timer, int interval, int sync,
752 tdm_client_vblank_handler2 func, void *user_data)
754 tdm_private_client *private_client = (tdm_private_client*)client;
755 tdm_client_output *output;
756 tdm_client_vblank_temp *vblank_temp;
759 TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
760 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
761 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
763 if (CHECK_WL_PROTOCOL_ERROR(private_client))
764 return TDM_ERROR_PROTOCOL_ERROR;
766 if (!private_client->temp_vblank) {
767 output = tdm_client_get_output(client, name, &ret);
768 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
770 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
771 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
774 tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
775 tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
777 vblank_temp = calloc(1, sizeof *vblank_temp);
778 TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
780 vblank_temp->func = func;
781 vblank_temp->user_data = user_data;
783 return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
788 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
790 tdm_private_client *private_client;
791 tdm_private_client_output *private_output = NULL;
792 struct wl_proxy *wrapper;
795 *error = TDM_ERROR_NONE;
798 TDM_ERR("'!client' failed");
800 *error = TDM_ERROR_INVALID_PARAMETER;
804 private_client = (tdm_private_client*)client;
806 pthread_mutex_lock(&private_client->lock);
808 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
810 *error = TDM_ERROR_PROTOCOL_ERROR;
811 pthread_mutex_unlock(&private_client->lock);
817 } else if (strncmp(name, "primary", 7) && strncmp(name, "default", 7)) {
819 *error = TDM_ERROR_INVALID_PARAMETER;
820 pthread_mutex_unlock(&private_client->lock);
824 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
825 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
826 pthread_mutex_unlock(&private_client->lock);
827 return (tdm_client_output*)private_output;
831 wrapper = wl_proxy_create_wrapper(private_client->tdm);
833 TDM_ERR("create output_wrapper failed");
835 *error = TDM_ERROR_OUT_OF_MEMORY;
836 pthread_mutex_unlock(&private_client->lock);
840 wl_proxy_set_queue(wrapper, private_client->queue);
842 private_output = calloc(1, sizeof *private_output);
843 if (!private_output) {
844 /* LCOV_EXCL_START */
845 wl_proxy_wrapper_destroy(wrapper);
846 TDM_ERR("alloc failed");
848 *error = TDM_ERROR_OUT_OF_MEMORY;
849 pthread_mutex_unlock(&private_client->lock);
855 private_output->private_client = private_client;
857 snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
858 private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
859 wl_proxy_wrapper_destroy(wrapper);
860 if (!private_output->output) {
861 /* LCOV_EXCL_START */
863 TDM_ERR("couldn't create output resource");
864 free(private_output);
866 *error = TDM_ERROR_OUT_OF_MEMORY;
867 pthread_mutex_unlock(&private_client->lock);
873 LIST_INITHEAD(&private_output->vblank_list);
874 LIST_INITHEAD(&private_output->change_handler_list);
876 wl_tdm_output_add_listener(private_output->output,
877 &tdm_client_output_listener, private_output);
878 wl_display_roundtrip_queue(private_client->display, private_client->queue);
880 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
882 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
883 wl_tdm_output_destroy(private_output->output);
884 free(private_output);
886 *error = TDM_ERROR_PROTOCOL_ERROR;
887 pthread_mutex_unlock(&private_client->lock);
891 LIST_ADDTAIL(&private_output->link, &private_client->output_list);
893 pthread_mutex_unlock(&private_client->lock);
895 return (tdm_client_output*)private_output;
899 tdm_client_output_add_change_handler(tdm_client_output *output,
900 tdm_client_output_change_handler func,
903 tdm_private_client_output *private_output;
904 tdm_private_client *private_client;
905 tdm_client_output_handler_info *h = NULL;
907 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
908 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
910 private_output = (tdm_private_client_output*)output;
911 private_client = private_output->private_client;
913 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
914 if (h->func == func && h->user_data == user_data) {
915 TDM_ERR("can't add twice");
916 return TDM_ERROR_BAD_REQUEST;
920 h = calloc(1, sizeof *h);
921 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
923 pthread_mutex_lock(&private_client->lock);
925 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
927 pthread_mutex_unlock(&private_client->lock);
928 return TDM_ERROR_PROTOCOL_ERROR;
931 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
932 wl_tdm_output_watch_output_changes(private_output->output, 1);
933 wl_display_roundtrip_queue(private_client->display, private_client->queue);
935 /* TODO: this is very tricky.
936 * If a client adds the change_handler, we might be able to guess that
937 * the client will watch the tdm client's fd and handle tdm events in
938 * event loop. Otherwise, we CAN'T make sure if a client has event loop
939 * which handles tdm events.
941 private_output->watch_output_changes = 1;
944 h->private_output = private_output;
946 h->user_data = user_data;
947 LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
948 LIST_INITHEAD(&h->call_link);
950 pthread_mutex_unlock(&private_client->lock);
952 return TDM_ERROR_NONE;
956 tdm_client_output_remove_change_handler(tdm_client_output *output,
957 tdm_client_output_change_handler func,
960 tdm_private_client_output *private_output;
961 tdm_private_client *private_client;
962 tdm_client_output_handler_info *h = NULL;
964 TDM_RETURN_IF_FAIL(output != NULL);
965 TDM_RETURN_IF_FAIL(func != NULL);
967 private_output = (tdm_private_client_output*)output;
968 private_client = private_output->private_client;
970 pthread_mutex_lock(&private_client->lock);
972 LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
973 if (h->func != func || h->user_data != user_data)
979 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
980 private_output->watch_output_changes = 0;
981 if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
982 wl_tdm_output_watch_output_changes(private_output->output, 0);
983 wl_display_roundtrip_queue(private_client->display, private_client->queue);
987 pthread_mutex_unlock(&private_client->lock);
992 pthread_mutex_unlock(&private_client->lock);
996 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
998 tdm_private_client_output *private_output;
999 tdm_private_client *private_client;
1001 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1002 TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1004 private_output = (tdm_private_client_output*)output;
1005 private_client = private_output->private_client;
1007 pthread_mutex_lock(&private_client->lock);
1009 if (private_output->watch_output_changes) {
1010 *refresh = private_output->refresh;
1011 pthread_mutex_unlock(&private_client->lock);
1012 return TDM_ERROR_NONE;
1015 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1016 pthread_mutex_unlock(&private_client->lock);
1017 return TDM_ERROR_PROTOCOL_ERROR;
1020 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1021 wl_tdm_output_get_mode(private_output->output);
1022 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1023 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1025 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1026 pthread_mutex_unlock(&private_client->lock);
1027 return TDM_ERROR_PROTOCOL_ERROR;
1030 *refresh = private_output->refresh;
1032 pthread_mutex_unlock(&private_client->lock);
1034 return TDM_ERROR_NONE;
1038 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1040 tdm_private_client_output *private_output;
1041 tdm_private_client *private_client;
1043 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1044 TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1046 private_output = (tdm_private_client_output*)output;
1047 private_client = private_output->private_client;
1049 pthread_mutex_lock(&private_client->lock);
1051 if (private_output->watch_output_changes) {
1052 *status = private_output->connection;
1053 pthread_mutex_unlock(&private_client->lock);
1054 return TDM_ERROR_NONE;
1057 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1058 pthread_mutex_unlock(&private_client->lock);
1059 return TDM_ERROR_PROTOCOL_ERROR;
1062 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1063 wl_tdm_output_get_connection(private_output->output);
1064 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1065 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1067 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1068 pthread_mutex_unlock(&private_client->lock);
1069 return TDM_ERROR_PROTOCOL_ERROR;
1072 *status = private_output->connection;
1074 pthread_mutex_unlock(&private_client->lock);
1076 return TDM_ERROR_NONE;
1080 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1082 tdm_private_client_output *private_output;
1083 tdm_private_client *private_client;
1085 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1086 TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1088 private_output = (tdm_private_client_output*)output;
1089 private_client = private_output->private_client;
1091 if (private_output->watch_output_changes) {
1092 *dpms = private_output->dpms;
1093 return TDM_ERROR_NONE;
1096 pthread_mutex_lock(&private_client->lock);
1098 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1099 pthread_mutex_unlock(&private_client->lock);
1100 return TDM_ERROR_PROTOCOL_ERROR;
1103 wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1104 wl_tdm_output_get_dpms(private_output->output);
1105 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1106 wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1108 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1109 pthread_mutex_unlock(&private_client->lock);
1110 return TDM_ERROR_PROTOCOL_ERROR;
1113 *dpms = private_output->dpms;
1115 pthread_mutex_unlock(&private_client->lock);
1117 return TDM_ERROR_NONE;
1121 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1123 tdm_private_client *private_client;
1124 tdm_private_client_output *private_output;
1125 tdm_private_client_vblank *private_vblank;
1126 struct wl_proxy *wrapper;
1129 *error = TDM_ERROR_NONE;
1132 TDM_ERR("'!output' failed");
1134 *error = TDM_ERROR_INVALID_PARAMETER;
1138 private_output = (tdm_private_client_output*)output;
1139 private_client = private_output->private_client;
1141 pthread_mutex_lock(&private_client->lock);
1143 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1145 *error = TDM_ERROR_PROTOCOL_ERROR;
1146 pthread_mutex_unlock(&private_client->lock);
1150 wrapper = wl_proxy_create_wrapper(private_output->output);
1152 TDM_ERR("create output_wrapper failed");
1154 *error = TDM_ERROR_OUT_OF_MEMORY;
1155 pthread_mutex_unlock(&private_client->lock);
1159 wl_proxy_set_queue(wrapper, private_client->queue);
1161 private_vblank = calloc(1, sizeof *private_vblank);
1162 if (!private_vblank) {
1163 /* LCOV_EXCL_START */
1165 TDM_ERR("alloc failed");
1166 wl_proxy_wrapper_destroy(wrapper);
1168 *error = TDM_ERROR_OUT_OF_MEMORY;
1169 pthread_mutex_unlock(&private_client->lock);
1172 /* LCOV_EXCL_STOP */
1175 private_vblank->private_output = private_output;
1177 private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1178 wl_proxy_wrapper_destroy(wrapper);
1179 if (!private_vblank->vblank) {
1180 /* LCOV_EXCL_START */
1182 TDM_ERR("couldn't create vblank resource");
1183 free(private_vblank);
1185 *error = TDM_ERROR_OUT_OF_MEMORY;
1186 pthread_mutex_unlock(&private_client->lock);
1189 /* LCOV_EXCL_STOP */
1193 private_vblank->fps = private_output->refresh;
1194 private_vblank->offset = 0;
1195 private_vblank->enable_fake = 0;
1197 LIST_INITHEAD(&private_vblank->wait_list);
1199 wl_tdm_vblank_add_listener(private_vblank->vblank,
1200 &tdm_client_vblank_listener, private_vblank);
1201 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1203 wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1205 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1206 wl_tdm_vblank_destroy(private_vblank->vblank);
1207 free(private_vblank);
1209 *error = TDM_ERROR_PROTOCOL_ERROR;
1210 pthread_mutex_unlock(&private_client->lock);
1214 LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1216 pthread_mutex_unlock(&private_client->lock);
1218 return (tdm_client_vblank*)private_vblank;
1222 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1224 tdm_private_client_vblank *private_vblank;
1225 tdm_private_client *private_client;
1226 tdm_client_wait_info *w = NULL, *ww = NULL;
1228 TDM_RETURN_IF_FAIL(vblank != NULL);
1230 private_vblank = vblank;
1231 private_client = private_vblank->private_output->private_client;
1233 pthread_mutex_lock(&private_client->lock);
1235 LIST_DEL(&private_vblank->link);
1237 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1242 wl_tdm_vblank_destroy(private_vblank->vblank);
1244 free(private_vblank);
1246 pthread_mutex_unlock(&private_client->lock);
1250 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1252 tdm_private_client_vblank *private_vblank;
1253 tdm_private_client *private_client;
1255 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1257 private_vblank = vblank;
1258 private_client = private_vblank->private_output->private_client;
1260 pthread_mutex_lock(&private_client->lock);
1262 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1263 pthread_mutex_unlock(&private_client->lock);
1264 return TDM_ERROR_PROTOCOL_ERROR;
1268 name = TDM_VBLANK_DEFAULT_NAME;
1270 strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1271 private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1273 wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1275 pthread_mutex_unlock(&private_client->lock);
1277 return TDM_ERROR_NONE;
1281 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1283 tdm_private_client_vblank *private_vblank;
1284 tdm_private_client *private_client;
1286 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1288 private_vblank = vblank;
1289 private_client = private_vblank->private_output->private_client;
1291 pthread_mutex_lock(&private_client->lock);
1292 private_vblank->sync = sync;
1293 pthread_mutex_unlock(&private_client->lock);
1295 return TDM_ERROR_NONE;
1299 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1301 tdm_private_client_vblank *private_vblank;
1302 tdm_private_client *private_client;
1304 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1305 TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1307 private_vblank = vblank;
1308 private_client = private_vblank->private_output->private_client;
1310 pthread_mutex_lock(&private_client->lock);
1312 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1313 pthread_mutex_unlock(&private_client->lock);
1314 return TDM_ERROR_PROTOCOL_ERROR;
1317 if (private_vblank->fps == fps) {
1318 pthread_mutex_unlock(&private_client->lock);
1319 return TDM_ERROR_NONE;
1322 private_vblank->fps = fps;
1324 wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1326 pthread_mutex_unlock(&private_client->lock);
1328 return TDM_ERROR_NONE;
1332 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1334 tdm_private_client_vblank *private_vblank;
1335 tdm_private_client *private_client;
1337 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1339 private_vblank = vblank;
1340 TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1342 private_client = private_vblank->private_output->private_client;
1344 pthread_mutex_lock(&private_client->lock);
1346 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1347 pthread_mutex_unlock(&private_client->lock);
1348 return TDM_ERROR_PROTOCOL_ERROR;
1351 if (private_vblank->offset == offset_ms) {
1352 pthread_mutex_unlock(&private_client->lock);
1353 return TDM_ERROR_NONE;
1356 private_vblank->offset = offset_ms;
1358 wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1360 pthread_mutex_unlock(&private_client->lock);
1362 return TDM_ERROR_NONE;
1366 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1368 tdm_private_client_vblank *private_vblank;
1369 tdm_private_client *private_client;
1371 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1373 private_vblank = vblank;
1374 private_client = private_vblank->private_output->private_client;
1376 pthread_mutex_lock(&private_client->lock);
1378 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1379 pthread_mutex_unlock(&private_client->lock);
1380 return TDM_ERROR_PROTOCOL_ERROR;
1383 if (private_vblank->enable_fake == enable_fake) {
1384 pthread_mutex_unlock(&private_client->lock);
1385 return TDM_ERROR_NONE;
1388 private_vblank->enable_fake = enable_fake;
1390 wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1392 pthread_mutex_unlock(&private_client->lock);
1394 return TDM_ERROR_NONE;
1398 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1400 tdm_private_client *private_client;
1401 tdm_private_client_output *private_output;
1402 tdm_private_client_vblank *private_vblank;
1403 tdm_client_wait_info *w;
1405 unsigned int req_sec, req_usec;
1408 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1409 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1410 /* can't support "interval 0" and "getting current_msc" things because
1411 * there is a socket communication between TDM client and server. It's impossible
1412 * to return the current msc or sequence immediately.
1414 TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1416 private_vblank = vblank;
1417 private_output = private_vblank->private_output;
1418 private_client = private_output->private_client;
1420 pthread_mutex_lock(&private_client->lock);
1422 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1423 pthread_mutex_unlock(&private_client->lock);
1424 return TDM_ERROR_PROTOCOL_ERROR;
1427 if (!private_vblank->started)
1428 private_vblank->started = 1;
1430 if (!private_vblank->enable_fake) {
1431 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1432 TDM_ERR("output disconnected");
1433 pthread_mutex_unlock(&private_client->lock);
1434 return TDM_ERROR_OUTPUT_DISCONNECTED;
1436 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1437 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1438 pthread_mutex_unlock(&private_client->lock);
1439 return TDM_ERROR_DPMS_OFF;
1443 w = calloc(1, sizeof *w);
1445 /* LCOV_EXCL_START */
1447 TDM_ERR("alloc failed");
1448 pthread_mutex_unlock(&private_client->lock);
1449 return TDM_ERROR_OUT_OF_MEMORY;
1451 /* LCOV_EXCL_STOP */
1454 w->private_vblank = private_vblank;
1456 w->user_data = user_data;
1458 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1459 LIST_INITHEAD(&w->call_link);
1461 clock_gettime(CLOCK_MONOTONIC, &tp);
1462 req_sec = (unsigned int)tp.tv_sec;
1463 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1465 w->req_id = ++private_output->req_id;
1466 w->req_time = TDM_TIME(req_sec, req_usec);
1467 w->need_free = (private_vblank->sync) ? 0 : 1;
1469 wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1471 if (private_vblank->enable_ttrace)
1472 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1474 TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1475 vblank, interval, w->req_id, w->req_time);
1477 private_vblank->req_time = w->req_time;
1479 if (private_vblank->last_time >= w->req_time)
1480 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1482 if (!private_vblank->sync) {
1483 wl_display_flush(private_client->display);
1484 pthread_mutex_unlock(&private_client->lock);
1485 return TDM_ERROR_NONE;
1488 /* LCOV_EXCL_START */
1490 while (ret != -1 && !w->need_free)
1491 ret = wl_display_dispatch(private_client->display);
1493 clock_gettime(CLOCK_MONOTONIC, &tp);
1494 TDM_DBG("block during %d us",
1495 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1496 - (req_sec * 1000000 + req_usec));
1501 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1502 pthread_mutex_unlock(&private_client->lock);
1503 return TDM_ERROR_PROTOCOL_ERROR;
1506 pthread_mutex_unlock(&private_client->lock);
1508 return TDM_ERROR_NONE;
1510 /* LCOV_EXCL_STOP */
1514 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1515 tdm_client_vblank_handler func, void *user_data)
1517 tdm_private_client *private_client;
1518 tdm_private_client_output *private_output;
1519 tdm_private_client_vblank *private_vblank;
1520 tdm_client_wait_info *w;
1522 unsigned int req_sec, req_usec;
1525 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1526 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1528 private_vblank = vblank;
1529 private_output = private_vblank->private_output;
1530 private_client = private_output->private_client;
1532 pthread_mutex_lock(&private_client->lock);
1534 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1535 pthread_mutex_unlock(&private_client->lock);
1536 return TDM_ERROR_PROTOCOL_ERROR;
1539 if (!private_vblank->started)
1540 private_vblank->started = 1;
1542 if (!private_vblank->enable_fake) {
1543 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1544 TDM_ERR("output disconnected");
1545 pthread_mutex_unlock(&private_client->lock);
1546 return TDM_ERROR_OUTPUT_DISCONNECTED;
1548 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1549 TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1550 pthread_mutex_unlock(&private_client->lock);
1551 return TDM_ERROR_DPMS_OFF;
1555 w = calloc(1, sizeof *w);
1557 /* LCOV_EXCL_START */
1559 TDM_ERR("alloc failed");
1560 pthread_mutex_unlock(&private_client->lock);
1561 return TDM_ERROR_OUT_OF_MEMORY;
1563 /* LCOV_EXCL_STOP */
1566 w->private_vblank = private_vblank;
1568 w->user_data = user_data;
1570 LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1571 LIST_INITHEAD(&w->call_link);
1573 clock_gettime(CLOCK_MONOTONIC, &tp);
1574 req_sec = (unsigned int)tp.tv_sec;
1575 req_usec = (unsigned int)(tp.tv_nsec / 1000);
1577 w->req_id = ++private_output->req_id;
1578 w->req_time = TDM_TIME(req_sec, req_usec);
1579 w->need_free = (private_vblank->sync) ? 0 : 1;
1581 wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1583 if (private_vblank->enable_ttrace)
1584 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1586 TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1587 vblank, sequence, w->req_id, w->req_time);
1589 private_vblank->req_time = w->req_time;
1591 if (private_vblank->last_time >= w->req_time)
1592 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1594 if (!private_vblank->sync) {
1595 wl_display_flush(private_client->display);
1596 pthread_mutex_unlock(&private_client->lock);
1597 return TDM_ERROR_NONE;
1600 /* LCOV_EXCL_START */
1602 while (ret != -1 && !w->need_free)
1603 ret = wl_display_dispatch(private_client->display);
1605 clock_gettime(CLOCK_MONOTONIC, &tp);
1606 TDM_DBG("block during %d us",
1607 ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1608 - (req_sec * 1000000 + req_usec));
1613 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1614 pthread_mutex_unlock(&private_client->lock);
1615 return TDM_ERROR_PROTOCOL_ERROR;
1618 pthread_mutex_unlock(&private_client->lock);
1620 return TDM_ERROR_NONE;
1622 /* LCOV_EXCL_STOP */
1626 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1628 tdm_private_client_vblank *private_vblank;
1630 TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1632 private_vblank = vblank;
1634 return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1637 static tbm_surface_h
1638 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1646 struct wl_array *plane_buf_idx,
1647 struct wl_array *plane_offset,
1648 struct wl_array *plane_stride,
1649 struct wl_array *plane_size,
1656 int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1657 tbm_surface_info_s info = { 0, };
1658 tbm_bo bos[TBM_SURF_PLANE_MAX];
1659 int i, numPlane, numName;
1660 tbm_surface_h tbm_surface;
1662 numPlane = tbm_surface_internal_get_num_planes(format);
1663 TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1666 info.height = height;
1667 info.format = format;
1670 info.num_planes = numPlane;
1673 for (i = 0; i < numPlane; i++) {
1674 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1675 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1676 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1685 for (i = 0; i < numName; i++) {
1687 bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1689 bos[i] = tbm_bo_import(bufmgr, names[i]);
1692 tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1693 if (tbm_surface == NULL) {
1708 for (i = 0; i < numName; i++)
1709 tbm_bo_unref(bos[i]);
1714 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1715 struct wl_tdm_voutput *wl_voutput,
1716 struct wl_buffer *wl_buffer,
1723 struct wl_array *plane_buf_idx,
1724 struct wl_array *plane_offset,
1725 struct wl_array *plane_stride,
1726 struct wl_array *plane_size,
1733 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1734 tdm_private_client_buffer *buffer = NULL;
1735 tbm_surface_h tbm_surface;
1737 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1739 buffer = calloc(1, sizeof *buffer);
1740 TDM_RETURN_IF_FAIL(buffer != NULL);
1742 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1743 width, height, format, bpp, size,
1745 plane_buf_idx, plane_offset, plane_stride, plane_size,
1749 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1751 tbm_surface_internal_ref(tbm_surface);
1752 wl_buffer_set_user_data(wl_buffer, tbm_surface);
1754 buffer->wl_buffer = wl_buffer;
1756 LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1765 wl_buffer_destroy(wl_buffer);
1769 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1770 struct wl_tdm_voutput *wl_voutput,
1771 struct wl_buffer *wl_buffer,
1778 struct wl_array *plane_buf_idx,
1779 struct wl_array *plane_offset,
1780 struct wl_array *plane_stride,
1781 struct wl_array *plane_size,
1788 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1789 tdm_private_client_buffer *buffer = NULL;
1790 tbm_surface_h tbm_surface;
1792 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1794 buffer = calloc(1, sizeof *buffer);
1795 TDM_RETURN_IF_FAIL(buffer != NULL);
1797 tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1798 width, height, format, bpp, size,
1800 plane_buf_idx, plane_offset, plane_stride, plane_size,
1804 TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1806 tbm_surface_internal_ref(tbm_surface);
1807 wl_buffer_set_user_data(wl_buffer, tbm_surface);
1809 buffer->wl_buffer = wl_buffer;
1811 LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1820 wl_buffer_destroy(wl_buffer);
1824 tdm_client_voutput_cb_buffer_destroy(void *data,
1825 struct wl_tdm_voutput *wl_voutput,
1826 struct wl_buffer *wl_buffer)
1828 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1829 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1830 tbm_surface_h tbm_surface = NULL;
1832 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1834 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1835 if (wl_buffer == cb->wl_buffer) {
1836 LIST_DEL(&cb->link);
1838 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1840 tbm_surface_internal_unref(tbm_surface);
1842 wl_buffer_set_user_data(wl_buffer, NULL);
1843 wl_buffer_destroy(wl_buffer);
1855 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
1857 tdm_private_client_voutput *private_voutput;
1858 tdm_private_client *private_client;
1859 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
1860 struct list_head call_list;
1862 private_voutput = (tdm_private_client_voutput *)data;
1863 TDM_RETURN_IF_FAIL(private_voutput != NULL);
1865 private_client = private_voutput->base.private_client;
1867 LIST_INITHEAD(&call_list);
1869 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
1870 LIST_ADDTAIL(&h->call_link, &call_list);
1873 pthread_mutex_unlock(&private_client->lock);
1874 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
1876 h->func(private_voutput, h->user_data);
1878 pthread_mutex_lock(&private_client->lock);
1882 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1884 tdm_private_client_voutput *private_voutput = data;
1886 private_voutput->msg = msg;
1889 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1890 tdm_client_voutput_cb_buffer_import_with_id,
1891 tdm_client_voutput_cb_buffer_import_with_fd,
1892 tdm_client_voutput_cb_buffer_destroy,
1893 tdm_client_voutput_cb_commit,
1894 tdm_client_voutput_cb_ack_message
1897 tdm_client_voutput *
1898 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1900 tdm_private_client *private_client;
1901 tdm_private_client_output *private_output;
1902 tdm_private_client_voutput *private_voutput;
1903 struct wl_proxy *wrapper;
1906 *error = TDM_ERROR_NONE;
1909 TDM_ERR("'!client' failed");
1911 *error = TDM_ERROR_INVALID_PARAMETER;
1916 TDM_ERR("'!name' failed");
1918 *error = TDM_ERROR_INVALID_PARAMETER;
1922 private_client = (tdm_private_client *)client;
1924 pthread_mutex_lock(&private_client->lock);
1926 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1928 *error = TDM_ERROR_PROTOCOL_ERROR;
1929 pthread_mutex_unlock(&private_client->lock);
1933 LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1934 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1936 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1937 pthread_mutex_unlock(&private_client->lock);
1942 wrapper = wl_proxy_create_wrapper(private_client->tdm);
1944 TDM_ERR("create virtual output wrapper failed");
1946 *error = TDM_ERROR_OUT_OF_MEMORY;
1947 pthread_mutex_unlock(&private_client->lock);
1951 wl_proxy_set_queue(wrapper, private_client->queue);
1953 private_voutput = calloc(1, sizeof *private_voutput);
1954 if (!private_voutput) {
1955 /* LOCV_EXCL_START */
1956 wl_proxy_wrapper_destroy(wrapper);
1957 TDM_ERR("alloc failed");
1959 *error = TDM_ERROR_OUT_OF_MEMORY;
1960 pthread_mutex_unlock(&private_client->lock);
1962 /* LOCV_EXCL_STOP */
1965 private_voutput->bufmgr = tbm_bufmgr_init(-1);
1966 if (private_voutput->bufmgr == NULL) {
1967 /* LCOV_EXCL_START */
1968 TDM_ERR("fail tbm_bufmgr_init");
1969 free(private_voutput);
1971 *error = TDM_ERROR_OUT_OF_MEMORY;
1972 pthread_mutex_unlock(&private_client->lock);
1974 /* LCOV_EXCL_STOP */
1977 LIST_INITHEAD(&private_voutput->commit_handler_list);
1978 LIST_INITHEAD(&private_voutput->buffer_list);
1980 private_voutput->base.private_client = private_client;
1982 private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name);
1983 wl_proxy_wrapper_destroy(wrapper);
1984 if (!private_voutput->wl_voutput) {
1985 /* LCOV_EXCL_START */
1986 TDM_ERR("couldn't create voutput resource");
1987 free(private_voutput);
1989 *error = TDM_ERROR_OUT_OF_MEMORY;
1990 pthread_mutex_unlock(&private_client->lock);
1992 /* LCOV_EXCL_STOP */
1995 wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
1996 &tdm_client_voutput_lisntener, private_voutput);
1997 wl_display_roundtrip_queue(private_client->display, private_client->queue);
1999 wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
2001 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2002 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2003 free(private_voutput);
2005 *error = TDM_ERROR_PROTOCOL_ERROR;
2006 pthread_mutex_unlock(&private_client->lock);
2010 if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
2012 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2013 free(private_voutput);
2015 *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type.
2016 pthread_mutex_unlock(&private_client->lock);
2020 pthread_mutex_unlock(&private_client->lock);
2022 return (tdm_client_voutput *)private_voutput;
2026 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2028 tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2029 tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2031 if (!private_voutput)
2034 if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2035 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2037 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2038 tbm_surface_h tbm_surface = NULL;
2042 LIST_DEL(&cb->link);
2044 tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2046 tbm_surface_internal_unref(tbm_surface);
2048 wl_buffer_set_user_data(cb->wl_buffer, NULL);
2049 wl_buffer_destroy(cb->wl_buffer);
2055 if (private_voutput->bufmgr)
2056 tbm_bufmgr_deinit(private_voutput->bufmgr);
2058 if (private_voutput->available_modes.modes)
2059 free(private_voutput->available_modes.modes);
2061 LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2066 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2068 free(private_voutput);
2072 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2074 tdm_private_client_voutput *private_voutput;
2076 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2078 if ((count > 0) && (modes == NULL))
2079 return TDM_ERROR_INVALID_PARAMETER;
2081 private_voutput = (tdm_private_client_voutput *)voutput;
2083 if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2084 return TDM_ERROR_BAD_REQUEST;
2086 if (private_voutput->available_modes.modes)
2087 free(private_voutput->available_modes.modes);
2089 private_voutput->available_modes.count = count;
2093 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2094 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2097 return TDM_ERROR_NONE;
2101 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2103 tdm_private_client_voutput *private_voutput;
2105 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2106 TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2107 TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2109 private_voutput = (tdm_private_client_voutput *)voutput;
2111 if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2112 return TDM_ERROR_BAD_REQUEST;
2114 private_voutput->mmwidth = mmWidth;
2115 private_voutput->mmheight = mmHeight;
2117 return TDM_ERROR_NONE;
2121 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2122 tdm_client_voutput_commit_handler func,
2125 tdm_private_client_voutput *private_voutput;
2126 tdm_private_client *private_client;
2127 tdm_client_voutput_commit_handler_info *h = NULL;
2129 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2130 TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2132 private_voutput = (tdm_private_client_voutput *)voutput;
2133 private_client = private_voutput->base.private_client;
2135 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2136 if (h->func == func && h->user_data == user_data) {
2137 TDM_ERR("can't add twice");
2138 return TDM_ERROR_BAD_REQUEST;
2142 h = calloc(1, sizeof *h);
2143 TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2145 pthread_mutex_lock(&private_client->lock);
2147 if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2149 pthread_mutex_unlock(&private_client->lock);
2150 return TDM_ERROR_PROTOCOL_ERROR;
2153 h->private_voutput = private_voutput;
2155 h->user_data = user_data;
2156 LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2157 LIST_INITHEAD(&h->call_link);
2159 pthread_mutex_unlock(&private_client->lock);
2161 return TDM_ERROR_NONE;
2165 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2166 tdm_client_voutput_commit_handler func,
2169 tdm_private_client_voutput *private_voutput;
2170 tdm_private_client *private_client;
2171 tdm_client_voutput_commit_handler_info *h = NULL;
2173 TDM_RETURN_IF_FAIL(voutput != NULL);
2174 TDM_RETURN_IF_FAIL(func != NULL);
2176 private_voutput = (tdm_private_client_voutput *)voutput;
2177 private_client = private_voutput->base.private_client;
2179 pthread_mutex_lock(&private_client->lock);
2181 LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2182 if (h->func != func || h->user_data != user_data)
2188 pthread_mutex_unlock(&private_client->lock);
2191 pthread_mutex_unlock(&private_client->lock);
2195 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2197 tdm_private_client_voutput *private_voutput;
2199 TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2201 private_voutput = (tdm_private_client_voutput *)voutput;
2202 wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2204 return TDM_ERROR_NONE;
2208 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2210 tdm_private_client_voutput *private_voutput;
2213 *error = TDM_ERROR_NONE;
2217 TDM_ERR("'!voutput' failed");
2219 *error = TDM_ERROR_INVALID_PARAMETER;
2223 private_voutput = (tdm_private_client_voutput *)voutput;
2225 return &private_voutput->base;
2229 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
2231 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2232 TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
2233 TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
2235 return TDM_ERROR_NONE;
2239 tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode)
2241 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2242 TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
2244 return TDM_ERROR_NONE;
2248 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2250 tdm_client_output_mode *modes, *mode;
2251 struct wl_array array;
2254 modes = private_voutput->available_modes.modes;
2255 size = sizeof(tdm_client_output_mode);
2257 wl_array_init(&array);
2258 for (i = 0; i < private_voutput->available_modes.count; i++) {
2259 mode = wl_array_add(&array, size);
2260 memcpy(mode, &modes[i], size);
2262 wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2263 wl_array_release(&array);
2267 tdm_client_output_connect(tdm_client_output *output)
2269 tdm_private_client_output *private_output;
2270 tdm_private_client_voutput *private_voutput;
2272 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2274 private_output = (tdm_private_client_output *)output;
2275 private_voutput = (tdm_private_client_voutput *)output;
2277 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
2278 TDM_ERROR_BAD_REQUEST);
2280 private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2282 _tdm_client_voutput_send_available_modes(private_voutput);
2284 wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2286 wl_tdm_voutput_connect(private_voutput->wl_voutput);
2288 return TDM_ERROR_NONE;
2292 tdm_client_output_disconnect(tdm_client_output *output)
2294 tdm_private_client_voutput *private_voutput;
2295 tdm_private_client_output *private_output;
2297 TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2299 private_output = (tdm_private_client_output *)output;
2300 private_voutput = (tdm_private_client_voutput *)output;
2302 TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
2303 TDM_ERROR_BAD_REQUEST);
2305 private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2307 wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2309 return TDM_ERROR_NONE;