@@ -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)
@@ -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.
@@ -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);
@@ -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,