From patchwork Mon Oct 2 09:49:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleksandr Grytsov X-Patchwork-Id: 9980575 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B4A1460384 for ; Mon, 2 Oct 2017 09:52:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A4D33288B1 for ; Mon, 2 Oct 2017 09:52:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9986428953; Mon, 2 Oct 2017 09:52:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.6 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CFBCD288B1 for ; Mon, 2 Oct 2017 09:52:02 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dyxM1-0005p3-1J; Mon, 02 Oct 2017 09:49:37 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dyxM0-0005oI-7p for xen-devel@lists.xenproject.org; Mon, 02 Oct 2017 09:49:36 +0000 Received: from [85.158.139.211] by server-1.bemta-5.messagelabs.com id 2F/3F-02036-FAB02D95; Mon, 02 Oct 2017 09:49:35 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrMIsWRWlGSWpSXmKPExsVyMfS6s+467ku RBtu+KVl83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBnTmicyFrwtq5j24DprA+OhgC5GLg4hgemM Ep9PHWQBcVgEXrJIHF7YzwTiSAj0s0pcmvuXtYuRE8jJkrh2/hcThJ0m8fTOfTYIu1xi34/PL CC2kIC8xMGWy+wQY6cxSTQvmAqWYBPQkrh/ewVYg4iAksS9VZPBBjELpEjsXdfG2MXIwSEsYC Rx9bkWSJhFQFVix5MesBJeAQeJB+faWCB2yUncPNfJDGJzCjhK7Fi5Hmqvg8TPxgbWCYyCCxg ZVjGqF6cWlaUW6RrrJRVlpmeU5CZm5ugaGpjq5aYWFyemp+YkJhXrJefnbmIEBhwDEOxg3PvP 6RCjJAeTkijvf45LkUJ8SfkplRmJxRnxRaU5qcWHGDU4OAR+Pv3bwijFkpefl6okwbuYC6hOs Cg1PbUiLTMHGBMwpRIcPEoivJNB0rzFBYm5xZnpEKlTjJYcF+5c+sPEcWDPLSDZcfPuHyYhsH lS4rw7QBoEQBoySvPgxsHi9hKjrJQwLyPQsUI8BalFuZklqPKvGMU5GJWEeS+CTOHJzCuB2/o K6CAmoIPmdF0AOagkESEl1cC4grVcUz+L980Fl1vZyZ9mrZW8Xr3tKo/MWmObh+bCC20vNNhY 5W+evOhVpuud1EK9WdvVE6+djFt4Xdj27c7pez48151qoXuHLcAr7+wLv66FEQu1nvExtmmxp omZbNkUHTn36fn/8qacJ2Xlf1r91JGaf+Dq66d72JOPFDsLHLVRtDOIq76jxFKckWioxVxUnA gA3HG1odYCAAA= X-Env-Sender: al1img@gmail.com X-Msg-Ref: server-10.tower-206.messagelabs.com!1506937774!85685940!1 X-Originating-IP: [209.85.215.67] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 17917 invoked from network); 2 Oct 2017 09:49:34 -0000 Received: from mail-lf0-f67.google.com (HELO mail-lf0-f67.google.com) (209.85.215.67) by server-10.tower-206.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 2 Oct 2017 09:49:34 -0000 Received: by mail-lf0-f67.google.com with SMTP id j73so1918654lfg.0 for ; Mon, 02 Oct 2017 02:49:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=OsTbXEeG6fzkLUIgrc6SyoEV76Ez9INBpnM82TMdbTk=; b=NC/ehKf/Q7hSyNyRiVAQwnqv40YOePqhP7FRGYcHt2U/S3XkhIQDzXUoAbe5vx5rfX 6nCjzevlO2Mh/1owJSNA22SAAGOjQqBBXOX4W9qUiqC5DDb7L12Gu00+jvON/kxp/Tdt hEbGL/Mpk3w1/yExqssUfd5Tex9BjUngV4dZmT4uGA5CI/M72t46VXvpgqcZndPy9z5h UhD3WHl1xiKVUt/mMh4ak92wt7PQXYPe450p1w49iX9U+ZTnWGZgEmeI37a5VmLe4C4R BTuFGAQJ2L61L/g/RjiKjnkMvx8Gqw3j4NmfKpHuFXZ87Z8nPHBv5VJfY2YNGA9JIEMW flcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=OsTbXEeG6fzkLUIgrc6SyoEV76Ez9INBpnM82TMdbTk=; b=mT7lvGOZSn/oTP9no2uufP9b0TSUofjbii7zV7ShpMANAsHywUOxJxLvlB/hQbfcZG gdTSfvaoiAFcLurMdGl2EkZTOHgdTXxJ5JJeNa2G2x4V69oQk3ne0AfjyJUGSGLlEasj nFQN/Uua4RaMfn9QzLDqtEEx9cSgjfMnBRepogKl4KIV9/rUfmi5a269UVyXCElwVNbZ VdEctVAT/ODDreUMNUyvqiOLZQ3SfxqZXkp2OWNknBXK576ILzc432G3EDTd6b2g/T7d PlFEPOhyHAS1UqLo13Yk7FlhdRLfCUvyfal5iON/SUD4O3/xRVZ7f19xb78jhPHwX9SZ 0iwA== X-Gm-Message-State: AHPjjUhy8qL4MQIJ8tNaFaYmAEUvLzEEU81Q3HHuB8rZXSS6HdkXVaKU J092XYQn4Uf55GdEUKkwBUtwlQ== X-Google-Smtp-Source: AOwi7QADO0JNnB5NgK4i9emDebvMcm/ZKwKtZM3ne7o2QcdqdaYGS8woJVYrtmKBP60xfzdOHwzBtw== X-Received: by 10.46.21.84 with SMTP id 20mr6380804ljv.168.1506937773534; Mon, 02 Oct 2017 02:49:33 -0700 (PDT) Received: from al1-pc.kyiv.epam.com (ll-74.141.223.85.sovam.net.ua. [85.223.141.74]) by smtp.gmail.com with ESMTPSA id b10sm2217504lje.15.2017.10.02.02.49.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 02 Oct 2017 02:49:33 -0700 (PDT) From: Oleksandr Grytsov To: xen-devel@lists.xenproject.org Date: Mon, 2 Oct 2017 12:49:21 +0300 Message-Id: <1506937764-30329-3-git-send-email-al1img@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506937764-30329-1-git-send-email-al1img@gmail.com> References: <1506937764-30329-1-git-send-email-al1img@gmail.com> Cc: ian.jackson@eu.citrix.com, wei.liu2@citrix.com, Oleksandr Grytsov Subject: [Xen-devel] [PATCH 2/5] libxl: add vsnd list and info X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Oleksandr Grytsov Add getting vsnd list amd info API Signed-off-by: Oleksandr Grytsov --- tools/libxl/libxl.h | 10 ++ tools/libxl/libxl_types.idl | 19 +++ tools/libxl/libxl_utils.h | 3 + tools/libxl/libxl_vsnd.c | 359 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 388 insertions(+), 3 deletions(-) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 7200d49..acb73ce 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -1927,6 +1927,16 @@ int libxl_device_vsnd_destroy(libxl_ctx *ctx, uint32_t domid, const libxl_asyncop_how *ao_how) LIBXL_EXTERNAL_CALLERS_ONLY; +libxl_device_vsnd *libxl_device_vsnd_list(libxl_ctx *ctx, + uint32_t domid, int *num) + LIBXL_EXTERNAL_CALLERS_ONLY; +void libxl_device_vsnd_list_free(libxl_device_vsnd* list, int num) + LIBXL_EXTERNAL_CALLERS_ONLY; +int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid, + libxl_device_vsnd *vsnd, + libxl_vsndinfo *vsndlinfo) + LIBXL_EXTERNAL_CALLERS_ONLY; + /* Keyboard */ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb, const libxl_asyncop_how *ao_how) diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index fb3e5e8..cd0c06f 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -988,6 +988,25 @@ libxl_vdisplinfo = Struct("vdisplinfo", [ ("connectors", Array(libxl_connectorinfo, "num_connectors")) ], dir=DIR_OUT) +libxl_streaminfo = Struct("streaminfo", [ + ("req_evtch", integer), + ("req_rref", integer) + ]) + +libxl_pcminfo = Struct("pcminfo", [ + ("streams", Array(libxl_streaminfo, "num_vsnd_streams")) + ]) + +libxl_vsndinfo = Struct("vsndinfo", [ + ("backend", string), + ("backend_id", uint32), + ("frontend", string), + ("frontend_id", uint32), + ("devid", libxl_devid), + ("state", integer), + ("pcms", Array(libxl_pcminfo, "num_vsnd_pcms")) + ]) + # NUMA node characteristics: size and free are how much memory it has, and how # much of it is free, respectively. dists is an array of distances from this # node to each other node. diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 9e743dc..5455752 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -82,6 +82,9 @@ int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid, int libxl_devid_to_device_vdispl(libxl_ctx *ctx, uint32_t domid, int devid, libxl_device_vdispl *vdispl); +int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid, + int devid, libxl_device_vsnd *vsnd); + int libxl_ctrlport_to_device_usbdev(libxl_ctx *ctx, uint32_t domid, int ctrl, int port, libxl_device_usbdev *usbdev); diff --git a/tools/libxl/libxl_vsnd.c b/tools/libxl/libxl_vsnd.c index 26885f9..0e7b29c 100644 --- a/tools/libxl/libxl_vsnd.c +++ b/tools/libxl/libxl_vsnd.c @@ -37,20 +37,239 @@ static int libxl__device_from_vsnd(libxl__gc *gc, uint32_t domid, return 0; } +static int libxl__sample_rates_from_string(libxl__gc *gc, const char *str, + libxl_vsnd_params *params) +{ + char *tmp = libxl__strdup(gc, str); + + params->num_sample_rates = 0; + params->sample_rates = NULL; + + char *p = strtok(tmp, " ,"); + + while (p != NULL) { + params->sample_rates = realloc(params->sample_rates, + sizeof(*params->sample_rates) * + (params->num_sample_rates + 1)); + params->sample_rates[params->num_sample_rates++] = strtoul(p, NULL, 0); + p = strtok(NULL, " ,"); + } + + return 0; +} + +static int libxl__sample_formats_from_string(libxl__gc *gc, const char *str, + libxl_vsnd_params *params) +{ + int rc; + char *tmp = libxl__strdup(gc, str); + + params->num_sample_formats = 0; + params->sample_formats = NULL; + + char *p = strtok(tmp, " ,"); + + while (p != NULL) { + params->sample_formats = realloc(params->sample_formats, + sizeof(*params->sample_formats) * + (params->num_sample_formats + 1)); + + libxl_vsnd_pcm_format format; + + rc = libxl_vsnd_pcm_format_from_string(p, &format); + if (rc) return rc; + + params->sample_formats[params->num_sample_formats++] = format; + p = strtok(NULL, " ,"); + } + + return 0; +} + +static int libxl__params_from_xenstore(libxl__gc *gc, const char *path, + libxl_vsnd_params *params) +{ + const char *tmp; + int rc; + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_RATES, + path), &tmp); + if (rc) return rc; + + if (tmp) { + rc = libxl__sample_rates_from_string(gc, tmp, params); + if (rc) return rc; + } + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_FORMATS, + path), &tmp); + if (rc) return rc; + + if (tmp) { + rc = libxl__sample_formats_from_string(gc, tmp, params); + if (rc) return rc; + } + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MIN, + path), &tmp); + if (rc) return rc; + + if (tmp) { + params->channels_min = strtoul(tmp, NULL, 0); + } + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MAX, + path), &tmp); + if (rc) return rc; + + if (tmp) { + params->channels_max = strtoul(tmp, NULL, 0); + } + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_BUFFER_SIZE, + path), &tmp); + if (rc) return rc; + + if (tmp) { + params->buffer_size = strtoul(tmp, NULL, 0); + } + + return 0; +} + +static int libxl__stream_from_xenstore(libxl__gc *gc, const char *path, + libxl_vsnd_stream *stream) +{ + const char *tmp; + int rc; + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_STREAM_UNIQUE_ID, + path), &tmp); + if (rc) return rc; + + if (tmp) { + stream->id = strtoul(tmp, NULL, 0); + } + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_TYPE, + path), &tmp); + if (rc) return rc; + + if (tmp) { + libxl_vsnd_stream_type type; + + rc = libxl_vsnd_stream_type_from_string(tmp, &type); + if (rc) return rc; + + stream->type = type; + } + + rc = libxl__params_from_xenstore(gc, path, &stream->params); + if (rc) return rc; + + return 0; +} + +static int libxl__pcm_from_xenstore(libxl__gc *gc, const char *path, + libxl_vsnd_pcm *pcm) +{ + libxl_ctx *ctx = libxl__gc_owner(gc); + const char *tmp; + int rc; + + pcm->name = xs_read(ctx->xsh, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_DEVICE_NAME, path), NULL); + + rc = libxl__params_from_xenstore(gc, path, &pcm->params); + + pcm->streams = NULL; + pcm->num_vsnd_streams = 0; + + do { + char *stream_path = GCSPRINTF("%s/%d", path, pcm->num_vsnd_streams); + + rc = libxl__xs_read_checked(gc, XBT_NULL, stream_path, &tmp); + if (rc) return rc; + + if (tmp) { + pcm->streams = realloc(pcm->streams, sizeof(*pcm->streams) * + (++pcm->num_vsnd_streams)); + + libxl_vsnd_stream_init(&pcm->streams[pcm->num_vsnd_streams - 1]); + + rc = libxl__stream_from_xenstore(gc, stream_path, + &pcm->streams[pcm->num_vsnd_streams + - 1]); + if (rc) return rc; + } + } while (tmp); + + + return 0; +} + static int libxl__vsnd_from_xenstore(libxl__gc *gc, const char *libxl_path, libxl_devid devid, libxl_device_vsnd *vsnd) { - const char *be_path; + libxl_ctx *ctx = libxl__gc_owner(gc); + const char *tmp; + const char *fe_path; int rc; vsnd->devid = devid; rc = libxl__xs_read_mandatory(gc, XBT_NULL, GCSPRINTF("%s/backend", libxl_path), - &be_path); + &tmp); + if (rc) return rc; + + rc = libxl__backendpath_parse_domid(gc, tmp, &vsnd->backend_domid); + if (rc) return rc; + + rc = libxl__xs_read_mandatory(gc, XBT_NULL, + GCSPRINTF("%s/frontend", libxl_path), + &fe_path); if (rc) return rc; - return libxl__backendpath_parse_domid(gc, be_path, &vsnd->backend_domid); + vsnd->short_name = xs_read(ctx->xsh, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_VCARD_SHORT_NAME, + fe_path), NULL); + + vsnd->long_name = xs_read(ctx->xsh, XBT_NULL, + GCSPRINTF("%s/"XENSND_FIELD_VCARD_LONG_NAME, + fe_path), NULL); + + rc = libxl__params_from_xenstore(gc, fe_path, &vsnd->params); + + vsnd->pcms = NULL; + vsnd->num_vsnd_pcms = 0; + + do { + char *pcm_path = GCSPRINTF("%s/%d", fe_path, vsnd->num_vsnd_pcms); + + rc = libxl__xs_read_checked(gc, XBT_NULL, pcm_path, &tmp); + if (rc) return rc; + + if (tmp) { + vsnd->pcms = realloc(vsnd->pcms, sizeof(*vsnd->pcms) * + (++vsnd->num_vsnd_pcms)); + + libxl_vsnd_pcm_init(&vsnd->pcms[vsnd->num_vsnd_pcms - 1]); + + rc = libxl__pcm_from_xenstore(gc, pcm_path, + &vsnd->pcms[vsnd->num_vsnd_pcms - 1]); + if (rc) return rc; + } + } while (tmp); + + return 0; } static void libxl__update_config_vsnd(libxl__gc *gc, @@ -286,10 +505,144 @@ static int libxl__set_xenstore_vsnd(libxl__gc *gc, uint32_t domid, return 0; } +static int libxl__device_stream_getinfo(libxl__gc *gc, const char *path, + libxl_vsnd_pcm* pcm, + libxl_pcminfo *info) +{ + const char *tmp; + int i; + int rc; + + info->num_vsnd_streams = pcm->num_vsnd_streams; + info->streams = malloc(sizeof(*info->streams) * info->num_vsnd_streams); + + for (i = 0; i < info->num_vsnd_streams; i++) + { + libxl_streaminfo_init(&info->streams[i]); + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/%d/"XENSND_FIELD_RING_REF, + path, i), &tmp); + if (rc) return rc; + + info->streams[i].req_rref = tmp ? strtoul(tmp, NULL, 10) : -1; + + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/%d/"XENSND_FIELD_EVT_CHNL, + path, i), &tmp); + if (rc) return rc; + + info->streams[i].req_evtch = tmp ? strtoul(tmp, NULL, 10) : -1; + } + + return 0; +} + +static int libxl__device_pcm_getinfo(libxl__gc *gc, const char *path, + libxl_device_vsnd *vsnd, + libxl_vsndinfo *info) +{ + int i; + int rc; + + info->num_vsnd_pcms = vsnd->num_vsnd_pcms; + info->pcms = malloc(sizeof(*info->pcms) * info->num_vsnd_pcms); + + for (i = 0; i < info->num_vsnd_pcms; i++) + { + libxl_pcminfo_init(&info->pcms[i]); + + rc = libxl__device_stream_getinfo(gc, GCSPRINTF("%s/%d", path, i), + &vsnd->pcms[i], &info->pcms[i]); + if (rc) return rc; + } + + return 0; +} + +int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid, + libxl_device_vsnd *vsnd, + libxl_vsndinfo *info) +{ + GC_INIT(ctx); + char *libxl_path, *dompath, *devpath; + const char *val; + int rc; + + libxl_vsndinfo_init(info); + dompath = libxl__xs_get_dompath(gc, domid); + info->devid = vsnd->devid; + + devpath = GCSPRINTF("%s/device/%s/%d", dompath, libxl__vsnd_devtype.entry, + info->devid); + libxl_path = GCSPRINTF("%s/device/%s/%d", + libxl__xs_libxl_path(gc, domid), + libxl__vsnd_devtype.entry, info->devid); + + info->backend = xs_read(ctx->xsh, XBT_NULL, + GCSPRINTF("%s/backend", libxl_path), NULL); + + rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id); + if (rc) goto out; + + val = xs_read(ctx->xsh, XBT_NULL, GCSPRINTF("%s/state", devpath), NULL); + + info->state = val ? strtoul(val, NULL, 10) : -1; + + info->frontend = xs_read(ctx->xsh, XBT_NULL, + GCSPRINTF("%s/frontend", libxl_path), NULL); + + info->frontend_id = domid; + + rc = libxl__device_pcm_getinfo(gc, devpath, vsnd, info); + if (rc) goto out; + + rc = 0; + +out: + GC_FREE; + return rc; +} + +int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid, + int devid, libxl_device_vsnd *vsnd) +{ + GC_INIT(ctx); + + libxl_device_vsnd *vsnds = NULL; + int n, i; + int rc; + + libxl_device_vsnd_init(vsnd); + + vsnds = libxl__device_list(gc, &libxl__vsnd_devtype, domid, &n); + + if (!vsnds) { rc = ERROR_NOTFOUND; goto out; } + + for (i = 0; i < n; ++i) { + if (devid == vsnds[i].devid) { + libxl_device_vsnd_copy(ctx, vsnd, &vsnds[i]); + rc = 0; + goto out; + } + } + + rc = ERROR_NOTFOUND; + +out: + + if (vsnds) + libxl__device_list_free(&libxl__vsnd_devtype, vsnds, n); + + GC_FREE; + return rc; +} + LIBXL_DEFINE_DEVICE_ADD(vsnd) static LIBXL_DEFINE_DEVICES_ADD(vsnd) LIBXL_DEFINE_DEVICE_REMOVE(vsnd) static LIBXL_DEFINE_UPDATE_DEVID(vsnd, "vsnd") +LIBXL_DEFINE_DEVICE_LIST(vsnd) DEFINE_DEVICE_TYPE_STRUCT(vsnd, .update_config = (device_update_config_fn_t) libxl__update_config_vsnd,