From patchwork Wed Oct 11 14:34:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417505 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 10DE8CD6E77 for ; Wed, 11 Oct 2023 14:35:55 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJQ-0000E3-S8; Wed, 11 Oct 2023 10:35:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJM-0000Cj-JU for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:45 -0400 Received: from mail-wm1-x32e.google.com ([2a00:1450:4864:20::32e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJK-0005N4-5L for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:44 -0400 Received: by mail-wm1-x32e.google.com with SMTP id 5b1f17b1804b1-40651a726acso64140825e9.1 for ; Wed, 11 Oct 2023 07:35:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034940; x=1697639740; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=K9/bQgVi7EVQ55waY6OsGtrFiCGqF5FOU5Dyb5Fjm5g=; b=vhek4DbtIXTOlJLeGA8spXdEUIwYTPu0H1ASfwzZ0bBhiimYTSEmtaoD9l9iiQYkCQ dJTHoazaRjQ2l/saC90Ibcj+KxVNssPc/t/7FeR30pHUeWolMFZF5JeAvyyBkphlZyn/ gy7KowN/ALk80tWZZCxhcgeXR9fFUoudrarqSIE1EpqEA3uKHiZtEfVSNafycYtFLAGf gut0DMlhIlqIHu78+KEUjDNNbXc4bW3DG9tF1M4XmaxBvPo+Ys7P68f8ZRC2RMLXH6Hj p0+DOZtzhvsuMBTlQZo7+/hrGUolgdtjpPJ00iNRcHjHc2MzKLEkEtEgcnRtv2YNlgF5 clFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034940; x=1697639740; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=K9/bQgVi7EVQ55waY6OsGtrFiCGqF5FOU5Dyb5Fjm5g=; b=kozQwd0U1KdNJlffSkUQU5WZwCtaYwxVQrQe+BKeAM5V5fTFazsYRAAF2srJiHYs1s t7fiJtJHBktzy/courv1ToR6bTbFv0ckfdc6OZPon3W7yhjGE9jFpqvitbtNSSwC6NxI xUpWD9HQCv4UePJNzllSHRTl4Yr/O/if4y0TIqaCX07BH3/hAlDyQRw4j/JlE76yKdV7 jYxbuXRQVllCc61eEqfHKJg+e3eBmvs42BsDyn5D2hhzll3VQc/GeD4z1bSzo9tVEIru ckVMG346RmqKEPRxYCVgq/p4X5cNMa1WwS71zBMfiEbovdv3eD1wDn4qqXNwg72NjMWN ovAA== X-Gm-Message-State: AOJu0Yz6HfMnPo6+rHHJFteZ4xOi6/KLf6ElcL00nJSSZ4Z0CKkZETcN 227C9+eyZ4DVeAik0nGUTIM0RyOmUTWK7+IVH6I= X-Google-Smtp-Source: AGHT+IGMTiIb6FYkgtz2agwLrw1K5aByLOL5YIhAjxsPylf7UWb/Pkxtht/nyRd2zNeVVJTcbjyVEw== X-Received: by 2002:a5d:5348:0:b0:32d:8961:d864 with SMTP id t8-20020a5d5348000000b0032d8961d864mr942385wrv.48.1697034940357; Wed, 11 Oct 2023 07:35:40 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:39 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 01/11] Add virtio-sound device stub Date: Wed, 11 Oct 2023 17:34:46 +0300 Message-Id: <03ecf1f615238fb25bc9fb4a6f6f4ae62594241e.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32e; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wm1-x32e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Add a new VIRTIO device for the virtio sound device id. Functionality will be added in the following commits. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Reviewed-by: Alex Bennée Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis --- MAINTAINERS | 6 + hw/virtio/Kconfig | 5 + hw/virtio/meson.build | 1 + hw/virtio/trace-events | 9 ++ hw/virtio/virtio-snd.c (new) | 223 +++++++++++++++++++++++++++ include/hw/virtio/virtio-snd.h (new) | 79 ++++++++++ 6 files changed, 323 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9e7dec4a58..701f12026a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2254,6 +2254,12 @@ F: hw/virtio/virtio-mem-pci.h F: hw/virtio/virtio-mem-pci.c F: include/hw/virtio/virtio-mem.h +virtio-snd +M: Manos Pitsidianakis +S: Supported +F: hw/virtio/virtio-snd*.c +F: include/hw/virtio/virtio-snd.h + nvme M: Keith Busch M: Klaus Jensen diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index 92c9cf6c96..d6f20657b3 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -17,6 +17,11 @@ config VIRTIO_PCI depends on PCI select VIRTIO +config VIRTIO_SND + bool + default y + depends on VIRTIO + config VIRTIO_MMIO bool select VIRTIO diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index c0055a7832..d0572b298c 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -35,6 +35,7 @@ specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) +specific_virtio_ss.add(when: 'CONFIG_VIRTIO_SND', if_true: files('virtio-snd.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c')) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 1cb9027d1e..96b997f427 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -154,3 +154,12 @@ virtio_pmem_flush_done(int type) "fsync return=%d" virtio_gpio_start(void) "start" virtio_gpio_stop(void) "stop" virtio_gpio_set_status(uint8_t status) "0x%x" + +#virtio-snd.c +virtio_snd_get_config(void *vdev, uint32_t jacks, uint32_t streams, uint32_t chmaps) "snd %p: get_config jacks=%"PRIu32" streams=%"PRIu32" chmaps=%"PRIu32"" +virtio_snd_set_config(void *vdev, uint32_t jacks, uint32_t new_jacks, uint32_t streams, uint32_t new_streams, uint32_t chmaps, uint32_t new_chmaps) "snd %p: set_config jacks from %"PRIu32"->%"PRIu32", streams from %"PRIu32"->%"PRIu32", chmaps from %"PRIu32"->%"PRIu32 +virtio_snd_get_features(void *vdev, uint64_t features) "snd %p: get_features 0x%"PRIx64 +virtio_snd_vm_state_running(void) "vm state running" +virtio_snd_vm_state_stopped(void) "vm state stopped" +virtio_snd_realize(void *snd) "snd %p: realize" +virtio_snd_unrealize(void *snd) "snd %p: unrealize" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c new file mode 100644 index 0000000000..adce9f371e --- /dev/null +++ b/hw/virtio/virtio-snd.c @@ -0,0 +1,223 @@ +/* + * VIRTIO Sound Device conforming to + * + * "Virtual I/O Device (VIRTIO) Version 1.2 + * Committee Specification Draft 01 + * 09 May 2022" + * + * + * + * Copyright (c) 2023 Emmanouil Pitsidianakis + * Copyright (C) 2019 OpenSynergy GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/iov.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "include/qemu/lockable.h" +#include "sysemu/runstate.h" +#include "trace.h" +#include "qapi/error.h" +#include "hw/virtio/virtio-snd.h" +#include "hw/core/cpu.h" + +#define VIRTIO_SOUND_VM_VERSION 1 +#define VIRTIO_SOUND_JACK_DEFAULT 0 +#define VIRTIO_SOUND_STREAM_DEFAULT 1 +#define VIRTIO_SOUND_CHMAP_DEFAULT 0 +#define VIRTIO_SOUND_HDA_FN_NID 0 + +static const VMStateDescription vmstate_virtio_snd_device = { + .name = TYPE_VIRTIO_SND, + .version_id = VIRTIO_SOUND_VM_VERSION, + .minimum_version_id = VIRTIO_SOUND_VM_VERSION, +}; + +static const VMStateDescription vmstate_virtio_snd = { + .name = "virtio-sound", + .minimum_version_id = VIRTIO_SOUND_VM_VERSION, + .version_id = VIRTIO_SOUND_VM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; + +static Property virtio_snd_properties[] = { + DEFINE_AUDIO_PROPERTIES(VirtIOSound, card), + DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks, + VIRTIO_SOUND_JACK_DEFAULT), + DEFINE_PROP_UINT32("streams", VirtIOSound, snd_conf.streams, + VIRTIO_SOUND_STREAM_DEFAULT), + DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps, + VIRTIO_SOUND_CHMAP_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void +virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + trace_virtio_snd_get_config(vdev, + s->snd_conf.jacks, + s->snd_conf.streams, + s->snd_conf.chmaps); + + memcpy(config, &s->snd_conf, sizeof(s->snd_conf)); +} + +static void +virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + const virtio_snd_config *sndconfig = + (const virtio_snd_config *)config; + + + trace_virtio_snd_set_config(vdev, + s->snd_conf.jacks, + sndconfig->jacks, + s->snd_conf.streams, + sndconfig->streams, + s->snd_conf.chmaps, + sndconfig->chmaps); + + memcpy(&s->snd_conf, sndconfig, sizeof(s->snd_conf)); +} + +/* + * Queue handler stub. + * + * @vdev: VirtIOSound device + * @vq: virtqueue + */ +static void virtio_snd_handle_queue(VirtIODevice *vdev, VirtQueue *vq) {} + +static uint64_t get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + /* + * virtio-v1.2-csd01, 5.14.3, + * Feature Bits + * None currently defined. + */ + VirtIOSound *s = VIRTIO_SND(vdev); + features |= s->features; + + trace_virtio_snd_get_features(vdev, features); + + return features; +} + +static void +virtio_snd_vm_state_change(void *opaque, bool running, + RunState state) +{ + if (running) { + trace_virtio_snd_vm_state_running(); + } else { + trace_virtio_snd_vm_state_stopped(); + } +} + +static void virtio_snd_realize(DeviceState *dev, Error **errp) +{ + ERRP_GUARD(); + VirtIOSound *vsnd = VIRTIO_SND(dev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + + vsnd->vmstate = + qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); + + trace_virtio_snd_realize(vsnd); + + virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); + virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); + + /* set number of jacks and streams */ + if (vsnd->snd_conf.jacks > 8) { + error_setg(errp, + "Invalid number of jacks: %"PRIu32, + vsnd->snd_conf.jacks); + return; + } + if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) { + error_setg(errp, + "Invalid number of streams: %"PRIu32, + vsnd->snd_conf.streams); + return; + } + + if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) { + error_setg(errp, + "Invalid number of channel maps: %"PRIu32, + vsnd->snd_conf.chmaps); + return; + } + + AUD_register_card("virtio-sound", &vsnd->card, errp); + + vsnd->queues[VIRTIO_SND_VQ_CONTROL] = + virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + vsnd->queues[VIRTIO_SND_VQ_EVENT] = + virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + vsnd->queues[VIRTIO_SND_VQ_TX] = + virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + vsnd->queues[VIRTIO_SND_VQ_RX] = + virtio_add_queue(vdev, 64, virtio_snd_handle_queue); +} + +static void virtio_snd_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSound *vsnd = VIRTIO_SND(dev); + + qemu_del_vm_change_state_handler(vsnd->vmstate); + trace_virtio_snd_unrealize(vsnd); + + AUD_remove_card(&vsnd->card); + virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]); + virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]); + virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]); + virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]); + virtio_cleanup(vdev); +} + + +static void virtio_snd_reset(VirtIODevice *vdev) {} + +static void virtio_snd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); + device_class_set_props(dc, virtio_snd_properties); + + dc->vmsd = &vmstate_virtio_snd; + vdc->vmsd = &vmstate_virtio_snd_device; + vdc->realize = virtio_snd_realize; + vdc->unrealize = virtio_snd_unrealize; + vdc->get_config = virtio_snd_get_config; + vdc->set_config = virtio_snd_set_config; + vdc->get_features = get_features; + vdc->reset = virtio_snd_reset; + vdc->legacy_features = 0; +} + +static const TypeInfo virtio_snd_types[] = { + { + .name = TYPE_VIRTIO_SND, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOSound), + .class_init = virtio_snd_class_init, + } +}; + +DEFINE_TYPES(virtio_snd_types) diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h new file mode 100644 index 0000000000..934e854a80 --- /dev/null +++ b/include/hw/virtio/virtio-snd.h @@ -0,0 +1,79 @@ +/* + * VIRTIO Sound Device conforming to + * + * "Virtual I/O Device (VIRTIO) Version 1.2 + * Committee Specification Draft 01 + * 09 May 2022" + * + * Copyright (c) 2023 Emmanouil Pitsidianakis + * Copyright (C) 2019 OpenSynergy GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef QEMU_VIRTIO_SOUND_H +#define QEMU_VIRTIO_SOUND_H + +#include "hw/virtio/virtio.h" +#include "audio/audio.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_snd.h" + +#define TYPE_VIRTIO_SND "virtio-sound" +#define VIRTIO_SND(obj) \ + OBJECT_CHECK(VirtIOSound, (obj), TYPE_VIRTIO_SND) + +/* CONFIGURATION SPACE */ + +typedef struct virtio_snd_config virtio_snd_config; + +/* COMMON DEFINITIONS */ + +/* common header for request/response*/ +typedef struct virtio_snd_hdr virtio_snd_hdr; + +/* event notification */ +typedef struct virtio_snd_event virtio_snd_event; + +/* common control request to query an item information */ +typedef struct virtio_snd_query_info virtio_snd_query_info; + +/* JACK CONTROL MESSAGES */ + +typedef struct virtio_snd_jack_hdr virtio_snd_jack_hdr; + +/* jack information structure */ +typedef struct virtio_snd_jack_info virtio_snd_jack_info; + +/* jack remapping control request */ +typedef struct virtio_snd_jack_remap virtio_snd_jack_remap; + +/* + * PCM CONTROL MESSAGES + */ +typedef struct virtio_snd_pcm_hdr virtio_snd_pcm_hdr; + +/* PCM stream info structure */ +typedef struct virtio_snd_pcm_info virtio_snd_pcm_info; + +/* set PCM stream params */ +typedef struct virtio_snd_pcm_set_params virtio_snd_pcm_set_params; + +/* I/O request header */ +typedef struct virtio_snd_pcm_xfer virtio_snd_pcm_xfer; + +/* I/O request status */ +typedef struct virtio_snd_pcm_status virtio_snd_pcm_status; + +typedef struct VirtIOSound { + VirtIODevice parent_obj; + + VirtQueue *queues[VIRTIO_SND_VQ_MAX]; + uint64_t features; + QEMUSoundCard card; + VMChangeStateEntry *vmstate; + virtio_snd_config snd_conf; +} VirtIOSound; +#endif From patchwork Wed Oct 11 14:34:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417507 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2D271CD6E7C for ; Wed, 11 Oct 2023 14:36:15 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJk-0000M9-CY; Wed, 11 Oct 2023 10:36:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJU-0000Fu-In for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:56 -0400 Received: from mail-wr1-x42a.google.com ([2a00:1450:4864:20::42a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJQ-0005O6-V2 for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:51 -0400 Received: by mail-wr1-x42a.google.com with SMTP id ffacd0b85a97d-3248ac76acbso6093710f8f.1 for ; Wed, 11 Oct 2023 07:35:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034944; x=1697639744; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bdoyLGD8Hh5MRb4py1jwZd/5mvisOOEae55CfDMdmAI=; b=nA98+kJI1/vVhYxFEz/45I9jJtEtIJoMw9dhOeyh39JMwptWRGbPsqtsBS5peI8Ftd a1K4vaFxb7kZ26ian40Lzhr7iXj/3sTY+5nI84iZ5uIU+2actxGesOEaa47q77w2hCdo Xl6VzNrB2s4lP0ookKOQ2RXvrDU2z5rqvb1exLyuZ76dUtz03RhPXACqiKeWfjLymnj7 +Ahoo7GCVfthgp7fc5w+RAiUJkCB35QpvZeE4nlBHoz/W/jCS5fCsGEji6ADiDbb69u5 ElNZGCi7NXT0SqmWxev6I6D4cjn4PTcBOEF+jGZxKj8mpjPGfmOLCTX42arG2Jk70Vu4 g8XA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034944; x=1697639744; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bdoyLGD8Hh5MRb4py1jwZd/5mvisOOEae55CfDMdmAI=; b=K4tWyKGcb5e3aMihiLnCeZZsJcAad6we7IAgnlElVXXQ3fZPb8+SoImrWHnsTFIyp2 RXk9WQDjwaiuUFUgGYaaC7/64CXlaOhpXSjnHk1W1w7L3iZOqJlfR2jYyc0R6A4zPABt EuoofPD3cULQ5+J4Xlaplx/SshyrKbSUpsCKVkOCBrNmf6abb15XMdYcPTWqcqtxoEKo OjzzTSrWhVzk3CWL3D5U7QGoD8JYAR/5mO8LWCe8aeG32X4FO6iMKaEzfJxbGHj+O6Db Ji2SQZCnlayxP2GxKhW28iufe2Yav2UMz5pVkUFZzOYGm7ok+MV64IGCPfu18VC44EGK 05fA== X-Gm-Message-State: AOJu0YwuQvunL2ES4Z08j39GfKLrudlsfBe8cnyQNNuCcZprgPlM+jmN IpkAdE8Bjo7SVqAgwLWSCd9/gNf3C7dIJDlHA6w= X-Google-Smtp-Source: AGHT+IF6oz21uFMzJ3HWqsUH8BjReVhew07F+33+gL9m6gwZx1Aa8971WfRfqXQ7pSPggFqRhqEZaA== X-Received: by 2002:a5d:6c69:0:b0:32c:eeee:d438 with SMTP id r9-20020a5d6c69000000b0032ceeeed438mr5350560wrz.54.1697034944496; Wed, 11 Oct 2023 07:35:44 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:43 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 02/11] Add virtio-sound-pci device Date: Wed, 11 Oct 2023 17:34:47 +0300 Message-Id: X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::42a; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x42a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis This patch adds a PCI wrapper device for the virtio-sound device. It is necessary to instantiate a virtio-snd device in a guest. All sound logic will be added to the virtio-snd device in the following commits. To add this device with a guest, you'll need a >=5.13 kernel compiled with CONFIG_SND_VIRTIO=y, which at the time of writing most distros have off by default. Use with following flags in the invocation: Pulseaudio: -audio driver=pa,model=virtio or -audio driver=pa,model=virtio,server=/run/user/1000/pulse/native sdl: -audio driver=sdl,model=virtio coreaudio (macos/darwin): -audio driver=coreaudio,model=virtio etc. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Reviewed-by: Alex Bennée Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis --- hw/virtio/meson.build | 1 + hw/virtio/virtio-snd-pci.c (new) | 93 ++++++++++++++++++++++++++++++++ hw/virtio/virtio-snd.c | 14 ++++- system/qdev-monitor.c | 1 + 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index d0572b298c..6233795018 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -67,6 +67,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-serial-pc virtio_pci_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c')) +virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SND', if_true: files('virtio-snd-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c')) virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-md-pci.c')) diff --git a/hw/virtio/virtio-snd-pci.c b/hw/virtio/virtio-snd-pci.c new file mode 100644 index 0000000000..afe50a5354 --- /dev/null +++ b/hw/virtio/virtio-snd-pci.c @@ -0,0 +1,93 @@ +/* + * VIRTIO Sound Device PCI Bindings + * + * Copyright (c) 2023 Emmanouil Pitsidianakis + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "qom/object.h" +#include "qapi/error.h" +#include "hw/audio/soundhw.h" +#include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-snd.h" + +/* + * virtio-snd-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_SND_PCI "virtio-sound-pci" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSoundPCI, VIRTIO_SND_PCI) + +struct VirtIOSoundPCI { + VirtIOPCIProxy parent_obj; + + VirtIOSound vdev; +}; + +static Property virtio_snd_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOSoundPCI *dev = VIRTIO_SND_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + virtio_pci_force_virtio_1(vpci_dev); + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void virtio_snd_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); + + device_class_set_props(dc, virtio_snd_pci_properties); + dc->desc = "Virtio Sound"; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); + + vpciklass->realize = virtio_snd_pci_realize; +} + +static void virtio_snd_pci_instance_init(Object *obj) +{ + VirtIOSoundPCI *dev = VIRTIO_SND_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SND); +} + +static const VirtioPCIDeviceTypeInfo virtio_snd_pci_info = { + .generic_name = TYPE_VIRTIO_SND_PCI, + .instance_size = sizeof(VirtIOSoundPCI), + .instance_init = virtio_snd_pci_instance_init, + .class_init = virtio_snd_pci_class_init, +}; + +/* Create a Virtio Sound PCI device, so '-audio driver,model=virtio' works. */ +static int virtio_snd_pci_init(PCIBus *bus, const char *audiodev) +{ + DeviceState *vdev = NULL; + VirtIOSoundPCI *dev = NULL; + + vdev = qdev_new(TYPE_VIRTIO_SND_PCI); + assert(vdev); + dev = VIRTIO_SND_PCI(vdev); + qdev_prop_set_string(DEVICE(&dev->vdev), "audiodev", audiodev); + qdev_realize_and_unref(vdev, BUS(bus), &error_fatal); + return 0; +} + +static void virtio_snd_pci_register(void) +{ + virtio_pci_types_register(&virtio_snd_pci_info); + pci_register_soundhw("virtio", "Virtio Sound", virtio_snd_pci_init); +} + +type_init(virtio_snd_pci_register); diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index adce9f371e..14bc32f476 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -63,36 +63,46 @@ static void virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config) { VirtIOSound *s = VIRTIO_SND(vdev); + virtio_snd_config *sndconfig = + (virtio_snd_config *)config; trace_virtio_snd_get_config(vdev, s->snd_conf.jacks, s->snd_conf.streams, s->snd_conf.chmaps); - memcpy(config, &s->snd_conf, sizeof(s->snd_conf)); + memcpy(sndconfig, &s->snd_conf, sizeof(s->snd_conf)); + cpu_to_le32s(&sndconfig->jacks); + cpu_to_le32s(&sndconfig->streams); + cpu_to_le32s(&sndconfig->chmaps); + } static void virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIOSound *s = VIRTIO_SND(vdev); const virtio_snd_config *sndconfig = (const virtio_snd_config *)config; trace_virtio_snd_set_config(vdev, s->snd_conf.jacks, sndconfig->jacks, s->snd_conf.streams, sndconfig->streams, s->snd_conf.chmaps, sndconfig->chmaps); - memcpy(&s->snd_conf, sndconfig, sizeof(s->snd_conf)); + memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config)); + le32_to_cpus(&s->snd_conf.jacks); + le32_to_cpus(&s->snd_conf.streams); + le32_to_cpus(&s->snd_conf.chmaps); + } /* * Queue handler stub. * * @vdev: VirtIOSound device * @vq: virtqueue */ diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 74f4e41338..2e9835ad88 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -68,48 +68,49 @@ typedef struct QDevAlias /* Please keep this table sorted by typename. */ static const QDevAlias qdev_alias_table[] = { { "AC97", "ac97" }, /* -soundhw name */ { "e1000", "e1000-82540em" }, { "ES1370", "es1370" }, /* -soundhw name */ { "ich9-ahci", "ahci" }, { "lsi53c895a", "lsi" }, { "virtio-9p-device", "virtio-9p", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-9p-ccw", "virtio-9p", QEMU_ARCH_VIRTIO_CCW }, { "virtio-9p-pci", "virtio-9p", QEMU_ARCH_VIRTIO_PCI }, { "virtio-balloon-device", "virtio-balloon", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-balloon-ccw", "virtio-balloon", QEMU_ARCH_VIRTIO_CCW }, { "virtio-balloon-pci", "virtio-balloon", QEMU_ARCH_VIRTIO_PCI }, { "virtio-blk-device", "virtio-blk", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_VIRTIO_CCW }, { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_VIRTIO_PCI }, { "virtio-gpu-device", "virtio-gpu", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-gpu-ccw", "virtio-gpu", QEMU_ARCH_VIRTIO_CCW }, { "virtio-gpu-pci", "virtio-gpu", QEMU_ARCH_VIRTIO_PCI }, { "virtio-gpu-gl-device", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-gpu-gl-pci", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_PCI }, { "virtio-input-host-device", "virtio-input-host", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-input-host-ccw", "virtio-input-host", QEMU_ARCH_VIRTIO_CCW }, { "virtio-input-host-pci", "virtio-input-host", QEMU_ARCH_VIRTIO_PCI }, { "virtio-iommu-pci", "virtio-iommu", QEMU_ARCH_VIRTIO_PCI }, { "virtio-keyboard-device", "virtio-keyboard", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-keyboard-ccw", "virtio-keyboard", QEMU_ARCH_VIRTIO_CCW }, { "virtio-keyboard-pci", "virtio-keyboard", QEMU_ARCH_VIRTIO_PCI }, { "virtio-mouse-device", "virtio-mouse", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-mouse-ccw", "virtio-mouse", QEMU_ARCH_VIRTIO_CCW }, { "virtio-mouse-pci", "virtio-mouse", QEMU_ARCH_VIRTIO_PCI }, { "virtio-net-device", "virtio-net", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-net-ccw", "virtio-net", QEMU_ARCH_VIRTIO_CCW }, { "virtio-net-pci", "virtio-net", QEMU_ARCH_VIRTIO_PCI }, { "virtio-rng-device", "virtio-rng", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-rng-ccw", "virtio-rng", QEMU_ARCH_VIRTIO_CCW }, { "virtio-rng-pci", "virtio-rng", QEMU_ARCH_VIRTIO_PCI }, { "virtio-scsi-device", "virtio-scsi", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-scsi-ccw", "virtio-scsi", QEMU_ARCH_VIRTIO_CCW }, { "virtio-scsi-pci", "virtio-scsi", QEMU_ARCH_VIRTIO_PCI }, { "virtio-serial-device", "virtio-serial", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_VIRTIO_CCW }, { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_VIRTIO_PCI}, + { "virtio-sound-pci", "virtio-sound", QEMU_ARCH_VIRTIO_PCI}, { "virtio-tablet-device", "virtio-tablet", QEMU_ARCH_VIRTIO_MMIO }, { "virtio-tablet-ccw", "virtio-tablet", QEMU_ARCH_VIRTIO_CCW }, { "virtio-tablet-pci", "virtio-tablet", QEMU_ARCH_VIRTIO_PCI }, { } }; From patchwork Wed Oct 11 14:34:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417512 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D1534CD6E7C for ; Wed, 11 Oct 2023 14:39:13 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJm-0000Ob-IT; Wed, 11 Oct 2023 10:36:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJZ-0000Kn-TI for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:00 -0400 Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJS-0005Pm-PE for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:54 -0400 Received: by mail-wr1-x429.google.com with SMTP id ffacd0b85a97d-3231df054c4so6214016f8f.0 for ; Wed, 11 Oct 2023 07:35:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034948; x=1697639748; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0N/3oZ15ILVF3SPyjOF6gh96qOEmYU2+9Pq0/zh/3Pk=; b=cG83EycUdRUqrDIfj/JPa470nbwZrOKOTJQ5ZrwO8aqVSCItJ4mvs6yDB0pSPHez3x kEdYa5eUbrvPg4N1ThAEFOpBLOWJTInsVmgNHlqQVHCgGXm9sLKpe3PTwvDnclOj9NRg fSfpA6YuAejXrJKvdepPFhInSKaF15FGYCfMZEtDa8zUaVCazVmfknF6iwu4YtXD4VP9 jObAlpSki8ycMKGEYhW15ZxIZEDXGi0tz2hSttRiTg7LAS2c3p+/u8kP1tfmb5osilqZ ZD0pY1CiOLv/effw09VuB8xLJLcCKfrpg3F5fENXNNMnEJxSfyjx1FTqVyRrHc3GjJET 9Juw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034948; x=1697639748; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0N/3oZ15ILVF3SPyjOF6gh96qOEmYU2+9Pq0/zh/3Pk=; b=YJ7KEqgZL7BENfnZaoYH7rypRAN1dG+zb0S3t0NaAKE9LhRFXgDYi011+qeYPKVPjn lDn2XwSDzCSti7ZjR5eGz9uiQ2Bm537yZ8nH2sa2UZ92ZY6oWschPZ8TaKgJxIvKO9jG gbjyOH9C+Gu9qqA3NoSmsY+KMqfnRQ1tBdFC1gHaBzKMPLQ71dbNfnEe4XjfmPl8X3qJ 4dhpBJtgj3958Q5BOwzUSsiZEjYTN4CGH5uCHLSaKgpKvHzgzRASHo+JXMCtL80hkbW0 YXT/XSGa2Y3sK1Htmu/R1fVqyV1MlMWrRnN5Um0O094V50KmJ7Zf5qAecPuhQcVpLdIx sUfQ== X-Gm-Message-State: AOJu0Yxz1KYYX2tdAA7bYwdKkT3DBwjccyYkshV1ToZMqrXIybib0X55 TgZOfswJ/xso+6fJR9oLxtDD1RqUJFfwkxS9fAo= X-Google-Smtp-Source: AGHT+IExm/padWvMVOO0Tk+15nG4Dnd6GskS2TWs7OoSWghSm17yheyLzu9ONi6HNfJStDYG8a8lvQ== X-Received: by 2002:a05:6000:1703:b0:32d:8958:d36b with SMTP id n3-20020a056000170300b0032d8958d36bmr1392122wrc.3.1697034948084; Wed, 11 Oct 2023 07:35:48 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:47 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 03/11] virtio-sound: handle control messages and streams Date: Wed, 11 Oct 2023 17:34:48 +0300 Message-Id: <5831b5cfa5666b040e8466c0e4cbb0b08c4fd4ec.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::429; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x429.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Receive guest requests in the control (CTRL) queue of the virtio sound device and reply with a NOT SUPPORTED error to all control commands. The receiving handler is virtio_snd_handle_ctrl(). It stores all control messages in the queue in the device's command queue. Then it calls virtio_snd_process_cmdq() to handle each message. The handler is process_cmd() which replies with VIRTIO_SND_S_NOT_SUPP. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Reviewed-by: Alex Bennée Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis --- hw/virtio/trace-events | 4 + hw/virtio/virtio-snd.c | 487 ++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-snd.h | 113 +++++++- 3 files changed, 595 insertions(+), 9 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 96b997f427..48043fed3e 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -163,3 +163,7 @@ virtio_snd_vm_state_running(void) "vm state running" virtio_snd_vm_state_stopped(void) "vm state stopped" virtio_snd_realize(void *snd) "snd %p: realize" virtio_snd_unrealize(void *snd) "snd %p: unrealize" +virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" +virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" +virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" +virtio_snd_handle_event(void) "event queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 14bc32f476..705dc07212 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -32,6 +32,29 @@ #define VIRTIO_SOUND_CHMAP_DEFAULT 0 #define VIRTIO_SOUND_HDA_FN_NID 0 +static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8) + | BIT(VIRTIO_SND_PCM_FMT_U8) + | BIT(VIRTIO_SND_PCM_FMT_S16) + | BIT(VIRTIO_SND_PCM_FMT_U16) + | BIT(VIRTIO_SND_PCM_FMT_S32) + | BIT(VIRTIO_SND_PCM_FMT_U32) + | BIT(VIRTIO_SND_PCM_FMT_FLOAT); + +static uint32_t supported_rates = BIT(VIRTIO_SND_PCM_RATE_5512) + | BIT(VIRTIO_SND_PCM_RATE_8000) + | BIT(VIRTIO_SND_PCM_RATE_11025) + | BIT(VIRTIO_SND_PCM_RATE_16000) + | BIT(VIRTIO_SND_PCM_RATE_22050) + | BIT(VIRTIO_SND_PCM_RATE_32000) + | BIT(VIRTIO_SND_PCM_RATE_44100) + | BIT(VIRTIO_SND_PCM_RATE_48000) + | BIT(VIRTIO_SND_PCM_RATE_64000) + | BIT(VIRTIO_SND_PCM_RATE_88200) + | BIT(VIRTIO_SND_PCM_RATE_96000) + | BIT(VIRTIO_SND_PCM_RATE_176400) + | BIT(VIRTIO_SND_PCM_RATE_192000) + | BIT(VIRTIO_SND_PCM_RATE_384000); + static const VMStateDescription vmstate_virtio_snd_device = { .name = TYPE_VIRTIO_SND, .version_id = VIRTIO_SOUND_VM_VERSION, @@ -81,32 +104,416 @@ static void virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIOSound *s = VIRTIO_SND(vdev); const virtio_snd_config *sndconfig = (const virtio_snd_config *)config; trace_virtio_snd_set_config(vdev, s->snd_conf.jacks, sndconfig->jacks, s->snd_conf.streams, sndconfig->streams, s->snd_conf.chmaps, sndconfig->chmaps); memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config)); le32_to_cpus(&s->snd_conf.jacks); le32_to_cpus(&s->snd_conf.streams); le32_to_cpus(&s->snd_conf.chmaps); } +static void +virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd) +{ + g_free(cmd->elem); + g_free(cmd); +} + +/* + * Get a specific stream from the virtio sound card device. + * Returns NULL if @stream_id is invalid or not allocated. + * + * @s: VirtIOSound device + * @stream_id: stream id + */ +static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s, + uint32_t stream_id) +{ + return stream_id >= s->snd_conf.streams ? NULL : + s->pcm->streams[stream_id]; +} + +/* + * Get params for a specific stream. + * + * @s: VirtIOSound device + * @stream_id: stream id + */ +static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s, + uint32_t stream_id) +{ + return stream_id >= s->snd_conf.streams ? NULL + : &s->pcm->pcm_params[stream_id]; +} + +/* + * Set the given stream params. + * Called by both virtio_snd_handle_pcm_set_params and during device + * initialization. + * Returns the response status code. (VIRTIO_SND_S_*). + * + * @s: VirtIOSound device + * @params: The PCM params as defined in the virtio specification + */ +static +uint32_t virtio_snd_set_pcm_params(VirtIOSound *s, + uint32_t stream_id, + virtio_snd_pcm_set_params *params) +{ + virtio_snd_pcm_set_params *st_params; + + if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n"); + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + } + + st_params = virtio_snd_pcm_get_params(s, stream_id); + + if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) { + error_report("Number of channels is not supported."); + return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + } + if (!(supported_formats & BIT(params->format))) { + error_report("Stream format is not supported."); + return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + } + if (!(supported_rates & BIT(params->rate))) { + error_report("Stream rate is not supported."); + return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + } + + st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes); + st_params->period_bytes = le32_to_cpu(params->period_bytes); + st_params->features = le32_to_cpu(params->features); + /* the following are uint8_t, so there's no need to bswap the values. */ + st_params->channels = params->channels; + st_params->format = params->format; + st_params->rate = params->rate; + + return cpu_to_le32(VIRTIO_SND_S_OK); +} + +/* + * Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_* + */ +static AudioFormat virtio_snd_get_qemu_format(uint32_t format) +{ + #define CASE(FMT) \ + case VIRTIO_SND_PCM_FMT_##FMT: \ + return AUDIO_FORMAT_##FMT; + + switch (format) { + CASE(U8) + CASE(S8) + CASE(U16) + CASE(S16) + CASE(U32) + CASE(S32) + case VIRTIO_SND_PCM_FMT_FLOAT: + return AUDIO_FORMAT_F32; + default: + g_assert_not_reached(); + } + + #undef CASE +} + +/* + * Get a QEMU Audiosystem compatible frequency value from a + * VIRTIO_SND_PCM_RATE_* + */ +static uint32_t virtio_snd_get_qemu_freq(uint32_t rate) +{ + #define CASE(RATE) \ + case VIRTIO_SND_PCM_RATE_##RATE: \ + return RATE; + + switch (rate) { + CASE(5512) + CASE(8000) + CASE(11025) + CASE(16000) + CASE(22050) + CASE(32000) + CASE(44100) + CASE(48000) + CASE(64000) + CASE(88200) + CASE(96000) + CASE(176400) + CASE(192000) + CASE(384000) + default: + g_assert_not_reached(); + } + + #undef CASE +} + +/* + * Get QEMU Audiosystem compatible audsettings from virtio based pcm stream + * params. + */ +static void virtio_snd_get_qemu_audsettings(audsettings *as, + virtio_snd_pcm_set_params *params) +{ + as->nchannels = MIN(AUDIO_MAX_CHANNELS, params->channels); + as->fmt = virtio_snd_get_qemu_format(params->format); + as->freq = virtio_snd_get_qemu_freq(params->rate); + as->endianness = target_words_bigendian() ? 1 : 0; +} + +/* + * Close a stream and free all its resources. + * + * @stream: VirtIOSoundPCMStream *stream + */ +static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream) +{ +} + /* - * Queue handler stub. + * Prepares a VirtIOSound card stream. + * Returns the response status code. (VIRTIO_SND_S_*). + * + * @s: VirtIOSound device + * @stream_id: stream id + */ +static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) +{ + audsettings as; + virtio_snd_pcm_set_params *params; + VirtIOSoundPCMStream *stream; + + if (s->pcm->streams == NULL || + s->pcm->pcm_params == NULL || + stream_id >= s->snd_conf.streams) { + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + } + + params = virtio_snd_pcm_get_params(s, stream_id); + if (params == NULL) { + return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + } + + stream = virtio_snd_pcm_get_stream(s, stream_id); + if (stream == NULL) { + stream = g_new0(VirtIOSoundPCMStream, 1); + stream->active = false; + stream->id = stream_id; + stream->pcm = s->pcm; + stream->s = s; + + /* + * stream_id >= s->snd_conf.streams was checked before so this is + * in-bounds + */ + s->pcm->streams[stream_id] = stream; + } + + virtio_snd_get_qemu_audsettings(&as, params); + stream->info.direction = stream_id < s->snd_conf.streams / 2 + + (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT; + stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID; + stream->info.features = 0; + stream->info.channels_min = 1; + stream->info.channels_max = as.nchannels; + stream->info.formats = supported_formats; + stream->info.rates = supported_rates; + stream->params = *params; + + stream->positions[0] = VIRTIO_SND_CHMAP_FL; + stream->positions[1] = VIRTIO_SND_CHMAP_FR; + stream->as = as; + + return cpu_to_le32(VIRTIO_SND_S_OK); +} + +static const char *print_code(uint32_t code) +{ + #define CASE(CODE) \ + case VIRTIO_SND_R_##CODE: \ + return "VIRTIO_SND_R_"#CODE + + switch (code) { + CASE(JACK_INFO); + CASE(JACK_REMAP); + CASE(PCM_INFO); + CASE(PCM_SET_PARAMS); + CASE(PCM_PREPARE); + CASE(PCM_RELEASE); + CASE(PCM_START); + CASE(PCM_STOP); + CASE(CHMAP_INFO); + default: + return "invalid code"; + } + + #undef CASE +}; + +/* + * The actual processing done in virtio_snd_process_cmdq(). + * + * @s: VirtIOSound device + * @cmd: control command request + */ +static inline void +process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) +{ + uint32_t code; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + 0, + &cmd->ctrl, + sizeof(virtio_snd_hdr)); + + if (msg_sz != sizeof(virtio_snd_hdr)) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); + return; + } + + code = le32_to_cpu(cmd->ctrl.code); + + trace_virtio_snd_handle_code(code, print_code(code)); + + switch (code) { + case VIRTIO_SND_R_JACK_INFO: + case VIRTIO_SND_R_JACK_REMAP: + qemu_log_mask(LOG_UNIMP, + "virtio_snd: jack functionality is unimplemented.\n"); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + break; + case VIRTIO_SND_R_PCM_INFO: + case VIRTIO_SND_R_PCM_SET_PARAMS: + case VIRTIO_SND_R_PCM_PREPARE: + case VIRTIO_SND_R_PCM_START: + case VIRTIO_SND_R_PCM_STOP: + case VIRTIO_SND_R_PCM_RELEASE: + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + break; + case VIRTIO_SND_R_CHMAP_INFO: + qemu_log_mask(LOG_UNIMP, + "virtio_snd: chmap info functionality is unimplemented.\n"); + trace_virtio_snd_handle_chmap_info(); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + break; + default: + /* error */ + error_report("virtio snd header not recognized: %"PRIu32, code); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + } + + iov_from_buf(cmd->elem->in_sg, + cmd->elem->in_num, + 0, + &cmd->resp, + sizeof(virtio_snd_hdr)); + virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); + virtio_notify(VIRTIO_DEVICE(s), cmd->vq); +} + +/* + * Consume all elements in command queue. + * + * @s: VirtIOSound device + */ +static void virtio_snd_process_cmdq(VirtIOSound *s) +{ + virtio_snd_ctrl_command *cmd; + + if (unlikely(qatomic_read(&s->processing_cmdq))) { + return; + } + + WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) { + qatomic_set(&s->processing_cmdq, true); + while (!QTAILQ_EMPTY(&s->cmdq)) { + cmd = QTAILQ_FIRST(&s->cmdq); + + /* process command */ + process_cmd(s, cmd); + + QTAILQ_REMOVE(&s->cmdq, cmd, next); + + virtio_snd_ctrl_cmd_free(cmd); + } + qatomic_set(&s->processing_cmdq, false); + } +} + +/* + * The control message handler. Pops an element from the control virtqueue, + * and stores them to VirtIOSound's cmdq queue and finally calls + * virtio_snd_process_cmdq() for processing. + * + * @vdev: VirtIOSound device + * @vq: Control virtqueue + */ +static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + VirtQueueElement *elem; + virtio_snd_ctrl_command *cmd; + + trace_virtio_snd_handle_ctrl(vdev, vq); + + if (!virtio_queue_ready(vq)) { + return; + } + + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + while (elem) { + cmd = g_new0(virtio_snd_ctrl_command, 1); + cmd->elem = elem; + cmd->vq = vq; + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); + QTAILQ_INSERT_TAIL(&s->cmdq, cmd, next); + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + } + + virtio_snd_process_cmdq(s); +} + +/* + * The event virtqueue handler. + * Not implemented yet. + * + * @vdev: VirtIOSound device + * @vq: event vq + */ +static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq) +{ + qemu_log_mask(LOG_UNIMP, "virtio_snd: event queue is unimplemented.\n"); + trace_virtio_snd_handle_event(); +} + +/* + * Stub buffer virtqueue handler. * * @vdev: VirtIOSound device * @vq: virtqueue */ -static void virtio_snd_handle_queue(VirtIODevice *vdev, VirtQueue *vq) {} +static void virtio_snd_handle_xfer(VirtIODevice *vdev, VirtQueue *vq) {} static uint64_t get_features(VirtIODevice *vdev, uint64_t features, Error **errp) @@ -138,68 +545,134 @@ virtio_snd_vm_state_change(void *opaque, bool running, static void virtio_snd_realize(DeviceState *dev, Error **errp) { ERRP_GUARD(); VirtIOSound *vsnd = VIRTIO_SND(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); + virtio_snd_pcm_set_params default_params = { 0 }; + uint32_t status; + vsnd->pcm = NULL; vsnd->vmstate = qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); trace_virtio_snd_realize(vsnd); + vsnd->pcm = g_new0(VirtIOSoundPCM, 1); + vsnd->pcm->snd = vsnd; + vsnd->pcm->streams = + g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams); + vsnd->pcm->pcm_params = + g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams); + virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); /* set number of jacks and streams */ if (vsnd->snd_conf.jacks > 8) { error_setg(errp, "Invalid number of jacks: %"PRIu32, vsnd->snd_conf.jacks); return; } if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) { error_setg(errp, "Invalid number of streams: %"PRIu32, vsnd->snd_conf.streams); return; } if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) { error_setg(errp, "Invalid number of channel maps: %"PRIu32, vsnd->snd_conf.chmaps); return; } AUD_register_card("virtio-sound", &vsnd->card, errp); + /* set default params for all streams */ + default_params.features = 0; + default_params.buffer_bytes = cpu_to_le32(8192); + default_params.period_bytes = cpu_to_le32(2048); + default_params.channels = 2; + default_params.format = VIRTIO_SND_PCM_FMT_S16; + default_params.rate = VIRTIO_SND_PCM_RATE_48000; vsnd->queues[VIRTIO_SND_VQ_CONTROL] = - virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl); vsnd->queues[VIRTIO_SND_VQ_EVENT] = - virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + virtio_add_queue(vdev, 64, virtio_snd_handle_event); vsnd->queues[VIRTIO_SND_VQ_TX] = - virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + virtio_add_queue(vdev, 64, virtio_snd_handle_xfer); vsnd->queues[VIRTIO_SND_VQ_RX] = - virtio_add_queue(vdev, 64, virtio_snd_handle_queue); + virtio_add_queue(vdev, 64, virtio_snd_handle_xfer); + qemu_mutex_init(&vsnd->cmdq_mutex); + QTAILQ_INIT(&vsnd->cmdq); + + for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { + status = virtio_snd_set_pcm_params(vsnd, i, &default_params); + if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { + error_setg(errp, + "Can't initalize stream params, device responded with %s.", + print_code(status)); + return; + } + status = virtio_snd_pcm_prepare(vsnd, i); + if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { + error_setg(errp, + "Can't prepare streams, device responded with %s.", + print_code(status)); + return; + } + } } static void virtio_snd_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSound *vsnd = VIRTIO_SND(dev); + VirtIOSoundPCMStream *stream; qemu_del_vm_change_state_handler(vsnd->vmstate); trace_virtio_snd_unrealize(vsnd); + if (vsnd->pcm) { + if (vsnd->pcm->streams) { + for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { + stream = vsnd->pcm->streams[i]; + if (stream) { + virtio_snd_process_cmdq(stream->s); + virtio_snd_pcm_close(stream); + g_free(stream); + } + } + g_free(vsnd->pcm->streams); + } + g_free(vsnd->pcm->pcm_params); + g_free(vsnd->pcm); + vsnd->pcm = NULL; + } AUD_remove_card(&vsnd->card); + qemu_mutex_destroy(&vsnd->cmdq_mutex); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]); virtio_cleanup(vdev); } -static void virtio_snd_reset(VirtIODevice *vdev) {} +static void virtio_snd_reset(VirtIODevice *vdev) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + virtio_snd_ctrl_command *cmd; + + WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) { + while (!QTAILQ_EMPTY(&s->cmdq)) { + cmd = QTAILQ_FIRST(&s->cmdq); + QTAILQ_REMOVE(&s->cmdq, cmd, next); + virtio_snd_ctrl_cmd_free(cmd); + } + } +} static void virtio_snd_class_init(ObjectClass *klass, void *data) { diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h index 934e854a80..4b4aaffff1 100644 --- a/include/hw/virtio/virtio-snd.h +++ b/include/hw/virtio/virtio-snd.h @@ -67,13 +67,122 @@ typedef struct virtio_snd_pcm_xfer virtio_snd_pcm_xfer; /* I/O request status */ typedef struct virtio_snd_pcm_status virtio_snd_pcm_status; -typedef struct VirtIOSound { +/* device structs */ + +typedef struct VirtIOSound VirtIOSound; + +typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream; + +typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command; + +typedef struct VirtIOSoundPCM VirtIOSoundPCM; + +struct VirtIOSoundPCM { + VirtIOSound *snd; + /* + * PCM parameters are a separate field instead of a VirtIOSoundPCMStream + * field, because the operation of PCM control requests is first + * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this + * means that some times we get parameters without having an allocated + * stream yet. + */ + virtio_snd_pcm_set_params *pcm_params; + VirtIOSoundPCMStream **streams; +}; + +struct VirtIOSoundPCMStream { + VirtIOSoundPCM *pcm; + virtio_snd_pcm_info info; + virtio_snd_pcm_set_params params; + uint32_t id; + /* channel position values (VIRTIO_SND_CHMAP_XXX) */ + uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE]; + VirtIOSound *s; + bool flushing; + audsettings as; + union { + SWVoiceIn *in; + SWVoiceOut *out; + } voice; + bool active; +}; + +/* + * PCM stream state machine. + * ------------------------- + * + * 5.14.6.6.1 PCM Command Lifecycle + * ================================ + * + * A PCM stream has the following command lifecycle: + * - `SET PARAMETERS` + * The driver negotiates the stream parameters (format, transport, etc) with + * the device. + * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. + * - `PREPARE` + * The device prepares the stream (allocates resources, etc). + * Possible valid transitions: `SET PARAMETERS`, `PREPARE`, `START`, + * `RELEASE`. Output only: the driver transfers data for pre-buffing. + * - `START` + * The device starts the stream (unmute, putting into running state, etc). + * Possible valid transitions: `STOP`. + * The driver transfers data to/from the stream. + * - `STOP` + * The device stops the stream (mute, putting into non-running state, etc). + * Possible valid transitions: `START`, `RELEASE`. + * - `RELEASE` + * The device releases the stream (frees resources, etc). + * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. + * + * +---------------+ +---------+ +---------+ +-------+ +-------+ + * | SetParameters | | Prepare | | Release | | Start | | Stop | + * +---------------+ +---------+ +---------+ +-------+ +-------+ + * |- | | | | + * || | | | | + * |< | | | | + * |------------->| | | | + * |<-------------| | | | + * | |- | | | + * | || | | | + * | |< | | | + * | |--------------------->| | + * | |---------->| | | + * | | | |-------->| + * | | | |<--------| + * | | |<-------------------| + * |<-------------------------| | | + * | |<----------| | | + * + * CTRL in the VirtIOSound device + * ============================== + * + * The control messages that affect the state of a stream arrive in the + * `virtio_snd_handle_ctrl()` queue callback and are of type `struct + * virtio_snd_ctrl_command`. They are stored in a queue field in the device + * type, `VirtIOSound`. This allows deferring the CTRL request completion if + * it's not immediately possible due to locking/state reasons. + * + * The CTRL message is finally handled in `process_cmd()`. + */ +struct VirtIOSound { VirtIODevice parent_obj; VirtQueue *queues[VIRTIO_SND_VQ_MAX]; uint64_t features; + VirtIOSoundPCM *pcm; QEMUSoundCard card; VMChangeStateEntry *vmstate; virtio_snd_config snd_conf; -} VirtIOSound; + QemuMutex cmdq_mutex; + QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq; + bool processing_cmdq; +}; + +struct virtio_snd_ctrl_command { + VirtQueueElement *elem; + VirtQueue *vq; + virtio_snd_hdr ctrl; + virtio_snd_hdr resp; + QTAILQ_ENTRY(virtio_snd_ctrl_command) next; +}; #endif From patchwork Wed Oct 11 14:34:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417515 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BAE4ECD6E77 for ; Wed, 11 Oct 2023 14:39:13 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJp-0000Z1-4u; Wed, 11 Oct 2023 10:36:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJh-0000LA-Mr for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:06 -0400 Received: from mail-wr1-x42d.google.com ([2a00:1450:4864:20::42d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJY-0005TL-7G for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:35:59 -0400 Received: by mail-wr1-x42d.google.com with SMTP id ffacd0b85a97d-31427ddd3fbso6474653f8f.0 for ; Wed, 11 Oct 2023 07:35:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034951; x=1697639751; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=t9MdLvdr3TSH2bUvE9n7JeOkT2T6hYu0LDOeAx0W1vs=; b=egkjcbsjyJGzl/T8r+GbW4tCIbGyxObnkZjBbN1zXMBBvLKcB0F0SkxJBI1hyVj69U dqGvwviA0VDeTLUFG5N1FDhEJxqQq+hJnf6c5KXsjbmyxSQRqfh8KM+ARfW6Ot06uOQq NFrcNihzSmz5KRerh7qLGhqQuMRv/+9ZikwecVpus1i4wRYYMs3ios/lnS48IZjZoDqe TVAaAz8PbbIQ/kI4EffJN0BS7iwm3uqm96kbmCP8qCZ+8OY3auDcvgAyDNysC9zT90Fr Lf41AlujfF6FQd9Qwz8YuoLzltDKyKwGb5UQxm/rxMuwLamfqxHnYgqvf6qw7gSvZPXt OLHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034951; x=1697639751; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=t9MdLvdr3TSH2bUvE9n7JeOkT2T6hYu0LDOeAx0W1vs=; b=HbPBTtHeVvnPOfn/HG389U1kudUBLgfHza/zf0Sl1FAVtcBzPvLJRXHxU8xsRWvgHX 4w8De0LPVQqOtAUww7hyB457qMPtbrWvfG4PHOdnqEuUsAC2gP88KBfbHPn8O73/SJS3 ysUnU0e/13cdHK7/og6CBBn3ddXErk+DLHKlqJ35tL1g6FXMWSW5iA7b9trYKHUE8eKj f8rmY503OcNHh7gCUaT3yIt+tgnC16bd8yTrtkgGbRse/qZyq/QC9vPmDKvNeK1s6zDD fd67Vg4s7dG+vDlkXvmpo4zoq0C/kBIkmxHQWQaAvukiKRCjJmmzTI5N8HpHPuvLFN26 gOpA== X-Gm-Message-State: AOJu0YxRFN0zH8RqUve2NrDN30UhIOZ/wS9n+VRpF3p/Ruvsi2/shw52 XxaNbSUQ3+qTSCgOmW1J+4VuNh/rfXccyQ4B4Ek= X-Google-Smtp-Source: AGHT+IG0MaZt8+YUIEvJA8GkWMPNgEgpTaNESYOBd3hOajR1HAOe6QU24RiuW/Y479bBLhnU9xwZBg== X-Received: by 2002:a05:6000:1f87:b0:32d:24c7:a268 with SMTP id bw7-20020a0560001f8700b0032d24c7a268mr5347003wrb.4.1697034951607; Wed, 11 Oct 2023 07:35:51 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:51 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 04/11] virtio-sound: handle VIRTIO_SND_R_PCM_INFO request Date: Wed, 11 Oct 2023 17:34:49 +0300 Message-Id: <425cbc2986aaf318fdb6a604baebf5a2f03cfe31.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::42d; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x42d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Respond to the VIRTIO_SND_R_PCM_INFO control request with the parameters of each requested PCM stream. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 1 + hw/virtio/virtio-snd.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 48043fed3e..88de2021c8 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -164,6 +164,7 @@ virtio_snd_vm_state_stopped(void) "vm state stopped" virtio_snd_realize(void *snd) "snd %p: realize" virtio_snd_unrealize(void *snd) "snd %p: unrealize" virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" +virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32 virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 705dc07212..ec945d55a7 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -147,22 +147,102 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s, /* * Get params for a specific stream. * * @s: VirtIOSound device * @stream_id: stream id */ static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s, uint32_t stream_id) { return stream_id >= s->snd_conf.streams ? NULL : &s->pcm->pcm_params[stream_id]; } +/* + * Handle the VIRTIO_SND_R_PCM_INFO request. + * The function writes the info structs to the request element. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + */ +static void virtio_snd_handle_pcm_info(VirtIOSound *s, + virtio_snd_ctrl_command *cmd) +{ + uint32_t stream_id, start_id, count, size; + virtio_snd_pcm_info val; + virtio_snd_query_info req; + VirtIOSoundPCMStream *stream = NULL; + g_autofree virtio_snd_pcm_info *pcm_info = NULL; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + 0, + &req, + sizeof(virtio_snd_query_info)); + + if (msg_sz != sizeof(virtio_snd_query_info)) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(virtio_snd_query_info)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + start_id = le32_to_cpu(req.start_id); + count = le32_to_cpu(req.count); + size = le32_to_cpu(req.size); + + if (iov_size(cmd->elem->in_sg, cmd->elem->in_num) < + sizeof(virtio_snd_hdr) + size * count) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + error_report("pcm info: buffer too small, got: %zu, needed: %zu", + iov_size(cmd->elem->in_sg, cmd->elem->in_num), + sizeof(virtio_snd_pcm_info)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + pcm_info = g_new0(virtio_snd_pcm_info, count); + for (uint32_t i = 0; i < count; i++) { + stream_id = i + start_id; + trace_virtio_snd_handle_pcm_info(stream_id); + stream = virtio_snd_pcm_get_stream(s, stream_id); + if (!stream) { + error_report("Invalid stream id: %"PRIu32, stream_id); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + val = stream->info; + val.hdr.hda_fn_nid = cpu_to_le32(val.hdr.hda_fn_nid); + val.features = cpu_to_le32(val.features); + val.formats = cpu_to_le64(val.formats); + val.rates = cpu_to_le64(val.rates); + /* + * 5.14.6.6.2.1 Device Requirements: Stream Information The device MUST + * NOT set undefined feature, format, rate and direction values. The + * device MUST initialize the padding bytes to 0. + */ + pcm_info[i] = val; + memset(&pcm_info[i].padding, 0, 5); + } + + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); + iov_from_buf(cmd->elem->in_sg, + cmd->elem->in_num, + sizeof(virtio_snd_hdr), + pcm_info, + sizeof(virtio_snd_pcm_info) * count); +} + /* * Set the given stream params. * Called by both virtio_snd_handle_pcm_set_params and during device * initialization. * Returns the response status code. (VIRTIO_SND_S_*). * * @s: VirtIOSound device * @params: The PCM params as defined in the virtio specification */ @@ -376,64 +456,66 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: + virtio_snd_handle_pcm_info(s, cmd); + break; case VIRTIO_SND_R_PCM_SET_PARAMS: case VIRTIO_SND_R_PCM_PREPARE: case VIRTIO_SND_R_PCM_START: case VIRTIO_SND_R_PCM_STOP: case VIRTIO_SND_R_PCM_RELEASE: cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ From patchwork Wed Oct 11 14:34:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417511 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 26ABACD6E7B for ; Wed, 11 Oct 2023 14:38:46 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJn-0000QC-9r; Wed, 11 Oct 2023 10:36:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJh-0000L9-Mn for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:06 -0400 Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJZ-0005VX-Mo for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:00 -0400 Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-4065f29e933so68238125e9.1 for ; Wed, 11 Oct 2023 07:35:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034955; x=1697639755; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uGiHMYRv14IcSlmSupNGhirJ2/W4kMmOARPqHyE4VPU=; b=ocGmUlDFV56yc8FW7voih73me7Ck53FbVyc7q0UYt7B78FRgzTERZKkJlENLxzG53Y l2IGcbDYNpD90Lgp+SQXcCgHXUabvcRmeBul0VAKi4CN4Vmver0ewLnNVLaZ6XcTQ4sj ELTDUkFEgKe17wSSp1qSBJDdrEMhH7zZJyqFxgqu2blQUfeqMNJ9Ir4Y12t2s+6WzIDM ouFVTKq0/F0/spWYVybAspqSAe1a/IGt+gGgDxdyyKlZqpEvh3WprCp8WZdTY4JRNQbH knHjclZQjF5e33v4deJeXztORiz5smc0YvVZ0PuydGMYklAmjwVah7Nm1McNwgTPguEp OJeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034955; x=1697639755; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uGiHMYRv14IcSlmSupNGhirJ2/W4kMmOARPqHyE4VPU=; b=v6NZzBo0cjQJA7nN92TcoN2E4oWgu0f3zIy7ZYfQVGK4WppSiGK0VvP811TqqlklBM TkOdQoi7PptKZE9vv2tqrU4JRPuCYMAwBf3ZNTu+NEje4rvb9bLtysipXsHPGYLJM3cy EJ7QC5SU3GgXPQSS+/DRasDQ7ZTvWbfYdXw2Q7rjqqOMWohzbKaadz7MKuSkNXAx4Bn/ zlVznB4Dwg3+8mteHz1d++XGQtqDr4sOfKsvmhURVseoNj4Jm1aATnGSd/IGjOprvrSG 6fAJbVsIyi/QBsX9S5RcgW7M97x/GgW3cuuOMQE4kDnZ17loaPfRH1TKHWwATyJ8jLPM NDGw== X-Gm-Message-State: AOJu0YyS2Me1nNIr9TWfNUyBeF0a8dbmGZ/aoYKqJcSWyICxM7gW4OGc DxSXfPAk5t/lqZcsYH/swiz2wPuIDTBWFZ3hpKw= X-Google-Smtp-Source: AGHT+IHfm/GVSkYzi/jgBe1C94QEHCsWNcA+O2R/2IjjIVGBKERH6RyOyullypRFo9aPnC6grME+5Q== X-Received: by 2002:adf:9795:0:b0:32d:8547:e440 with SMTP id s21-20020adf9795000000b0032d8547e440mr1808033wrb.38.1697034955079; Wed, 11 Oct 2023 07:35:55 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:54 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 05/11] virtio-sound: handle VIRTIO_SND_R_PCM_{START,STOP} Date: Wed, 11 Oct 2023 17:34:50 +0300 Message-Id: X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::331; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wm1-x331.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Handle the start and stop control messages for a stream_id. This request does nothing at the moment except for replying to it. Audio playback or capture will be started/stopped here in follow-up commits. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 1 + hw/virtio/virtio-snd.c | 49 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 88de2021c8..7044b110b7 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -165,6 +165,7 @@ virtio_snd_realize(void *snd) "snd %p: realize" virtio_snd_unrealize(void *snd) "snd %p: unrealize" virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32 +virtio_snd_handle_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32 virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index ec945d55a7..50b5a9d5df 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -426,29 +426,70 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) static const char *print_code(uint32_t code) { #define CASE(CODE) \ case VIRTIO_SND_R_##CODE: \ return "VIRTIO_SND_R_"#CODE switch (code) { CASE(JACK_INFO); CASE(JACK_REMAP); CASE(PCM_INFO); CASE(PCM_SET_PARAMS); CASE(PCM_PREPARE); CASE(PCM_RELEASE); CASE(PCM_START); CASE(PCM_STOP); CASE(CHMAP_INFO); default: return "invalid code"; } #undef CASE }; +/* + * Handles VIRTIO_SND_R_PCM_START. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + * @start: whether to start or stop the device + */ +static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s, + virtio_snd_ctrl_command *cmd, + bool start) +{ + VirtIOSoundPCMStream *stream; + virtio_snd_pcm_hdr req; + uint32_t stream_id; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + 0, + &req, + sizeof(virtio_snd_pcm_hdr)); + + if (msg_sz != sizeof(virtio_snd_pcm_hdr)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + stream_id = le32_to_cpu(req.stream_id); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); + trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" : + "VIRTIO_SND_R_PCM_STOP", stream_id); + stream = virtio_snd_pcm_get_stream(s, stream_id); + if (stream == NULL) { + error_report("Invalid stream id: %"PRIu32, req.stream_id); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + stream->active = start; +} + /* * The actual processing done in virtio_snd_process_cmdq(). * * @s: VirtIOSound device * @cmd: control command request */ @@ -456,66 +497,70 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: virtio_snd_handle_pcm_info(s, cmd); break; - case VIRTIO_SND_R_PCM_SET_PARAMS: - case VIRTIO_SND_R_PCM_PREPARE: case VIRTIO_SND_R_PCM_START: + virtio_snd_handle_pcm_start_stop(s, cmd, true); + break; case VIRTIO_SND_R_PCM_STOP: + virtio_snd_handle_pcm_start_stop(s, cmd, false); + break; + case VIRTIO_SND_R_PCM_SET_PARAMS: + case VIRTIO_SND_R_PCM_PREPARE: case VIRTIO_SND_R_PCM_RELEASE: cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ From patchwork Wed Oct 11 14:34:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417508 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6563ECD6E77 for ; Wed, 11 Oct 2023 14:36:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJm-0000Ne-4D; Wed, 11 Oct 2023 10:36:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJj-0000MA-Kt for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:08 -0400 Received: from mail-wr1-x433.google.com ([2a00:1450:4864:20::433]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJh-0005a4-1D for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:07 -0400 Received: by mail-wr1-x433.google.com with SMTP id ffacd0b85a97d-32d834ec222so923286f8f.0 for ; Wed, 11 Oct 2023 07:36:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034959; x=1697639759; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Rw730jgi6g3YenzrLg55f3D1p6dxBieuNtNcazwlqmU=; b=vlF+/erp5VGd98NqBgK1FXWHu8LT4U8Mxuv2B7CJ4+L1bLhKKJxwQ8yfHyj/S924ps aNIoBLRxcuM8K0ujXxVxb3U4rTR3BlQzssakQOWep1cJ4Xc0eHBV/hZC3Nand5LjCK+j 60PEKlCUeX6C+46JOpnnzeNGq0O68t331/YEhHcwR4dYH8kd34yjOHQ1juRmizUHnExF hjLjaFmK5p8riFSmRPN/rnZinGBjHv9JZkRNqRbYbcBsSVDfthmMvxIX+sA3j59w9FFq nt/RnlKgK98qIvZXjVQZ6jzqYwQLMF4q2mevMCcVPJUSb7F0GYxjbZHNskzCE7nzUZoR fsdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034959; x=1697639759; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Rw730jgi6g3YenzrLg55f3D1p6dxBieuNtNcazwlqmU=; b=GTGu74gEzkY3uA3zJe91fexGIv1OWvvTnnV24N4LAEu3JJFm+oO054rzb3W7Ok9aFw oMnQCCUSPGPefuLO/Vr7v7/Z1OCNdIId0l1DKtbFqJKybhNqoZb1yOhB9tmovlDr5XJy nEralgxXADNO4ZzhIDqT7rH/hC86W5W5BJIKEDY6+nv7/nWALrB7mJ7bW3Qw4RxN3coM X6NqzWt0WxWd+ipDeLoVmI6Iq/9/Q64fTvmOtyNLed1qYlBknUiQf9sUbXRTP6ExkIN3 nBw6j0nN+s+QfXI0R2lC0dre2UvmnHdb4JDNK7Eg6WBo7H5WXv+YEUUjlMaIpey8hBUB z50w== X-Gm-Message-State: AOJu0YxcN4btEKMQd4tYciV3NvgbW6pWzqtKSV4lIb5d+w6bQiZcGMz6 Pb7IBw4LFx/GJ8DhxrA7rLTht7ey8JIDVzAP4m8= X-Google-Smtp-Source: AGHT+IF+3L6b0MBszsmaOjc6DIX2F50wiSnpdQzbLyQt5nE7kus9Pdr8+R5HItSfKFp+DJtd0nikTQ== X-Received: by 2002:adf:fdd0:0:b0:31f:f9aa:a456 with SMTP id i16-20020adffdd0000000b0031ff9aaa456mr18703176wrs.2.1697034958750; Wed, 11 Oct 2023 07:35:58 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.35.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:35:58 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 06/11] virtio-sound: handle VIRTIO_SND_R_PCM_SET_PARAMS Date: Wed, 11 Oct 2023 17:34:51 +0300 Message-Id: <68ac43df35b1be1a43ce56b5a3de7822b1315901.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::433; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x433.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Handle the set parameters control request. It reconfigures a stream based on a guest's preference if the values are valid and supported. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 1 + hw/virtio/virtio-snd.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 7044b110b7..7907b610c1 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -163,6 +163,7 @@ virtio_snd_vm_state_running(void) "vm state running" virtio_snd_vm_state_stopped(void) "vm state stopped" virtio_snd_realize(void *snd) "snd %p: realize" virtio_snd_unrealize(void *snd) "snd %p: unrealize" +virtio_snd_handle_pcm_set_params(uint32_t stream) "VIRTIO_SND_PCM_SET_PARAMS called for stream %"PRIu32 virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32 virtio_snd_handle_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32 diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 50b5a9d5df..6a7545536b 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -250,43 +250,75 @@ static uint32_t virtio_snd_set_pcm_params(VirtIOSound *s, uint32_t stream_id, virtio_snd_pcm_set_params *params) { virtio_snd_pcm_set_params *st_params; if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n"); return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } st_params = virtio_snd_pcm_get_params(s, stream_id); if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) { error_report("Number of channels is not supported."); return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); } if (!(supported_formats & BIT(params->format))) { error_report("Stream format is not supported."); return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); } if (!(supported_rates & BIT(params->rate))) { error_report("Stream rate is not supported."); return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); } st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes); st_params->period_bytes = le32_to_cpu(params->period_bytes); st_params->features = le32_to_cpu(params->features); /* the following are uint8_t, so there's no need to bswap the values. */ st_params->channels = params->channels; st_params->format = params->format; st_params->rate = params->rate; return cpu_to_le32(VIRTIO_SND_S_OK); } +/* + * Handles the VIRTIO_SND_R_PCM_SET_PARAMS request. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + */ +static void virtio_snd_handle_pcm_set_params(VirtIOSound *s, + virtio_snd_ctrl_command *cmd) +{ + virtio_snd_pcm_set_params req = { 0 }; + uint32_t stream_id; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + 0, + &req, + sizeof(virtio_snd_pcm_set_params)); + + if (msg_sz != sizeof(virtio_snd_pcm_set_params)) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_set_params)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + stream_id = le32_to_cpu(req.hdr.stream_id); + trace_virtio_snd_handle_pcm_set_params(stream_id); + cmd->resp.code = virtio_snd_set_pcm_params(s, stream_id, &req); +} + /* * Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_* */ @@ -497,70 +529,72 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: virtio_snd_handle_pcm_info(s, cmd); break; case VIRTIO_SND_R_PCM_START: virtio_snd_handle_pcm_start_stop(s, cmd, true); break; case VIRTIO_SND_R_PCM_STOP: virtio_snd_handle_pcm_start_stop(s, cmd, false); break; case VIRTIO_SND_R_PCM_SET_PARAMS: + virtio_snd_handle_pcm_set_params(s, cmd); + break; case VIRTIO_SND_R_PCM_PREPARE: case VIRTIO_SND_R_PCM_RELEASE: cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ From patchwork Wed Oct 11 14:34:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417516 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EB67BCD6E7B for ; Wed, 11 Oct 2023 14:39:19 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJp-0000Z3-4D; Wed, 11 Oct 2023 10:36:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJk-0000Mi-KH for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:09 -0400 Received: from mail-wm1-x330.google.com ([2a00:1450:4864:20::330]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJh-0005ax-1M for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:07 -0400 Received: by mail-wm1-x330.google.com with SMTP id 5b1f17b1804b1-4075c58ac39so13207195e9.3 for ; Wed, 11 Oct 2023 07:36:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034962; x=1697639762; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FlzxZ7mnmxeFu1X7bYV06Uym0W+edwy+53fqD4+XWAg=; b=muO63A2Hn9kdJcsKpR4gLBvPdLpvury6wZhkrYLahzK0A+uDI+XYhG1ynBxWKaFmDM koy0CjJAcIqFL/CefN/X0RupLTIUq0Fxj3bIobp8z/tJw7Ld43uXeCOcka1/PHY0I7tD KTuGX5Ca7Mc2s4CkISgHaWV884P24QQT6QwnmK8BIe3jOhZYvgdxSdvxogRriadMqLiG SqaR61LqNVMHRTcEXLnRBieGWGmAwO8mbZ8JrRf+9fD6fKFC3qhTd5o6bUc0da7Cgx8q po9/xH44bHlNBifDNivKQ2OdQtpiPQj4rEUOD6B/hds6CokEajNmz3f3j09yELP4SUOD oquQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034962; x=1697639762; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FlzxZ7mnmxeFu1X7bYV06Uym0W+edwy+53fqD4+XWAg=; b=spXbqZoI0u3qe/ZeXxC1jtnCbtogbJd1XzmLl+jaj1bNJ9LMlfv9E9GtXbd2EFsH+K LXX/EtfQJP7bXJkGBsr71nwgfoOLMF8wzrdaA6PR9MiS0BifjCXvAGuCLMSM0oS26bii TTuO9y3ZhcnVX0eGDBqPmBBCHpPz9g5FADB9WcQNXv+wiGjkJ1NkfvXqpfIzAX5AaoYC NQHzYfyoGb3oEuKBpMp8CQD5pC0L3OabN76VVF05fEiESLHq0aLwYDtMkLvHSJnMpXwh lOUm8fIcIM0nR1g0Y5z8OvdSgI3NvbaQoODiEHFyepVIYl8fVtsYmNC5+nHal38vSXlx WjKA== X-Gm-Message-State: AOJu0YxaB/r/jqkUYf7WPKvhEPHkducejDi6fKXzdQ9YtqEZCIY00Ukq RlmS6hxbVnHbA9JmoWmzjgnJbBVA1yu4tofZCA4= X-Google-Smtp-Source: AGHT+IEy6ANFVjRMsVaA3+MuAHnAnbppknfU49sJ+rmVaBGev697aR7wsA2mUOEhe5/eExPyJ00l+w== X-Received: by 2002:a7b:cd85:0:b0:406:5463:3f51 with SMTP id y5-20020a7bcd85000000b0040654633f51mr19162956wmj.25.1697034962538; Wed, 11 Oct 2023 07:36:02 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.36.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:36:02 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 07/11] virtio-sound: handle VIRTIO_SND_R_PCM_PREPARE Date: Wed, 11 Oct 2023 17:34:52 +0300 Message-Id: <175e6fbe7501f27a1b6d8fcfaa3f47a4ba2ece74.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::330; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wm1-x330.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Handles the PCM prepare control request. It initializes a PCM stream when the guests asks for it. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/virtio-snd.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 6a7545536b..49cd9f3ca4 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -458,30 +458,52 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) static const char *print_code(uint32_t code) { #define CASE(CODE) \ case VIRTIO_SND_R_##CODE: \ return "VIRTIO_SND_R_"#CODE switch (code) { CASE(JACK_INFO); CASE(JACK_REMAP); CASE(PCM_INFO); CASE(PCM_SET_PARAMS); CASE(PCM_PREPARE); CASE(PCM_RELEASE); CASE(PCM_START); CASE(PCM_STOP); CASE(CHMAP_INFO); default: return "invalid code"; } #undef CASE }; +/* + * Handles VIRTIO_SND_R_PCM_PREPARE. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + */ +static void virtio_snd_handle_pcm_prepare(VirtIOSound *s, + virtio_snd_ctrl_command *cmd) +{ + uint32_t stream_id; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + sizeof(virtio_snd_hdr), + &stream_id, + sizeof(stream_id)); + + stream_id = le32_to_cpu(stream_id); + cmd->resp.code = msg_sz == sizeof(stream_id) + ? virtio_snd_pcm_prepare(s, stream_id) + : cpu_to_le32(VIRTIO_SND_S_BAD_MSG); +} + /* * Handles VIRTIO_SND_R_PCM_START. * * @s: VirtIOSound device * @cmd: The request command queue element from VirtIOSound cmdq field * @start: whether to start or stop the device */ @@ -529,72 +551,74 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: virtio_snd_handle_pcm_info(s, cmd); break; case VIRTIO_SND_R_PCM_START: virtio_snd_handle_pcm_start_stop(s, cmd, true); break; case VIRTIO_SND_R_PCM_STOP: virtio_snd_handle_pcm_start_stop(s, cmd, false); break; case VIRTIO_SND_R_PCM_SET_PARAMS: virtio_snd_handle_pcm_set_params(s, cmd); break; case VIRTIO_SND_R_PCM_PREPARE: + virtio_snd_handle_pcm_prepare(s, cmd); + break; case VIRTIO_SND_R_PCM_RELEASE: cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ From patchwork Wed Oct 11 14:34:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417514 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5A1BACD6E7E for ; Wed, 11 Oct 2023 14:39:14 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJo-0000WU-Df; Wed, 11 Oct 2023 10:36:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJn-0000Qr-Da for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:11 -0400 Received: from mail-wr1-x434.google.com ([2a00:1450:4864:20::434]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJl-0005iA-DL for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:11 -0400 Received: by mail-wr1-x434.google.com with SMTP id ffacd0b85a97d-323ef9a8b59so6549863f8f.3 for ; Wed, 11 Oct 2023 07:36:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034966; x=1697639766; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2TDi/nXVyf7XMp9ikxQgSEBIh+2+xuwQ3eJjsMsNyQ0=; b=wNpxiUdzHfibTvZ/+og2gqvB9zqSd8e6NmygIyyGCRn67GojPPRQpslyx9gGFyI88h 0jf3l/DhefguRuljW1gP4AshcDTR8ro97znlD2IvoYhHC9K/jpM51eM/VOERt5vYYjM7 t9suaLpE+TAaIiexZyGgpGjDspC4u5KnWKjWUQ+YspraVQqeBcsPMbIuOi1ZsaQzKjE1 fQ2ps33F7UfLylBD9C8Kr66SsvvLIfxccpN6sZOgVTn+LHr+HKXy6un4eQZuyHneM2sT /cfJGq4LtvWW8uCMDB9jYLLV8JV7Xl2WLNIgRTjMHuIIL+1lbcKMy6heAN9mch5P2QNS nZHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034966; x=1697639766; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2TDi/nXVyf7XMp9ikxQgSEBIh+2+xuwQ3eJjsMsNyQ0=; b=ozOg63+FSt3YB+CnbWbx5U/dS5v1AMnNcQyB3aL96Vlw4sdQW6H8+SxQ4okiQ/ZO9p 9igeVEBNaW2u5aqIG3fnG+NYAdNhvTj4utZjhNU6aaw4Kl0YCixCjXJecfUs6VJ3hEk1 S7s4n2dCWm1ZX+NoJ5FT/RaB0V9lO6o3ejNxmyUPYU8udbq25h7UoR/Pdg8ZytTsNrE7 mdA7dMHCGfhHqaDI+R6mmaXNBIQfc/jc1KMjMsbvxcnouREXmok80fsMwJkyFXxtuuCr tgwbWQgXD7KimQQ5ISa1uaZBjAMhc6revHpQUBlBjgfa9v7CfoO9llddlQB2rLnaMJVt xguw== X-Gm-Message-State: AOJu0Yzd6DkCSYN7EypCzwWm+OrzWa6clRBrIz5q0nckBuxQulA1tyOL WOALRcBh5NsdWab93bNXPs8O4pnaH+pEfOy4YGI= X-Google-Smtp-Source: AGHT+IF4wB7j05FjHK4jEeiqJO0MxSlyZiLlHDr1uQfBbMrOEE0n38QViidA48CBbc5RO27fyHDasw== X-Received: by 2002:a5d:664a:0:b0:31f:f91c:d872 with SMTP id f10-20020a5d664a000000b0031ff91cd872mr20594249wrw.19.1697034966549; Wed, 11 Oct 2023 07:36:06 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.36.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:36:06 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 08/11] virtio-sound: handle VIRTIO_SND_R_PCM_RELEASE Date: Wed, 11 Oct 2023 17:34:53 +0300 Message-Id: <93a5b96b58b6623e99953ce1440627760eca7cc2.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::434; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x434.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Handle the PCM release control request, which is necessary for flushing pending sound IO. No IO is handled yet so currently it only replies to the request. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 1 + hw/virtio/virtio-snd.c | 48 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 7907b610c1..b0789a6e7e 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -167,6 +167,7 @@ virtio_snd_handle_pcm_set_params(uint32_t stream) "VIRTIO_SND_PCM_SET_PARAMS cal virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32 virtio_snd_handle_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32 +virtio_snd_handle_pcm_release(uint32_t stream) "VIRTIO_SND_PCM_RELEASE called for stream %"PRIu32 virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 49cd9f3ca4..ca873fd6d4 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -503,47 +503,93 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s, /* * Handles VIRTIO_SND_R_PCM_START. * * @s: VirtIOSound device * @cmd: The request command queue element from VirtIOSound cmdq field * @start: whether to start or stop the device */ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s, virtio_snd_ctrl_command *cmd, bool start) { VirtIOSoundPCMStream *stream; virtio_snd_pcm_hdr req; uint32_t stream_id; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &req, sizeof(virtio_snd_pcm_hdr)); if (msg_sz != sizeof(virtio_snd_pcm_hdr)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr)); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream_id = le32_to_cpu(req.stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" : "VIRTIO_SND_R_PCM_STOP", stream_id); stream = virtio_snd_pcm_get_stream(s, stream_id); if (stream == NULL) { error_report("Invalid stream id: %"PRIu32, req.stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream->active = start; } +/* + * Handles VIRTIO_SND_R_PCM_RELEASE. Releases the buffer resources allocated to + * a stream. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + */ +static void virtio_snd_handle_pcm_release(VirtIOSound *s, + virtio_snd_ctrl_command *cmd) +{ + uint32_t stream_id; + VirtIOSoundPCMStream *stream; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + sizeof(virtio_snd_hdr), + &stream_id, + sizeof(stream_id)); + + if (msg_sz != sizeof(stream_id)) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(stream_id)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + stream_id = le32_to_cpu(stream_id); + trace_virtio_snd_handle_pcm_release(stream_id); + stream = virtio_snd_pcm_get_stream(s, stream_id); + if (stream == NULL) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + error_report("already released stream %"PRIu32, stream_id); + virtio_error(VIRTIO_DEVICE(s), + "already released stream %"PRIu32, + stream_id); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); +} + /* * The actual processing done in virtio_snd_process_cmdq(). * * @s: VirtIOSound device * @cmd: control command request */ @@ -551,74 +597,74 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: virtio_snd_handle_pcm_info(s, cmd); break; case VIRTIO_SND_R_PCM_START: virtio_snd_handle_pcm_start_stop(s, cmd, true); break; case VIRTIO_SND_R_PCM_STOP: virtio_snd_handle_pcm_start_stop(s, cmd, false); break; case VIRTIO_SND_R_PCM_SET_PARAMS: virtio_snd_handle_pcm_set_params(s, cmd); break; case VIRTIO_SND_R_PCM_PREPARE: virtio_snd_handle_pcm_prepare(s, cmd); break; case VIRTIO_SND_R_PCM_RELEASE: - cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); + virtio_snd_handle_pcm_release(s, cmd); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ From patchwork Wed Oct 11 14:34:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417509 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 78FB0CD6E77 for ; Wed, 11 Oct 2023 14:37:06 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJw-000138-TD; Wed, 11 Oct 2023 10:36:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJu-000111-E1 for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:18 -0400 Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJp-0005nM-Ru for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:18 -0400 Received: by mail-wm1-x32d.google.com with SMTP id 5b1f17b1804b1-40572aeb6d0so64889925e9.1 for ; Wed, 11 Oct 2023 07:36:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034971; x=1697639771; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+5MYIcjXsp03D+e3fMwDl/7RfUyaMrEKMyOxa1Vp02k=; b=UF53E+jnHfJq4imTD3zE9o/osfv0sECM+4LwBVLaAipK81zbHLInMqgfhue+JoGpLu MAlGOF7cQitEbK8rfTU9d2QTCRY8BXaG5uE0oTzN57AMzMbfGu5dSkp5r76QZ9MyBJX6 Ti9YnB7nlJ9DhKWqyJ3FjfrIGbvcwGgeBRwPoMJg+4Q3Czj8gA2XjPN7AYszyyr3CCqW mxgjZtd63S2siv9nU5gN9TFvMwvUhdVgBL62NACgI3oqg9LsQgU+rkDRczHuHal8V08R k+ZTJwb6mJehwi1Gg4+E0Me5nOf0NUZK2L/xCa2oWNJ6b/SvPR5Ic31WOPhZWG4dAsGQ VLzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034971; x=1697639771; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+5MYIcjXsp03D+e3fMwDl/7RfUyaMrEKMyOxa1Vp02k=; b=JW/vsJIP9yP0NfYss0fkjMU3i6hWjzgsLLx69ejAkGr5MOxtywXkUyVswCn88VsgBR xGL3LPzXNr0HdOdDmv3O0oCg1t6eJC0ANy8QAWEP4l3xqKX8Th5apaOscw6oDGfoT3Oh 5WrtTphvAdrA/6mKWEnIABTT0QJmKzhVK0PDE5OMpns+DVpGXTieeU94ETXW1L8Aufzx SI9NTC6VqpCafHQ+flfR6ohQHVZhNX5AQle56g2VHGCDp4MB6p0dG1orMxyl1MkVgAx4 viX1vjbe9Lbzw/vWeSUOgPa3O12U7gAhmER/OI542VMZwZ6Wr/kgAcsSQlinTtcmjNen S+UA== X-Gm-Message-State: AOJu0Yy4FAwm4tVG07JBWKqHQ8A0OWokUJHPKewcWIkLAja2cTisf6Kf Vd3aMn+WMI1IbUIKmcTlfkjkJ0g/hNDinxHWJIc= X-Google-Smtp-Source: AGHT+IE7UsxrldRHVTESNeH/uhZmvzn7X6BlVmiaIewMo12tS181YNnEFHDFKQ15YqJhrYtKLFcMmA== X-Received: by 2002:a05:6000:1cca:b0:320:8d6:74f5 with SMTP id bf10-20020a0560001cca00b0032008d674f5mr17426398wrb.28.1697034971347; Wed, 11 Oct 2023 07:36:11 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.36.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:36:10 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 09/11] virtio-sound: implement audio output (TX) Date: Wed, 11 Oct 2023 17:34:54 +0300 Message-Id: <34be52e56ea9ecae9cb3e9efc05688de967af84e.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32d; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wm1-x32d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis Handle output IO messages in the transmit (TX) virtqueue. It allocates a VirtIOSoundPCMBuffer for each IO message and copies the data buffer to it. When the IO buffer is written to the host's sound card, the guest will be notified that it has been consumed. The lifetime of an IO message is: 1. Guest sends IO message to TX virtqueue. 2. QEMU adds it to the appropriate stream's IO buffer queue. 3. Sometime later, the host audio backend calls the output callback, virtio_snd_pcm_out_cb(), which is defined with an AUD_open_out() call. The callback gets an available number of bytes the backend can receive. Then it writes data from the IO buffer queue to the backend. If at any time a buffer is exhausted, it is returned to the guest as completed. 4. If the guest releases the stream, its buffer queue is flushed by attempting to write any leftover data to the audio backend and releasing all IO messages back to the guest. This is how according to the spec the guest knows the release was successful. Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin Signed-off-by: Anton Yakovlev Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 2 + hw/virtio/virtio-snd.c | 288 ++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-snd.h | 47 ++++++ 3 files changed, 332 insertions(+), 5 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index b0789a6e7e..a31531970d 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -171,3 +171,5 @@ virtio_snd_handle_pcm_release(uint32_t stream) "VIRTIO_SND_PCM_RELEASE called fo virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" +virtio_snd_pcm_stream_flush(uint32_t stream) "flushing stream %"PRIu32 +virtio_snd_handle_xfer(void) "tx/rx queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index ca873fd6d4..5e9513fb26 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -32,6 +32,10 @@ #define VIRTIO_SOUND_CHMAP_DEFAULT 0 #define VIRTIO_SOUND_HDA_FN_NID 0 +static void virtio_snd_pcm_out_cb(void *data, int available); +static void virtio_snd_process_cmdq(VirtIOSound *s); +static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream); + static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8) | BIT(VIRTIO_SND_PCM_FMT_U8) | BIT(VIRTIO_SND_PCM_FMT_S16) @@ -123,6 +127,13 @@ virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config) } +static void +virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer) +{ + g_free(buffer->elem); + g_free(buffer); +} + static void virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd) { @@ -392,66 +403,88 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as, /* * Close a stream and free all its resources. * * @stream: VirtIOSoundPCMStream *stream */ static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream) { + if (stream) { + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { + virtio_snd_pcm_flush(stream); + AUD_close_out(&stream->pcm->snd->card, stream->voice.out); + stream->voice.out = NULL; + } + } } /* * Prepares a VirtIOSound card stream. * Returns the response status code. (VIRTIO_SND_S_*). * * @s: VirtIOSound device * @stream_id: stream id */ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) { audsettings as; virtio_snd_pcm_set_params *params; VirtIOSoundPCMStream *stream; if (s->pcm->streams == NULL || s->pcm->pcm_params == NULL || stream_id >= s->snd_conf.streams) { return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } params = virtio_snd_pcm_get_params(s, stream_id); if (params == NULL) { return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } stream = virtio_snd_pcm_get_stream(s, stream_id); if (stream == NULL) { stream = g_new0(VirtIOSoundPCMStream, 1); stream->active = false; stream->id = stream_id; stream->pcm = s->pcm; stream->s = s; + qemu_mutex_init(&stream->queue_mutex); + QSIMPLEQ_INIT(&stream->queue); + QSIMPLEQ_INIT(&stream->invalid); /* * stream_id >= s->snd_conf.streams was checked before so this is * in-bounds */ s->pcm->streams[stream_id] = stream; } virtio_snd_get_qemu_audsettings(&as, params); stream->info.direction = stream_id < s->snd_conf.streams / 2 + (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT; stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID; stream->info.features = 0; stream->info.channels_min = 1; stream->info.channels_max = as.nchannels; stream->info.formats = supported_formats; stream->info.rates = supported_rates; stream->params = *params; stream->positions[0] = VIRTIO_SND_CHMAP_FL; stream->positions[1] = VIRTIO_SND_CHMAP_FR; stream->as = as; + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { + stream->voice.out = AUD_open_out(&s->card, + stream->voice.out, + "virtio-sound.out", + stream, + virtio_snd_pcm_out_cb, + &as); + AUD_set_volume_out(stream->voice.out, 0, 255, 255); + } else { + qemu_log_mask(LOG_UNIMP, "virtio_snd: input/capture is unimplemented."); + } + return cpu_to_le32(VIRTIO_SND_S_OK); } @@ -503,93 +536,136 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s, /* * Handles VIRTIO_SND_R_PCM_START. * * @s: VirtIOSound device * @cmd: The request command queue element from VirtIOSound cmdq field * @start: whether to start or stop the device */ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s, virtio_snd_ctrl_command *cmd, bool start) { VirtIOSoundPCMStream *stream; virtio_snd_pcm_hdr req; uint32_t stream_id; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &req, sizeof(virtio_snd_pcm_hdr)); if (msg_sz != sizeof(virtio_snd_pcm_hdr)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr)); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream_id = le32_to_cpu(req.stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" : "VIRTIO_SND_R_PCM_STOP", stream_id); + stream = virtio_snd_pcm_get_stream(s, stream_id); - if (stream == NULL) { - error_report("Invalid stream id: %"PRIu32, req.stream_id); + if (stream) { + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + stream->active = start; + } + if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { + AUD_set_active_out(stream->voice.out, start); + } + } else { + error_report("Invalid stream id: %"PRIu32, stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream->active = start; } /* - * Handles VIRTIO_SND_R_PCM_RELEASE. Releases the buffer resources allocated to - * a stream. + * Returns the number of I/O messages that are being processed. + * + * @stream: VirtIOSoundPCMStream + */ +static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream) +{ + VirtIOSoundPCMBuffer *buffer, *next; + size_t count = 0; + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) { + count += 1; + } + QSIMPLEQ_FOREACH_SAFE(buffer, &stream->invalid, entry, next) { + count += 1; + } + } + return count; +} + +/* + * Handles VIRTIO_SND_R_PCM_RELEASE. * * @s: VirtIOSound device * @cmd: The request command queue element from VirtIOSound cmdq field */ static void virtio_snd_handle_pcm_release(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t stream_id; VirtIOSoundPCMStream *stream; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, sizeof(virtio_snd_hdr), &stream_id, sizeof(stream_id)); if (msg_sz != sizeof(stream_id)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(stream_id)); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream_id = le32_to_cpu(stream_id); trace_virtio_snd_handle_pcm_release(stream_id); stream = virtio_snd_pcm_get_stream(s, stream_id); if (stream == NULL) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ error_report("already released stream %"PRIu32, stream_id); virtio_error(VIRTIO_DEVICE(s), "already released stream %"PRIu32, stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } + + if (virtio_snd_pcm_get_io_msgs_count(stream)) { + /* + * virtio-v1.2-csd01, 5.14.6.6.5.1, + * Device Requirements: Stream Release + * + * - The device MUST complete all pending I/O messages for the + * specified stream ID. + * - The device MUST NOT complete the control request while there + * are pending I/O messages for the specified stream ID. + */ + trace_virtio_snd_pcm_stream_flush(stream_id); + virtio_snd_pcm_flush(stream); + } + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); } /* * The actual processing done in virtio_snd_process_cmdq(). * * @s: VirtIOSound device * @cmd: control command request */ @@ -728,19 +804,121 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) /* * The event virtqueue handler. * Not implemented yet. * * @vdev: VirtIOSound device * @vq: event vq */ static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq) { qemu_log_mask(LOG_UNIMP, "virtio_snd: event queue is unimplemented.\n"); trace_virtio_snd_handle_event(); } +/* + * The tx virtqueue handler. Makes the buffers available to their respective + * streams for consumption. + * + * @vdev: VirtIOSound device + * @vq: tx virtqueue + */ +static void virtio_snd_handle_tx(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + VirtIOSoundPCMStream *stream = NULL; + VirtIOSoundPCMBuffer *buffer; + VirtQueueElement *elem; + size_t msg_sz, size; + virtio_snd_pcm_xfer hdr; + virtio_snd_pcm_status resp = { 0 }; + uint32_t stream_id; + /* + * If any of the I/O messages are invalid, put them in stream->invalid and + * return them after the for loop. + */ + bool must_empty_invalid_queue = false; + + if (!virtio_queue_ready(vq)) { + return; + } + trace_virtio_snd_handle_xfer(); + + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + /* get the message hdr object */ + msg_sz = iov_to_buf(elem->out_sg, + elem->out_num, + 0, + &hdr, + sizeof(virtio_snd_pcm_xfer)); + if (msg_sz != sizeof(virtio_snd_pcm_xfer)) { + goto tx_err; + } + stream_id = le32_to_cpu(hdr.stream_id); + + if (stream_id >= s->snd_conf.streams + || s->pcm->streams[stream_id] == NULL) { + goto tx_err; + } + + stream = s->pcm->streams[stream_id]; + if (stream->info.direction != VIRTIO_SND_D_OUTPUT) { + goto tx_err; + } + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + size = iov_size(elem->out_sg, elem->out_num) - msg_sz; + + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size); + buffer->elem = elem; + buffer->populated = false; + buffer->vq = vq; + buffer->size = size; + buffer->offset = 0; + + QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry); + } + continue; + +tx_err: + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + must_empty_invalid_queue = true; + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); + buffer->elem = elem; + buffer->vq = vq; + QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry); + } + } + + if (must_empty_invalid_queue) { + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->invalid)) { + buffer = QSIMPLEQ_FIRST(&stream->invalid); + + resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + 0, + &resp, + sizeof(virtio_snd_pcm_status)); + virtqueue_push(vq, buffer->elem, sizeof(virtio_snd_pcm_status)); + QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry); + virtio_snd_pcm_buffer_free(buffer); + } + /* + * Notify vq about virtio_snd_pcm_status responses. + * Buffer responses must be notified separately later. + */ + virtio_notify(vdev, vq); + } + } +} + /* * Stub buffer virtqueue handler. * * @vdev: VirtIOSound device * @vq: virtqueue */ @@ -776,116 +954,216 @@ virtio_snd_vm_state_change(void *opaque, bool running, static void virtio_snd_realize(DeviceState *dev, Error **errp) { ERRP_GUARD(); VirtIOSound *vsnd = VIRTIO_SND(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); virtio_snd_pcm_set_params default_params = { 0 }; uint32_t status; vsnd->pcm = NULL; vsnd->vmstate = qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); trace_virtio_snd_realize(vsnd); vsnd->pcm = g_new0(VirtIOSoundPCM, 1); vsnd->pcm->snd = vsnd; vsnd->pcm->streams = g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams); vsnd->pcm->pcm_params = g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams); virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); /* set number of jacks and streams */ if (vsnd->snd_conf.jacks > 8) { error_setg(errp, "Invalid number of jacks: %"PRIu32, vsnd->snd_conf.jacks); return; } if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) { error_setg(errp, "Invalid number of streams: %"PRIu32, vsnd->snd_conf.streams); return; } if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) { error_setg(errp, "Invalid number of channel maps: %"PRIu32, vsnd->snd_conf.chmaps); return; } AUD_register_card("virtio-sound", &vsnd->card, errp); /* set default params for all streams */ default_params.features = 0; default_params.buffer_bytes = cpu_to_le32(8192); default_params.period_bytes = cpu_to_le32(2048); default_params.channels = 2; default_params.format = VIRTIO_SND_PCM_FMT_S16; default_params.rate = VIRTIO_SND_PCM_RATE_48000; vsnd->queues[VIRTIO_SND_VQ_CONTROL] = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl); vsnd->queues[VIRTIO_SND_VQ_EVENT] = virtio_add_queue(vdev, 64, virtio_snd_handle_event); vsnd->queues[VIRTIO_SND_VQ_TX] = - virtio_add_queue(vdev, 64, virtio_snd_handle_xfer); + virtio_add_queue(vdev, 64, virtio_snd_handle_tx); vsnd->queues[VIRTIO_SND_VQ_RX] = virtio_add_queue(vdev, 64, virtio_snd_handle_xfer); qemu_mutex_init(&vsnd->cmdq_mutex); QTAILQ_INIT(&vsnd->cmdq); for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { status = virtio_snd_set_pcm_params(vsnd, i, &default_params); if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { error_setg(errp, "Can't initalize stream params, device responded with %s.", print_code(status)); return; } status = virtio_snd_pcm_prepare(vsnd, i); if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { error_setg(errp, "Can't prepare streams, device responded with %s.", print_code(status)); return; } } } +static inline void return_tx_buffer(VirtIOSoundPCMStream *stream, + VirtIOSoundPCMBuffer *buffer) +{ + virtio_snd_pcm_status resp = { 0 }; + resp.status = cpu_to_le32(VIRTIO_SND_S_OK); + resp.latency_bytes = cpu_to_le32((uint32_t)buffer->size); + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + 0, + &resp, + sizeof(virtio_snd_pcm_status)); + virtqueue_push(buffer->vq, + buffer->elem, + sizeof(virtio_snd_pcm_status)); + virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq); + QSIMPLEQ_REMOVE(&stream->queue, + buffer, + VirtIOSoundPCMBuffer, + entry); + virtio_snd_pcm_buffer_free(buffer); +} + +/* + * AUD_* output callback. + * + * @data: VirtIOSoundPCMStream stream + * @available: number of bytes that can be written with AUD_write() + */ +static void virtio_snd_pcm_out_cb(void *data, int available) +{ + VirtIOSoundPCMStream *stream = data; + VirtIOSoundPCMBuffer *buffer; + size_t size; + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->queue)) { + buffer = QSIMPLEQ_FIRST(&stream->queue); + if (!virtio_queue_ready(buffer->vq)) { + return; + } + if (!stream->active) { + /* Stream has stopped, so do not perform AUD_write. */ + return_tx_buffer(stream, buffer); + continue; + } + if (!buffer->populated) { + iov_to_buf(buffer->elem->out_sg, + buffer->elem->out_num, + sizeof(virtio_snd_pcm_xfer), + buffer->data, + buffer->size); + buffer->populated = true; + } + for (;;) { + size = AUD_write(stream->voice.out, + buffer->data + buffer->offset, + MIN(buffer->size, available)); + assert(size <= MIN(buffer->size, available)); + if (size == 0) { + /* break out of both loops */ + available = 0; + break; + } + buffer->size -= size; + buffer->offset += size; + available -= size; + if (buffer->size < 1) { + return_tx_buffer(stream, buffer); + break; + } + if (!available) { + break; + } + } + if (!available) { + break; + } + } + } +} + +/* + * Flush all buffer data from this stream's queue into the driver's virtual + * queue. + * + * @stream: VirtIOSoundPCMStream *stream + */ +static inline void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream) +{ + VirtIOSoundPCMBuffer *buffer; + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->queue)) { + buffer = QSIMPLEQ_FIRST(&stream->queue); + return_tx_buffer(stream, buffer); + } + } +} + static void virtio_snd_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSound *vsnd = VIRTIO_SND(dev); VirtIOSoundPCMStream *stream; qemu_del_vm_change_state_handler(vsnd->vmstate); trace_virtio_snd_unrealize(vsnd); if (vsnd->pcm) { if (vsnd->pcm->streams) { for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { stream = vsnd->pcm->streams[i]; if (stream) { virtio_snd_process_cmdq(stream->s); virtio_snd_pcm_close(stream); + qemu_mutex_destroy(&stream->queue_mutex); g_free(stream); } } g_free(vsnd->pcm->streams); } g_free(vsnd->pcm->pcm_params); g_free(vsnd->pcm); vsnd->pcm = NULL; } AUD_remove_card(&vsnd->card); qemu_mutex_destroy(&vsnd->cmdq_mutex); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]); virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]); virtio_cleanup(vdev); } diff --git a/include/hw/virtio/virtio-snd.h b/include/hw/virtio/virtio-snd.h index 4b4aaffff1..ee64f2a537 100644 --- a/include/hw/virtio/virtio-snd.h +++ b/include/hw/virtio/virtio-snd.h @@ -77,6 +77,50 @@ typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command; typedef struct VirtIOSoundPCM VirtIOSoundPCM; +typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer; + +/* + * The VirtIO sound spec reuses layouts and values from the High Definition + * Audio spec (virtio/v1.2: 5.14 Sound Device). This struct handles each I/O + * message's buffer (virtio/v1.2: 5.14.6.8 PCM I/O Messages). + * + * In the case of TX (i.e. playback) buffers, we defer reading the raw PCM data + * from the virtqueue until QEMU's sound backsystem calls the output callback. + * This is tracked by the `bool populated;` field, which is set to true when + * data has been read into our own buffer for consumption. + * + * VirtIOSoundPCMBuffer has a dynamic size since it includes the raw PCM data + * in its allocation. It must be initialized and destroyed as follows: + * + * size_t size = [[derived from owned VQ element descriptor sizes]]; + * buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size); + * buffer->elem = [[owned VQ element]]; + * + * [..] + * + * g_free(buffer->elem); + * g_free(buffer); + */ +struct VirtIOSoundPCMBuffer { + QSIMPLEQ_ENTRY(VirtIOSoundPCMBuffer) entry; + VirtQueueElement *elem; + VirtQueue *vq; + size_t size; + /* + * In TX / Plaback, `offset` represents the first unused position inside + * `data`. If `offset == size` then there are no unused data left. + */ + uint64_t offset; + /* Used for the TX queue for lazy I/O copy from `elem` */ + bool populated; + /* + * VirtIOSoundPCMBuffer is an unsized type because it ends with an array of + * bytes. The size of `data` is determined from the I/O message's read-only + * or write-only size when allocating VirtIOSoundPCMBuffer. + */ + uint8_t data[]; +}; + struct VirtIOSoundPCM { VirtIOSound *snd; /* @@ -93,74 +137,77 @@ struct VirtIOSoundPCM { struct VirtIOSoundPCMStream { VirtIOSoundPCM *pcm; virtio_snd_pcm_info info; virtio_snd_pcm_set_params params; uint32_t id; /* channel position values (VIRTIO_SND_CHMAP_XXX) */ uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE]; VirtIOSound *s; bool flushing; audsettings as; union { SWVoiceIn *in; SWVoiceOut *out; } voice; + QemuMutex queue_mutex; bool active; + QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue; + QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid; }; /* * PCM stream state machine. * ------------------------- * * 5.14.6.6.1 PCM Command Lifecycle * ================================ * * A PCM stream has the following command lifecycle: * - `SET PARAMETERS` * The driver negotiates the stream parameters (format, transport, etc) with * the device. * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. * - `PREPARE` * The device prepares the stream (allocates resources, etc). * Possible valid transitions: `SET PARAMETERS`, `PREPARE`, `START`, * `RELEASE`. Output only: the driver transfers data for pre-buffing. * - `START` * The device starts the stream (unmute, putting into running state, etc). * Possible valid transitions: `STOP`. * The driver transfers data to/from the stream. * - `STOP` * The device stops the stream (mute, putting into non-running state, etc). * Possible valid transitions: `START`, `RELEASE`. * - `RELEASE` * The device releases the stream (frees resources, etc). * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. * * +---------------+ +---------+ +---------+ +-------+ +-------+ * | SetParameters | | Prepare | | Release | | Start | | Stop | * +---------------+ +---------+ +---------+ +-------+ +-------+ * |- | | | | * || | | | | * |< | | | | * |------------->| | | | * |<-------------| | | | * | |- | | | * | || | | | * | |< | | | * | |--------------------->| | * | |---------->| | | * | | | |-------->| * | | | |<--------| * | | |<-------------------| * |<-------------------------| | | * | |<----------| | | * * CTRL in the VirtIOSound device * ============================== * * The control messages that affect the state of a stream arrive in the * `virtio_snd_handle_ctrl()` queue callback and are of type `struct * virtio_snd_ctrl_command`. They are stored in a queue field in the device * type, `VirtIOSound`. This allows deferring the CTRL request completion if * it's not immediately possible due to locking/state reasons. * * The CTRL message is finally handled in `process_cmd()`. */ From patchwork Wed Oct 11 14:34:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417513 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E1782CD6E7D for ; Wed, 11 Oct 2023 14:39:13 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaJz-00017o-0h; Wed, 11 Oct 2023 10:36:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJx-00015m-1C for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:21 -0400 Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJu-0005ny-1s for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:20 -0400 Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-40684f53bfcso64213955e9.0 for ; Wed, 11 Oct 2023 07:36:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034976; x=1697639776; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=loCeEjYyI3MRpfj/jU2k9YVJvBGocqpOc4S1cbP0uGc=; b=EYtFoV9RWhIVW2/1OkyYnyGzOdwXggVzNwv9r9Qi4vEdlCn3mHYckW4i24ZgWFK9Yr A4QTUoxo47pwd1mJnfFIlsePbO7o5nVP2eW8NkzacGNySTgU+1S71BZtshb3yz/R6/l+ Dv6hQvHQ6puV3AGpXiVOp9DwROPTnnYYLQ0wgqBbiQsZ9K37o/criH+tB0dE5kR7Q1mS 5D7Fj+quixezffEuufxWJtG3/LQPvcJoWT0OGIYRam+cd1T371QHa+WbJMAAXbnd1AVz 9tc9LwbHzv7j3noQvp0F0UavfoaOz7lRMadENunZOjA7wcLFPyzyd741OnZOK2JSUTbF YAGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034976; x=1697639776; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=loCeEjYyI3MRpfj/jU2k9YVJvBGocqpOc4S1cbP0uGc=; b=vAwBQ3dCtY4WTVKKpsALL+lr60oSLf39EFLiPrQWUFHzjSuKIhTvhBtp9W9+Gflt8r Wj/nNdwp24/IGErAmuwDzvMxVVOticM1dYiXvlvwK+X3+jp51DvDpeZoxRnnlDxzWsVF B9UOU6xxbPBcpEWJhbz5vYFKz14HzLe3Opw6XMxiCiyAveBx871esMlFrHSROQuRxfXQ gkOVCuuzpo0mnzMDSnpDrBOYD8zWhrMeK7xTjEYAKWQy+5oZ4WWG4iMhW5XVpCm6rggq FOEK1LXnlOKgVddfITerF0fBM6BZf3p7tp00uAH4dierjWlwuH20GweL2622iU1pYiSI HU0g== X-Gm-Message-State: AOJu0YxAgjyqdjEXqAayBCiPBEebRdFGUYFQ6ZuLlyjD3n31WBPP5Zpx Suf5d89cIpcBJaHB1S92+qcpg23TTxbrAkD/Wqo= X-Google-Smtp-Source: AGHT+IFzH44rQ8k/GhUWbCzS5ndlO/yQoSEatB6qxCfou6RIqXP8A0h+fLG7PvR05kIP669+dKFa4A== X-Received: by 2002:a1c:7c17:0:b0:3fe:ba7:f200 with SMTP id x23-20020a1c7c17000000b003fe0ba7f200mr19236371wmc.20.1697034975866; Wed, 11 Oct 2023 07:36:15 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.36.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:36:15 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 10/11] virtio-sound: implement audio capture (RX) Date: Wed, 11 Oct 2023 17:34:55 +0300 Message-Id: <68f9e0f298b82c8447200814698593a7304d16d1.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32b; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wm1-x32b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis To perform audio capture we duplicate the TX logic of the previous commit with the following difference: we receive data from the QEMU audio backend and write it in the virt queue IO buffers the guest sends to QEMU. When they are full (i.e. they have `period_bytes` amount of data) or when recording stops in QEMU's audio backend, the buffer is returned to the guest by notifying it. Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- hw/virtio/trace-events | 3 +- hw/virtio/virtio-snd.c | 262 +++++++++++++++++++++++++++++++++++------ 2 files changed, 230 insertions(+), 35 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index a31531970d..56a2f44981 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -172,4 +172,5 @@ virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PR virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" virtio_snd_pcm_stream_flush(uint32_t stream) "flushing stream %"PRIu32 -virtio_snd_handle_xfer(void) "tx/rx queue callback called" +virtio_snd_handle_tx_xfer(void) "tx queue callback called" +virtio_snd_handle_rx_xfer(void) "rx queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 5e9513fb26..636ea08c1a 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -1,40 +1,41 @@ /* * VIRTIO Sound Device conforming to * * "Virtual I/O Device (VIRTIO) Version 1.2 * Committee Specification Draft 01 * 09 May 2022" * * * * Copyright (c) 2023 Emmanouil Pitsidianakis * Copyright (C) 2019 OpenSynergy GmbH * * This work is licensed under the terms of the GNU GPL, version 2 or * (at your option) any later version. See the COPYING file in the * top-level directory. */ #include "qemu/osdep.h" #include "qemu/iov.h" #include "qemu/log.h" #include "qemu/error-report.h" #include "include/qemu/lockable.h" #include "sysemu/runstate.h" #include "trace.h" #include "qapi/error.h" #include "hw/virtio/virtio-snd.h" #include "hw/core/cpu.h" #define VIRTIO_SOUND_VM_VERSION 1 #define VIRTIO_SOUND_JACK_DEFAULT 0 -#define VIRTIO_SOUND_STREAM_DEFAULT 1 +#define VIRTIO_SOUND_STREAM_DEFAULT 2 #define VIRTIO_SOUND_CHMAP_DEFAULT 0 #define VIRTIO_SOUND_HDA_FN_NID 0 static void virtio_snd_pcm_out_cb(void *data, int available); static void virtio_snd_process_cmdq(VirtIOSound *s); static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream); +static void virtio_snd_pcm_in_cb(void *data, int available); static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8) | BIT(VIRTIO_SND_PCM_FMT_U8) @@ -403,87 +404,96 @@ static void virtio_snd_get_qemu_audsettings(audsettings *as, /* * Close a stream and free all its resources. * * @stream: VirtIOSoundPCMStream *stream */ static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream) { if (stream) { + virtio_snd_pcm_flush(stream); if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { - virtio_snd_pcm_flush(stream); AUD_close_out(&stream->pcm->snd->card, stream->voice.out); stream->voice.out = NULL; + } else if (stream->info.direction == VIRTIO_SND_D_INPUT) { + AUD_close_in(&stream->pcm->snd->card, stream->voice.in); + stream->voice.in = NULL; } } } /* * Prepares a VirtIOSound card stream. * Returns the response status code. (VIRTIO_SND_S_*). * * @s: VirtIOSound device * @stream_id: stream id */ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) { audsettings as; virtio_snd_pcm_set_params *params; VirtIOSoundPCMStream *stream; if (s->pcm->streams == NULL || s->pcm->pcm_params == NULL || stream_id >= s->snd_conf.streams) { return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } params = virtio_snd_pcm_get_params(s, stream_id); if (params == NULL) { return cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } stream = virtio_snd_pcm_get_stream(s, stream_id); if (stream == NULL) { stream = g_new0(VirtIOSoundPCMStream, 1); stream->active = false; stream->id = stream_id; stream->pcm = s->pcm; stream->s = s; qemu_mutex_init(&stream->queue_mutex); QSIMPLEQ_INIT(&stream->queue); QSIMPLEQ_INIT(&stream->invalid); /* * stream_id >= s->snd_conf.streams was checked before so this is * in-bounds */ s->pcm->streams[stream_id] = stream; } virtio_snd_get_qemu_audsettings(&as, params); stream->info.direction = stream_id < s->snd_conf.streams / 2 + (s->snd_conf.streams & 1) ? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT; stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID; stream->info.features = 0; stream->info.channels_min = 1; stream->info.channels_max = as.nchannels; stream->info.formats = supported_formats; stream->info.rates = supported_rates; stream->params = *params; stream->positions[0] = VIRTIO_SND_CHMAP_FL; stream->positions[1] = VIRTIO_SND_CHMAP_FR; stream->as = as; if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { stream->voice.out = AUD_open_out(&s->card, stream->voice.out, "virtio-sound.out", stream, virtio_snd_pcm_out_cb, &as); AUD_set_volume_out(stream->voice.out, 0, 255, 255); } else { - qemu_log_mask(LOG_UNIMP, "virtio_snd: input/capture is unimplemented."); + stream->voice.in = AUD_open_in(&s->card, + stream->voice.in, + "virtio-sound.in", + stream, + virtio_snd_pcm_in_cb, + &as); + AUD_set_volume_in(stream->voice.in, 0, 255, 255); } return cpu_to_le32(VIRTIO_SND_S_OK); } @@ -536,54 +546,56 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s, /* * Handles VIRTIO_SND_R_PCM_START. * * @s: VirtIOSound device * @cmd: The request command queue element from VirtIOSound cmdq field * @start: whether to start or stop the device */ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s, virtio_snd_ctrl_command *cmd, bool start) { VirtIOSoundPCMStream *stream; virtio_snd_pcm_hdr req; uint32_t stream_id; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &req, sizeof(virtio_snd_pcm_hdr)); if (msg_sz != sizeof(virtio_snd_pcm_hdr)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_pcm_hdr)); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream_id = le32_to_cpu(req.stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); trace_virtio_snd_handle_pcm_start_stop(start ? "VIRTIO_SND_R_PCM_START" : "VIRTIO_SND_R_PCM_STOP", stream_id); stream = virtio_snd_pcm_get_stream(s, stream_id); if (stream) { WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { stream->active = start; } if (stream->info.direction == VIRTIO_SND_D_OUTPUT) { AUD_set_active_out(stream->voice.out, start); + } else { + AUD_set_active_in(stream->voice.in, start); } } else { error_report("Invalid stream id: %"PRIu32, stream_id); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); return; } stream->active = start; } /* * Returns the number of I/O messages that are being processed. * * @stream: VirtIOSoundPCMStream */ @@ -804,80 +816,122 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) /* * The event virtqueue handler. * Not implemented yet. * * @vdev: VirtIOSound device * @vq: event vq */ static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq) { qemu_log_mask(LOG_UNIMP, "virtio_snd: event queue is unimplemented.\n"); trace_virtio_snd_handle_event(); } +static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSoundPCMBuffer *buffer = NULL; + VirtIOSoundPCMStream *stream = NULL; + virtio_snd_pcm_status resp = { 0 }; + VirtIOSound *vsnd = VIRTIO_SND(vdev); + bool any = false; + + for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { + stream = vsnd->pcm->streams[i]; + if (stream) { + any = false; + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->invalid)) { + buffer = QSIMPLEQ_FIRST(&stream->invalid); + if (buffer->vq != vq) { + break; + } + any = true; + resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + 0, + &resp, + sizeof(virtio_snd_pcm_status)); + virtqueue_push(vq, + buffer->elem, + sizeof(virtio_snd_pcm_status)); + QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry); + virtio_snd_pcm_buffer_free(buffer); + } + if (any) { + /* + * Notify vq about virtio_snd_pcm_status responses. + * Buffer responses must be notified separately later. + */ + virtio_notify(vdev, vq); + } + } + } + } +} + /* * The tx virtqueue handler. Makes the buffers available to their respective * streams for consumption. * * @vdev: VirtIOSound device * @vq: tx virtqueue */ -static void virtio_snd_handle_tx(VirtIODevice *vdev, VirtQueue *vq) +static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSound *s = VIRTIO_SND(vdev); VirtIOSoundPCMStream *stream = NULL; VirtIOSoundPCMBuffer *buffer; VirtQueueElement *elem; size_t msg_sz, size; virtio_snd_pcm_xfer hdr; - virtio_snd_pcm_status resp = { 0 }; uint32_t stream_id; /* * If any of the I/O messages are invalid, put them in stream->invalid and * return them after the for loop. */ bool must_empty_invalid_queue = false; if (!virtio_queue_ready(vq)) { return; } - trace_virtio_snd_handle_xfer(); + trace_virtio_snd_handle_tx_xfer(); for (;;) { elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { break; } /* get the message hdr object */ msg_sz = iov_to_buf(elem->out_sg, elem->out_num, 0, &hdr, sizeof(virtio_snd_pcm_xfer)); if (msg_sz != sizeof(virtio_snd_pcm_xfer)) { goto tx_err; } stream_id = le32_to_cpu(hdr.stream_id); if (stream_id >= s->snd_conf.streams || s->pcm->streams[stream_id] == NULL) { goto tx_err; } stream = s->pcm->streams[stream_id]; if (stream->info.direction != VIRTIO_SND_D_OUTPUT) { goto tx_err; } WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { size = iov_size(elem->out_sg, elem->out_num) - msg_sz; buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size); buffer->elem = elem; buffer->populated = false; buffer->vq = vq; buffer->size = size; buffer->offset = 0; QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry); } continue; @@ -885,44 +939,96 @@ static void virtio_snd_handle_tx(VirtIODevice *vdev, VirtQueue *vq) tx_err: WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { must_empty_invalid_queue = true; buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); buffer->elem = elem; buffer->vq = vq; QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry); } } if (must_empty_invalid_queue) { - WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { - while (!QSIMPLEQ_EMPTY(&stream->invalid)) { - buffer = QSIMPLEQ_FIRST(&stream->invalid); - - resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); - iov_from_buf(buffer->elem->in_sg, - buffer->elem->in_num, - 0, - &resp, - sizeof(virtio_snd_pcm_status)); - virtqueue_push(vq, buffer->elem, sizeof(virtio_snd_pcm_status)); - QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry); - virtio_snd_pcm_buffer_free(buffer); - } - /* - * Notify vq about virtio_snd_pcm_status responses. - * Buffer responses must be notified separately later. - */ - virtio_notify(vdev, vq); - } + empty_invalid_queue(vdev, vq); } } /* - * Stub buffer virtqueue handler. + * The rx virtqueue handler. Makes the buffers available to their respective + * streams for consumption. * * @vdev: VirtIOSound device - * @vq: virtqueue + * @vq: rx virtqueue */ -static void virtio_snd_handle_xfer(VirtIODevice *vdev, VirtQueue *vq) {} +static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSound *s = VIRTIO_SND(vdev); + VirtIOSoundPCMStream *stream = NULL; + VirtIOSoundPCMBuffer *buffer; + VirtQueueElement *elem; + size_t msg_sz, size; + virtio_snd_pcm_xfer hdr; + uint32_t stream_id; + /* + * if any of the I/O messages are invalid, put them in stream->invalid and + * return them after the for loop. + */ + bool must_empty_invalid_queue = false; + + if (!virtio_queue_ready(vq)) { + return; + } + trace_virtio_snd_handle_rx_xfer(); + + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + /* get the message hdr object */ + msg_sz = iov_to_buf(elem->out_sg, + elem->out_num, + 0, + &hdr, + sizeof(virtio_snd_pcm_xfer)); + if (msg_sz != sizeof(virtio_snd_pcm_xfer)) { + goto rx_err; + } + stream_id = le32_to_cpu(hdr.stream_id); + + if (stream_id >= s->snd_conf.streams + || !s->pcm->streams[stream_id]) { + goto rx_err; + } + + stream = s->pcm->streams[stream_id]; + if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) { + goto rx_err; + } + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + size = iov_size(elem->in_sg, elem->in_num) - + sizeof(virtio_snd_pcm_status); + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size); + buffer->elem = elem; + buffer->vq = vq; + buffer->size = 0; + buffer->offset = 0; + QSIMPLEQ_INSERT_TAIL(&stream->queue, buffer, entry); + } + continue; + +rx_err: + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + must_empty_invalid_queue = true; + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); + buffer->elem = elem; + buffer->vq = vq; + QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry); + } + } + + if (must_empty_invalid_queue) { + empty_invalid_queue(vdev, vq); + } +} static uint64_t get_features(VirtIODevice *vdev, uint64_t features, Error **errp) @@ -954,82 +1060,82 @@ virtio_snd_vm_state_change(void *opaque, bool running, static void virtio_snd_realize(DeviceState *dev, Error **errp) { ERRP_GUARD(); VirtIOSound *vsnd = VIRTIO_SND(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); virtio_snd_pcm_set_params default_params = { 0 }; uint32_t status; vsnd->pcm = NULL; vsnd->vmstate = qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); trace_virtio_snd_realize(vsnd); vsnd->pcm = g_new0(VirtIOSoundPCM, 1); vsnd->pcm->snd = vsnd; vsnd->pcm->streams = g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams); vsnd->pcm->pcm_params = g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams); virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); /* set number of jacks and streams */ if (vsnd->snd_conf.jacks > 8) { error_setg(errp, "Invalid number of jacks: %"PRIu32, vsnd->snd_conf.jacks); return; } if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) { error_setg(errp, "Invalid number of streams: %"PRIu32, vsnd->snd_conf.streams); return; } if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) { error_setg(errp, "Invalid number of channel maps: %"PRIu32, vsnd->snd_conf.chmaps); return; } AUD_register_card("virtio-sound", &vsnd->card, errp); /* set default params for all streams */ default_params.features = 0; default_params.buffer_bytes = cpu_to_le32(8192); default_params.period_bytes = cpu_to_le32(2048); default_params.channels = 2; default_params.format = VIRTIO_SND_PCM_FMT_S16; default_params.rate = VIRTIO_SND_PCM_RATE_48000; vsnd->queues[VIRTIO_SND_VQ_CONTROL] = virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl); vsnd->queues[VIRTIO_SND_VQ_EVENT] = virtio_add_queue(vdev, 64, virtio_snd_handle_event); vsnd->queues[VIRTIO_SND_VQ_TX] = - virtio_add_queue(vdev, 64, virtio_snd_handle_tx); + virtio_add_queue(vdev, 64, virtio_snd_handle_tx_xfer); vsnd->queues[VIRTIO_SND_VQ_RX] = - virtio_add_queue(vdev, 64, virtio_snd_handle_xfer); + virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer); qemu_mutex_init(&vsnd->cmdq_mutex); QTAILQ_INIT(&vsnd->cmdq); for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { status = virtio_snd_set_pcm_params(vsnd, i, &default_params); if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { error_setg(errp, "Can't initalize stream params, device responded with %s.", print_code(status)); return; } status = virtio_snd_pcm_prepare(vsnd, i); if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { error_setg(errp, "Can't prepare streams, device responded with %s.", print_code(status)); return; } } } @@ -1059,76 +1165,164 @@ static inline void return_tx_buffer(VirtIOSoundPCMStream *stream, /* * AUD_* output callback. * * @data: VirtIOSoundPCMStream stream * @available: number of bytes that can be written with AUD_write() */ static void virtio_snd_pcm_out_cb(void *data, int available) { VirtIOSoundPCMStream *stream = data; VirtIOSoundPCMBuffer *buffer; size_t size; WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { while (!QSIMPLEQ_EMPTY(&stream->queue)) { buffer = QSIMPLEQ_FIRST(&stream->queue); if (!virtio_queue_ready(buffer->vq)) { return; } if (!stream->active) { /* Stream has stopped, so do not perform AUD_write. */ return_tx_buffer(stream, buffer); continue; } if (!buffer->populated) { iov_to_buf(buffer->elem->out_sg, buffer->elem->out_num, sizeof(virtio_snd_pcm_xfer), buffer->data, buffer->size); buffer->populated = true; } for (;;) { size = AUD_write(stream->voice.out, buffer->data + buffer->offset, MIN(buffer->size, available)); assert(size <= MIN(buffer->size, available)); if (size == 0) { /* break out of both loops */ available = 0; break; } buffer->size -= size; buffer->offset += size; available -= size; if (buffer->size < 1) { return_tx_buffer(stream, buffer); break; } if (!available) { break; } } if (!available) { break; } } } } /* - * Flush all buffer data from this stream's queue into the driver's virtual - * queue. + * Flush all buffer data from this input stream's queue into the driver's + * virtual queue. + * + * @stream: VirtIOSoundPCMStream *stream + */ +static inline void return_rx_buffer(VirtIOSoundPCMStream *stream, + VirtIOSoundPCMBuffer *buffer) +{ + virtio_snd_pcm_status resp = { 0 }; + resp.status = cpu_to_le32(VIRTIO_SND_S_OK); + resp.latency_bytes = 0; + /* Copy data -if any- to guest */ + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + 0, + buffer->data, + buffer->size); + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + buffer->size, + &resp, + sizeof(virtio_snd_pcm_status)); + virtqueue_push(buffer->vq, + buffer->elem, + sizeof(virtio_snd_pcm_status) + buffer->size); + virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq); + QSIMPLEQ_REMOVE(&stream->queue, + buffer, + VirtIOSoundPCMBuffer, + entry); + virtio_snd_pcm_buffer_free(buffer); +} + + +/* + * AUD_* input callback. + * + * @data: VirtIOSoundPCMStream stream + * @available: number of bytes that can be read with AUD_read() + */ +static void virtio_snd_pcm_in_cb(void *data, int available) +{ + VirtIOSoundPCMStream *stream = data; + VirtIOSoundPCMBuffer *buffer; + size_t size; + + WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { + while (!QSIMPLEQ_EMPTY(&stream->queue)) { + buffer = QSIMPLEQ_FIRST(&stream->queue); + if (!virtio_queue_ready(buffer->vq)) { + return; + } + if (!stream->active) { + /* Stream has stopped, so do not perform AUD_read. */ + return_rx_buffer(stream, buffer); + continue; + } + + for (;;) { + size = AUD_read(stream->voice.in, + buffer->data + buffer->size, + MIN(available, (stream->params.period_bytes - + buffer->size))); + if (!size) { + available = 0; + break; + } + buffer->size += size; + available -= size; + if (buffer->size >= stream->params.period_bytes) { + return_rx_buffer(stream, buffer); + break; + } + if (!available) { + break; + } + } + if (!available) { + break; + } + } + } +} + +/* + * Flush all buffer data from this output stream's queue into the driver's + * virtual queue. * * @stream: VirtIOSoundPCMStream *stream */ static inline void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream) { VirtIOSoundPCMBuffer *buffer; + void (*cb)(VirtIOSoundPCMStream *, VirtIOSoundPCMBuffer *) = + (stream->info.direction == VIRTIO_SND_D_OUTPUT) ? return_tx_buffer : + return_rx_buffer; WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { while (!QSIMPLEQ_EMPTY(&stream->queue)) { buffer = QSIMPLEQ_FIRST(&stream->queue); - return_tx_buffer(stream, buffer); + cb(stream, buffer); } } } From patchwork Wed Oct 11 14:34:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Manos Pitsidianakis X-Patchwork-Id: 13417510 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 657A7CD6E7B for ; Wed, 11 Oct 2023 14:37:21 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqaK2-00019M-0C; Wed, 11 Oct 2023 10:36:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqaJz-00018C-5h for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:23 -0400 Received: from mail-wr1-x42b.google.com ([2a00:1450:4864:20::42b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qqaJx-0005oP-BJ for qemu-devel@nongnu.org; Wed, 11 Oct 2023 10:36:22 -0400 Received: by mail-wr1-x42b.google.com with SMTP id ffacd0b85a97d-3247cefa13aso6282148f8f.1 for ; Wed, 11 Oct 2023 07:36:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1697034979; x=1697639779; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ufC+dD4Md7A3Zyn0mFl7NjM0gBjP2OM76JBiL0XIFTA=; b=AuiB7DZU9qlwZMRuEONJvDSA+nML65rVX8DlgpTXWImWvbUV+Ih2glKDslUGPWP8su T/1mmxUAWrpJ5qWcmudObcdSTwvCadotOkZmv+vGg7d/9XnEdQBuJl2C2QVXXj8U1LhS Ypn7LjcD4l1xFrT/gSTGdvt6NOZxMsmwv2matkH0Le6Fag/lIIQ31lXIFyUNcWCOYBqB BshLpzCOlshHgfCFquh0j+BPRWJv2YTULh6TyDPaqcUjYON8e2LiVUxvdHYGSVYosBz2 UGeM7DjjfuFqUqUOZE/VNHOXd3yIdFLrUNjeWxYMa8ijqvjkRRfqoKBL7yzxo7HuZOqd P6ZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697034979; x=1697639779; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ufC+dD4Md7A3Zyn0mFl7NjM0gBjP2OM76JBiL0XIFTA=; b=YYJYzzOSr8MFekqZwJ1QuiuI1VM0C/m8GK5Mry902WQdLb++9h/F2ht4Sy8XIzdG9T 09RYzJKYcEXDg/cTBm0VnjIVCA410Jm7sMJ3oydavmg5U3jSw9df19eH7FV+reDs3YCc tDPBkvCcGF1JMldL9hc7VYksRbw+B/WqOYATbtlm4Tgj+KwUkaNQ+9ywq60PS9sxwZ4v X+A3wenMVftALEx/EjzoEqPseHM+brvt0vnywFPuCyFjlFvISESP0AdtXUZo8YpOMhVt xIMGooRvzxZX69vBPQDkX2NqK7rrXLKM3BNIrrECV4uNAoZipYi/IEtmnU3nl1kIk0MB 4Gqw== X-Gm-Message-State: AOJu0Yxm7Q1xP7pgtT/AndynQU+vQ6x1Uv44RG3J/tyFDIFGYM4pvNBk Ogf28bjVHUJ98Iib7rbMXCZMGMOn6AEL2odjB6M= X-Google-Smtp-Source: AGHT+IFixuiyrXL/KosL2gSt6U6TvT2/Iew3TGKNaikPZOFH7ravNQb+GoYSXt2Tdv8ToPFal3ZHbA== X-Received: by 2002:a5d:48cb:0:b0:322:707e:a9fd with SMTP id p11-20020a5d48cb000000b00322707ea9fdmr16920177wrs.34.1697034979447; Wed, 11 Oct 2023 07:36:19 -0700 (PDT) Received: from localhost.localdomain (adsl-26.37.6.0.tellas.gr. [37.6.0.26]) by smtp.gmail.com with ESMTPSA id n8-20020a5d4208000000b003253523d767sm15599869wrq.109.2023.10.11.07.36.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Oct 2023 07:36:18 -0700 (PDT) From: Manos Pitsidianakis X-Google-Original-From: Manos Pitsidianakis To: qemu-devel@nongnu.org Cc: Emmanouil Pitsidianakis , "Igor Skalkin" , "Anton Yakovlev" , "Paolo Bonzini" , "Gerd Hoffmann" , "Michael S. Tsirkin" , "Marcel Apfelbaum" , =?utf-8?q?Daniel_P=2E_Berr?= =?utf-8?q?ang=C3=A9?= , "Eduardo Habkost" , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Volker_R=C3=BCmelin?= , =?utf-8?b?S8WRdsOh?= =?utf-8?b?Z8OzLCBab2x0w6Fu?= , =?utf-8?q?Alex_Benn?= =?utf-8?q?=C3=A9e?= , =?utf-8?q?Philippe_Mathieu-Da?= =?utf-8?q?ud=C3=A9?= , "Mark Cave-Ayland" , "Stefano Garzarella" Subject: [PATCH v11 11/11] docs/system: add basic virtio-snd documentation Date: Wed, 11 Oct 2023 17:34:56 +0300 Message-Id: <885b01fe272541fdab5583780d4c3a59bfd8e734.1696935992.git.manos.pitsidianakis@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::42b; envelope-from=manos.pitsidianakis@linaro.org; helo=mail-wr1-x42b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Emmanouil Pitsidianakis This commit adds basic documentation for using virtio-snd. Signed-off-by: Emmanouil Pitsidianakis Reviewed-by: Alex Bennée --- MAINTAINERS | 1 + docs/system/device-emulation.rst | 1 + docs/system/devices/virtio-snd.rst (new) | 49 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 701f12026a..a32e512a61 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2259,6 +2259,7 @@ M: Manos Pitsidianakis S: Supported F: hw/virtio/virtio-snd*.c F: include/hw/virtio/virtio-snd.h +F: docs/system/devices/virtio-snd.rst nvme M: Keith Busch diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index 4491c4cbf7..dae19446e5 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -79,20 +79,21 @@ in a PCI slot to the exclusive use of the guest. Emulated Devices ~~~~~~~~~~~~~~~~ .. toctree:: :maxdepth: 1 devices/can.rst devices/ccid.rst devices/cxl.rst devices/ivshmem.rst devices/keyboard.rst devices/net.rst devices/nvme.rst devices/usb.rst devices/vhost-user.rst devices/virtio-pmem.rst + devices/virtio-snd.rst devices/vhost-user-rng.rst devices/canokey.rst devices/usb-u2f.rst devices/igb.rst diff --git a/docs/system/devices/virtio-snd.rst b/docs/system/devices/virtio-snd.rst new file mode 100644 index 0000000000..2a9187fd70 --- /dev/null +++ b/docs/system/devices/virtio-snd.rst @@ -0,0 +1,49 @@ +virtio sound +============ + +This document explains the setup and usage of the Virtio sound device. +The Virtio sound device is a paravirtualized sound card device. + +Linux kernel support +-------------------- + +Virtio sound requires a guest Linux kernel built with the +``CONFIG_SND_VIRTIO`` option. + +Description +----------- + +Virtio sound implements capture and playback from inside a guest using the +configured audio backend of the host machine. + +Device properties +----------------- + +The Virtio sound device can be configured with the following properties: + + * ``jacks`` number of physical jacks (Unimplemented). + * ``streams`` number of PCM streams. At the moment, no stream configuration is supported: the first one will always be a playback stream, an optional second will always be a capture stream. Adding more will cycle stream directions from playback to capture. + * ``chmaps`` number of channel maps (Unimplemented). + +All streams are stereo and have the default channel positions ``Front left, right``. + +Examples +-------- + +Add an audio device and an audio backend at once with ``-audio`` and ``model=virtio``: + + * pulseaudio: ``-audio driver=pa,model=virtio`` + or ``-audio driver=pa,model=virtio,server=/run/user/1000/pulse/native`` + * sdl: ``-audio driver=sdl,model=virtio`` + * coreaudio: ``-audio driver=coreaudio,model=virtio`` + +etc. + +To specifically add virtualized sound devices, you have to specify a PCI device +and an audio backend listed with ``-audio driver=help`` that works on your host +machine, e.g.: + +:: + + -device virtio-sound-pci,audiodev=my_audiodev \ + -audiodev alsa,id=my_audiodev