]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/audio/virtio-snd.c
virtio-sound: handle VIRTIO_SND_R_PCM_RELEASE
[thirdparty/qemu.git] / hw / audio / virtio-snd.c
CommitLineData
2880e676
MP
1/*
2 * VIRTIO Sound Device conforming to
3 *
4 * "Virtual I/O Device (VIRTIO) Version 1.2
5 * Committee Specification Draft 01
6 * 09 May 2022"
7 *
8 * <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-52900014>
9 *
10 * Copyright (c) 2023 Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
11 * Copyright (C) 2019 OpenSynergy GmbH
12 *
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.
16 */
17
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"
28
29#define VIRTIO_SOUND_VM_VERSION 1
30#define VIRTIO_SOUND_JACK_DEFAULT 0
31#define VIRTIO_SOUND_STREAM_DEFAULT 1
32#define VIRTIO_SOUND_CHMAP_DEFAULT 0
33#define VIRTIO_SOUND_HDA_FN_NID 0
34
eb9ad377
MP
35static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
36 | BIT(VIRTIO_SND_PCM_FMT_U8)
37 | BIT(VIRTIO_SND_PCM_FMT_S16)
38 | BIT(VIRTIO_SND_PCM_FMT_U16)
39 | BIT(VIRTIO_SND_PCM_FMT_S32)
40 | BIT(VIRTIO_SND_PCM_FMT_U32)
41 | BIT(VIRTIO_SND_PCM_FMT_FLOAT);
42
43static uint32_t supported_rates = BIT(VIRTIO_SND_PCM_RATE_5512)
44 | BIT(VIRTIO_SND_PCM_RATE_8000)
45 | BIT(VIRTIO_SND_PCM_RATE_11025)
46 | BIT(VIRTIO_SND_PCM_RATE_16000)
47 | BIT(VIRTIO_SND_PCM_RATE_22050)
48 | BIT(VIRTIO_SND_PCM_RATE_32000)
49 | BIT(VIRTIO_SND_PCM_RATE_44100)
50 | BIT(VIRTIO_SND_PCM_RATE_48000)
51 | BIT(VIRTIO_SND_PCM_RATE_64000)
52 | BIT(VIRTIO_SND_PCM_RATE_88200)
53 | BIT(VIRTIO_SND_PCM_RATE_96000)
54 | BIT(VIRTIO_SND_PCM_RATE_176400)
55 | BIT(VIRTIO_SND_PCM_RATE_192000)
56 | BIT(VIRTIO_SND_PCM_RATE_384000);
57
2880e676
MP
58static const VMStateDescription vmstate_virtio_snd_device = {
59 .name = TYPE_VIRTIO_SND,
60 .version_id = VIRTIO_SOUND_VM_VERSION,
61 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
62};
63
64static const VMStateDescription vmstate_virtio_snd = {
65 .name = TYPE_VIRTIO_SND,
66 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
67 .version_id = VIRTIO_SOUND_VM_VERSION,
68 .fields = (VMStateField[]) {
69 VMSTATE_VIRTIO_DEVICE,
70 VMSTATE_END_OF_LIST()
71 },
72};
73
74static Property virtio_snd_properties[] = {
75 DEFINE_AUDIO_PROPERTIES(VirtIOSound, card),
76 DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks,
77 VIRTIO_SOUND_JACK_DEFAULT),
78 DEFINE_PROP_UINT32("streams", VirtIOSound, snd_conf.streams,
79 VIRTIO_SOUND_STREAM_DEFAULT),
80 DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps,
81 VIRTIO_SOUND_CHMAP_DEFAULT),
82 DEFINE_PROP_END_OF_LIST(),
83};
84
85static void
86virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
87{
88 VirtIOSound *s = VIRTIO_SND(vdev);
89 virtio_snd_config *sndconfig =
90 (virtio_snd_config *)config;
91 trace_virtio_snd_get_config(vdev,
92 s->snd_conf.jacks,
93 s->snd_conf.streams,
94 s->snd_conf.chmaps);
95
96 memcpy(sndconfig, &s->snd_conf, sizeof(s->snd_conf));
97 cpu_to_le32s(&sndconfig->jacks);
98 cpu_to_le32s(&sndconfig->streams);
99 cpu_to_le32s(&sndconfig->chmaps);
100
101}
102
103static void
104virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
105{
106 VirtIOSound *s = VIRTIO_SND(vdev);
107 const virtio_snd_config *sndconfig =
108 (const virtio_snd_config *)config;
109
110
111 trace_virtio_snd_set_config(vdev,
112 s->snd_conf.jacks,
113 sndconfig->jacks,
114 s->snd_conf.streams,
115 sndconfig->streams,
116 s->snd_conf.chmaps,
117 sndconfig->chmaps);
118
119 memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
120 le32_to_cpus(&s->snd_conf.jacks);
121 le32_to_cpus(&s->snd_conf.streams);
122 le32_to_cpus(&s->snd_conf.chmaps);
123
124}
125
eb9ad377
MP
126static void
127virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd)
128{
129 g_free(cmd->elem);
130 g_free(cmd);
131}
132
133/*
134 * Get a specific stream from the virtio sound card device.
135 * Returns NULL if @stream_id is invalid or not allocated.
136 *
137 * @s: VirtIOSound device
138 * @stream_id: stream id
139 */
140static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s,
141 uint32_t stream_id)
142{
143 return stream_id >= s->snd_conf.streams ? NULL :
144 s->pcm->streams[stream_id];
145}
146
147/*
148 * Get params for a specific stream.
149 *
150 * @s: VirtIOSound device
151 * @stream_id: stream id
152 */
153static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
154 uint32_t stream_id)
155{
156 return stream_id >= s->snd_conf.streams ? NULL
157 : &s->pcm->pcm_params[stream_id];
158}
159
0ff05dd2
MP
160/*
161 * Handle the VIRTIO_SND_R_PCM_INFO request.
162 * The function writes the info structs to the request element.
163 *
164 * @s: VirtIOSound device
165 * @cmd: The request command queue element from VirtIOSound cmdq field
166 */
167static void virtio_snd_handle_pcm_info(VirtIOSound *s,
168 virtio_snd_ctrl_command *cmd)
169{
170 uint32_t stream_id, start_id, count, size;
171 virtio_snd_pcm_info val;
172 virtio_snd_query_info req;
173 VirtIOSoundPCMStream *stream = NULL;
174 g_autofree virtio_snd_pcm_info *pcm_info = NULL;
175 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
176 cmd->elem->out_num,
177 0,
178 &req,
179 sizeof(virtio_snd_query_info));
180
181 if (msg_sz != sizeof(virtio_snd_query_info)) {
182 /*
183 * TODO: do we need to set DEVICE_NEEDS_RESET?
184 */
185 qemu_log_mask(LOG_GUEST_ERROR,
186 "%s: virtio-snd command size incorrect %zu vs \
187 %zu\n", __func__, msg_sz, sizeof(virtio_snd_query_info));
188 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
189 return;
190 }
191
192 start_id = le32_to_cpu(req.start_id);
193 count = le32_to_cpu(req.count);
194 size = le32_to_cpu(req.size);
195
196 if (iov_size(cmd->elem->in_sg, cmd->elem->in_num) <
197 sizeof(virtio_snd_hdr) + size * count) {
198 /*
199 * TODO: do we need to set DEVICE_NEEDS_RESET?
200 */
201 error_report("pcm info: buffer too small, got: %zu, needed: %zu",
202 iov_size(cmd->elem->in_sg, cmd->elem->in_num),
203 sizeof(virtio_snd_pcm_info));
204 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
205 return;
206 }
207
208 pcm_info = g_new0(virtio_snd_pcm_info, count);
209 for (uint32_t i = 0; i < count; i++) {
210 stream_id = i + start_id;
211 trace_virtio_snd_handle_pcm_info(stream_id);
212 stream = virtio_snd_pcm_get_stream(s, stream_id);
213 if (!stream) {
214 error_report("Invalid stream id: %"PRIu32, stream_id);
215 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
216 return;
217 }
218 val = stream->info;
219 val.hdr.hda_fn_nid = cpu_to_le32(val.hdr.hda_fn_nid);
220 val.features = cpu_to_le32(val.features);
221 val.formats = cpu_to_le64(val.formats);
222 val.rates = cpu_to_le64(val.rates);
223 /*
224 * 5.14.6.6.2.1 Device Requirements: Stream Information The device MUST
225 * NOT set undefined feature, format, rate and direction values. The
226 * device MUST initialize the padding bytes to 0.
227 */
228 pcm_info[i] = val;
229 memset(&pcm_info[i].padding, 0, 5);
230 }
231
232 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
233 iov_from_buf(cmd->elem->in_sg,
234 cmd->elem->in_num,
235 sizeof(virtio_snd_hdr),
236 pcm_info,
237 sizeof(virtio_snd_pcm_info) * count);
238}
239
eb9ad377
MP
240/*
241 * Set the given stream params.
242 * Called by both virtio_snd_handle_pcm_set_params and during device
243 * initialization.
244 * Returns the response status code. (VIRTIO_SND_S_*).
245 *
246 * @s: VirtIOSound device
247 * @params: The PCM params as defined in the virtio specification
248 */
249static
250uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
251 uint32_t stream_id,
252 virtio_snd_pcm_set_params *params)
253{
254 virtio_snd_pcm_set_params *st_params;
255
256 if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) {
257 /*
258 * TODO: do we need to set DEVICE_NEEDS_RESET?
259 */
260 virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
261 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
262 }
263
264 st_params = virtio_snd_pcm_get_params(s, stream_id);
265
266 if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
267 error_report("Number of channels is not supported.");
268 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
269 }
270 if (!(supported_formats & BIT(params->format))) {
271 error_report("Stream format is not supported.");
272 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
273 }
274 if (!(supported_rates & BIT(params->rate))) {
275 error_report("Stream rate is not supported.");
276 return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
277 }
278
279 st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
280 st_params->period_bytes = le32_to_cpu(params->period_bytes);
281 st_params->features = le32_to_cpu(params->features);
282 /* the following are uint8_t, so there's no need to bswap the values. */
283 st_params->channels = params->channels;
284 st_params->format = params->format;
285 st_params->rate = params->rate;
286
287 return cpu_to_le32(VIRTIO_SND_S_OK);
288}
289
64704ce0
MP
290/*
291 * Handles the VIRTIO_SND_R_PCM_SET_PARAMS request.
292 *
293 * @s: VirtIOSound device
294 * @cmd: The request command queue element from VirtIOSound cmdq field
295 */
296static void virtio_snd_handle_pcm_set_params(VirtIOSound *s,
297 virtio_snd_ctrl_command *cmd)
298{
299 virtio_snd_pcm_set_params req = { 0 };
300 uint32_t stream_id;
301 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
302 cmd->elem->out_num,
303 0,
304 &req,
305 sizeof(virtio_snd_pcm_set_params));
306
307 if (msg_sz != sizeof(virtio_snd_pcm_set_params)) {
308 /*
309 * TODO: do we need to set DEVICE_NEEDS_RESET?
310 */
311 qemu_log_mask(LOG_GUEST_ERROR,
312 "%s: virtio-snd command size incorrect %zu vs \
313 %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_set_params));
314 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
315 return;
316 }
317 stream_id = le32_to_cpu(req.hdr.stream_id);
318 trace_virtio_snd_handle_pcm_set_params(stream_id);
319 cmd->resp.code = virtio_snd_set_pcm_params(s, stream_id, &req);
320}
321
eb9ad377
MP
322/*
323 * Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_*
324 */
325static AudioFormat virtio_snd_get_qemu_format(uint32_t format)
326{
327 #define CASE(FMT) \
328 case VIRTIO_SND_PCM_FMT_##FMT: \
329 return AUDIO_FORMAT_##FMT;
330
331 switch (format) {
332 CASE(U8)
333 CASE(S8)
334 CASE(U16)
335 CASE(S16)
336 CASE(U32)
337 CASE(S32)
338 case VIRTIO_SND_PCM_FMT_FLOAT:
339 return AUDIO_FORMAT_F32;
340 default:
341 g_assert_not_reached();
342 }
343
344 #undef CASE
345}
346
347/*
348 * Get a QEMU Audiosystem compatible frequency value from a
349 * VIRTIO_SND_PCM_RATE_*
350 */
351static uint32_t virtio_snd_get_qemu_freq(uint32_t rate)
352{
353 #define CASE(RATE) \
354 case VIRTIO_SND_PCM_RATE_##RATE: \
355 return RATE;
356
357 switch (rate) {
358 CASE(5512)
359 CASE(8000)
360 CASE(11025)
361 CASE(16000)
362 CASE(22050)
363 CASE(32000)
364 CASE(44100)
365 CASE(48000)
366 CASE(64000)
367 CASE(88200)
368 CASE(96000)
369 CASE(176400)
370 CASE(192000)
371 CASE(384000)
372 default:
373 g_assert_not_reached();
374 }
375
376 #undef CASE
377}
378
379/*
380 * Get QEMU Audiosystem compatible audsettings from virtio based pcm stream
381 * params.
382 */
383static void virtio_snd_get_qemu_audsettings(audsettings *as,
384 virtio_snd_pcm_set_params *params)
385{
386 as->nchannels = MIN(AUDIO_MAX_CHANNELS, params->channels);
387 as->fmt = virtio_snd_get_qemu_format(params->format);
388 as->freq = virtio_snd_get_qemu_freq(params->rate);
389 as->endianness = target_words_bigendian() ? 1 : 0;
390}
391
392/*
393 * Close a stream and free all its resources.
394 *
395 * @stream: VirtIOSoundPCMStream *stream
396 */
397static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
398{
399}
400
2880e676 401/*
eb9ad377
MP
402 * Prepares a VirtIOSound card stream.
403 * Returns the response status code. (VIRTIO_SND_S_*).
404 *
405 * @s: VirtIOSound device
406 * @stream_id: stream id
407 */
408static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
409{
410 audsettings as;
411 virtio_snd_pcm_set_params *params;
412 VirtIOSoundPCMStream *stream;
413
414 if (s->pcm->streams == NULL ||
415 s->pcm->pcm_params == NULL ||
416 stream_id >= s->snd_conf.streams) {
417 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
418 }
419
420 params = virtio_snd_pcm_get_params(s, stream_id);
421 if (params == NULL) {
422 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
423 }
424
425 stream = virtio_snd_pcm_get_stream(s, stream_id);
426 if (stream == NULL) {
427 stream = g_new0(VirtIOSoundPCMStream, 1);
428 stream->active = false;
429 stream->id = stream_id;
430 stream->pcm = s->pcm;
431 stream->s = s;
432
433 /*
434 * stream_id >= s->snd_conf.streams was checked before so this is
435 * in-bounds
436 */
437 s->pcm->streams[stream_id] = stream;
438 }
439
440 virtio_snd_get_qemu_audsettings(&as, params);
441 stream->info.direction = stream_id < s->snd_conf.streams / 2 +
442 (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
443 stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
444 stream->info.features = 0;
445 stream->info.channels_min = 1;
446 stream->info.channels_max = as.nchannels;
447 stream->info.formats = supported_formats;
448 stream->info.rates = supported_rates;
449 stream->params = *params;
450
451 stream->positions[0] = VIRTIO_SND_CHMAP_FL;
452 stream->positions[1] = VIRTIO_SND_CHMAP_FR;
453 stream->as = as;
454
455 return cpu_to_le32(VIRTIO_SND_S_OK);
456}
457
458static const char *print_code(uint32_t code)
459{
460 #define CASE(CODE) \
461 case VIRTIO_SND_R_##CODE: \
462 return "VIRTIO_SND_R_"#CODE
463
464 switch (code) {
465 CASE(JACK_INFO);
466 CASE(JACK_REMAP);
467 CASE(PCM_INFO);
468 CASE(PCM_SET_PARAMS);
469 CASE(PCM_PREPARE);
470 CASE(PCM_RELEASE);
471 CASE(PCM_START);
472 CASE(PCM_STOP);
473 CASE(CHMAP_INFO);
474 default:
475 return "invalid code";
476 }
477
478 #undef CASE
479};
480
e5788b8f
MP
481/*
482 * Handles VIRTIO_SND_R_PCM_PREPARE.
483 *
484 * @s: VirtIOSound device
485 * @cmd: The request command queue element from VirtIOSound cmdq field
486 */
487static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
488 virtio_snd_ctrl_command *cmd)
489{
490 uint32_t stream_id;
491 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
492 cmd->elem->out_num,
493 sizeof(virtio_snd_hdr),
494 &stream_id,
495 sizeof(stream_id));
496
497 stream_id = le32_to_cpu(stream_id);
498 cmd->resp.code = msg_sz == sizeof(stream_id)
499 ? virtio_snd_pcm_prepare(s, stream_id)
500 : cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
501}
502
fa131d4a
MP
503/*
504 * Handles VIRTIO_SND_R_PCM_START.
505 *
506 * @s: VirtIOSound device
507 * @cmd: The request command queue element from VirtIOSound cmdq field
508 * @start: whether to start or stop the device
509 */
510static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
511 virtio_snd_ctrl_command *cmd,
512 bool start)
513{
514 VirtIOSoundPCMStream *stream;
515 virtio_snd_pcm_hdr req;
516 uint32_t stream_id;
517 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
518 cmd->elem->out_num,
519 0,
520 &req,
521 sizeof(virtio_snd_pcm_hdr));
522
523 if (msg_sz != sizeof(virtio_snd_pcm_hdr)) {
524 qemu_log_mask(LOG_GUEST_ERROR,
525 "%s: virtio-snd command size incorrect %zu vs \
526 %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr));
527 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
528 return;
529 }
530
531 stream_id = le32_to_cpu(req.stream_id);
532 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
533 trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" :
534 "VIRTIO_SND_R_PCM_STOP", stream_id);
535 stream = virtio_snd_pcm_get_stream(s, stream_id);
536 if (stream == NULL) {
537 error_report("Invalid stream id: %"PRIu32, req.stream_id);
538 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
539 return;
540 }
541 stream->active = start;
542}
543
d48800d7
MP
544/*
545 * Handles VIRTIO_SND_R_PCM_RELEASE. Releases the buffer resources allocated to
546 * a stream.
547 *
548 * @s: VirtIOSound device
549 * @cmd: The request command queue element from VirtIOSound cmdq field
550 */
551static void virtio_snd_handle_pcm_release(VirtIOSound *s,
552 virtio_snd_ctrl_command *cmd)
553{
554 uint32_t stream_id;
555 VirtIOSoundPCMStream *stream;
556 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
557 cmd->elem->out_num,
558 sizeof(virtio_snd_hdr),
559 &stream_id,
560 sizeof(stream_id));
561
562 if (msg_sz != sizeof(stream_id)) {
563 /*
564 * TODO: do we need to set DEVICE_NEEDS_RESET?
565 */
566 qemu_log_mask(LOG_GUEST_ERROR,
567 "%s: virtio-snd command size incorrect %zu vs \
568 %zu\n", __func__, msg_sz, sizeof(stream_id));
569 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
570 return;
571 }
572
573 stream_id = le32_to_cpu(stream_id);
574 trace_virtio_snd_handle_pcm_release(stream_id);
575 stream = virtio_snd_pcm_get_stream(s, stream_id);
576 if (stream == NULL) {
577 /*
578 * TODO: do we need to set DEVICE_NEEDS_RESET?
579 */
580 error_report("already released stream %"PRIu32, stream_id);
581 virtio_error(VIRTIO_DEVICE(s),
582 "already released stream %"PRIu32,
583 stream_id);
584 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
585 return;
586 }
587 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
588}
589
eb9ad377
MP
590/*
591 * The actual processing done in virtio_snd_process_cmdq().
592 *
593 * @s: VirtIOSound device
594 * @cmd: control command request
595 */
596static inline void
597process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
598{
599 uint32_t code;
600 size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
601 cmd->elem->out_num,
602 0,
603 &cmd->ctrl,
604 sizeof(virtio_snd_hdr));
605
606 if (msg_sz != sizeof(virtio_snd_hdr)) {
607 /*
608 * TODO: do we need to set DEVICE_NEEDS_RESET?
609 */
610 qemu_log_mask(LOG_GUEST_ERROR,
611 "%s: virtio-snd command size incorrect %zu vs \
612 %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr));
613 return;
614 }
615
616 code = le32_to_cpu(cmd->ctrl.code);
617
618 trace_virtio_snd_handle_code(code, print_code(code));
619
620 switch (code) {
621 case VIRTIO_SND_R_JACK_INFO:
622 case VIRTIO_SND_R_JACK_REMAP:
623 qemu_log_mask(LOG_UNIMP,
624 "virtio_snd: jack functionality is unimplemented.\n");
625 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
626 break;
627 case VIRTIO_SND_R_PCM_INFO:
0ff05dd2
MP
628 virtio_snd_handle_pcm_info(s, cmd);
629 break;
eb9ad377 630 case VIRTIO_SND_R_PCM_START:
fa131d4a
MP
631 virtio_snd_handle_pcm_start_stop(s, cmd, true);
632 break;
eb9ad377 633 case VIRTIO_SND_R_PCM_STOP:
fa131d4a
MP
634 virtio_snd_handle_pcm_start_stop(s, cmd, false);
635 break;
636 case VIRTIO_SND_R_PCM_SET_PARAMS:
64704ce0
MP
637 virtio_snd_handle_pcm_set_params(s, cmd);
638 break;
fa131d4a 639 case VIRTIO_SND_R_PCM_PREPARE:
e5788b8f
MP
640 virtio_snd_handle_pcm_prepare(s, cmd);
641 break;
eb9ad377 642 case VIRTIO_SND_R_PCM_RELEASE:
d48800d7 643 virtio_snd_handle_pcm_release(s, cmd);
eb9ad377
MP
644 break;
645 case VIRTIO_SND_R_CHMAP_INFO:
646 qemu_log_mask(LOG_UNIMP,
647 "virtio_snd: chmap info functionality is unimplemented.\n");
648 trace_virtio_snd_handle_chmap_info();
649 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
650 break;
651 default:
652 /* error */
653 error_report("virtio snd header not recognized: %"PRIu32, code);
654 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
655 }
656
657 iov_from_buf(cmd->elem->in_sg,
658 cmd->elem->in_num,
659 0,
660 &cmd->resp,
661 sizeof(virtio_snd_hdr));
662 virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
663 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
664}
665
666/*
667 * Consume all elements in command queue.
668 *
669 * @s: VirtIOSound device
670 */
671static void virtio_snd_process_cmdq(VirtIOSound *s)
672{
673 virtio_snd_ctrl_command *cmd;
674
675 if (unlikely(qatomic_read(&s->processing_cmdq))) {
676 return;
677 }
678
679 WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
680 qatomic_set(&s->processing_cmdq, true);
681 while (!QTAILQ_EMPTY(&s->cmdq)) {
682 cmd = QTAILQ_FIRST(&s->cmdq);
683
684 /* process command */
685 process_cmd(s, cmd);
686
687 QTAILQ_REMOVE(&s->cmdq, cmd, next);
688
689 virtio_snd_ctrl_cmd_free(cmd);
690 }
691 qatomic_set(&s->processing_cmdq, false);
692 }
693}
694
695/*
696 * The control message handler. Pops an element from the control virtqueue,
697 * and stores them to VirtIOSound's cmdq queue and finally calls
698 * virtio_snd_process_cmdq() for processing.
699 *
700 * @vdev: VirtIOSound device
701 * @vq: Control virtqueue
702 */
703static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
704{
705 VirtIOSound *s = VIRTIO_SND(vdev);
706 VirtQueueElement *elem;
707 virtio_snd_ctrl_command *cmd;
708
709 trace_virtio_snd_handle_ctrl(vdev, vq);
710
711 if (!virtio_queue_ready(vq)) {
712 return;
713 }
714
715 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
716 while (elem) {
717 cmd = g_new0(virtio_snd_ctrl_command, 1);
718 cmd->elem = elem;
719 cmd->vq = vq;
720 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
721 QTAILQ_INSERT_TAIL(&s->cmdq, cmd, next);
722 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
723 }
724
725 virtio_snd_process_cmdq(s);
726}
727
728/*
729 * The event virtqueue handler.
730 * Not implemented yet.
731 *
732 * @vdev: VirtIOSound device
733 * @vq: event vq
734 */
735static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq)
736{
737 qemu_log_mask(LOG_UNIMP, "virtio_snd: event queue is unimplemented.\n");
738 trace_virtio_snd_handle_event();
739}
740
741/*
742 * Stub buffer virtqueue handler.
2880e676
MP
743 *
744 * @vdev: VirtIOSound device
745 * @vq: virtqueue
746 */
eb9ad377 747static void virtio_snd_handle_xfer(VirtIODevice *vdev, VirtQueue *vq) {}
2880e676
MP
748
749static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
750 Error **errp)
751{
752 /*
753 * virtio-v1.2-csd01, 5.14.3,
754 * Feature Bits
755 * None currently defined.
756 */
757 VirtIOSound *s = VIRTIO_SND(vdev);
758 features |= s->features;
759
760 trace_virtio_snd_get_features(vdev, features);
761
762 return features;
763}
764
765static void
766virtio_snd_vm_state_change(void *opaque, bool running,
767 RunState state)
768{
769 if (running) {
770 trace_virtio_snd_vm_state_running();
771 } else {
772 trace_virtio_snd_vm_state_stopped();
773 }
774}
775
776static void virtio_snd_realize(DeviceState *dev, Error **errp)
777{
778 ERRP_GUARD();
779 VirtIOSound *vsnd = VIRTIO_SND(dev);
780 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
eb9ad377
MP
781 virtio_snd_pcm_set_params default_params = { 0 };
782 uint32_t status;
2880e676 783
eb9ad377 784 vsnd->pcm = NULL;
2880e676
MP
785 vsnd->vmstate =
786 qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
787
788 trace_virtio_snd_realize(vsnd);
789
eb9ad377
MP
790 vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
791 vsnd->pcm->snd = vsnd;
792 vsnd->pcm->streams =
793 g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
794 vsnd->pcm->pcm_params =
795 g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
796
2880e676
MP
797 virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
798 virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
799
800 /* set number of jacks and streams */
801 if (vsnd->snd_conf.jacks > 8) {
802 error_setg(errp,
803 "Invalid number of jacks: %"PRIu32,
804 vsnd->snd_conf.jacks);
805 return;
806 }
807 if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) {
808 error_setg(errp,
809 "Invalid number of streams: %"PRIu32,
810 vsnd->snd_conf.streams);
811 return;
812 }
813
814 if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) {
815 error_setg(errp,
816 "Invalid number of channel maps: %"PRIu32,
817 vsnd->snd_conf.chmaps);
818 return;
819 }
820
821 AUD_register_card("virtio-sound", &vsnd->card, errp);
822
eb9ad377
MP
823 /* set default params for all streams */
824 default_params.features = 0;
825 default_params.buffer_bytes = cpu_to_le32(8192);
826 default_params.period_bytes = cpu_to_le32(2048);
827 default_params.channels = 2;
828 default_params.format = VIRTIO_SND_PCM_FMT_S16;
829 default_params.rate = VIRTIO_SND_PCM_RATE_48000;
2880e676 830 vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
eb9ad377 831 virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
2880e676 832 vsnd->queues[VIRTIO_SND_VQ_EVENT] =
eb9ad377 833 virtio_add_queue(vdev, 64, virtio_snd_handle_event);
2880e676 834 vsnd->queues[VIRTIO_SND_VQ_TX] =
eb9ad377 835 virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
2880e676 836 vsnd->queues[VIRTIO_SND_VQ_RX] =
eb9ad377
MP
837 virtio_add_queue(vdev, 64, virtio_snd_handle_xfer);
838 qemu_mutex_init(&vsnd->cmdq_mutex);
839 QTAILQ_INIT(&vsnd->cmdq);
840
841 for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
842 status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
843 if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
844 error_setg(errp,
845 "Can't initalize stream params, device responded with %s.",
846 print_code(status));
847 return;
848 }
849 status = virtio_snd_pcm_prepare(vsnd, i);
850 if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
851 error_setg(errp,
852 "Can't prepare streams, device responded with %s.",
853 print_code(status));
854 return;
855 }
856 }
2880e676
MP
857}
858
859static void virtio_snd_unrealize(DeviceState *dev)
860{
861 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
862 VirtIOSound *vsnd = VIRTIO_SND(dev);
eb9ad377 863 VirtIOSoundPCMStream *stream;
2880e676
MP
864
865 qemu_del_vm_change_state_handler(vsnd->vmstate);
866 trace_virtio_snd_unrealize(vsnd);
867
eb9ad377
MP
868 if (vsnd->pcm) {
869 if (vsnd->pcm->streams) {
870 for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
871 stream = vsnd->pcm->streams[i];
872 if (stream) {
873 virtio_snd_process_cmdq(stream->s);
874 virtio_snd_pcm_close(stream);
875 g_free(stream);
876 }
877 }
878 g_free(vsnd->pcm->streams);
879 }
880 g_free(vsnd->pcm->pcm_params);
881 g_free(vsnd->pcm);
882 vsnd->pcm = NULL;
883 }
2880e676 884 AUD_remove_card(&vsnd->card);
eb9ad377 885 qemu_mutex_destroy(&vsnd->cmdq_mutex);
2880e676
MP
886 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
887 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
888 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
889 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]);
890 virtio_cleanup(vdev);
891}
892
893
eb9ad377
MP
894static void virtio_snd_reset(VirtIODevice *vdev)
895{
896 VirtIOSound *s = VIRTIO_SND(vdev);
897 virtio_snd_ctrl_command *cmd;
898
899 WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
900 while (!QTAILQ_EMPTY(&s->cmdq)) {
901 cmd = QTAILQ_FIRST(&s->cmdq);
902 QTAILQ_REMOVE(&s->cmdq, cmd, next);
903 virtio_snd_ctrl_cmd_free(cmd);
904 }
905 }
906}
2880e676
MP
907
908static void virtio_snd_class_init(ObjectClass *klass, void *data)
909{
910 DeviceClass *dc = DEVICE_CLASS(klass);
911 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
912
913
914 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
915 device_class_set_props(dc, virtio_snd_properties);
916
917 dc->vmsd = &vmstate_virtio_snd;
918 vdc->vmsd = &vmstate_virtio_snd_device;
919 vdc->realize = virtio_snd_realize;
920 vdc->unrealize = virtio_snd_unrealize;
921 vdc->get_config = virtio_snd_get_config;
922 vdc->set_config = virtio_snd_set_config;
923 vdc->get_features = get_features;
924 vdc->reset = virtio_snd_reset;
925 vdc->legacy_features = 0;
926}
927
928static const TypeInfo virtio_snd_types[] = {
929 {
930 .name = TYPE_VIRTIO_SND,
931 .parent = TYPE_VIRTIO_DEVICE,
932 .instance_size = sizeof(VirtIOSound),
933 .class_init = virtio_snd_class_init,
934 }
935};
936
937DEFINE_TYPES(virtio_snd_types)