[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC 2/6] libxl: implementation of PV audio device interface



From: Pavlo Suikov <pavlo.suikov@xxxxxxxxxxxxxxx>

PV Audio device interface is implemented in libxl and xl with
full support for device control

Signed-off-by: Pavlo Suikov <pavlo.suikov@xxxxxxxxxxxxxxx>
Signed-off-by: Glib Golubytskyi <glib.golubytskyi@xxxxxxxxxxxxxxx>
Signed-off-by: Iurii Konovalenko <iurii.konovalenko@xxxxxxxxxxxxxxx>
---
 tools/libxl/libxl.c                  | 351 ++++++++++++++++++++++++++++++++++-
 tools/libxl/libxl.h                  |  16 ++
 tools/libxl/libxl_create.c           |  39 +++-
 tools/libxl/libxl_device.c           |   2 +
 tools/libxl/libxl_internal.c         |   4 +
 tools/libxl/libxl_internal.h         |  20 +-
 tools/libxl/libxl_types.idl          |  32 ++++
 tools/libxl/libxl_types_internal.idl |   1 +
 tools/libxl/libxl_utils.h            |   3 +
 tools/libxl/xl.h                     |   3 +
 tools/libxl/xl_cmdimpl.c             | 229 ++++++++++++++++++++++-
 tools/libxl/xl_cmdtable.c            |  20 ++
 12 files changed, 715 insertions(+), 5 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 09c4bc7..d96172d 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2593,7 +2593,344 @@ exit:
     return rc;
 }
 
+/******************************************************************************/
+
+int libxl__device_vsnd_setdefault(libxl__gc *gc, libxl_device_vsnd *vsnd)
+{
+    int rc;
+
+    rc = libxl__resolve_domid(gc, vsnd->backend_domname, &vsnd->backend_domid);
+
+    return rc;
+}
+
+static int libxl__device_from_vsnd(libxl__gc *gc, uint32_t domid, 
libxl_device_vsnd *vsnd, libxl__device *device)
+{
+   device->backend_devid   = vsnd->devid;
+   device->backend_domid   = vsnd->backend_domid;
+   device->backend_kind    = LIBXL__DEVICE_KIND_VSND;
+   device->devid           = vsnd->devid;
+   device->domid           = domid;
+   device->kind            = LIBXL__DEVICE_KIND_VSND;
+
+   return 0;
+}
+
+static int libxl__device_vsnd_from_xs_be(libxl__gc *gc,
+                                        const char *be_path,
+                                        libxl_device_vsnd *vsnd)
+{
+    const char *tmp;
+    int rc;
+
+    libxl_device_vsnd_init(vsnd);
+
+    tmp = READ_BACKEND(gc, "device-id");
+    if (tmp)
+        vsnd->devid = atoi(tmp);
+    else
+        vsnd->devid = 0;
+
+    vsnd->short_name = READ_BACKEND(gc, "short-name");
+    vsnd->long_name = READ_BACKEND(gc, "long-name");
+    vsnd->sample_formats = READ_BACKEND(gc, "sample-formats");
+    vsnd->rates = READ_BACKEND(gc, "rates");
+
+    tmp = READ_BACKEND(gc, "channels-min");
+    if (tmp)
+        vsnd->channels_min = atoi(tmp);
+    else
+        vsnd->channels_min = 0;
+
+    tmp = READ_BACKEND(gc, "channels-max");
+    if (tmp)
+        vsnd->channels_max = atoi(tmp);
+    else
+        vsnd->channels_max = 0;
+
+    tmp = READ_BACKEND(gc, "priority");
+    if (tmp)
+        vsnd->priority = atoi(tmp);
+    else
+        vsnd->priority = 0;
+
+    vsnd->slave_device = READ_BACKEND(gc, "slave-device");
+
+    rc = 0;
+ out:
+    return rc;
+}
+
+int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid,
+                              int devid, libxl_device_vsnd *vsnd)
+{
+    GC_INIT(ctx);
+    char *dompath, *path;
+    int rc = ERROR_FAIL;
+
+    libxl_device_vsnd_init(vsnd);
+    dompath = libxl__xs_get_dompath(gc, domid);
+    if (!dompath)
+        goto out;
+
+    path = libxl__xs_read(gc, XBT_NULL,
+                          libxl__sprintf(gc, "%s/device/vsnd/%d/backend",
+                                         dompath, devid));
+    if (!path)
+        goto out;
+
+    rc = libxl__device_vsnd_from_xs_be(gc, path, vsnd);
+    if (rc) goto out;
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+
+void libxl__device_vsnd_add(libxl__egc *egc, uint32_t domid, libxl_device_vsnd 
*vsnd, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device *device;
+    int rc;
+    xs_transaction_t t = XBT_NULL;
+    libxl_domain_config d_config;
+    libxl_device_vsnd vsnd_saved;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_vsnd_init(&vsnd_saved);
+    libxl_device_vsnd_copy(CTX, &vsnd_saved, vsnd);
+
+    rc = libxl__device_vsnd_setdefault(gc, vsnd);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 32, 1);
+    back = flexarray_make(gc, 32, 1);
+    if (vsnd->devid == -1) {
+        if ((vsnd->devid = libxl__device_nextid(gc, domid, "vsnd")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    libxl__update_config_vsnd(gc, &vsnd_saved, vsnd);
+
+    GCNEW(device);
+    rc = libxl__device_from_vsnd(gc, domid, vsnd, device);
+    if ( rc != 0 ) goto out;
+
+    flexarray_append(back, "DomD");
+    flexarray_append(back, "1");
+    flexarray_append(back, "DomU");
+    flexarray_append(back, "2");
+    flexarray_append(back, "device-id");
+    flexarray_append(back, GCSPRINTF("%d", vsnd->devid));
+    flexarray_append(back, "short-name");
+    flexarray_append(back, vsnd->short_name);
+    flexarray_append(back, "long-name");
+    flexarray_append(back, vsnd->long_name);
+    flexarray_append(back, "sample-formats");
+    flexarray_append(back, vsnd->sample_formats);
+    flexarray_append(back, "rates");
+    flexarray_append(back, vsnd->rates);
+    flexarray_append(back, "channels-min");
+    flexarray_append(back, GCSPRINTF("%d", vsnd->channels_min));
+    flexarray_append(back, "channels-max");
+    flexarray_append(back, GCSPRINTF("%d", vsnd->channels_max));
+    flexarray_append(back, "priority");
+    flexarray_append(back, GCSPRINTF("%d", vsnd->priority));
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", 1));
+    flexarray_append(back, "slave-device");
+    flexarray_append(back, vsnd->slave_device);
+
+    flexarray_append(front, "device-id");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->devid));
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, GCSPRINTF("%d", 1));
+    flexarray_append(front, "alsa-card-id");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->alsa_card_id));
+    flexarray_append(front, "short-name");
+    flexarray_append(front, vsnd->short_name);
+    flexarray_append(front, "long-name");
+    flexarray_append(front, vsnd->long_name);
+    flexarray_append(front, "sample-formats");
+    flexarray_append(front, vsnd->sample_formats);
+    flexarray_append(front, "rates");
+    flexarray_append(front, vsnd->rates);
+    flexarray_append(front, "channels-min");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->channels_min));
+    flexarray_append(front, "channels-max");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->channels_max));
+    flexarray_append(front, "buffer-bytes-max");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->buffer_bytes_max));
+    flexarray_append(front, "period-bytes-min");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->period_bytes_min));
+    flexarray_append(front, "period-bytes-max");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->period_bytes_max));
+    flexarray_append(front, "period-min");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->period_min));
+    flexarray_append(front, "period-max");
+    flexarray_append(front, GCSPRINTF("%d", vsnd->period_max));
+
+    if (aodev->update_json) {
+        lock = libxl__lock_domain_userdata(gc, domid);
+        if (!lock) {
+            rc = ERROR_LOCK_FAIL;
+            goto out;
+        }
+
+        rc = libxl__get_domain_configuration(gc, domid, &d_config);
+        LOG(INFO, "aodev updates JSON, libxl__get_domain_configuration 
returned %d", rc);
+        if (rc) goto out;
+
+        DEVICE_ADD(vsnd, vsnds, domid, &vsnd_saved, COMPARE_DEVID, &d_config);
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        rc = libxl__device_exists(gc, t, device);
+        if (rc < 0) goto out;
+        if (rc == 1) {              /* already exists in xenstore */
+            LOG(ERROR, "device already exists in xenstore");
+            aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */
+            rc = ERROR_DEVICE_EXISTS;
+            goto out;
+        }
 
+        if (aodev->update_json) {
+            rc = libxl__set_domain_configuration(gc, domid, &d_config);
+            if (rc) goto out;
+        }
+
+        libxl__device_generic_add(gc, t, device,
+                                  libxl__xs_kvs_of_flexarray(gc, back,
+                                                             back->count),
+                                  libxl__xs_kvs_of_flexarray(gc, front,
+                                                             front->count),
+                                  NULL);
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    libxl__wait_device_connection(egc, aodev);
+
+    rc = 0;
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_vsnd_dispose(&vsnd_saved);
+    libxl_domain_config_dispose(&d_config);
+    aodev->rc = rc;
+    if(rc) aodev->callback(egc, aodev);
+    return;
+
+}
+
+libxl_device_vsnd *libxl_device_vsnd_list(libxl_ctx *ctx, uint32_t domid, int 
*num)
+{
+    GC_INIT(ctx);
+
+    libxl_device_vsnd* vsnds = NULL;
+    char* fe_path = NULL;
+    char** dir = NULL;
+    unsigned int ndirs = 0;
+
+    *num = 0;
+
+    fe_path = libxl__sprintf(gc, "%s/device/vsnd", libxl__xs_get_dompath(gc, 
domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
+    if (dir && ndirs) {
+       vsnds = malloc(sizeof(*vsnds) * ndirs);
+       libxl_device_vsnd* vsnd;
+       libxl_device_vsnd* end = vsnds + ndirs;
+       for(vsnd = vsnds; vsnd < end; ++vsnd, ++dir) {
+          char* tmp;
+
+          libxl_device_vsnd_init(vsnd);
+
+          vsnd->devid = atoi(*dir);
+
+          tmp = libxl__xs_read(gc, XBT_NULL,
+                GCSPRINTF("%s/%s/backend-id",
+                   fe_path, *dir));
+          vsnd->backend_domid = atoi(tmp);
+       }
+    }
+    *num = ndirs;
+
+    GC_FREE;
+    return vsnds;
+}
+
+int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid, 
libxl_device_vsnd *vsnd, libxl_vsndinfo *vsndinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *vsndpath;
+    char *val;
+    int rc = 0;
+
+    libxl_vsndinfo_init(vsndinfo);
+    dompath = libxl__xs_get_dompath(gc, domid);
+    vsndinfo->devid = vsnd->devid;
+
+    vsndpath = GCSPRINTF("%s/device/vsnd/%d", dompath, vsndinfo->devid);
+    vsndinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+          GCSPRINTF("%s/backend", vsndpath), NULL);
+    if (!vsndinfo->backend) {
+        goto err;
+    }
+    if(!libxl__xs_read(gc, XBT_NULL, vsndinfo->backend)) {
+       goto err;
+    }
+
+    val = libxl__xs_read(gc, XBT_NULL,
+          GCSPRINTF("%s/backend-id", vsndpath));
+    vsndinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+          GCSPRINTF("%s/state", vsndpath));
+    vsndinfo->state = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+          GCSPRINTF("%s/event-channel", vsndpath));
+    vsndinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+          GCSPRINTF("%s/ring-ref", vsndpath));
+    vsndinfo->rref = val ? strtoul(val, NULL, 10) : -1;
+
+    vsndinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
+          GCSPRINTF("%s/frontend", vsndinfo->backend), NULL);
+
+    val = libxl__xs_read(gc, XBT_NULL,
+          GCSPRINTF("%s/frontend-id", vsndinfo->backend));
+    vsndinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    goto exit;
+err:
+    rc = ERROR_FAIL;
+exit:
+    GC_FREE;
+    return rc;
+}
 
 
/******************************************************************************/
 
@@ -4410,6 +4747,8 @@ out:
  * libxl_device_vtpm_destroy
  * libxl_device_vrtc_remove
  * libxl_device_vrtc_destroy
+ * libxl_device_vsnd_remove
+ * libxl_device_vsnd_destroy
  */
 #define DEFINE_DEVICE_REMOVE(type, removedestroy, f)                    \
     int libxl_device_##type##_##removedestroy(libxl_ctx *ctx,           \
@@ -4465,6 +4804,10 @@ DEFINE_DEVICE_REMOVE(vtpm, destroy, 1)
 DEFINE_DEVICE_REMOVE(vrtc, remove, 0)
 DEFINE_DEVICE_REMOVE(vrtc, destroy, 1)
 
+/* vsnd */
+DEFINE_DEVICE_REMOVE(vsnd, remove, 0)
+DEFINE_DEVICE_REMOVE(vsnd, destroy, 1)
+
 /* channel/console hotunplug is not implemented. There are 2 possibilities:
  * 1. add support for secondary consoles to xenconsoled
  * 2. dynamically add/remove qemu chardevs via qmp messages. */
@@ -4479,6 +4822,7 @@ DEFINE_DEVICE_REMOVE(vrtc, destroy, 1)
  * libxl_device_nic_add
  * libxl_device_vtpm_add
  * libxl_device_vrtc_add
+ * libxl_device_vsnd_add
  */
 
 #define DEFINE_DEVICE_ADD(type)                                         \
@@ -4513,6 +4857,9 @@ DEFINE_DEVICE_ADD(vtpm)
 /* vrtc */
 DEFINE_DEVICE_ADD(vrtc)
 
+/* vsnd */
+DEFINE_DEVICE_ADD(vsnd)
+
 #undef DEFINE_DEVICE_ADD
 
 
/******************************************************************************/
@@ -6956,7 +7303,7 @@ int libxl_retrieve_domain_configuration(libxl_ctx *ctx, 
uint32_t domid,
         d_config->b_info.max_memkb = max_memkb;
     }
 
-    /* Devices: disk, nic, vtpm, pcidev etc. */
+    /* Devices: disk, nic, vtpm, vsnd, pcidev etc. */
 
     /* The MERGE macro implements following logic:
      * 0. retrieve JSON (done by now)
@@ -7030,6 +7377,8 @@ int libxl_retrieve_domain_configuration(libxl_ctx *ctx, 
uint32_t domid,
 
     MERGE(vrtc, vrtcs, COMPARE_DEVID, {});
 
+    MERGE(vsnd, vsnds, COMPARE_DEVID, {});
+
     MERGE(pci, pcidevs, COMPARE_PCI, {});
 
     /* Take care of removable device. We maintain invariant in the
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 9243b86..3cb67e2 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1451,6 +1451,22 @@ int libxl_device_vrtc_destroy(libxl_ctx *ctx, uint32_t 
domid,
 libxl_device_vrtc *libxl_device_vrtc_list(libxl_ctx *ctx, uint32_t domid, int 
*num);
 int libxl_device_vrtc_getinfo(libxl_ctx *ctx, uint32_t domid,
                               libxl_device_vrtc *vrtc, libxl_vrtcinfo 
*vrtcinfo);
+/* Audio */
+int libxl_device_vsnd_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vsnd 
*vsnd,
+                          const libxl_asyncop_how *ao_how)
+                          LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vsnd_remove(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_vsnd *vsnd,
+                             const libxl_asyncop_how *ao_how)
+                             LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vsnd_destroy(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vsnd *vsnd,
+                              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);
+int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vsnd *vsnd, libxl_vsndinfo 
*vsndinfo);
 
 /* Keyboard */
 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 1206c34..8ff4178 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -736,6 +736,8 @@ static void domcreate_attach_vtpms(libxl__egc *egc, 
libxl__multidev *multidev,
                                    int ret);
 static void domcreate_attach_vrtcs(libxl__egc *egc, libxl__multidev *multidev,
                                    int ret);
+static void domcreate_attach_vsnds(libxl__egc *egc, libxl__multidev *multidev,
+                                   int ret);
 static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *aodevs,
                                  int ret);
 static void domcreate_attach_dtdev(libxl__egc *egc,
@@ -1427,12 +1429,45 @@ static void domcreate_attach_vrtcs(libxl__egc *egc,
    if (d_config->num_vrtcs > 0) {
        /* Attach vrtcs */
        libxl__multidev_begin(ao, &dcs->multidev);
-       dcs->multidev.callback = domcreate_attach_pci;
+       dcs->multidev.callback = domcreate_attach_vsnds;
        libxl__add_vrtcs(egc, ao, domid, d_config, &dcs->multidev);
        libxl__multidev_prepared(egc, &dcs->multidev, 0);
        return;
    }
 
+   domcreate_attach_vsnds(egc, multidev, 0);
+   return;
+
+error_out:
+   assert(ret);
+   domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_attach_vsnds(libxl__egc *egc,
+                                   libxl__multidev *multidev,
+                                   int ret)
+{
+   libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
+   STATE_AO_GC(dcs->ao);
+   int domid = dcs->guest_domid;
+
+   libxl_domain_config* const d_config = dcs->guest_config;
+
+   if(ret) {
+       LOG(ERROR, "unable to add vrtc devices");
+       goto error_out;
+   }
+
+   /* Plug vsnd devices */
+   if (d_config->num_vsnds > 0) {
+       /* Attach vsnds */
+       libxl__multidev_begin(ao, &dcs->multidev);
+       dcs->multidev.callback = domcreate_attach_pci;
+       libxl__add_vsnds(egc, ao, domid, d_config, &dcs->multidev);
+       libxl__multidev_prepared(egc, &dcs->multidev, 0);
+       return;
+   }
+
    domcreate_attach_pci(egc, multidev, 0);
    return;
 
@@ -1454,7 +1489,7 @@ static void domcreate_attach_pci(libxl__egc *egc, 
libxl__multidev *multidev,
     libxl_domain_config *const d_config = dcs->guest_config;
 
     if (ret) {
-        LOG(ERROR, "unable to add vrtc devices");
+        LOG(ERROR, "unable to add vsnd devices");
         goto error_out;
     }
 
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 72f09a0..419af16 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -545,6 +545,7 @@ void libxl__multidev_prepared(libxl__egc *egc,
  * libxl__add_nics
  * libxl__add_vtpms
  * libxl__add_vrtcs
+ * libxl__add_vsnds
  */
 
 #define DEFINE_DEVICES_ADD(type)                                        \
@@ -565,6 +566,7 @@ DEFINE_DEVICES_ADD(disk)
 DEFINE_DEVICES_ADD(nic)
 DEFINE_DEVICES_ADD(vtpm)
 DEFINE_DEVICES_ADD(vrtc)
+DEFINE_DEVICES_ADD(vsnd)
 
 #undef DEFINE_DEVICES_ADD
 
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index 366ea05..f75840d 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -547,6 +547,10 @@ void libxl__update_domain_configuration(libxl__gc *gc,
     for (i = 0; i < src->num_vtpms; i++)
         libxl__update_config_vtpm(gc, &dst->vtpms[i], &src->vtpms[i]);
 
+    /* update vsnd information */
+    for (i = 0; i < src->num_vsnds; i++)
+        libxl__update_config_vsnd(gc, &dst->vsnds[i], &src->vsnds[i]);
+
     /* update guest UUID */
     libxl_uuid_copy(CTX, &dst->c_info.uuid, &src->c_info.uuid);
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2a423b5..d78dd79 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -477,7 +477,8 @@ typedef struct {
     (dev)->backend_kind == LIBXL__DEVICE_KIND_QDISK || \
     (dev)->backend_kind == LIBXL__DEVICE_KIND_VFB || \
     (dev)->backend_kind == LIBXL__DEVICE_KIND_VKBD || \
-    (dev)->backend_kind == LIBXL__DEVICE_KIND_VRTC)
+    (dev)->backend_kind == LIBXL__DEVICE_KIND_VRTC || \
+    (dev)->backend_kind == LIBXL__DEVICE_KIND_VSND)
 
 #define XC_PCI_BDF             "0x%x, 0x%x, 0x%x, 0x%x"
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -1188,6 +1189,7 @@ _hidden int libxl__device_nic_setdefault(libxl__gc *gc, 
libxl_device_nic *nic,
                                          uint32_t domid);
 _hidden int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm 
*vtpm);
 _hidden int libxl__device_vrtc_setdefault(libxl__gc *gc, libxl_device_vrtc 
*vrtc);
+_hidden int libxl__device_vsnd_setdefault(libxl__gc *gc, libxl_device_vsnd 
*vsnd);
 _hidden int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb);
 _hidden int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb);
 _hidden int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci);
@@ -2572,6 +2574,11 @@ _hidden void libxl__device_vrtc_add(libxl__egc *egc, 
uint32_t domid,
                                     libxl_device_vrtc *vrtc,
                                     libxl__ao_device *aodev);
 
+/* AO operation to connect a sound device */
+_hidden void libxl__device_vsnd_add(libxl__egc *egc, uint32_t domid,
+                                    libxl_device_vsnd *vsnd,
+                                    libxl__ao_device *aodev);
+
 /* Internal function to connect a vkb device */
 _hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
                                   libxl_device_vkb *vkb);
@@ -3291,6 +3298,10 @@ _hidden void libxl__add_vtpms(libxl__egc *egc, libxl__ao 
*ao, uint32_t domid,
 _hidden void libxl__add_vrtcs(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
                              libxl_domain_config *d_config,
                              libxl__multidev *multidev);
+
+_hidden void libxl__add_vsnds(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                             libxl_domain_config *d_config,
+                             libxl__multidev *multidev);
 /*----- device model creation -----*/
 
 /* First layer; wraps libxl__spawn_spawn. */
@@ -3954,6 +3965,13 @@ static inline void libxl__update_config_vtpm(libxl__gc 
*gc,
     libxl_uuid_copy(CTX, &dst->uuid, &src->uuid);
 }
 
+static inline void libxl__update_config_vsnd(libxl__gc *gc,
+                                             libxl_device_vsnd *dst,
+                                             libxl_device_vsnd *src)
+{
+    dst->devid = src->devid;
+}
+
 /* Macros used to compare device identifier. Returns true if the two
  * devices have same identifier. */
 #define COMPARE_DEVID(a, b) ((a)->devid == (b)->devid)
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 27a750c..8fa29b1 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -551,6 +551,26 @@ libxl_device_vrtc = Struct("device_vrtc", [
     ("device", string),
     ])
 
+libxl_device_vsnd = Struct("device_vsnd", [
+    ("backend_domid", libxl_domid),
+    ("backend_domname", string),
+    ("devid", libxl_devid),
+    ("short_name", string),
+    ("long_name", string),
+    ("sample_formats", string),
+    ("rates", string),
+    ("channels_min", integer),
+    ("channels_max", integer),
+    ("priority", integer),
+    ("slave_device", string),
+    ("alsa_card_id", integer),
+    ("buffer_bytes_max", integer),
+    ("period_bytes_min", integer),
+    ("period_bytes_max", integer),
+    ("period_min", integer),
+    ("period_max", integer),
+    ])
+
 libxl_device_disk = Struct("device_disk", [
     ("backend_domid", libxl_domid),
     ("backend_domname", string),
@@ -639,6 +659,7 @@ libxl_domain_config = Struct("domain_config", [
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
     ("vrtcs", Array(libxl_device_vrtc, "num_vrtcs")),
+    ("vsnds", Array(libxl_device_vsnd, "num_vsnds")),
     # a channel manifests as a console with a name,
     # see docs/misc/channels.txt
     ("channels", Array(libxl_device_channel, "num_channels")),
@@ -695,6 +716,17 @@ libxl_vrtcinfo = Struct("vrtcinfo", [
     ("rref", integer),
     ], dir=DIR_OUT)
 
+libxl_vsndinfo = Struct("vsndinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("state", integer),
+    ("evtch", integer),
+    ("rref", integer),
+    ], dir=DIR_OUT)
+
 libxl_vcpuinfo = Struct("vcpuinfo", [
     ("vcpuid", uint32),
     ("cpu", uint32),
diff --git a/tools/libxl/libxl_types_internal.idl 
b/tools/libxl/libxl_types_internal.idl
index 764efb8..ec63e23 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -23,6 +23,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (7, "CONSOLE"),
     (8, "VTPM"),
     (9, "VRTC"),
+    (10, "VSND"),
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h
index d1b825c..f6532ce 100644
--- a/tools/libxl/libxl_utils.h
+++ b/tools/libxl/libxl_utils.h
@@ -80,6 +80,9 @@ int libxl_devid_to_device_vtpm(libxl_ctx *ctx, uint32_t domid,
 int libxl_devid_to_device_vrtc(libxl_ctx *ctx, uint32_t domid,
                                int devid, libxl_device_vrtc *vrtc);
 
+int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_vsnd *vsnd);
+
 int libxl_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *bitmap, int n_bits);
     /* Allocated bimap is from malloc, libxl_bitmap_dispose() to be
      * called by the application when done. */
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 3d46efb..81a78c0 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -85,6 +85,9 @@ int main_blockdetach(int argc, char **argv);
 int main_vrtcattach(int argc, char **argv);
 int main_vrtclist(int argc, char **argv);
 int main_vrtcdetach(int argc, char **argv);
+int main_vsndattach(int argc, char **argv);
+int main_vsndlist(int argc, char **argv);
+int main_vsnddetach(int argc, char **argv);
 int main_vtpmattach(int argc, char **argv);
 int main_vtpmlist(int argc, char **argv);
 int main_vtpmdetach(int argc, char **argv);
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 77701e0..cb2d8c6 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -627,6 +627,15 @@ static void set_default_nic_values(libxl_device_nic *nic)
     }
 }
 
+static void set_default_vsnd_values(libxl_device_vsnd *vsnd)
+{
+    vsnd->short_name = "Unknown";
+    vsnd->long_name = "Unknown";
+    vsnd->sample_formats = "";
+    vsnd->rates = "";
+    vsnd->slave_device = "";
+}
+
 static void split_string_into_string_list(const char *str,
                                           const char *delim,
                                           libxl_string_list *psl)
@@ -1262,7 +1271,7 @@ static void parse_config_data(const char *config_source,
     const char *buf;
     long l, vcpus = 0;
     XLU_Config *config;
-    XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms, *vrtcs;
+    XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms, 
*vrtcs, *vsnds;
     XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs;
     int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
     int pci_power_mgmt = 0;
@@ -1892,6 +1901,83 @@ static void parse_config_data(const char *config_source,
         }
     }
 
+    if (!xlu_cfg_get_list(config, "vsnd", &vsnds, 0, 0)) {
+        d_config->num_vsnds = 0;
+        d_config->vsnds = NULL;
+        while ((buf = xlu_cfg_get_listitem(vsnds, d_config->num_vsnds)) != 
NULL) {
+            libxl_device_vsnd *vsnd;
+            libxl_string_list pairs;
+            char *path = NULL;
+            int len;
+
+            vsnd = ARRAY_EXTEND_INIT(d_config->vsnds, d_config->num_vsnds,
+                                   libxl_device_vsnd_init);
+
+            split_string_into_string_list(buf, ",", &pairs);
+            len = libxl_string_list_length(&pairs);
+
+            for (i = 0; i < len; i++) {
+                char *key, *key_untrimmed, *value, *value_untrimmed;
+                int rc;
+                rc = split_string_into_pair(pairs[i], "=",
+                                            &key_untrimmed,
+                                            &value_untrimmed);
+                if (rc != 0) {
+                    fprintf(stderr, "failed to parse vsnd configuration: %s",
+                            pairs[i]);
+                    exit(1);
+                }
+                trim(isspace, key_untrimmed, &key);
+                trim(isspace, value_untrimmed, &value);
+
+                if (!strcmp(key, "backendid")) {
+                    vsnd->backend_domid = atoi(value);
+                } else if (!strcmp(key, "backend")) {
+                    replace_string(&vsnd->backend_domname, value);
+                } else if (!strcmp(key, "devid")) {
+                    vsnd->devid = atoi(value);
+                } else if (!strcmp(key, "shortname")) {
+                    replace_string(&vsnd->short_name, value);
+                } else if (!strcmp(key, "longname")) {
+                    replace_string(&vsnd->long_name, value);
+                } else if (!strcmp(key, "sampleformats")) {
+                    replace_string(&vsnd->sample_formats, value);
+                } else if (!strcmp(key, "rates")) {
+                    replace_string(&vsnd->rates, value);
+                } else if (!strcmp(key, "channels_min")) {
+                    vsnd->channels_min = atoi(value);
+                } else if (!strcmp(key, "channels_max")) {
+                    vsnd->channels_max = atoi(value);
+                } else if (!strcmp(key, "priority")) {
+                    vsnd->priority = atoi(value);
+                } else if (!strcmp(key, "slave")) {
+                    replace_string(&vsnd->slave_device, value);
+                } else if (!strcmp(key, "alsacardid")) {
+                    vsnd->alsa_card_id = atoi(value);
+                } else if (!strcmp(key, "bufferbytesmax")) {
+                    vsnd->buffer_bytes_max = atoi(value);
+                } else if (!strcmp(key, "periodbytesmin")) {
+                    vsnd->period_bytes_min = atoi(value);
+                } else if (!strcmp(key, "periodbytesmax")) {
+                    vsnd->period_bytes_max = atoi(value);
+                } else if (!strcmp(key, "periodmin")) {
+                    vsnd->period_min = atoi(value);
+                } else if (!strcmp(key, "periodmax")) {
+                    vsnd->period_max = atoi(value);
+                } else {
+                    fprintf(stderr, "unknown vsnd parameter '%s',"
+                                  " ignoring\n", key);
+                }
+                free(key);
+                free(key_untrimmed);
+                free(value);
+                free(value_untrimmed);
+            }
+            libxl_string_list_dispose(&pairs);
+            free(path);
+        }
+    }
+
     if (!xlu_cfg_get_list (config, "channel", &channels, 0, 0)) {
         d_config->num_channels = 0;
         d_config->channels = NULL;
@@ -6894,6 +6980,147 @@ int main_vrtcdetach(int argc, char **argv)
     return rc;
 }
 
+
+int main_vsndattach(int argc, char **argv)
+{
+    int opt;
+    uint32_t fe_domid;
+    libxl_device_vsnd vsnd;
+    char *oparg;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "vsnd-attach", 1) {
+        /* No options */
+    }
+
+    if (libxl_domain_qualifier_to_domid(ctx, argv[optind], &fe_domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[optind]);
+        return 1;
+    }
+    optind++;
+
+    libxl_device_vsnd_init(&vsnd);
+    set_default_vsnd_values(&vsnd);
+
+    for (argv += optind+1, argc -= optind+1; argc > 0; ++argv, --argc) {
+        if (MATCH_OPTION("backend", *argv, oparg)) {
+            replace_string(&vsnd.backend_domname, oparg);
+        } else if (MATCH_OPTION("devid", *argv, oparg)) {
+            vsnd.devid = atoi(oparg);
+        } else if (MATCH_OPTION("shortname", *argv, oparg)) {
+            replace_string(&vsnd.short_name, oparg);
+        } else if (MATCH_OPTION("longname", *argv, oparg)) {
+            replace_string(&vsnd.long_name, oparg);
+        } else if (MATCH_OPTION("sampleformats", *argv, oparg)) {
+            replace_string(&vsnd.sample_formats, oparg);
+        } else if (MATCH_OPTION("rates", *argv, oparg)) {
+            replace_string(&vsnd.rates, oparg);
+        } else if (MATCH_OPTION("channelsmin", *argv, oparg)) {
+            vsnd.channels_min = atoi(oparg);
+        } else if (MATCH_OPTION("channelsmax", *argv, oparg)) {
+            vsnd.channels_max = atoi(oparg);
+        } else if (MATCH_OPTION("priority", *argv, oparg)) {
+            vsnd.priority = atoi(oparg);
+        } else if (MATCH_OPTION("slave", *argv, oparg)) {
+            replace_string(&vsnd.slave_device, oparg);
+        } else if (MATCH_OPTION("alsacardid", *argv, oparg)) {
+            vsnd.alsa_card_id = atoi(oparg);
+        } else if (MATCH_OPTION("bufferbytesmax", *argv, oparg)) {
+            vsnd.buffer_bytes_max = atoi(oparg);
+        } else if (MATCH_OPTION("periodbytesmin", *argv, oparg)) {
+            vsnd.period_bytes_min = atoi(oparg);
+        } else if (MATCH_OPTION("periodbytesmax", *argv, oparg)) {
+            vsnd.period_bytes_max = atoi(oparg);
+        } else if (MATCH_OPTION("periodmin", *argv, oparg)) {
+            vsnd.period_min = atoi(oparg);
+        } else if (MATCH_OPTION("periodmax", *argv, oparg)) {
+            vsnd.period_max = atoi(oparg);
+        } else {
+            fprintf(stderr, "unrecognized argument `%s'\n", *argv);
+            return 1;
+        }
+    }
+
+    if (dryrun_only) {
+        char *json = libxl_device_vsnd_to_json(ctx, &vsnd);
+        printf("vsnd: %s\n", json);
+        free(json);
+        if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(-1); }
+        return 0;
+    }
+
+    if (libxl_device_vsnd_add(ctx, fe_domid, &vsnd, 0)) {
+        fprintf(stderr, "libxl_device_vsnd_add failed.\n");
+        return 1;
+    }
+    return 0;
+}
+
+int main_vsndlist(int argc, char **argv)
+{
+    int opt;
+    int i, nb;
+    libxl_device_vsnd *vsnds;
+    libxl_vsndinfo vsndinfo;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "vsnd-list", 1) {
+        /* No options */
+    }
+
+    printf("%-5s %-3s %-6s %-5s %-6s %-8s %-40s %-40s\n",
+           "Vdev", "BE", "handle", "state", "evt-ch", "ring-ref", "BE-path", 
"FE-path");
+    for (argv += optind, argc -= optind; argc > 0; --argc, ++argv) {
+        uint32_t domid;
+        if (libxl_domain_qualifier_to_domid(ctx, *argv, &domid) < 0) {
+            fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+            continue;
+        }
+        vsnds = libxl_device_vsnd_list(ctx, domid, &nb);
+        if (!vsnds) {
+            continue;
+        }
+        for (i=0; i<nb; i++) {
+            if (!libxl_device_vsnd_getinfo(ctx, domid, &vsnds[i], &vsndinfo)) {
+                /*      Vdev BE   hdl  st   evch rref BE-path FE-path */
+                printf("%-5d %-3d %-6d %-5d %-6d %-8d %-40s %-40s\n",
+                       vsndinfo.devid, vsndinfo.backend_id, 
vsndinfo.frontend_id,
+                       vsndinfo.state, vsndinfo.evtch, vsndinfo.rref, 
vsndinfo.backend,
+                       vsndinfo.frontend);
+                libxl_vsndinfo_dispose(&vsndinfo);
+            }
+            libxl_device_vsnd_dispose(&vsnds[i]);
+        }
+        free(vsnds);
+    }
+    return 0;
+}
+
+int main_vsnddetach(int argc, char **argv)
+{
+    uint32_t domid, devid;
+    int opt, rc = 0;
+    libxl_device_vsnd vsnd;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "vsnd-detach", 2) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind]);
+    devid = atoi(argv[optind+1]);
+
+    if (libxl_devid_to_device_vsnd(ctx, domid, devid, &vsnd)) {
+        fprintf(stderr, "Error: Device %s not connected.\n", argv[optind+1]);
+        return 1;
+    }
+
+    rc = libxl_device_vsnd_remove(ctx, domid, &vsnd, 0);
+    if (rc) {
+        fprintf(stderr, "libxl_device_vsnd_remove failed.\n");
+        return 1;
+    }
+    libxl_device_vsnd_dispose(&vsnd);
+    return rc;
+}
+
 int main_vtpmattach(int argc, char **argv)
 {
     int opt;
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index 8b8971e..78f0700 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -366,6 +366,26 @@ struct cmd_spec cmd_table[] = {
       "Destroy a domain's virtual rtc device",
       "<Domain> <DevId>",
     },
+    { "vsnd-attach",
+      &main_vsndattach, 1, 1,
+      "Create a new virtual audio device",
+      "<Domain> [backend=<BackDomain>] [devid=<DeviceId>] 
[shortname=<ShortName>]\n"
+      "[longname=<LongName>] [sampleformats=<SampleFormats>] [rates=<Rates>]\n"
+      "[channelsmin=<ChannelsMin>] [channelsmax=<ChannelsMax>] 
[priority=<Priority>]\n"
+      "[slave=<SlaveDevice>] [alsacardid=<AlsaCardId>] 
[bufferbytesmax=<BufferBytesMax>]\n"
+      "[periodbytesmin=<PeriodBytesMin>] [periodbytesmax=<PeriodBytesMax>]\n"
+      "[periodmin=<PeriodMin>] [periodmax=<PeriodMax>]",
+    },
+    { "vsnd-list",
+      &main_vsndlist, 0, 0,
+      "List virtual audio devices for a domain",
+      "<Domain(s)>",
+    },
+    { "vsnd-detach",
+      &main_vsnddetach, 0, 1,
+      "Destroy a domain's virtual audio device",
+      "<Domain> <DevId|uuid>",
+    },
     { "vtpm-attach",
       &main_vtpmattach, 1, 1,
       "Create a new virtual TPM device",
-- 
2.8.2


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.