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