1 /*
2 * Copyright (C) 2016 EPAM Systems Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_internal.h"
16
17 #include <xen/io/sndif.h>
18
libxl__device_vsnd_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_vsnd * vsnd,bool hotplug)19 static int libxl__device_vsnd_setdefault(libxl__gc *gc, uint32_t domid,
20 libxl_device_vsnd *vsnd,
21 bool hotplug)
22 {
23 return libxl__resolve_domid(gc, vsnd->backend_domname,
24 &vsnd->backend_domid);
25 }
26
libxl__device_from_vsnd(libxl__gc * gc,uint32_t domid,libxl_device_vsnd * vsnd,libxl__device * device)27 static int libxl__device_from_vsnd(libxl__gc *gc, uint32_t domid,
28 libxl_device_vsnd *vsnd,
29 libxl__device *device)
30 {
31 device->backend_devid = vsnd->devid;
32 device->backend_domid = vsnd->backend_domid;
33 device->backend_kind = LIBXL__DEVICE_KIND_VSND;
34 device->devid = vsnd->devid;
35 device->domid = domid;
36 device->kind = LIBXL__DEVICE_KIND_VSND;
37
38 return 0;
39 }
40
libxl__sample_rates_from_string(libxl__gc * gc,const char * str,libxl_vsnd_params * params)41 static int libxl__sample_rates_from_string(libxl__gc *gc, const char *str,
42 libxl_vsnd_params *params)
43 {
44 char *tmp = libxl__strdup(gc, str);
45
46 params->num_sample_rates = 0;
47 params->sample_rates = NULL;
48
49 char *p = strtok(tmp, " ,");
50
51 while (p != NULL) {
52 params->sample_rates = libxl__realloc(NOGC, params->sample_rates,
53 sizeof(*params->sample_rates) *
54 (params->num_sample_rates + 1));
55 params->sample_rates[params->num_sample_rates++] = strtoul(p, NULL, 0);
56 p = strtok(NULL, " ,");
57 }
58
59 return 0;
60 }
61
libxl__sample_formats_from_string(libxl__gc * gc,const char * str,libxl_vsnd_params * params)62 static int libxl__sample_formats_from_string(libxl__gc *gc, const char *str,
63 libxl_vsnd_params *params)
64 {
65 int rc;
66 char *tmp = libxl__strdup(gc, str);
67
68 params->num_sample_formats = 0;
69 params->sample_formats = NULL;
70
71 char *p = strtok(tmp, " ,");
72
73 while (p != NULL) {
74 params->sample_formats = libxl__realloc(NOGC, params->sample_formats,
75 sizeof(*params->sample_formats) *
76 (params->num_sample_formats + 1));
77
78 libxl_vsnd_pcm_format format;
79
80 rc = libxl_vsnd_pcm_format_from_string(p, &format);
81 if (rc) goto out;
82
83 params->sample_formats[params->num_sample_formats++] = format;
84 p = strtok(NULL, " ,");
85 }
86
87 rc = 0;
88
89 out:
90 return rc;
91 }
92
libxl__params_from_xenstore(libxl__gc * gc,const char * path,libxl_vsnd_params * params)93 static int libxl__params_from_xenstore(libxl__gc *gc, const char *path,
94 libxl_vsnd_params *params)
95 {
96 const char *tmp;
97 int rc;
98
99 rc = libxl__xs_read_checked(gc, XBT_NULL,
100 GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_RATES,
101 path), &tmp);
102 if (rc) goto out;
103
104 if (tmp) {
105 rc = libxl__sample_rates_from_string(gc, tmp, params);
106 if (rc) goto out;
107 }
108
109 rc = libxl__xs_read_checked(gc, XBT_NULL,
110 GCSPRINTF("%s/"XENSND_FIELD_SAMPLE_FORMATS,
111 path), &tmp);
112 if (rc) goto out;
113
114 if (tmp) {
115 rc = libxl__sample_formats_from_string(gc, tmp, params);
116 if (rc) goto out;
117 }
118
119 rc = libxl__xs_read_checked(gc, XBT_NULL,
120 GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MIN,
121 path), &tmp);
122 if (rc) goto out;
123
124 if (tmp) {
125 params->channels_min = strtoul(tmp, NULL, 0);
126 }
127
128 rc = libxl__xs_read_checked(gc, XBT_NULL,
129 GCSPRINTF("%s/"XENSND_FIELD_CHANNELS_MAX,
130 path), &tmp);
131 if (rc) goto out;
132
133 if (tmp) {
134 params->channels_max = strtoul(tmp, NULL, 0);
135 }
136
137 rc = libxl__xs_read_checked(gc, XBT_NULL,
138 GCSPRINTF("%s/"XENSND_FIELD_BUFFER_SIZE,
139 path), &tmp);
140 if (rc) goto out;
141
142 if (tmp) {
143 params->buffer_size = strtoul(tmp, NULL, 0);
144 }
145
146 rc = 0;
147
148 out:
149 return rc;
150 }
151
libxl__stream_from_xenstore(libxl__gc * gc,const char * path,libxl_vsnd_stream * stream)152 static int libxl__stream_from_xenstore(libxl__gc *gc, const char *path,
153 libxl_vsnd_stream *stream)
154 {
155 const char *tmp;
156 int rc;
157
158 stream->unique_id = xs_read(CTX->xsh, XBT_NULL,
159 GCSPRINTF("%s/"XENSND_FIELD_STREAM_UNIQUE_ID,
160 path), NULL);
161
162 rc = libxl__xs_read_checked(gc, XBT_NULL,
163 GCSPRINTF("%s/"XENSND_FIELD_TYPE,
164 path), &tmp);
165 if (rc) goto out;
166
167 if (tmp) {
168 libxl_vsnd_stream_type type;
169
170 rc = libxl_vsnd_stream_type_from_string(tmp, &type);
171 if (rc) goto out;
172
173 stream->type = type;
174 }
175
176 rc = libxl__params_from_xenstore(gc, path, &stream->params);
177 if (rc) goto out;
178
179 rc = 0;
180
181 out:
182 return rc;
183 }
184
libxl__pcm_from_xenstore(libxl__gc * gc,const char * path,libxl_vsnd_pcm * pcm)185 static int libxl__pcm_from_xenstore(libxl__gc *gc, const char *path,
186 libxl_vsnd_pcm *pcm)
187 {
188 const char *tmp;
189 int rc;
190
191 pcm->name = xs_read(CTX->xsh, XBT_NULL,
192 GCSPRINTF("%s/"XENSND_FIELD_DEVICE_NAME, path), NULL);
193
194 rc = libxl__params_from_xenstore(gc, path, &pcm->params);
195 if (rc) goto out;
196
197 pcm->streams = NULL;
198 pcm->num_vsnd_streams = 0;
199
200 do {
201 char *stream_path = GCSPRINTF("%s/%d", path, pcm->num_vsnd_streams);
202
203 rc = libxl__xs_read_checked(gc, XBT_NULL, stream_path, &tmp);
204 if (rc) goto out;
205
206 if (tmp) {
207 pcm->streams = libxl__realloc(NOGC, pcm->streams,
208 sizeof(*pcm->streams) *
209 (++pcm->num_vsnd_streams));
210
211 libxl_vsnd_stream_init(&pcm->streams[pcm->num_vsnd_streams - 1]);
212
213 rc = libxl__stream_from_xenstore(gc, stream_path,
214 &pcm->streams[pcm->num_vsnd_streams
215 - 1]);
216 if (rc) goto out;
217 }
218 } while (tmp);
219
220 rc = 0;
221
222 out:
223 return rc;
224 }
225
libxl__vsnd_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_devid devid,libxl_device_vsnd * vsnd)226 static int libxl__vsnd_from_xenstore(libxl__gc *gc, const char *libxl_path,
227 libxl_devid devid,
228 libxl_device_vsnd *vsnd)
229 {
230 const char *tmp;
231 const char *fe_path;
232 int rc;
233
234 vsnd->devid = devid;
235 rc = libxl__xs_read_mandatory(gc, XBT_NULL,
236 GCSPRINTF("%s/backend", libxl_path),
237 &tmp);
238 if (rc) goto out;
239
240 rc = libxl__backendpath_parse_domid(gc, tmp, &vsnd->backend_domid);
241 if (rc) goto out;
242
243 rc = libxl__xs_read_mandatory(gc, XBT_NULL,
244 GCSPRINTF("%s/frontend", libxl_path),
245 &fe_path);
246 if (rc) goto out;
247
248 vsnd->short_name = xs_read(CTX->xsh, XBT_NULL,
249 GCSPRINTF("%s/"XENSND_FIELD_VCARD_SHORT_NAME,
250 fe_path), NULL);
251
252 vsnd->long_name = xs_read(CTX->xsh, XBT_NULL,
253 GCSPRINTF("%s/"XENSND_FIELD_VCARD_LONG_NAME,
254 fe_path), NULL);
255
256 rc = libxl__params_from_xenstore(gc, fe_path, &vsnd->params);
257 if (rc) goto out;
258
259 vsnd->pcms = NULL;
260 vsnd->num_vsnd_pcms = 0;
261
262 do {
263 char *pcm_path = GCSPRINTF("%s/%d", fe_path, vsnd->num_vsnd_pcms);
264
265 rc = libxl__xs_read_checked(gc, XBT_NULL, pcm_path, &tmp);
266 if (rc) goto out;
267
268 if (tmp) {
269 vsnd->pcms = libxl__realloc(NOGC, vsnd->pcms, sizeof(*vsnd->pcms) *
270 (++vsnd->num_vsnd_pcms));
271
272 libxl_vsnd_pcm_init(&vsnd->pcms[vsnd->num_vsnd_pcms - 1]);
273
274 rc = libxl__pcm_from_xenstore(gc, pcm_path,
275 &vsnd->pcms[vsnd->num_vsnd_pcms - 1]);
276 if (rc) goto out;
277 }
278 } while (tmp);
279
280 rc = 0;
281
282 out:
283 return rc;
284 }
285
libxl__update_config_vsnd(libxl__gc * gc,libxl_device_vsnd * dst,libxl_device_vsnd * src)286 static void libxl__update_config_vsnd(libxl__gc *gc,
287 libxl_device_vsnd *dst,
288 libxl_device_vsnd *src)
289 {
290 dst->devid = src->devid;
291 }
292
libxl_device_vsnd_compare(const libxl_device_vsnd * d1,const libxl_device_vsnd * d2)293 static int libxl_device_vsnd_compare(const libxl_device_vsnd *d1,
294 const libxl_device_vsnd *d2)
295 {
296 return COMPARE_DEVID(d1, d2);
297 }
298
libxl__device_vsnd_add(libxl__egc * egc,uint32_t domid,libxl_device_vsnd * vsnd,libxl__ao_device * aodev)299 static void libxl__device_vsnd_add(libxl__egc *egc, uint32_t domid,
300 libxl_device_vsnd *vsnd,
301 libxl__ao_device *aodev)
302 {
303 libxl__device_add_async(egc, domid, &libxl__vsnd_devtype, vsnd, aodev);
304 }
305
libxl__rates_to_str_vsnd(char * str,uint32_t * sample_rates,int num_sample_rates)306 static unsigned int libxl__rates_to_str_vsnd(char *str, uint32_t *sample_rates,
307 int num_sample_rates)
308 {
309 unsigned int len;
310 int i;
311
312 len = 0;
313
314 if (num_sample_rates == 0) goto out;
315
316 for (i = 0; i < num_sample_rates - 1; i++) {
317 if (str) {
318 len += sprintf(&str[len], "%u,", sample_rates[i]);
319 } else {
320 len += snprintf(NULL, 0, "%u,", sample_rates[i]);
321 }
322 }
323
324 if (str) {
325 len += sprintf(&str[len], "%u", sample_rates[i]);
326 } else {
327 len += snprintf(NULL, 0, "%u", sample_rates[i]);
328 }
329
330 out:
331 return len;
332 }
333
libxl__formats_to_str_vsnd(char * str,libxl_vsnd_pcm_format * sample_formats,int num_sample_formats)334 static unsigned int libxl__formats_to_str_vsnd(char *str,
335 libxl_vsnd_pcm_format *sample_formats,
336 int num_sample_formats)
337 {
338 unsigned int len;
339 int i;
340
341 len = 0;
342
343 if (num_sample_formats == 0) goto out;
344
345 for (i = 0; i < num_sample_formats - 1; i++) {
346 if (str) {
347 len += sprintf(&str[len], "%s,",
348 libxl_vsnd_pcm_format_to_string(sample_formats[i]));
349 } else {
350 len += snprintf(NULL, 0, "%s,",
351 libxl_vsnd_pcm_format_to_string(sample_formats[i]));
352 }
353 }
354
355 if (str) {
356 len += sprintf(&str[len], "%s",
357 libxl_vsnd_pcm_format_to_string(sample_formats[i]));
358 } else {
359 len += snprintf(NULL, 0, "%s",
360 libxl_vsnd_pcm_format_to_string(sample_formats[i]));
361 }
362
363 out:
364 return len;
365 }
366
libxl__set_params_vsnd(libxl__gc * gc,char * path,libxl_vsnd_params * params,flexarray_t * front)367 static int libxl__set_params_vsnd(libxl__gc *gc, char *path,
368 libxl_vsnd_params *params, flexarray_t *front)
369 {
370 char *buffer;
371 int len;
372 int rc;
373
374 if (params->sample_rates) {
375 /* calculate required string size */
376 len = libxl__rates_to_str_vsnd(NULL, params->sample_rates,
377 params->num_sample_rates);
378
379 if (len) {
380 buffer = libxl__malloc(gc, len + 1);
381
382 libxl__rates_to_str_vsnd(buffer, params->sample_rates,
383 params->num_sample_rates);
384 rc = flexarray_append_pair(front,
385 GCSPRINTF("%s"XENSND_FIELD_SAMPLE_RATES,
386 path), buffer);
387 if (rc) goto out;
388 }
389 }
390
391 if (params->sample_formats) {
392 /* calculate required string size */
393 len = libxl__formats_to_str_vsnd(NULL, params->sample_formats,
394 params->num_sample_formats);
395
396 if (len) {
397 buffer = libxl__malloc(gc, len + 1);
398
399 libxl__formats_to_str_vsnd(buffer, params->sample_formats,
400 params->num_sample_formats);
401 rc = flexarray_append_pair(front,
402 GCSPRINTF("%s"XENSND_FIELD_SAMPLE_FORMATS,
403 path), buffer);
404 if (rc) goto out;
405 }
406 }
407
408 if (params->channels_min) {
409 rc = flexarray_append_pair(front,
410 GCSPRINTF("%s"XENSND_FIELD_CHANNELS_MIN, path),
411 GCSPRINTF("%u", params->channels_min));
412 if (rc) goto out;
413 }
414
415 if (params->channels_max) {
416 rc = flexarray_append_pair(front,
417 GCSPRINTF("%s"XENSND_FIELD_CHANNELS_MAX, path),
418 GCSPRINTF("%u", params->channels_max));
419 if (rc) goto out;
420 }
421
422 if (params->buffer_size) {
423 rc = flexarray_append_pair(front,
424 GCSPRINTF("%s"XENSND_FIELD_BUFFER_SIZE, path),
425 GCSPRINTF("%u", params->buffer_size));
426 if (rc) goto out;
427 }
428
429 rc = 0;
430
431 out:
432 return rc;
433 }
434
libxl__set_streams_vsnd(libxl__gc * gc,char * path,libxl_vsnd_stream * streams,int num_streams,flexarray_t * front)435 static int libxl__set_streams_vsnd(libxl__gc *gc, char *path,
436 libxl_vsnd_stream *streams,
437 int num_streams, flexarray_t *front)
438 {
439 int i;
440 int rc;
441
442 for (i = 0; i < num_streams; i++) {
443 rc = flexarray_append_pair(front,
444 GCSPRINTF("%s%d/"XENSND_FIELD_STREAM_UNIQUE_ID, path, i),
445 streams[i].unique_id);
446 if (rc) goto out;
447
448 const char *type = libxl_vsnd_stream_type_to_string(streams[i].type);
449
450 if (type) {
451 rc = flexarray_append_pair(front,
452 GCSPRINTF("%s%d/"XENSND_FIELD_TYPE, path, i),
453 (char *)type);
454 if (rc) goto out;
455 }
456
457 rc = libxl__set_params_vsnd(gc, GCSPRINTF("%s%d/", path, i),
458 &streams[i].params, front);
459 if (rc) goto out;
460 }
461
462 rc = 0;
463
464 out:
465 return rc;
466 }
467
libxl__set_pcms_vsnd(libxl__gc * gc,libxl_vsnd_pcm * pcms,int num_pcms,flexarray_t * front)468 static int libxl__set_pcms_vsnd(libxl__gc *gc, libxl_vsnd_pcm *pcms,
469 int num_pcms, flexarray_t *front)
470 {
471 int i;
472 int rc;
473
474 for (i = 0; i < num_pcms; i++) {
475 if (pcms[i].name) {
476 rc = flexarray_append_pair(front,
477 GCSPRINTF("%d/"XENSND_FIELD_DEVICE_NAME, i),
478 pcms[i].name);
479 if (rc) goto out;
480 }
481
482 char *path = GCSPRINTF("%d/", i);
483
484 rc = libxl__set_params_vsnd(gc, path, &pcms[i].params, front);
485 if (rc) goto out;
486
487 rc = libxl__set_streams_vsnd(gc, path, pcms[i].streams,
488 pcms[i].num_vsnd_streams, front);
489 if (rc) goto out;
490 }
491
492 rc = 0;
493
494 out:
495 return rc;
496 }
497
libxl__set_xenstore_vsnd(libxl__gc * gc,uint32_t domid,libxl_device_vsnd * vsnd,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)498 static int libxl__set_xenstore_vsnd(libxl__gc *gc, uint32_t domid,
499 libxl_device_vsnd *vsnd,
500 flexarray_t *back, flexarray_t *front,
501 flexarray_t *ro_front)
502 {
503 int rc;
504
505 if (vsnd->long_name) {
506 rc = flexarray_append_pair(front, XENSND_FIELD_VCARD_LONG_NAME,
507 vsnd->long_name);
508 if (rc) goto out;
509 }
510
511 if (vsnd->short_name) {
512 rc = flexarray_append_pair(front, XENSND_FIELD_VCARD_SHORT_NAME,
513 vsnd->short_name);
514 if (rc) goto out;
515 }
516
517 rc = libxl__set_params_vsnd(gc, "", &vsnd->params, front);
518 if (rc) goto out;
519
520 rc = libxl__set_pcms_vsnd(gc, vsnd->pcms, vsnd->num_vsnd_pcms, front);
521 if (rc) goto out;
522
523 rc = 0;
524
525 out:
526 return rc;
527 }
528
libxl__device_stream_getinfo(libxl__gc * gc,const char * path,libxl_vsnd_pcm * pcm,libxl_pcminfo * info)529 static int libxl__device_stream_getinfo(libxl__gc *gc, const char *path,
530 libxl_vsnd_pcm* pcm,
531 libxl_pcminfo *info)
532 {
533 const char *tmp;
534 int i;
535 int rc;
536
537 info->num_vsnd_streams = pcm->num_vsnd_streams;
538 info->streams = libxl__malloc(NOGC, sizeof(*info->streams) * info->num_vsnd_streams);
539
540 for (i = 0; i < info->num_vsnd_streams; i++)
541 {
542 libxl_streaminfo_init(&info->streams[i]);
543
544 rc = libxl__xs_read_checked(gc, XBT_NULL,
545 GCSPRINTF("%s/%d/"XENSND_FIELD_RING_REF,
546 path, i), &tmp);
547 if (rc) goto out;
548
549 info->streams[i].req_rref = tmp ? strtoul(tmp, NULL, 10) : -1;
550
551 rc = libxl__xs_read_checked(gc, XBT_NULL,
552 GCSPRINTF("%s/%d/"XENSND_FIELD_EVT_CHNL,
553 path, i), &tmp);
554 if (rc) goto out;
555
556 info->streams[i].req_evtch = tmp ? strtoul(tmp, NULL, 10) : -1;
557 }
558
559 rc = 0;
560
561 out:
562 return rc;
563 }
564
libxl__device_pcm_getinfo(libxl__gc * gc,const char * path,const libxl_device_vsnd * vsnd,libxl_vsndinfo * info)565 static int libxl__device_pcm_getinfo(libxl__gc *gc, const char *path,
566 const libxl_device_vsnd *vsnd,
567 libxl_vsndinfo *info)
568 {
569 int i;
570 int rc;
571
572 info->num_vsnd_pcms = vsnd->num_vsnd_pcms;
573 info->pcms = libxl__malloc(NOGC, sizeof(*info->pcms) * info->num_vsnd_pcms);
574
575 for (i = 0; i < info->num_vsnd_pcms; i++)
576 {
577 libxl_pcminfo_init(&info->pcms[i]);
578
579 rc = libxl__device_stream_getinfo(gc, GCSPRINTF("%s/%d", path, i),
580 &vsnd->pcms[i], &info->pcms[i]);
581 if (rc) goto out;
582 }
583
584 rc = 0;
585
586 out:
587 return rc;
588 }
589
libxl_device_vsnd_getinfo(libxl_ctx * ctx,uint32_t domid,const libxl_device_vsnd * vsnd,libxl_vsndinfo * info)590 int libxl_device_vsnd_getinfo(libxl_ctx *ctx, uint32_t domid,
591 const libxl_device_vsnd *vsnd,
592 libxl_vsndinfo *info)
593 {
594 GC_INIT(ctx);
595 char *libxl_path, *dompath, *devpath;
596 const char *val;
597 int rc;
598
599 libxl_vsndinfo_init(info);
600 dompath = libxl__xs_get_dompath(gc, domid);
601 info->devid = vsnd->devid;
602
603 devpath = libxl__domain_device_frontend_path(gc, domid, info->devid,
604 LIBXL__DEVICE_KIND_VSND);
605 libxl_path = libxl__domain_device_libxl_path(gc, domid, info->devid,
606 LIBXL__DEVICE_KIND_VSND);
607
608 info->backend = xs_read(ctx->xsh, XBT_NULL,
609 GCSPRINTF("%s/backend", libxl_path), NULL);
610
611 rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id);
612 if (rc) goto out;
613
614 val = xs_read(ctx->xsh, XBT_NULL, GCSPRINTF("%s/state", devpath), NULL);
615
616 info->state = val ? strtoul(val, NULL, 10) : -1;
617
618 info->frontend = xs_read(ctx->xsh, XBT_NULL,
619 GCSPRINTF("%s/frontend", libxl_path), NULL);
620
621 info->frontend_id = domid;
622
623 rc = libxl__device_pcm_getinfo(gc, devpath, vsnd, info);
624 if (rc) goto out;
625
626 rc = 0;
627
628 out:
629 GC_FREE;
630 return rc;
631 }
632
libxl_devid_to_device_vsnd(libxl_ctx * ctx,uint32_t domid,int devid,libxl_device_vsnd * vsnd)633 int libxl_devid_to_device_vsnd(libxl_ctx *ctx, uint32_t domid,
634 int devid, libxl_device_vsnd *vsnd)
635 {
636 GC_INIT(ctx);
637
638 libxl_device_vsnd *vsnds = NULL;
639 int n, i;
640 int rc;
641
642 libxl_device_vsnd_init(vsnd);
643
644 vsnds = libxl__device_list(gc, &libxl__vsnd_devtype, domid, &n);
645
646 if (!vsnds) { rc = ERROR_NOTFOUND; goto out; }
647
648 for (i = 0; i < n; ++i) {
649 if (devid == vsnds[i].devid) {
650 libxl_device_vsnd_copy(ctx, vsnd, &vsnds[i]);
651 rc = 0;
652 goto out;
653 }
654 }
655
656 rc = ERROR_NOTFOUND;
657
658 out:
659 if (vsnds)
660 libxl__device_list_free(&libxl__vsnd_devtype, vsnds, n);
661
662 GC_FREE;
663 return rc;
664 }
665
666 static LIBXL_DEFINE_UPDATE_DEVID(vsnd)
667 static LIBXL_DEFINE_DEVICES_ADD(vsnd)
668
669 LIBXL_DEFINE_DEVICE_ADD(vsnd)
670 LIBXL_DEFINE_DEVICE_REMOVE(vsnd)
671 LIBXL_DEFINE_DEVICE_LIST(vsnd)
672
673 DEFINE_DEVICE_TYPE_STRUCT(vsnd, VSND,
674 .update_config = (device_update_config_fn_t) libxl__update_config_vsnd,
675 .from_xenstore = (device_from_xenstore_fn_t) libxl__vsnd_from_xenstore,
676 .set_xenstore_config = (device_set_xenstore_config_fn_t)
677 libxl__set_xenstore_vsnd
678 );
679
680 /*
681 * Local variables:
682 * mode: C
683 * c-basic-offset: 4
684 * indent-tabs-mode: nil
685 * End:
686 */
687