target/loongarch: Fix query-cpu-model-expansion to reject props
[qemu/armbru.git] / hw / audio / virtio-snd.c
blobea2aeaef14347010c9601f4466f99949502463f4
1 /*
2 * VIRTIO Sound Device conforming to
4 * "Virtual I/O Device (VIRTIO) Version 1.2
5 * Committee Specification Draft 01
6 * 09 May 2022"
8 * <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-52900014>
10 * Copyright (c) 2023 Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
11 * Copyright (C) 2019 OpenSynergy GmbH
13 * This work is licensed under the terms of the GNU GPL, version 2 or
14 * (at your option) any later version. See the COPYING file in the
15 * top-level directory.
18 #include "qemu/osdep.h"
19 #include "qemu/iov.h"
20 #include "qemu/log.h"
21 #include "qemu/error-report.h"
22 #include "include/qemu/lockable.h"
23 #include "sysemu/runstate.h"
24 #include "trace.h"
25 #include "qapi/error.h"
26 #include "hw/audio/virtio-snd.h"
27 #include "hw/core/cpu.h"
29 #define VIRTIO_SOUND_VM_VERSION 1
30 #define VIRTIO_SOUND_JACK_DEFAULT 0
31 #define VIRTIO_SOUND_STREAM_DEFAULT 2
32 #define VIRTIO_SOUND_CHMAP_DEFAULT 0
33 #define VIRTIO_SOUND_HDA_FN_NID 0
35 static void virtio_snd_pcm_out_cb(void *data, int available);
36 static void virtio_snd_process_cmdq(VirtIOSound *s);
37 static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
38 static void virtio_snd_pcm_in_cb(void *data, int available);
39 static void virtio_snd_unrealize(DeviceState *dev);
41 static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
42 | BIT(VIRTIO_SND_PCM_FMT_U8)
43 | BIT(VIRTIO_SND_PCM_FMT_S16)
44 | BIT(VIRTIO_SND_PCM_FMT_U16)
45 | BIT(VIRTIO_SND_PCM_FMT_S32)
46 | BIT(VIRTIO_SND_PCM_FMT_U32)
47 | BIT(VIRTIO_SND_PCM_FMT_FLOAT);
49 static uint32_t supported_rates = BIT(VIRTIO_SND_PCM_RATE_5512)
50 | BIT(VIRTIO_SND_PCM_RATE_8000)
51 | BIT(VIRTIO_SND_PCM_RATE_11025)
52 | BIT(VIRTIO_SND_PCM_RATE_16000)
53 | BIT(VIRTIO_SND_PCM_RATE_22050)
54 | BIT(VIRTIO_SND_PCM_RATE_32000)
55 | BIT(VIRTIO_SND_PCM_RATE_44100)
56 | BIT(VIRTIO_SND_PCM_RATE_48000)
57 | BIT(VIRTIO_SND_PCM_RATE_64000)
58 | BIT(VIRTIO_SND_PCM_RATE_88200)
59 | BIT(VIRTIO_SND_PCM_RATE_96000)
60 | BIT(VIRTIO_SND_PCM_RATE_176400)
61 | BIT(VIRTIO_SND_PCM_RATE_192000)
62 | BIT(VIRTIO_SND_PCM_RATE_384000);
64 static const VMStateDescription vmstate_virtio_snd_device = {
65 .name = TYPE_VIRTIO_SND,
66 .version_id = VIRTIO_SOUND_VM_VERSION,
67 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
70 static const VMStateDescription vmstate_virtio_snd = {
71 .name = TYPE_VIRTIO_SND,
72 .unmigratable = 1,
73 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
74 .version_id = VIRTIO_SOUND_VM_VERSION,
75 .fields = (const VMStateField[]) {
76 VMSTATE_VIRTIO_DEVICE,
77 VMSTATE_END_OF_LIST()
81 static Property virtio_snd_properties[] = {
82 DEFINE_AUDIO_PROPERTIES(VirtIOSound, card),
83 DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks,
84 VIRTIO_SOUND_JACK_DEFAULT),
85 DEFINE_PROP_UINT32("streams", VirtIOSound, snd_conf.streams,
86 VIRTIO_SOUND_STREAM_DEFAULT),
87 DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps,
88 VIRTIO_SOUND_CHMAP_DEFAULT),
89 DEFINE_PROP_END_OF_LIST(),
92 static void
93 virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
95 VirtIOSound *s = VIRTIO_SND(vdev);
96 virtio_snd_config *sndconfig =
97 (virtio_snd_config *)config;
98 trace_virtio_snd_get_config(vdev,
99 s->snd_conf.jacks,
100 s->snd_conf.streams,
101 s->snd_conf.chmaps);
103 memcpy(sndconfig, &s->snd_conf, sizeof(s->snd_conf));
104 cpu_to_le32s(&sndconfig->jacks);
105 cpu_to_le32s(&sndconfig->streams);
106 cpu_to_le32s(&sndconfig->chmaps);
110 static void
111 virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
113 VirtIOSound *s = VIRTIO_SND(vdev);
114 const virtio_snd_config *sndconfig =
115 (const virtio_snd_config *)config;
118 trace_virtio_snd_set_config(vdev,
119 s->snd_conf.jacks,
120 sndconfig->jacks,
121 s->snd_conf.streams,
122 sndconfig->streams,
123 s->snd_conf.chmaps,
124 sndconfig->chmaps);
126 memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
127 le32_to_cpus(&s->snd_conf.jacks);
128 le32_to_cpus(&s->snd_conf.streams);
129 le32_to_cpus(&s->snd_conf.chmaps);
133 static void
134 virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer)
136 g_free(buffer->elem);
137 g_free(buffer);
140 static void
141 virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd)
143 g_free(cmd->elem);
144 g_free(cmd);
148 * Get a specific stream from the virtio sound card device.
149 * Returns NULL if @stream_id is invalid or not allocated.
151 * @s: VirtIOSound device
152 * @stream_id: stream id
154 static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
155 uint32_t stream_id)
157 return stream_id >= s->snd_conf.streams ? NULL :
158 s->pcm->streams[stream_id];
162 * Get params for a specific stream.
164 * @s: VirtIOSound device
165 * @stream_id: stream id
167 static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
168 uint32_t stream_id)
170 return stream_id >= s->snd_conf.streams ? NULL
171 : &s->pcm->pcm_params[stream_id];
175 * Handle the VIRTIO_SND_R_PCM_INFO request.
176 * The function writes the info structs to the request element.
178 * @s: VirtIOSound device
179 * @cmd: The request command queue element from VirtIOSound cmdq field
181 static void virtio_snd_handle_pcm_info(VirtIOSound *s,
182 virtio_snd_ctrl_command *cmd)
184 uint32_t stream_id, start_id, count, size;
185 virtio_snd_pcm_info val;
186 virtio_snd_query_info req;
187 VirtIOSoundPCMStream *stream = NULL;
188 g_autofree virtio_snd_pcm_info *pcm_info = NULL;
189 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
190 cmd->elem->out_num,
192 &req,
193 sizeof(virtio_snd_query_info));
195 if (msg_sz != sizeof(virtio_snd_query_info)) {
197 * TODO: do we need to set DEVICE_NEEDS_RESET?
199 qemu_log_mask(LOG_GUEST_ERROR,
200 "%s: virtio-snd command size incorrect %zu vs \
201 %zu\n", __func__, msg_sz, sizeof(virtio_snd_query_info));
202 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
203 return;
206 start_id = le32_to_cpu(req.start_id);
207 count = le32_to_cpu(req.count);
208 size = le32_to_cpu(req.size);
210 if (iov_size(cmd->elem->in_sg, cmd->elem->in_num) <
211 sizeof(virtio_snd_hdr) + size * count) {
213 * TODO: do we need to set DEVICE_NEEDS_RESET?
215 error_report("pcm info: buffer too small, got: %zu, needed: %zu",
216 iov_size(cmd->elem->in_sg, cmd->elem->in_num),
217 sizeof(virtio_snd_pcm_info));
218 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
219 return;
222 pcm_info = g_new0(virtio_snd_pcm_info, count);
223 for (uint32_t i = 0; i < count; i++) {
224 stream_id = i + start_id;
225 trace_virtio_snd_handle_pcm_info(stream_id);
226 stream = virtio_snd_pcm_get_stream(s, stream_id);
227 if (!stream) {
228 error_report("Invalid stream id: %"PRIu32, stream_id);
229 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
230 return;
232 val = stream->info;
233 val.hdr.hda_fn_nid = cpu_to_le32(val.hdr.hda_fn_nid);
234 val.features = cpu_to_le32(val.features);
235 val.formats = cpu_to_le64(val.formats);
236 val.rates = cpu_to_le64(val.rates);
238 * 5.14.6.6.2.1 Device Requirements: Stream Information The device MUST
239 * NOT set undefined feature, format, rate and direction values. The
240 * device MUST initialize the padding bytes to 0.
242 pcm_info[i] = val;
243 memset(&pcm_info[i].padding, 0, 5);
246 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
247 iov_from_buf(cmd->elem->in_sg,
248 cmd->elem->in_num,
249 sizeof(virtio_snd_hdr),
250 pcm_info,
251 sizeof(virtio_snd_pcm_info) * count);
255 * Set the given stream params.
256 * Called by both virtio_snd_handle_pcm_set_params and during device
257 * initialization.
258 * Returns the response status code. (VIRTIO_SND_S_*).
260 * @s: VirtIOSound device
261 * @params: The PCM params as defined in the virtio specification
263 static
264 uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
265 uint32_t stream_id,
266 virtio_snd_pcm_set_params *params)
268 virtio_snd_pcm_set_params *st_params;
270 if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) {
272 * TODO: do we need to set DEVICE_NEEDS_RESET?
274 virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
275 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
278 st_params = virtio_snd_pcm_get_params(s, stream_id);
280 if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
281 error_report("Number of channels is not supported.");
282 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
284 if (!(supported_formats & BIT(params->format))) {
285 error_report("Stream format is not supported.");
286 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
288 if (!(supported_rates & BIT(params->rate))) {
289 error_report("Stream rate is not supported.");
290 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
293 st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
294 st_params->period_bytes = le32_to_cpu(params->period_bytes);
295 st_params->features = le32_to_cpu(params->features);
296 /* the following are uint8_t, so there's no need to bswap the values. */
297 st_params->channels = params->channels;
298 st_params->format = params->format;
299 st_params->rate = params->rate;
301 return cpu_to_le32(VIRTIO_SND_S_OK);
305 * Handles the VIRTIO_SND_R_PCM_SET_PARAMS request.
307 * @s: VirtIOSound device
308 * @cmd: The request command queue element from VirtIOSound cmdq field
310 static void virtio_snd_handle_pcm_set_params(VirtIOSound *s,
311 virtio_snd_ctrl_command *cmd)
313 virtio_snd_pcm_set_params req = { 0 };
314 uint32_t stream_id;
315 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
316 cmd->elem->out_num,
318 &req,
319 sizeof(virtio_snd_pcm_set_params));
321 if (msg_sz != sizeof(virtio_snd_pcm_set_params)) {
323 * TODO: do we need to set DEVICE_NEEDS_RESET?
325 qemu_log_mask(LOG_GUEST_ERROR,
326 "%s: virtio-snd command size incorrect %zu vs \
327 %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_set_params));
328 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
329 return;
331 stream_id = le32_to_cpu(req.hdr.stream_id);
332 trace_virtio_snd_handle_pcm_set_params(stream_id);
333 cmd->resp.code = virtio_snd_set_pcm_params(s, stream_id, &req);
337 * Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_*
339 static AudioFormat virtio_snd_get_qemu_format(uint32_t format)
341 #define CASE(FMT) \
342 case VIRTIO_SND_PCM_FMT_##FMT: \
343 return AUDIO_FORMAT_##FMT;
345 switch (format) {
346 CASE(U8)
347 CASE(S8)
348 CASE(U16)
349 CASE(S16)
350 CASE(U32)
351 CASE(S32)
352 case VIRTIO_SND_PCM_FMT_FLOAT:
353 return AUDIO_FORMAT_F32;
354 default:
355 g_assert_not_reached();
358 #undef CASE
362 * Get a QEMU Audiosystem compatible frequency value from a
363 * VIRTIO_SND_PCM_RATE_*
365 static uint32_t virtio_snd_get_qemu_freq(uint32_t rate)
367 #define CASE(RATE) \
368 case VIRTIO_SND_PCM_RATE_##RATE: \
369 return RATE;
371 switch (rate) {
372 CASE(5512)
373 CASE(8000)
374 CASE(11025)
375 CASE(16000)
376 CASE(22050)
377 CASE(32000)
378 CASE(44100)
379 CASE(48000)
380 CASE(64000)
381 CASE(88200)
382 CASE(96000)
383 CASE(176400)
384 CASE(192000)
385 CASE(384000)
386 default:
387 g_assert_not_reached();
390 #undef CASE
394 * Get QEMU Audiosystem compatible audsettings from virtio based pcm stream
395 * params.
397 static void virtio_snd_get_qemu_audsettings(audsettings *as,
398 virtio_snd_pcm_set_params *params)
400 as->nchannels = MIN(AUDIO_MAX_CHANNELS, params->channels);
401 as->fmt = virtio_snd_get_qemu_format(params->format);
402 as->freq = virtio_snd_get_qemu_freq(params->rate);
403 as->endianness = target_words_bigendian() ? 1 : 0;
407 * Close a stream and free all its resources.
409 * @stream: VirtIOSoundPCMStream *stream
411 static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
413 if (stream) {
414 virtio_snd_pcm_flush(stream);
415 if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
416 AUD_close_out(&stream->pcm->snd->card, stream->voice.out);
417 stream->voice.out = NULL;
418 } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
419 AUD_close_in(&stream->pcm->snd->card, stream->voice.in);
420 stream->voice.in = NULL;
426 * Prepares a VirtIOSound card stream.
427 * Returns the response status code. (VIRTIO_SND_S_*).
429 * @s: VirtIOSound device
430 * @stream_id: stream id
432 static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
434 audsettings as;
435 virtio_snd_pcm_set_params *params;
436 VirtIOSoundPCMStream *stream;
438 if (s->pcm->streams == NULL ||
439 s->pcm->pcm_params == NULL ||
440 stream_id >= s->snd_conf.streams) {
441 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
444 params = virtio_snd_pcm_get_params(s, stream_id);
445 if (params == NULL) {
446 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
449 stream = virtio_snd_pcm_get_stream(s, stream_id);
450 if (stream == NULL) {
451 stream = g_new0(VirtIOSoundPCMStream, 1);
452 stream->active = false;
453 stream->id = stream_id;
454 stream->pcm = s->pcm;
455 stream->s = s;
456 qemu_mutex_init(&stream->queue_mutex);
457 QSIMPLEQ_INIT(&stream->queue);
458 QSIMPLEQ_INIT(&stream->invalid);
461 * stream_id >= s->snd_conf.streams was checked before so this is
462 * in-bounds
464 s->pcm->streams[stream_id] = stream;
467 virtio_snd_get_qemu_audsettings(&as, params);
468 stream->info.direction = stream_id < s->snd_conf.streams / 2 +
469 (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
470 stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
471 stream->info.features = 0;
472 stream->info.channels_min = 1;
473 stream->info.channels_max = as.nchannels;
474 stream->info.formats = supported_formats;
475 stream->info.rates = supported_rates;
476 stream->params = *params;
478 stream->positions[0] = VIRTIO_SND_CHMAP_FL;
479 stream->positions[1] = VIRTIO_SND_CHMAP_FR;
480 stream->as = as;
482 if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
483 stream->voice.out = AUD_open_out(&s->card,
484 stream->voice.out,
485 "virtio-sound.out",
486 stream,
487 virtio_snd_pcm_out_cb,
488 &as);
489 AUD_set_volume_out(stream->voice.out, 0, 255, 255);
490 } else {
491 stream->voice.in = AUD_open_in(&s->card,
492 stream->voice.in,
493 "virtio-sound.in",
494 stream,
495 virtio_snd_pcm_in_cb,
496 &as);
497 AUD_set_volume_in(stream->voice.in, 0, 255, 255);
500 return cpu_to_le32(VIRTIO_SND_S_OK);
503 static const char *print_code(uint32_t code)
505 #define CASE(CODE) \
506 case VIRTIO_SND_R_##CODE: \
507 return "VIRTIO_SND_R_"#CODE
509 switch (code) {
510 CASE(JACK_INFO);
511 CASE(JACK_REMAP);
512 CASE(PCM_INFO);
513 CASE(PCM_SET_PARAMS);
514 CASE(PCM_PREPARE);
515 CASE(PCM_RELEASE);
516 CASE(PCM_START);
517 CASE(PCM_STOP);
518 CASE(CHMAP_INFO);
519 default:
520 return "invalid code";
523 #undef CASE
527 * Handles VIRTIO_SND_R_PCM_PREPARE.
529 * @s: VirtIOSound device
530 * @cmd: The request command queue element from VirtIOSound cmdq field
532 static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
533 virtio_snd_ctrl_command *cmd)
535 uint32_t stream_id;
536 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
537 cmd->elem->out_num,
538 sizeof(virtio_snd_hdr),
539 &stream_id,
540 sizeof(stream_id));
542 stream_id = le32_to_cpu(stream_id);
543 cmd->resp.code = msg_sz == sizeof(stream_id)
544 ? virtio_snd_pcm_prepare(s, stream_id)
545 : cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
549 * Handles VIRTIO_SND_R_PCM_START.
551 * @s: VirtIOSound device
552 * @cmd: The request command queue element from VirtIOSound cmdq field
553 * @start: whether to start or stop the device
555 static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
556 virtio_snd_ctrl_command *cmd,
557 bool start)
559 VirtIOSoundPCMStream *stream;
560 virtio_snd_pcm_hdr req;
561 uint32_t stream_id;
562 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
563 cmd->elem->out_num,
565 &req,
566 sizeof(virtio_snd_pcm_hdr));
568 if (msg_sz != sizeof(virtio_snd_pcm_hdr)) {
569 qemu_log_mask(LOG_GUEST_ERROR,
570 "%s: virtio-snd command size incorrect %zu vs \
571 %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr));
572 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
573 return;
576 stream_id = le32_to_cpu(req.stream_id);
577 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
578 trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" :
579 "VIRTIO_SND_R_PCM_STOP", stream_id);
581 stream = virtio_snd_pcm_get_stream(s, stream_id);
582 if (stream) {
583 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
584 stream->active = start;
586 if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
587 AUD_set_active_out(stream->voice.out, start);
588 } else {
589 AUD_set_active_in(stream->voice.in, start);
591 } else {
592 error_report("Invalid stream id: %"PRIu32, stream_id);
593 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
594 return;
596 stream->active = start;
600 * Returns the number of I/O messages that are being processed.
602 * @stream: VirtIOSoundPCMStream
604 static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
606 VirtIOSoundPCMBuffer *buffer, *next;
607 size_t count = 0;
609 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
610 QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
611 count += 1;
613 QSIMPLEQ_FOREACH_SAFE(buffer, &stream->invalid, entry, next) {
614 count += 1;
617 return count;
621 * Handles VIRTIO_SND_R_PCM_RELEASE.
623 * @s: VirtIOSound device
624 * @cmd: The request command queue element from VirtIOSound cmdq field
626 static void virtio_snd_handle_pcm_release(VirtIOSound *s,
627 virtio_snd_ctrl_command *cmd)
629 uint32_t stream_id;
630 VirtIOSoundPCMStream *stream;
631 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
632 cmd->elem->out_num,
633 sizeof(virtio_snd_hdr),
634 &stream_id,
635 sizeof(stream_id));
637 if (msg_sz != sizeof(stream_id)) {
639 * TODO: do we need to set DEVICE_NEEDS_RESET?
641 qemu_log_mask(LOG_GUEST_ERROR,
642 "%s: virtio-snd command size incorrect %zu vs \
643 %zu\n", __func__, msg_sz, sizeof(stream_id));
644 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
645 return;
648 stream_id = le32_to_cpu(stream_id);
649 trace_virtio_snd_handle_pcm_release(stream_id);
650 stream = virtio_snd_pcm_get_stream(s, stream_id);
651 if (stream == NULL) {
653 * TODO: do we need to set DEVICE_NEEDS_RESET?
655 error_report("already released stream %"PRIu32, stream_id);
656 virtio_error(VIRTIO_DEVICE(s),
657 "already released stream %"PRIu32,
658 stream_id);
659 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
660 return;
663 if (virtio_snd_pcm_get_io_msgs_count(stream)) {
665 * virtio-v1.2-csd01, 5.14.6.6.5.1,
666 * Device Requirements: Stream Release
668 * - The device MUST complete all pending I/O messages for the
669 * specified stream ID.
670 * - The device MUST NOT complete the control request while there
671 * are pending I/O messages for the specified stream ID.
673 trace_virtio_snd_pcm_stream_flush(stream_id);
674 virtio_snd_pcm_flush(stream);
677 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
681 * The actual processing done in virtio_snd_process_cmdq().
683 * @s: VirtIOSound device
684 * @cmd: control command request
686 static inline void
687 process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
689 uint32_t code;
690 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
691 cmd->elem->out_num,
693 &cmd->ctrl,
694 sizeof(virtio_snd_hdr));
696 if (msg_sz != sizeof(virtio_snd_hdr)) {
698 * TODO: do we need to set DEVICE_NEEDS_RESET?
700 qemu_log_mask(LOG_GUEST_ERROR,
701 "%s: virtio-snd command size incorrect %zu vs \
702 %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr));
703 return;
706 code = le32_to_cpu(cmd->ctrl.code);
708 trace_virtio_snd_handle_code(code, print_code(code));
710 switch (code) {
711 case VIRTIO_SND_R_JACK_INFO:
712 case VIRTIO_SND_R_JACK_REMAP:
713 qemu_log_mask(LOG_UNIMP,
714 "virtio_snd: jack functionality is unimplemented.\n");
715 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
716 break;
717 case VIRTIO_SND_R_PCM_INFO:
718 virtio_snd_handle_pcm_info(s, cmd);
719 break;
720 case VIRTIO_SND_R_PCM_START:
721 virtio_snd_handle_pcm_start_stop(s, cmd, true);
722 break;
723 case VIRTIO_SND_R_PCM_STOP:
724 virtio_snd_handle_pcm_start_stop(s, cmd, false);
725 break;
726 case VIRTIO_SND_R_PCM_SET_PARAMS:
727 virtio_snd_handle_pcm_set_params(s, cmd);
728 break;
729 case VIRTIO_SND_R_PCM_PREPARE:
730 virtio_snd_handle_pcm_prepare(s, cmd);
731 break;
732 case VIRTIO_SND_R_PCM_RELEASE:
733 virtio_snd_handle_pcm_release(s, cmd);
734 break;
735 case VIRTIO_SND_R_CHMAP_INFO:
736 qemu_log_mask(LOG_UNIMP,
737 "virtio_snd: chmap info functionality is unimplemented.\n");
738 trace_virtio_snd_handle_chmap_info();
739 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
740 break;
741 default:
742 /* error */
743 error_report("virtio snd header not recognized: %"PRIu32, code);
744 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
747 iov_from_buf(cmd->elem->in_sg,
748 cmd->elem->in_num,
750 &cmd->resp,
751 sizeof(virtio_snd_hdr));
752 virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
753 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
757 * Consume all elements in command queue.
759 * @s: VirtIOSound device
761 static void virtio_snd_process_cmdq(VirtIOSound *s)
763 virtio_snd_ctrl_command *cmd;
765 if (unlikely(qatomic_read(&s->processing_cmdq))) {
766 return;
769 WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
770 qatomic_set(&s->processing_cmdq, true);
771 while (!QTAILQ_EMPTY(&s->cmdq)) {
772 cmd = QTAILQ_FIRST(&s->cmdq);
774 /* process command */
775 process_cmd(s, cmd);
777 QTAILQ_REMOVE(&s->cmdq, cmd, next);
779 virtio_snd_ctrl_cmd_free(cmd);
781 qatomic_set(&s->processing_cmdq, false);
786 * The control message handler. Pops an element from the control virtqueue,
787 * and stores them to VirtIOSound's cmdq queue and finally calls
788 * virtio_snd_process_cmdq() for processing.
790 * @vdev: VirtIOSound device
791 * @vq: Control virtqueue
793 static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
795 VirtIOSound *s = VIRTIO_SND(vdev);
796 VirtQueueElement *elem;
797 virtio_snd_ctrl_command *cmd;
799 trace_virtio_snd_handle_ctrl(vdev, vq);
801 if (!virtio_queue_ready(vq)) {
802 return;
805 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
806 while (elem) {
807 cmd = g_new0(virtio_snd_ctrl_command, 1);
808 cmd->elem = elem;
809 cmd->vq = vq;
810 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
811 QTAILQ_INSERT_TAIL(&s->cmdq, cmd, next);
812 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
815 virtio_snd_process_cmdq(s);
819 * The event virtqueue handler.
820 * Not implemented yet.
822 * @vdev: VirtIOSound device
823 * @vq: event vq
825 static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq)
827 qemu_log_mask(LOG_UNIMP, "virtio_snd: event queue is unimplemented.\n");
828 trace_virtio_snd_handle_event();
831 static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq)
833 VirtIOSoundPCMBuffer *buffer = NULL;
834 VirtIOSoundPCMStream *stream = NULL;
835 virtio_snd_pcm_status resp = { 0 };
836 VirtIOSound *vsnd = VIRTIO_SND(vdev);
837 bool any = false;
839 for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
840 stream = vsnd->pcm->streams[i];
841 if (stream) {
842 any = false;
843 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
844 while (!QSIMPLEQ_EMPTY(&stream->invalid)) {
845 buffer = QSIMPLEQ_FIRST(&stream->invalid);
846 if (buffer->vq != vq) {
847 break;
849 any = true;
850 resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
851 iov_from_buf(buffer->elem->in_sg,
852 buffer->elem->in_num,
854 &resp,
855 sizeof(virtio_snd_pcm_status));
856 virtqueue_push(vq,
857 buffer->elem,
858 sizeof(virtio_snd_pcm_status));
859 QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry);
860 virtio_snd_pcm_buffer_free(buffer);
862 if (any) {
864 * Notify vq about virtio_snd_pcm_status responses.
865 * Buffer responses must be notified separately later.
867 virtio_notify(vdev, vq);
875 * The tx virtqueue handler. Makes the buffers available to their respective
876 * streams for consumption.
878 * @vdev: VirtIOSound device
879 * @vq: tx virtqueue
881 static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
883 VirtIOSound *s = VIRTIO_SND(vdev);
884 VirtIOSoundPCMStream *stream = NULL;
885 VirtIOSoundPCMBuffer *buffer;
886 VirtQueueElement *elem;
887 size_t msg_sz, size;
888 virtio_snd_pcm_xfer hdr;
889 uint32_t stream_id;
891 * If any of the I/O messages are invalid, put them in stream->invalid and
892 * return them after the for loop.
894 bool must_empty_invalid_queue = false;
896 if (!virtio_queue_ready(vq)) {
897 return;
899 trace_virtio_snd_handle_tx_xfer();
901 for (;;) {
902 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
903 if (!elem) {
904 break;
906 /* get the message hdr object */
907 msg_sz = iov_to_buf(elem->out_sg,
908 elem->out_num,
910 &hdr,
911 sizeof(virtio_snd_pcm_xfer));
912 if (msg_sz != sizeof(virtio_snd_pcm_xfer)) {
913 goto tx_err;
915 stream_id = le32_to_cpu(hdr.stream_id);
917 if (stream_id >= s->snd_conf.streams
918 || s->pcm->streams[stream_id] == NULL) {
919 goto tx_err;
922 stream = s->pcm->streams[stream_id];
923 if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
924 goto tx_err;
927 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
928 size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
930 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
931 buffer->elem = elem;
932 buffer->populated = false;
933 buffer->vq = vq;
934 buffer->size = size;
935 buffer->offset = 0;
937 QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
939 continue;
941 tx_err:
942 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
943 must_empty_invalid_queue = true;
944 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
945 buffer->elem = elem;
946 buffer->vq = vq;
947 QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry);
951 if (must_empty_invalid_queue) {
952 empty_invalid_queue(vdev, vq);
957 * The rx virtqueue handler. Makes the buffers available to their respective
958 * streams for consumption.
960 * @vdev: VirtIOSound device
961 * @vq: rx virtqueue
963 static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
965 VirtIOSound *s = VIRTIO_SND(vdev);
966 VirtIOSoundPCMStream *stream = NULL;
967 VirtIOSoundPCMBuffer *buffer;
968 VirtQueueElement *elem;
969 size_t msg_sz, size;
970 virtio_snd_pcm_xfer hdr;
971 uint32_t stream_id;
973 * if any of the I/O messages are invalid, put them in stream->invalid and
974 * return them after the for loop.
976 bool must_empty_invalid_queue = false;
978 if (!virtio_queue_ready(vq)) {
979 return;
981 trace_virtio_snd_handle_rx_xfer();
983 for (;;) {
984 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
985 if (!elem) {
986 break;
988 /* get the message hdr object */
989 msg_sz = iov_to_buf(elem->out_sg,
990 elem->out_num,
992 &hdr,
993 sizeof(virtio_snd_pcm_xfer));
994 if (msg_sz != sizeof(virtio_snd_pcm_xfer)) {
995 goto rx_err;
997 stream_id = le32_to_cpu(hdr.stream_id);
999 if (stream_id >= s->snd_conf.streams
1000 || !s->pcm->streams[stream_id]) {
1001 goto rx_err;
1004 stream = s->pcm->streams[stream_id];
1005 if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
1006 goto rx_err;
1008 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
1009 size = iov_size(elem->in_sg, elem->in_num) -
1010 sizeof(virtio_snd_pcm_status);
1011 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
1012 buffer->elem = elem;
1013 buffer->vq = vq;
1014 buffer->size = 0;
1015 buffer->offset = 0;
1016 QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry);
1018 continue;
1020 rx_err:
1021 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
1022 must_empty_invalid_queue = true;
1023 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
1024 buffer->elem = elem;
1025 buffer->vq = vq;
1026 QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry);
1030 if (must_empty_invalid_queue) {
1031 empty_invalid_queue(vdev, vq);
1035 static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
1036 Error **errp)
1039 * virtio-v1.2-csd01, 5.14.3,
1040 * Feature Bits
1041 * None currently defined.
1043 VirtIOSound *s = VIRTIO_SND(vdev);
1044 features |= s->features;
1046 trace_virtio_snd_get_features(vdev, features);
1048 return features;
1051 static void
1052 virtio_snd_vm_state_change(void *opaque, bool running,
1053 RunState state)
1055 if (running) {
1056 trace_virtio_snd_vm_state_running();
1057 } else {
1058 trace_virtio_snd_vm_state_stopped();
1062 static void virtio_snd_realize(DeviceState *dev, Error **errp)
1064 ERRP_GUARD();
1065 VirtIOSound *vsnd = VIRTIO_SND(dev);
1066 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1067 virtio_snd_pcm_set_params default_params = { 0 };
1068 uint32_t status;
1070 trace_virtio_snd_realize(vsnd);
1072 /* check number of jacks and streams */
1073 if (vsnd->snd_conf.jacks > 8) {
1074 error_setg(errp,
1075 "Invalid number of jacks: %"PRIu32,
1076 vsnd->snd_conf.jacks);
1077 return;
1079 if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) {
1080 error_setg(errp,
1081 "Invalid number of streams: %"PRIu32,
1082 vsnd->snd_conf.streams);
1083 return;
1086 if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) {
1087 error_setg(errp,
1088 "Invalid number of channel maps: %"PRIu32,
1089 vsnd->snd_conf.chmaps);
1090 return;
1093 if (!AUD_register_card("virtio-sound", &vsnd->card, errp)) {
1094 return;
1097 vsnd->vmstate =
1098 qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
1100 vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
1101 vsnd->pcm->snd = vsnd;
1102 vsnd->pcm->streams =
1103 g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
1104 vsnd->pcm->pcm_params =
1105 g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
1107 virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
1108 virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
1110 /* set default params for all streams */
1111 default_params.features = 0;
1112 default_params.buffer_bytes = cpu_to_le32(8192);
1113 default_params.period_bytes = cpu_to_le32(2048);
1114 default_params.channels = 2;
1115 default_params.format = VIRTIO_SND_PCM_FMT_S16;
1116 default_params.rate = VIRTIO_SND_PCM_RATE_48000;
1117 vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
1118 virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
1119 vsnd->queues[VIRTIO_SND_VQ_EVENT] =
1120 virtio_add_queue(vdev, 64, virtio_snd_handle_event);
1121 vsnd->queues[VIRTIO_SND_VQ_TX] =
1122 virtio_add_queue(vdev, 64, virtio_snd_handle_tx_xfer);
1123 vsnd->queues[VIRTIO_SND_VQ_RX] =
1124 virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
1125 qemu_mutex_init(&vsnd->cmdq_mutex);
1126 QTAILQ_INIT(&vsnd->cmdq);
1128 for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
1129 status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
1130 if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
1131 error_setg(errp,
1132 "Can't initialize stream params, device responded with %s.",
1133 print_code(status));
1134 goto error_cleanup;
1136 status = virtio_snd_pcm_prepare(vsnd, i);
1137 if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
1138 error_setg(errp,
1139 "Can't prepare streams, device responded with %s.",
1140 print_code(status));
1141 goto error_cleanup;
1145 return;
1147 error_cleanup:
1148 virtio_snd_unrealize(dev);
1151 static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
1152 VirtIOSoundPCMBuffer *buffer)
1154 virtio_snd_pcm_status resp = { 0 };
1155 resp.status = cpu_to_le32(VIRTIO_SND_S_OK);
1156 resp.latency_bytes = cpu_to_le32((uint32_t)buffer->size);
1157 iov_from_buf(buffer->elem->in_sg,
1158 buffer->elem->in_num,
1160 &resp,
1161 sizeof(virtio_snd_pcm_status));
1162 virtqueue_push(buffer->vq,
1163 buffer->elem,
1164 sizeof(virtio_snd_pcm_status));
1165 virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
1166 QSIMPLEQ_REMOVE(&stream->queue,
1167 buffer,
1168 VirtIOSoundPCMBuffer,
1169 entry);
1170 virtio_snd_pcm_buffer_free(buffer);
1174 * AUD_* output callback.
1176 * @data: VirtIOSoundPCMStream stream
1177 * @available: number of bytes that can be written with AUD_write()
1179 static void virtio_snd_pcm_out_cb(void *data, int available)
1181 VirtIOSoundPCMStream *stream = data;
1182 VirtIOSoundPCMBuffer *buffer;
1183 size_t size;
1185 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
1186 while (!QSIMPLEQ_EMPTY(&stream->queue)) {
1187 buffer = QSIMPLEQ_FIRST(&stream->queue);
1188 if (!virtio_queue_ready(buffer->vq)) {
1189 return;
1191 if (!stream->active) {
1192 /* Stream has stopped, so do not perform AUD_write. */
1193 return_tx_buffer(stream, buffer);
1194 continue;
1196 if (!buffer->populated) {
1197 iov_to_buf(buffer->elem->out_sg,
1198 buffer->elem->out_num,
1199 sizeof(virtio_snd_pcm_xfer),
1200 buffer->data,
1201 buffer->size);
1202 buffer->populated = true;
1204 for (;;) {
1205 size = AUD_write(stream->voice.out,
1206 buffer->data + buffer->offset,
1207 MIN(buffer->size, available));
1208 assert(size <= MIN(buffer->size, available));
1209 if (size == 0) {
1210 /* break out of both loops */
1211 available = 0;
1212 break;
1214 buffer->size -= size;
1215 buffer->offset += size;
1216 available -= size;
1217 if (buffer->size < 1) {
1218 return_tx_buffer(stream, buffer);
1219 break;
1221 if (!available) {
1222 break;
1225 if (!available) {
1226 break;
1233 * Flush all buffer data from this input stream's queue into the driver's
1234 * virtual queue.
1236 * @stream: VirtIOSoundPCMStream *stream
1238 static inline void return_rx_buffer(VirtIOSoundPCMStream *stream,
1239 VirtIOSoundPCMBuffer *buffer)
1241 virtio_snd_pcm_status resp = { 0 };
1242 resp.status = cpu_to_le32(VIRTIO_SND_S_OK);
1243 resp.latency_bytes = 0;
1244 /* Copy data -if any- to guest */
1245 iov_from_buf(buffer->elem->in_sg,
1246 buffer->elem->in_num,
1248 buffer->data,
1249 buffer->size);
1250 iov_from_buf(buffer->elem->in_sg,
1251 buffer->elem->in_num,
1252 buffer->size,
1253 &resp,
1254 sizeof(virtio_snd_pcm_status));
1255 virtqueue_push(buffer->vq,
1256 buffer->elem,
1257 sizeof(virtio_snd_pcm_status) + buffer->size);
1258 virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
1259 QSIMPLEQ_REMOVE(&stream->queue,
1260 buffer,
1261 VirtIOSoundPCMBuffer,
1262 entry);
1263 virtio_snd_pcm_buffer_free(buffer);
1268 * AUD_* input callback.
1270 * @data: VirtIOSoundPCMStream stream
1271 * @available: number of bytes that can be read with AUD_read()
1273 static void virtio_snd_pcm_in_cb(void *data, int available)
1275 VirtIOSoundPCMStream *stream = data;
1276 VirtIOSoundPCMBuffer *buffer;
1277 size_t size;
1279 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
1280 while (!QSIMPLEQ_EMPTY(&stream->queue)) {
1281 buffer = QSIMPLEQ_FIRST(&stream->queue);
1282 if (!virtio_queue_ready(buffer->vq)) {
1283 return;
1285 if (!stream->active) {
1286 /* Stream has stopped, so do not perform AUD_read. */
1287 return_rx_buffer(stream, buffer);
1288 continue;
1291 for (;;) {
1292 size = AUD_read(stream->voice.in,
1293 buffer->data + buffer->size,
1294 MIN(available, (stream->params.period_bytes -
1295 buffer->size)));
1296 if (!size) {
1297 available = 0;
1298 break;
1300 buffer->size += size;
1301 available -= size;
1302 if (buffer->size >= stream->params.period_bytes) {
1303 return_rx_buffer(stream, buffer);
1304 break;
1306 if (!available) {
1307 break;
1310 if (!available) {
1311 break;
1318 * Flush all buffer data from this output stream's queue into the driver's
1319 * virtual queue.
1321 * @stream: VirtIOSoundPCMStream *stream
1323 static inline void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
1325 VirtIOSoundPCMBuffer *buffer;
1326 void (*cb)(VirtIOSoundPCMStream *, VirtIOSoundPCMBuffer *) =
1327 (stream->info.direction == VIRTIO_SND_D_OUTPUT) ? return_tx_buffer :
1328 return_rx_buffer;
1330 WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
1331 while (!QSIMPLEQ_EMPTY(&stream->queue)) {
1332 buffer = QSIMPLEQ_FIRST(&stream->queue);
1333 cb(stream, buffer);
1338 static void virtio_snd_unrealize(DeviceState *dev)
1340 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1341 VirtIOSound *vsnd = VIRTIO_SND(dev);
1342 VirtIOSoundPCMStream *stream;
1344 qemu_del_vm_change_state_handler(vsnd->vmstate);
1345 trace_virtio_snd_unrealize(vsnd);
1347 if (vsnd->pcm) {
1348 if (vsnd->pcm->streams) {
1349 for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
1350 stream = vsnd->pcm->streams[i];
1351 if (stream) {
1352 virtio_snd_process_cmdq(stream->s);
1353 virtio_snd_pcm_close(stream);
1354 qemu_mutex_destroy(&stream->queue_mutex);
1355 g_free(stream);
1358 g_free(vsnd->pcm->streams);
1360 g_free(vsnd->pcm->pcm_params);
1361 g_free(vsnd->pcm);
1362 vsnd->pcm = NULL;
1364 AUD_remove_card(&vsnd->card);
1365 qemu_mutex_destroy(&vsnd->cmdq_mutex);
1366 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
1367 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
1368 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
1369 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]);
1370 virtio_cleanup(vdev);
1374 static void virtio_snd_reset(VirtIODevice *vdev)
1376 VirtIOSound *s = VIRTIO_SND(vdev);
1377 virtio_snd_ctrl_command *cmd;
1379 WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
1380 while (!QTAILQ_EMPTY(&s->cmdq)) {
1381 cmd = QTAILQ_FIRST(&s->cmdq);
1382 QTAILQ_REMOVE(&s->cmdq, cmd, next);
1383 virtio_snd_ctrl_cmd_free(cmd);
1388 static void virtio_snd_class_init(ObjectClass *klass, void *data)
1390 DeviceClass *dc = DEVICE_CLASS(klass);
1391 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
1394 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
1395 device_class_set_props(dc, virtio_snd_properties);
1397 dc->vmsd = &vmstate_virtio_snd;
1398 vdc->vmsd = &vmstate_virtio_snd_device;
1399 vdc->realize = virtio_snd_realize;
1400 vdc->unrealize = virtio_snd_unrealize;
1401 vdc->get_config = virtio_snd_get_config;
1402 vdc->set_config = virtio_snd_set_config;
1403 vdc->get_features = get_features;
1404 vdc->reset = virtio_snd_reset;
1405 vdc->legacy_features = 0;
1408 static const TypeInfo virtio_snd_types[] = {
1410 .name = TYPE_VIRTIO_SND,
1411 .parent = TYPE_VIRTIO_DEVICE,
1412 .instance_size = sizeof(VirtIOSound),
1413 .class_init = virtio_snd_class_init,
1417 DEFINE_TYPES(virtio_snd_types)