Re: [PATCH v2 1/4] MAINTAINERS: drop audio maintainership

2024-05-29 Thread Volker Rümelin
Am 28.05.24 um 12:02 schrieb Gerd Hoffmann:
>   Hi,
>
>>>  virtio-snd
>>> -M: Gerd Hoffmann 
>>> -R: Manos Pitsidianakis 
>>> +M: Manos Pitsidianakis 
>>> +R: Matias Ezequiel Vara Larsen 
>>>  S: Supported
>>>  F: hw/audio/virtio-snd.c
>>>  F: hw/audio/virtio-snd-pci.c
>> While extra reviewers are always helpful, someone like Volker would
>> make sense, not someone without any contributions:
> Matias volunteered to help (via reply to v1 of the series), and for
> 'reviewer' role I don't see a reason to be strict.  'Maintainer' would
> be a different story of course.
>
> If Volker wants step up (I see you cc'ed him already) I happily add
> him too.

Hi,

I'm sorry, but at the moment I can't step up as reviewer. As you
probably know, I'm doing this in my free time and the time I can
dedicate to QEMU is quite limited at the moment. I don't think the QEMU
developers need an unresponsive reviewer.

However, I continue to read the qemu-devel mailing list and will speak
up if I think something is wrong.

With best regards,
Volker




Re: [PULL 20/38] accel/whpx: Use accel-specific per-vcpu @dirty field

2024-04-28 Thread Volker Rümelin
Am 26.04.24 um 21:41 schrieb Philippe Mathieu-Daudé:
> WHPX has a specific use of the CPUState::vcpu_dirty field
> (CPUState::vcpu_dirty is not used by common code).
> To make this field accel-specific, add and use a new
> @dirty variable in the AccelCPUState structure.
>
> Signed-off-by: Philippe Mathieu-Daudé 
> Reviewed-by: Richard Henderson 
> Message-Id: <20240424174506.326-2-phi...@linaro.org>
> ---
>  target/i386/whpx/whpx-all.c | 23 ---
>  1 file changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
> index 31eec7048c..b08e644517 100644
> --- a/target/i386/whpx/whpx-all.c
> +++ b/target/i386/whpx/whpx-all.c

> @@ -2235,7 +2236,7 @@ int whpx_init_vcpu(CPUState *cpu)
>  }
>  
>  vcpu->interruptable = true;
> -cpu->vcpu_dirty = true;

Hi Philippe,

cpu->accel is NULL here. You probably wanted to write

+    vcpu->dirty = true;

instead of

+    cpu->accel->dirty = true;

I think your patch for nvmm_init_vcpu() in target/i386/nvmm/nvmm-all.c
has the same issue.

With best regards,
Volker

> +cpu->accel->dirty = true;
>  cpu->accel = vcpu;
>  max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
>  qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);




Re: [PATCH] target/i386/translate.c: always write 32-bits for SGDT and SIDT

2024-04-22 Thread Volker Rümelin
Am 20.04.24 um 07:40 schrieb Mark Cave-Ayland:
> On 20/04/2024 02:21, Richard Henderson wrote:
>
>> On 4/19/24 12:51, Mark Cave-Ayland wrote:
>>> The various Intel CPU manuals claim that SGDT and SIDT can write
>>> either 24-bits
>>> or 32-bits depending upon the operand size, but this is incorrect.
>>> Not only do
>>> the Intel CPU manuals give contradictory information between processor
>>> revisions, but this information doesn't even match real-life behaviour.
>>>
>>> In fact, tests on real hardware show that the CPU always writes
>>> 32-bits for SGDT
>>> and SIDT, and this behaviour is required for at least OS/2 Warp and
>>> WFW 3.11 with
>>> Win32s to function correctly. Remove the masking applied due to the
>>> operand size
>>> for SGDT and SIDT so that the TCG behaviour matches the behaviour on
>>> real
>>> hardware.
>>>
>>> Signed-off-by: Mark Cave-Ayland 
>>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2198
>>>
>>> -- 
>>> MCA: Whilst I don't have a copy of OS/2 Warp handy, I've confirmed
>>> that this
>>> patch fixes the issue in WFW 3.11 with Win32s. For more technical
>>> information I
>>> highly recommend the excellent write-up at
>>> https://www.os2museum.com/wp/sgdtsidt-fiction-and-reality/.
>>> ---
>>>   target/i386/tcg/translate.c | 14 --
>>>   1 file changed, 8 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
>>> index 76a42c679c..3026eb6774 100644
>>> --- a/target/i386/tcg/translate.c
>>> +++ b/target/i386/tcg/translate.c
>>> @@ -5846,9 +5846,10 @@ static bool disas_insn(DisasContext *s,
>>> CPUState *cpu)
>>>   gen_op_st_v(s, MO_16, s->T0, s->A0);
>>>   gen_add_A0_im(s, 2);
>>>   tcg_gen_ld_tl(s->T0, tcg_env, offsetof(CPUX86State,
>>> gdt.base));
>>> -    if (dflag == MO_16) {
>>> -    tcg_gen_andi_tl(s->T0, s->T0, 0xff);
>>> -    }
>>> +    /*
>>> + * NB: Despite claims to the contrary in Intel CPU
>>> documentation,
>>> + * all 32-bits are written regardless of operand size.
>>> + */
>>
>> Current documentation agrees that all 32 bits are written, so I don't
>> think you need this comment:
>
> Ah that's good to know the docs are now correct. I added the comment
> as there was a lot of conflicting information around for older CPUs so
> I thought it was worth an explicit mention.
>
> If everyone agrees a version without comments is preferable, I can
> re-send an updated version without them included.
>

Hi Mark,

I wouldn't remove the comment.

Quote from the Intel® 64 and IA-32 Architectures Software Developer’s
Manual Volume 2B: Instruction Set Reference, M-U March 2024:

IA-32 Architecture Compatibility
The 16-bit form of SGDT is compatible with the Intel 286 processor if
the upper 8 bits are not referenced. The Intel 286 processor fills these
bits with 1s; processor generations later than the Intel 286 processor
fill these bits with 0s.

Intel still claims the upper 8 bits are filled with 0s, but the
Operation pseudo code below is correct. The same is true for SIDT.

With best regards,
Volker

>>    IF OperandSize =16 or OperandSize = 32 (* Legacy or Compatibility
>> Mode *)
>>  THEN
>>    DEST[0:15] := GDTR(Limit);
>>    DEST[16:47] := GDTR(Base); (* Full 32-bit base address stored *)
>>    FI;
>>
>>
>> Anyway,
>> Reviewed-by: Richard Henderson 
>
> Thanks!
>
>
> ATB,
>
> Mark.
>
>
>




Re: [PATCH] usb-audio: Fix invalid values in AudioControl descriptors

2024-03-17 Thread Volker Rümelin
Am 09.03.24 um 18:29 schrieb Joonas Kankaala:
> This fixes the invalid bInterfaceProtocol value 0x04 in the USB audio
> AudioControl descriptors. It should be zero. While Linux and Windows
> forgive this error, macOS 14 Sonoma does not. The usb-audio device does
> not appear in macOS sound settings even though the device is recognized
> and shows up in USB system information. According to the USB audio class
> specs 1.0-4.0, valid values are 0x00, 0x20, 0x30 and 0x40. (Note also
> that Linux prints the warning "unknown interface protocol 0x4, assuming
> v1", but then proceeds as if the value was zero.)
>
> This also fixes the invalid wTotalLength value in the multi-channel
> setup AudioControl interface header descriptor (used when multi=on
> and out.mixing-engine off). The combined length of all the descriptors
> there add up to 0x37, not 0x38. In Linux, "lsusb -D ..." displays
> incomplete descriptor information when this length is incorrect.
>
> Signed-off-by: Joonas Kankaala 

lsusb also misinterprets the invalid interface protocol 0x4 and uses
0x30 instead.

Reviewed-by: Volker Rümelin 

> ---
>  hw/usb/dev-audio.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
> index d5ac1f8962..1897fff9e6 100644
> --- a/hw/usb/dev-audio.c
> +++ b/hw/usb/dev-audio.c
> @@ -124,7 +124,6 @@ static const USBDescIface desc_iface[] = {
>  .bNumEndpoints = 0,
>  .bInterfaceClass   = USB_CLASS_AUDIO,
>  .bInterfaceSubClass= USB_SUBCLASS_AUDIO_CONTROL,
> -.bInterfaceProtocol= 0x04,
>  .iInterface= STRING_USBAUDIO_CONTROL,
>  .ndesc = 4,
>  .descs = (USBDescOther[]) {
> @@ -282,7 +281,6 @@ static const USBDescIface desc_iface_multi[] = {
>  .bNumEndpoints = 0,
>  .bInterfaceClass   = USB_CLASS_AUDIO,
>  .bInterfaceSubClass= USB_SUBCLASS_AUDIO_CONTROL,
> -.bInterfaceProtocol= 0x04,
>  .iInterface= STRING_USBAUDIO_CONTROL,
>  .ndesc = 4,
>  .descs = (USBDescOther[]) {
> @@ -293,7 +291,7 @@ static const USBDescIface desc_iface_multi[] = {
>  USB_DT_CS_INTERFACE,/*  u8  bDescriptorType */
>  DST_AC_HEADER,  /*  u8  bDescriptorSubtype */
>  U16(0x0100),/* u16  bcdADC */
> -U16(0x38),  /* u16  wTotalLength */
> +U16(0x37),  /* u16  wTotalLength */
>  0x01,   /*  u8  bInCollection */
>  0x01,   /*  u8  baInterfaceNr */
>  }




Re: [PULL 14/25] hw/i386/pc: Confine system flash handling to pc_sysfw

2024-02-25 Thread Volker Rümelin
Am 21.02.24 um 22:16 schrieb Philippe Mathieu-Daudé:
> From: Bernhard Beschow 
>
> Rather than distributing PC system flash handling across three files, let's
> confine it to one. Now, pc_system_firmware_init() creates, configures and 
> cleans
> up the system flash which makes the code easier to understand. It also avoids
> the extra call to pc_system_flash_cleanup_unused() in the Xen case.
>
> Signed-off-by: Bernhard Beschow 
> Reviewed-by: Philippe Mathieu-Daudé 
> Message-ID: <20240208220349.4948-7-shen...@gmail.com>
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
>  include/hw/i386/pc.h | 2 --
>  hw/i386/pc.c | 1 -
>  hw/i386/pc_piix.c| 1 -
>  hw/i386/pc_sysfw.c   | 6 --
>  4 files changed, 4 insertions(+), 6 deletions(-)

Hi Bernhard,

this patch breaks QEMU on my system.

./qemu-system-x86_64 -machine q35,pflash0=pflash0-storage -blockdev
driver=file,node-name=pflash0-storage,filename=/usr/share/qemu/ovmf-x86_64.bin,read-only=true
qemu-system-x86_64: Property 'pc-q35-9.0-machine.pflash0' not found

I had to revert cb05cc1602 ("hw/i386/pc_sysfw: Inline
pc_system_flash_create() and remove it") and 6f6ad2b245 ("hw/i386/pc:
Confine system flash handling to pc_sysfw") to make it work again.

With best regards,
Volker

> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index 0a8a96600c..e8f4af5d5c 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -193,8 +193,6 @@ void pc_i8259_create(ISABus *isa_bus, qemu_irq 
> *i8259_irqs);
>  #define TYPE_PORT92 "port92"
>  
>  /* pc_sysfw.c */
> -void pc_system_flash_create(PCMachineState *pcms);
> -void pc_system_flash_cleanup_unused(PCMachineState *pcms);
>  void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
>  bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
> int *data_len);
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index e526498164..1ee41a5e56 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -1733,7 +1733,6 @@ static void pc_machine_initfn(Object *obj)
>  #endif
>  pcms->default_bus_bypass_iommu = false;
>  
> -pc_system_flash_create(pcms);
>  pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
>  object_property_add_alias(OBJECT(pcms), "pcspk-audiodev",
>OBJECT(pcms->pcspk), "audiodev");
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 34203927e1..ec7c07b362 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -231,7 +231,6 @@ static void pc_init1(MachineState *machine,
>  assert(machine->ram_size == x86ms->below_4g_mem_size +
>  x86ms->above_4g_mem_size);
>  
> -pc_system_flash_cleanup_unused(pcms);
>  if (machine->kernel_filename != NULL) {
>  /* For xen HVM direct kernel boot, load linux here */
>  xen_load_linux(pcms);
> diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
> index c8d9e71b88..b4c3833352 100644
> --- a/hw/i386/pc_sysfw.c
> +++ b/hw/i386/pc_sysfw.c
> @@ -91,7 +91,7 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
>  return PFLASH_CFI01(dev);
>  }
>  
> -void pc_system_flash_create(PCMachineState *pcms)
> +static void pc_system_flash_create(PCMachineState *pcms)
>  {
>  PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
>  
> @@ -103,7 +103,7 @@ void pc_system_flash_create(PCMachineState *pcms)
>  }
>  }
>  
> -void pc_system_flash_cleanup_unused(PCMachineState *pcms)
> +static void pc_system_flash_cleanup_unused(PCMachineState *pcms)
>  {
>  char *prop_name;
>  int i;
> @@ -212,6 +212,8 @@ void pc_system_firmware_init(PCMachineState *pcms,
>  return;
>  }
>  
> +pc_system_flash_create(pcms);
> +
>  /* Map legacy -drive if=pflash to machine properties */
>  for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
>  pflash_cfi01_legacy_drive(pcms->flash[i],




[PATCH v2 09/11] hw/audio/virtio-sound: introduce virtio_snd_set_active()

2024-02-18 Thread Volker Rümelin
Split out the function virtio_snd_pcm_set_active() from
virtio_snd_pcm_start_stop(). A later patch also needs this
new funcion. There is no functional change.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 21 -
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index a1d14caba0..06a27ef8d9 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -471,6 +471,21 @@ static void virtio_snd_pcm_open(VirtIOSoundPCMStream 
*stream)
 }
 }
 
+/*
+ * Activate/deactivate a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ * @active: whether to activate or deactivate the stream
+ */
+static void virtio_snd_pcm_set_active(VirtIOSoundPCMStream *stream, bool 
active)
+{
+if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+AUD_set_active_out(stream->voice.out, active);
+} else {
+AUD_set_active_in(stream->voice.in, active);
+}
+}
+
 /*
  * Close a stream and free all its resources.
  *
@@ -606,11 +621,7 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
 stream->state = VSND_PCMSTREAM_STATE_STOPPED;
 }
 
-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);
-}
+virtio_snd_pcm_set_active(stream, start);
 
 return cpu_to_le32(VIRTIO_SND_S_OK);
 }
-- 
2.35.3




[PATCH v2 08/11] hw/audio/virtio-sound: introduce virtio_snd_pcm_open()

2024-02-18 Thread Volker Rümelin
Split out the function virtio_snd_pcm_open() from
virtio_snd_pcm_prepare(). A later patch also needs
the new function. There is no functional change.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 57 +++
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index bbbdd01aa9..a1d14caba0 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -441,6 +441,36 @@ static void virtio_snd_get_qemu_audsettings(audsettings 
*as,
 as->endianness = target_words_bigendian() ? 1 : 0;
 }
 
+/*
+ * Open a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ */
+static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
+{
+virtio_snd_get_qemu_audsettings(>as, >params);
+stream->positions[0] = VIRTIO_SND_CHMAP_FL;
+stream->positions[1] = VIRTIO_SND_CHMAP_FR;
+
+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 {
+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);
+}
+}
+
 /*
  * Close a stream and free all its resources.
  *
@@ -466,8 +496,6 @@ static void virtio_snd_pcm_close(VirtIOSoundPCMStream 
*stream)
  */
 static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
 {
-audsettings as;
-virtio_snd_pcm_set_params *params;
 VirtIOSoundPCMStream *stream;
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
@@ -484,30 +512,7 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
 }
 
-params = virtio_snd_pcm_get_params(s, stream_id);
-
-virtio_snd_get_qemu_audsettings(, 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(>card,
- stream->voice.out,
- "virtio-sound.out",
- stream,
- virtio_snd_pcm_out_cb,
- );
-AUD_set_volume_out(stream->voice.out, 0, 255, 255);
-} else {
-stream->voice.in = AUD_open_in(>card,
-stream->voice.in,
-"virtio-sound.in",
-stream,
-virtio_snd_pcm_in_cb,
-);
-AUD_set_volume_in(stream->voice.in, 0, 255, 255);
-}
+virtio_snd_pcm_open(stream);
 
 stream->state = VSND_PCMSTREAM_STATE_PREPARED;
 
-- 
2.35.3




[PATCH v2 06/11] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()

2024-02-18 Thread Volker Rümelin
Split out virtio_snd_pcm_start_stop(). This is a preparation
for the next patch so that it doesn't become too big.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Volker Rümelin 
---
 hw/audio/trace-events |  3 ++-
 hw/audio/virtio-snd.c | 57 ---
 2 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index b1870ff224..7554bfcc60 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -50,7 +50,8 @@ 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
+virtio_snd_handle_pcm_start(uint32_t stream) "VIRTIO_SND_R_PCM_START called 
for stream %"PRIu32
+virtio_snd_handle_pcm_stop(uint32_t stream) "VIRTIO_SND_R_PCM_STOP 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"
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 2b630ada82..435ce26430 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -533,7 +533,42 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
 }
 
 /*
- * Handles VIRTIO_SND_R_PCM_START.
+ * Starts/Stops a VirtIOSound card stream.
+ * Returns the response status code. (VIRTIO_SND_S_*).
+ *
+ * @s: VirtIOSound device
+ * @stream_id: stream id
+ * @start: whether to start or stop the stream
+ */
+static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
+  uint32_t stream_id,
+  bool start)
+{
+VirtIOSoundPCMStream *stream;
+
+stream = virtio_snd_pcm_get_stream(s, stream_id);
+if (!stream) {
+return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+}
+
+if (start) {
+trace_virtio_snd_handle_pcm_start(stream_id);
+} else {
+trace_virtio_snd_handle_pcm_stop(stream_id);
+}
+
+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);
+}
+
+return cpu_to_le32(VIRTIO_SND_S_OK);
+}
+
+/*
+ * Handles VIRTIO_SND_R_PCM_START and VIRTIO_SND_R_PCM_STOP.
  *
  * @s: VirtIOSound device
  * @cmd: The request command queue element from VirtIOSound cmdq field
@@ -543,7 +578,6 @@ 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,
@@ -561,24 +595,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound 
*s,
 }
 
 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) {
-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;
+cmd->resp.code = virtio_snd_pcm_start_stop(s, stream_id, start);
 }
 
 /*
-- 
2.35.3




[PATCH v2 05/11] hw/audio/virtio-sound: free all stream buffers on reset

2024-02-18 Thread Volker Rümelin
All remaining stream buffers in the stream queues must
be freed after a reset. This is the initial state of the
virtio-sound device.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index e5497b6bf6..2b630ada82 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -1318,12 +1318,23 @@ static void virtio_snd_reset(VirtIODevice *vdev)
 {
 VirtIOSound *s = VIRTIO_SND(vdev);
 virtio_snd_ctrl_command *cmd;
+uint32_t i;
 
 while (!QTAILQ_EMPTY(>cmdq)) {
 cmd = QTAILQ_FIRST(>cmdq);
 QTAILQ_REMOVE(>cmdq, cmd, next);
 virtio_snd_ctrl_cmd_free(cmd);
 }
+
+for (i = 0; i < s->snd_conf.streams; i++) {
+VirtIOSoundPCMStream *stream = >streams[i];
+VirtIOSoundPCMBuffer *buffer;
+
+while ((buffer = QSIMPLEQ_FIRST(>queue))) {
+QSIMPLEQ_REMOVE_HEAD(>queue, entry);
+virtio_snd_pcm_buffer_free(buffer);
+}
+}
 }
 
 static void virtio_snd_class_init(ObjectClass *klass, void *data)
-- 
2.35.3




[PATCH v2 02/11] hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler

2024-02-18 Thread Volker Rümelin
A malicious guest may trigger a segmentation fault in the tx/rx xfer
handlers. On handler entry the stream variable is initialized with
NULL. If the first element of the virtio queue has an invalid size
or an invalid stream id, the error handling code dereferences the
stream variable NULL pointer.

Don't try to handle the invalid virtio queue element with a stream
queue. Instead, push the invalid queue element back to the guest
immediately.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 100 ++
 include/hw/audio/virtio-snd.h |   1 -
 2 files changed, 29 insertions(+), 72 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index e604d8f30c..b87653daf4 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -456,7 +456,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 stream->s = s;
 qemu_mutex_init(>queue_mutex);
 QSIMPLEQ_INIT(>queue);
-QSIMPLEQ_INIT(>invalid);
 
 /*
  * stream_id >= s->snd_conf.streams was checked before so this is
@@ -611,9 +610,6 @@ static size_t 
virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
 QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
 count += 1;
 }
-QSIMPLEQ_FOREACH_SAFE(buffer, >invalid, entry, next) {
-count += 1;
-}
 }
 return count;
 }
@@ -831,47 +827,19 @@ static void virtio_snd_handle_event(VirtIODevice *vdev, 
VirtQueue *vq)
 trace_virtio_snd_handle_event();
 }
 
-static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq)
+static void push_bad_msg_resp(VirtQueue *vq, VirtQueueElement *elem)
 {
-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(>queue_mutex) {
-while (!QSIMPLEQ_EMPTY(>invalid)) {
-buffer = QSIMPLEQ_FIRST(>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,
- ,
- sizeof(virtio_snd_pcm_status));
-virtqueue_push(vq,
-   buffer->elem,
-   sizeof(virtio_snd_pcm_status));
-QSIMPLEQ_REMOVE_HEAD(>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);
-}
-}
-}
-}
+size_t msg_sz;
+
+resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+msg_sz = iov_from_buf(elem->in_sg,
+  elem->in_num,
+  0,
+  ,
+  sizeof(virtio_snd_pcm_status));
+virtqueue_push(vq, elem, msg_sz);
+g_free(elem);
 }
 
 /*
@@ -890,11 +858,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 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;
+bool notify = false;
 
 if (!virtio_queue_ready(vq)) {
 return;
@@ -942,17 +906,16 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 continue;
 
 tx_err:
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-must_empty_invalid_queue = true;
-buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
-buffer->elem = elem;
-buffer->vq = vq;
-QSIMPLEQ_INSERT_TAIL(>invalid, buffer, entry);
-}
+push_bad_msg_resp(vq, elem);
+notify = true;
 }
 
-if (must_empty_invalid_queue) {
-empty_invalid_queue(vdev, vq);
+if (notify) {
+/*
+ * Notify vq about virtio_snd_pcm_status responses.
+ * Buffer responses must be notified separately later.
+ */
+ virtio_notify(vdev, vq);
 }
 }
 
@@ -972,11 +935,7 @@ static void

[PATCH v2 07/11] hw/audio/virtio-sound: add stream state variable

2024-02-18 Thread Volker Rümelin
So far, only rudimentary checks have been made to ensure that
the guest only performs state transitions permitted in
virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
variable per audio stream and check all state transitions.

Because only permitted state transitions are possible, only one
copy of the audio stream parameters is required and these do not
need to be initialised with default values.

The state variable will also make it easier to restore the audio
stream after migration.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 213 ++
 include/hw/audio/virtio-snd.h |  20 +---
 2 files changed, 111 insertions(+), 122 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 435ce26430..bbbdd01aa9 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -31,11 +31,30 @@
 #define VIRTIO_SOUND_CHMAP_DEFAULT 0
 #define VIRTIO_SOUND_HDA_FN_NID 0
 
+#define VSND_PCMSTREAM_STATE_F_PARAMS_SET  0x1
+#define VSND_PCMSTREAM_STATE_F_PREPARED0x2
+#define VSND_PCMSTREAM_STATE_F_ACTIVE  0x4
+
+#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
+#define VSND_PCMSTREAM_STATE_PARAMS_SET(1 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+#define VSND_PCMSTREAM_STATE_PREPARED  (2 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_STARTED   (4 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED \
+   | VSND_PCMSTREAM_STATE_F_ACTIVE)
+#define VSND_PCMSTREAM_STATE_STOPPED   (6 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_RELEASED  (7 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+
 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 void virtio_snd_unrealize(DeviceState *dev);
 
 static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
   | BIT(VIRTIO_SND_PCM_FMT_U8)
@@ -153,8 +172,8 @@ virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd)
 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];
+return stream_id >= s->snd_conf.streams ? NULL
+: >streams[stream_id];
 }
 
 /*
@@ -167,7 +186,7 @@ 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
-: >pcm->pcm_params[stream_id];
+: >streams[stream_id].params;
 }
 
 /*
@@ -253,11 +272,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
 
 /*
  * 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
+ * @stream_id: stream id
  * @params: The PCM params as defined in the virtio specification
  */
 static
@@ -265,9 +283,10 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
uint32_t stream_id,
virtio_snd_pcm_set_params *params)
 {
+VirtIOSoundPCMStream *stream;
 virtio_snd_pcm_set_params *st_params;
 
-if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) {
+if (stream_id >= s->snd_conf.streams) {
 /*
  * TODO: do we need to set DEVICE_NEEDS_RESET?
  */
@@ -275,7 +294,17 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
 }
 
-st_params = virtio_snd_pcm_get_params(s, stream_id);
+stream = virtio_snd_pcm_get_stream(s, stream_id);
+
+switch (stream->state) {
+case VSND_PCMSTREAM_STATE_UNINITIALIZED:
+case VSND_PCMSTREAM_STATE_PARAMS_SET:
+case VSND_PCMSTREAM_STATE_PREPARED:
+case VSND_PCMSTREAM_STATE_RELEASED:
+break;
+default:
+return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+}
 
 if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
 error_report("Number of channels is not supported.");
@@ -290,6 +319,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound 

[PATCH v2 03/11] hw/audio/virtio-sound: remove command and stream mutexes

2024-02-18 Thread Volker Rümelin
All code in virtio-snd.c runs with the BQL held. Remove the
command queue mutex and the stream queue mutexes. The qatomic
functions are also not needed.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 215 +++---
 include/hw/audio/virtio-snd.h |   3 -
 2 files changed, 93 insertions(+), 125 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index b87653daf4..7ed5f3de3e 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -19,7 +19,6 @@
 #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"
@@ -454,7 +453,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 stream->id = stream_id;
 stream->pcm = s->pcm;
 stream->s = s;
-qemu_mutex_init(>queue_mutex);
 QSIMPLEQ_INIT(>queue);
 
 /*
@@ -580,9 +578,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
 if (stream) {
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-stream->active = start;
-}
+stream->active = start;
 if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
 AUD_set_active_out(stream->voice.out, start);
 } else {
@@ -606,10 +602,8 @@ static size_t 
virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
 VirtIOSoundPCMBuffer *buffer, *next;
 size_t count = 0;
 
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
-count += 1;
-}
+QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
+count += 1;
 }
 return count;
 }
@@ -760,23 +754,15 @@ static void virtio_snd_process_cmdq(VirtIOSound *s)
 {
 virtio_snd_ctrl_command *cmd;
 
-if (unlikely(qatomic_read(>processing_cmdq))) {
-return;
-}
-
-WITH_QEMU_LOCK_GUARD(>cmdq_mutex) {
-qatomic_set(>processing_cmdq, true);
-while (!QTAILQ_EMPTY(>cmdq)) {
-cmd = QTAILQ_FIRST(>cmdq);
+while (!QTAILQ_EMPTY(>cmdq)) {
+cmd = QTAILQ_FIRST(>cmdq);
 
-/* process command */
-process_cmd(s, cmd);
+/* process command */
+process_cmd(s, cmd);
 
-QTAILQ_REMOVE(>cmdq, cmd, next);
+QTAILQ_REMOVE(>cmdq, cmd, next);
 
-virtio_snd_ctrl_cmd_free(cmd);
-}
-qatomic_set(>processing_cmdq, false);
+virtio_snd_ctrl_cmd_free(cmd);
 }
 }
 
@@ -891,18 +877,16 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 goto tx_err;
 }
 
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
+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;
+buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
+buffer->elem = elem;
+buffer->populated = false;
+buffer->vq = vq;
+buffer->size = size;
+buffer->offset = 0;
 
-QSIMPLEQ_INSERT_TAIL(>queue, buffer, entry);
-}
+QSIMPLEQ_INSERT_TAIL(>queue, buffer, entry);
 continue;
 
 tx_err:
@@ -967,16 +951,14 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
 goto rx_err;
 }
-WITH_QEMU_LOCK_GUARD(>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(>queue, buffer, entry);
-}
+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(>queue, buffer, entry);
 continue;
 
 rx_err:
@@ -1083,7 +1065,6 @@ static void virtio_snd_realize(DeviceState *dev, Error 
**errp)
 virtio_add_queue(vdev, 64, virtio_snd_handle_tx_xfer);
 vsnd->queues[VIRTIO_SND_VQ_RX] =
 virtio_

[PATCH v2 04/11] hw/audio/virtio-sound: allocate an array of streams

2024-02-18 Thread Volker Rümelin
It is much easier to migrate an array of structs than individual
structs that are accessed via a pointer to a pointer to an array
of pointers to struct.

For this reason, allocate an array of streams in
virtio_snd_realize() and initialise all stream variables that
are constant at runtime immediately after allocation.

This makes it easier to remove the virtio_snd_set_pcm_params()
and virtio_snd_pcm_prepare() calls in the realisation phase and
to migrate the audio streams of the virtio sound device after
the next few patches.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 37 ++-
 include/hw/audio/virtio-snd.h |  1 +
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 7ed5f3de3e..e5497b6bf6 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -448,12 +448,9 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
 if (stream == NULL) {
-stream = g_new0(VirtIOSoundPCMStream, 1);
+stream = >streams[stream_id];
 stream->active = false;
-stream->id = stream_id;
 stream->pcm = s->pcm;
-stream->s = s;
-QSIMPLEQ_INIT(>queue);
 
 /*
  * stream_id >= s->snd_conf.streams was checked before so this is
@@ -463,14 +460,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 }
 
 virtio_snd_get_qemu_audsettings(, 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;
@@ -1040,6 +1029,25 @@ static void virtio_snd_realize(DeviceState *dev, Error 
**errp)
 vsnd->vmstate =
 qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
 
+vsnd->streams = g_new0(VirtIOSoundPCMStream, vsnd->snd_conf.streams);
+
+for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
+VirtIOSoundPCMStream *stream = >streams[i];
+
+stream->id = i;
+stream->s = vsnd;
+QSIMPLEQ_INIT(>queue);
+stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
+stream->info.features = 0;
+stream->info.formats = supported_formats;
+stream->info.rates = supported_rates;
+stream->info.direction =
+i < vsnd->snd_conf.streams / 2 + (vsnd->snd_conf.streams & 1)
+? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
+stream->info.channels_min = 1;
+stream->info.channels_max = 2;
+}
+
 vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
 vsnd->pcm->snd = vsnd;
 vsnd->pcm->streams =
@@ -1280,14 +1288,13 @@ static void virtio_snd_unrealize(DeviceState *dev)
 qemu_del_vm_change_state_handler(vsnd->vmstate);
 trace_virtio_snd_unrealize(vsnd);
 
-if (vsnd->pcm) {
+if (vsnd->streams) {
 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);
@@ -1295,6 +1302,8 @@ static void virtio_snd_unrealize(DeviceState *dev)
 g_free(vsnd->pcm->pcm_params);
 g_free(vsnd->pcm);
 vsnd->pcm = NULL;
+g_free(vsnd->streams);
+vsnd->streams = NULL;
 }
 AUD_remove_card(>card);
 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index a2868067fb..95aef8192a 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -215,6 +215,7 @@ struct VirtIOSound {
 VirtQueue *queues[VIRTIO_SND_VQ_MAX];
 uint64_t features;
 VirtIOSoundPCM *pcm;
+VirtIOSoundPCMStream *streams;
 QEMUSoundCard card;
 VMChangeStateEntry *vmstate;
 virtio_snd_config snd_conf;
-- 
2.35.3




[PATCH v2 11/11] hw/audio/virtio-sound: add placeholder for buffer write position

2024-02-18 Thread Volker Rümelin
When a running audio stream is migrated, on average half of a
recording stream buffer is lost or half of a playback stream
buffer is played twice. Add a placeholder for the write position
of the current stream buffer to the migrated data. Additional
program code is required to resolve the above issues. However,
the placeholder makes it possible to add code in a backwards and
forwards compatible way.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 2 ++
 include/hw/audio/virtio-snd.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index b0a0ff2456..453c3a37ba 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -82,6 +82,7 @@ static const VMStateDescription vmstate_virtio_snd_stream = {
 .name = "virtio-sound-stream",
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32(state, VirtIOSoundPCMStream),
+VMSTATE_UINT32(buf_wpos, VirtIOSoundPCMStream),
 VMSTATE_UINT32(info.hdr.hda_fn_nid, VirtIOSoundPCMStream),
 VMSTATE_UINT32(info.features, VirtIOSoundPCMStream),
 VMSTATE_UINT64(info.formats, VirtIOSoundPCMStream),
@@ -1395,6 +1396,7 @@ static int virtio_snd_post_load(VirtIODevice *vdev)
 virtio_snd_pcm_set_active(stream, true);
 }
 }
+stream->buf_wpos = 0;
 }
 
 for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index 457d18d196..9be0276996 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -124,6 +124,8 @@ struct VirtIOSoundPCMStream {
 virtio_snd_pcm_set_params params;
 uint32_t id;
 uint32_t state;
+/* placeholder: write position in current VirtIOSoundPCMBuffer */
+uint32_t buf_wpos;
 /* channel position values (VIRTIO_SND_CHMAP_XXX) */
 uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
 VirtIOSound *s;
-- 
2.35.3




[PATCH v2 10/11] hw/audio/virtio-sound: add missing vmstate fields

2024-02-18 Thread Volker Rümelin
The virtio-sound device is currently not migratable. Add the
missing VMSTATE fields, enable migration and reconnect the audio
streams after migration.

The queue_inuse[] array variables mimic the inuse variable in
struct VirtQueue which is private. They are needed to restart
the virtio queues after migration.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 84 +++
 include/hw/audio/virtio-snd.h |  1 +
 2 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 06a27ef8d9..b0a0ff2456 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -25,7 +25,6 @@
 #include "hw/audio/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 2
 #define VIRTIO_SOUND_CHMAP_DEFAULT 0
@@ -79,17 +78,40 @@ static uint32_t supported_rates = 
BIT(VIRTIO_SND_PCM_RATE_5512)
 | BIT(VIRTIO_SND_PCM_RATE_192000)
 | BIT(VIRTIO_SND_PCM_RATE_384000);
 
+static const VMStateDescription vmstate_virtio_snd_stream = {
+.name = "virtio-sound-stream",
+.fields = (const VMStateField[]) {
+VMSTATE_UINT32(state, VirtIOSoundPCMStream),
+VMSTATE_UINT32(info.hdr.hda_fn_nid, VirtIOSoundPCMStream),
+VMSTATE_UINT32(info.features, VirtIOSoundPCMStream),
+VMSTATE_UINT64(info.formats, VirtIOSoundPCMStream),
+VMSTATE_UINT64(info.rates, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.direction, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.channels_min, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.channels_max, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.buffer_bytes, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.period_bytes, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.features, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.channels, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.format, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.rate, VirtIOSoundPCMStream),
+VMSTATE_END_OF_LIST()
+},
+};
+
 static const VMStateDescription vmstate_virtio_snd_device = {
-.name = TYPE_VIRTIO_SND,
-.version_id = VIRTIO_SOUND_VM_VERSION,
-.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
+.name = "virtio-sound-device",
+.fields = (const VMStateField[]) {
+VMSTATE_UINT32_ARRAY(queue_inuse, VirtIOSound, VIRTIO_SND_VQ_MAX),
+VMSTATE_STRUCT_VARRAY_POINTER_UINT32(streams, VirtIOSound,
+snd_conf.streams,
+vmstate_virtio_snd_stream, VirtIOSoundPCMStream),
+VMSTATE_END_OF_LIST()
+},
 };
 
 static const VMStateDescription vmstate_virtio_snd = {
-.name = TYPE_VIRTIO_SND,
-.unmigratable = 1,
-.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
-.version_id = VIRTIO_SOUND_VM_VERSION,
+.name = "virtio-sound",
 .fields = (const VMStateField[]) {
 VMSTATE_VIRTIO_DEVICE,
 VMSTATE_END_OF_LIST()
@@ -812,6 +834,7 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
  sizeof(virtio_snd_hdr));
 virtqueue_push(cmd->vq, cmd->elem,
sizeof(virtio_snd_hdr) + cmd->payload_size);
+s->queue_inuse[VIRTIO_SND_VQ_CONTROL] -= 1;
 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
 }
 
@@ -858,6 +881,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 
 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
 while (elem) {
+s->queue_inuse[VIRTIO_SND_VQ_CONTROL] += 1;
 cmd = g_new0(virtio_snd_ctrl_command, 1);
 cmd->elem = elem;
 cmd->vq = vq;
@@ -946,6 +970,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 goto tx_err;
 }
 
+s->queue_inuse[VIRTIO_SND_VQ_TX] += 1;
 size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
 
 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
@@ -1019,6 +1044,8 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 if (stream->info.direction != VIRTIO_SND_D_INPUT) {
 goto rx_err;
 }
+
+s->queue_inuse[VIRTIO_SND_VQ_RX] += 1;
 size = iov_size(elem->in_sg, elem->in_num) -
 sizeof(virtio_snd_pcm_status);
 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
@@ -1154,6 +1181,7 @@ static inline void return_tx_buffer(VirtIOSoundPCMStream 
*stream,
 virtqueue_push(buffer->vq,
buffer->elem,
sizeof(virtio_snd_pcm_status));
+stream->s->queue_inuse[VIRTIO_SND_VQ_TX] -= 1;
 virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
 QSIMPLEQ_REMOVE(>queue,
 buffer,
@@ -1245,6 +1273,7 @@ static inline void return_rx_buffer(VirtIOS

[PATCH v2 01/11] hw/audio/virtio-sound: return correct command response size

2024-02-18 Thread Volker Rümelin
The payload size returned by command VIRTIO_SND_R_PCM_INFO is
wrong. The code in process_cmd() assumes that all commands
return only a virtio_snd_hdr payload, but some commands like
VIRTIO_SND_R_PCM_INFO may return an additional payload.

Add a zero initialized payload_size variable to struct
virtio_snd_ctrl_command to allow for additional payloads.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 7 +--
 include/hw/audio/virtio-snd.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index ea2aeaef14..e604d8f30c 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -243,12 +243,13 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
 memset(_info[i].padding, 0, 5);
 }
 
+cmd->payload_size = sizeof(virtio_snd_pcm_info) * count;
 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);
+ cmd->payload_size);
 }
 
 /*
@@ -749,7 +750,8 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
  0,
  >resp,
  sizeof(virtio_snd_hdr));
-virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
+virtqueue_push(cmd->vq, cmd->elem,
+   sizeof(virtio_snd_hdr) + cmd->payload_size);
 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
 }
 
@@ -808,6 +810,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 cmd->elem = elem;
 cmd->vq = vq;
 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
+/* implicit cmd->payload_size = 0; */
 QTAILQ_INSERT_TAIL(>cmdq, cmd, next);
 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
 }
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index c3767f442b..3d79181364 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -230,6 +230,7 @@ struct virtio_snd_ctrl_command {
 VirtQueue *vq;
 virtio_snd_hdr ctrl;
 virtio_snd_hdr resp;
+size_t payload_size;
 QTAILQ_ENTRY(virtio_snd_ctrl_command) next;
 };
 #endif
-- 
2.35.3




[PATCH v2 00/11] virtio-sound migration part 1

2024-02-18 Thread Volker Rümelin
Here is the first part of my virtio-sound patches. Most of them are a
preparation to make migration work. Patch 10/11 enables migration.

The second part isn't finished yet and will have to do with virtio-sound
jack and channel maps configuration and migration.

Patch 01/11 "hw/audio/virtio-sound: return correct command response
size", patch 02/11 "hw/audio/virtio-sound: fix segmentation fault in
tx/rx xfer handler" and patch 05/11 "hw/audio/virtio-sound: free all
stream buffers on reset" are candidates for stable-8.2. Patch 05/11
either needs patches 03/11 and 04/11 or has to be rewritten for stable-8.2.

v2:
The patches were reordered to facilitate the backport of 3 patches to
QEMU stable-8.2.

Patch 02/11 "fix segmentation fault in tx/rx xfer handler" has been
completely rewritten.

Patch 04/11 "hw/audio/virtio-sound: allocate an array of streams" has
been renamed. The subject and the commit message describe the patch better.

Patch 05/11 "hw/audio/virtio-sound: free all stream buffers on reset" is
an additional patch.

Patch 07/11 "hw/audio/virtio-sound: add stream state variable" resets
the state variable on reset. Once a stream has been opened, it will only
be closed after a reset or when QEMU shuts down.

Patch 10/11 "add missing vmstate fields" resets the inuse variables on
reset.

Volker Rümelin (11):
  hw/audio/virtio-sound: return correct command response size
  hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler
  hw/audio/virtio-sound: remove command and stream mutexes
  hw/audio/virtio-sound: allocate an array of streams
  hw/audio/virtio-sound: free all stream buffers on reset
  hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
  hw/audio/virtio-sound: add stream state variable
  hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
  hw/audio/virtio-sound: introduce virtio_snd_set_active()
  hw/audio/virtio-sound: add missing vmstate fields
  hw/audio/virtio-sound: add placeholder for buffer write position

 hw/audio/trace-events |   3 +-
 hw/audio/virtio-snd.c | 776 ++
 include/hw/audio/virtio-snd.h |  29 +-
 3 files changed, 427 insertions(+), 381 deletions(-)

-- 
2.35.3



Re: [PATCH 05/10] hw/audio/virtio-sound: return correct command response size

2024-02-18 Thread Volker Rümelin
Am 05.01.24 um 12:36 schrieb Marc-André Lureau:
> Hi
>
> On Fri, Jan 5, 2024 at 12:34 AM Volker Rümelin  wrote:
>> The payload size returned by command VIRTIO_SND_R_PCM_INFO is
>> wrong. The code in process_cmd() assumes that all commands
>> return only a virtio_snd_hdr payload, but some commands like
>> VIRTIO_SND_R_PCM_INFO may return an additional payload.
>>
>> Add a zero initialized payload_size variable to struct
>> virtio_snd_ctrl_command to allow for additional payloads.
>>
>> Signed-off-by: Volker Rümelin 
>> ---
>>  hw/audio/virtio-snd.c | 7 +--
>>  include/hw/audio/virtio-snd.h | 1 +
>>  2 files changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>> index a2817a64b5..9f3269d72b 100644
>> --- a/hw/audio/virtio-snd.c
>> +++ b/hw/audio/virtio-snd.c
>> @@ -262,12 +262,13 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
>>  memset(_info[i].padding, 0, 5);
>>  }
>>
>> +cmd->payload_size = sizeof(virtio_snd_pcm_info) * count;
>>  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);
>> + cmd->payload_size);
> iov_from_buf() return value should probably be checked to match the
> expected written size..
>
> The earlier check for iov_size() is then probably redundant. Hmm, it
> checks for req.size, which should probably match
> sizeof(virtio_snd_pcm_info) too.

I wouldn't like to change that in this patch. There are more places in
this device and also in other virtio devices where this is done in
exactly the same way.

>
>>  }
>>
>>  /*
>> @@ -805,7 +806,8 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
>>   0,
>>   >resp,
>>   sizeof(virtio_snd_hdr));
>> -virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
>> +virtqueue_push(cmd->vq, cmd->elem,
>> +   sizeof(virtio_snd_hdr) + cmd->payload_size);
>>  virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
>>  }
>>
>> @@ -856,6 +858,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
>> VirtQueue *vq)
>>  cmd->elem = elem;
>>  cmd->vq = vq;
>>  cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
>> +/* implicit cmd->payload_size = 0; */
>>  QTAILQ_INSERT_TAIL(>cmdq, cmd, next);
>>  elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
>>  }
>> diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
>> index d1a68444d0..d6e08bd30d 100644
>> --- a/include/hw/audio/virtio-snd.h
>> +++ b/include/hw/audio/virtio-snd.h
>> @@ -210,6 +210,7 @@ struct virtio_snd_ctrl_command {
>>  VirtQueue *vq;
>>  virtio_snd_hdr ctrl;
>>  virtio_snd_hdr resp;
>> +size_t payload_size;
>>  QTAILQ_ENTRY(virtio_snd_ctrl_command) next;
>>  };
>>  #endif
>> --
>> 2.35.3
>>
> otherwise, lgtm. Should it be backported to -stable ?

Yes, I will cc qemu-stable in my v2 series. While the Linux virtio sound
driver ignores the returned "used length", this is required by the
virtio specification.

> Reviewed-by: Marc-André Lureau 
>




Re: [PATCH 02/10] hw/audio/virtio-sound: allocate all streams in advance

2024-01-06 Thread Volker Rümelin
Am 05.01.24 um 11:54 schrieb Marc-André Lureau:
> Hi
>
> On Fri, Jan 5, 2024 at 12:34 AM Volker Rümelin  wrote:
>> It is much easier to migrate an array of structs than individual
>> structs that are accessed via a pointer to a pointer to an array
>> of pointers to struct, where some pointers can also be NULL.
>>
>> For this reason, the audio streams are already allocated during
>> the realization phase and all stream variables that are constant
>> at runtime are initialised immediately after allocation. This is
>> a step towards being able to migrate the audio streams of the
>> virtio sound device after the next few patches.
>>
>> Signed-off-by: Volker Rümelin 
>> ---
>>  hw/audio/virtio-snd.c | 35 ++-
>>  include/hw/audio/virtio-snd.h |  1 +
>>  2 files changed, 23 insertions(+), 13 deletions(-)
>>
>> diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
>> index 8344f61c64..36b1bb502c 100644
>> --- a/hw/audio/virtio-snd.c
>> +++ b/hw/audio/virtio-snd.c
>> @@ -447,11 +447,9 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
>> uint32_t stream_id)
>>
>>  stream = virtio_snd_pcm_get_stream(s, stream_id);
>>  if (stream == NULL) {
>> -stream = g_new0(VirtIOSoundPCMStream, 1);
>> +stream = >streams[stream_id];
>>  stream->active = false;
>> -stream->id = stream_id;
>>  stream->pcm = s->pcm;
>> -stream->s = s;
>>  QSIMPLEQ_INIT(>queue);
>>  QSIMPLEQ_INIT(>invalid);
> note: I can't find where s->pcm->streams[stream_id] is reset to NULL
> on pcm_release...

Hi Marc-André,

right, I'll have to remove the subordinate clause from the commit
message where I claim some pointers can be NULL. All streams get
allocated in virtio_snd_realize() with calls of virtio_snd_pcm_prepare()
and get freed in virtio_snd_unrealize().

>> @@ -463,14 +461,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
>> uint32_t stream_id)
>>  }
>>
>>  virtio_snd_get_qemu_audsettings(, 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;
>> @@ -1074,6 +1064,24 @@ static void virtio_snd_realize(DeviceState *dev, 
>> Error **errp)
>>  vsnd->vmstate =
>>  qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
>>
>> +vsnd->streams = g_new0(VirtIOSoundPCMStream, vsnd->snd_conf.streams);
>> +
>> +for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
>> +VirtIOSoundPCMStream *stream = >streams[i];
>> +
>> +stream->id = i;
>> +stream->s = vsnd;
>> +stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
>> +stream->info.features = 0;
>> +stream->info.formats = supported_formats;
>> +stream->info.rates = supported_rates;
>> +stream->info.direction =
>> +i < vsnd->snd_conf.streams / 2 + (vsnd->snd_conf.streams & 1)
>> +? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
>> +stream->info.channels_min = 1;
>> +stream->info.channels_max = 2;
> Fixed max channels set to 2.. ? before this was set to
> MIN(AUDIO_MAX_CHANNELS, params->channels)

Before my patch params->channels and stream->info.max_channels were also
2 at the time the guest driver queried stream info. They got initialized
in function virtio_snd_realize().

default_params.channels = 2;
...
status = virtio_snd_set_pcm_params(vsnd, i, _params);
...
status = virtio_snd_pcm_prepare(vsnd, i);

The guest may not update stream->info variables. They are configuration
information set when QEMU starts. This was wrong in
virtio_snd_pcm_prepare().

>
>> +}
>> +
>>  vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
>>  vsnd->pcm->snd = vsnd;
>>  vsnd->pcm->streams =
>> @@ -1314,14 +1322,13 @@ static void virtio_snd_unrealize(DeviceState *dev)
>>  qemu_del_vm_change_state_handler(vsnd->vmstate);
>>  trace_

[PATCH 07/10] hw/audio/virtio-sound: introduce virtio_snd_set_active()

2024-01-04 Thread Volker Rümelin
Split out the function virtio_snd_pcm_set_active() from
virtio_snd_pcm_start_stop(). A later patch also needs this
new funcion. There is no functional change.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 21 -
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index a1d2b3367e..16e8c49655 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -473,6 +473,21 @@ static void virtio_snd_pcm_open(VirtIOSoundPCMStream 
*stream)
 }
 }
 
+/*
+ * Activate/deactivate a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ * @active: whether to activate or deactivate the stream
+ */
+static void virtio_snd_pcm_set_active(VirtIOSoundPCMStream *stream, bool 
active)
+{
+if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
+AUD_set_active_out(stream->voice.out, active);
+} else {
+AUD_set_active_in(stream->voice.in, active);
+}
+}
+
 /*
  * Close a stream and free all its resources.
  *
@@ -613,11 +628,7 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
 stream->state = VSND_PCMSTREAM_STATE_STOPPED;
 }
 
-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);
-}
+virtio_snd_pcm_set_active(stream, start);
 
 return cpu_to_le32(VIRTIO_SND_S_OK);
 }
-- 
2.35.3




[PATCH 04/10] hw/audio/virtio-sound: add stream state variable

2024-01-04 Thread Volker Rümelin
So far, only rudimentary checks have been made to ensure that
the guest only performs state transitions permitted in
virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
variable per audio stream and check all state transitions.

Because only permitted state transitions are possible, only one
copy of the audio stream parameters is required and these do not
need to be initialised with default values.

The state variable will also make it easier to restore the audio
stream after migration.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 219 ++
 include/hw/audio/virtio-snd.h |  20 +---
 2 files changed, 116 insertions(+), 123 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 040bc32ebe..a2817a64b5 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -31,11 +31,31 @@
 #define VIRTIO_SOUND_CHMAP_DEFAULT 0
 #define VIRTIO_SOUND_HDA_FN_NID 0
 
+#define VSND_PCMSTREAM_STATE_F_PARAMS_SET  0x1
+#define VSND_PCMSTREAM_STATE_F_PREPARED0x2
+#define VSND_PCMSTREAM_STATE_F_ACTIVE  0x4
+
+#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
+#define VSND_PCMSTREAM_STATE_PARAMS_SET(1 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+#define VSND_PCMSTREAM_STATE_PREPARED  (2 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_STARTED   (4 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED \
+   | VSND_PCMSTREAM_STATE_F_ACTIVE)
+#define VSND_PCMSTREAM_STATE_STOPPED   (6 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET 
\
+   | VSND_PCMSTREAM_STATE_F_PREPARED)
+#define VSND_PCMSTREAM_STATE_RELEASED  (7 \
+   | VSND_PCMSTREAM_STATE_F_PARAMS_SET)
+
 static void virtio_snd_pcm_out_cb(void *data, int available);
 static void virtio_snd_process_cmdq(VirtIOSound *s);
+static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream);
 static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
 static void virtio_snd_pcm_in_cb(void *data, int available);
-static void virtio_snd_unrealize(DeviceState *dev);
 
 static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
   | BIT(VIRTIO_SND_PCM_FMT_U8)
@@ -153,8 +173,8 @@ virtio_snd_ctrl_cmd_free(virtio_snd_ctrl_command *cmd)
 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];
+return stream_id >= s->snd_conf.streams ? NULL
+: >streams[stream_id];
 }
 
 /*
@@ -167,7 +187,7 @@ 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
-: >pcm->pcm_params[stream_id];
+: >streams[stream_id].params;
 }
 
 /*
@@ -252,11 +272,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
 
 /*
  * 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
+ * @stream_id: stream id
  * @params: The PCM params as defined in the virtio specification
  */
 static
@@ -264,9 +283,10 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
uint32_t stream_id,
virtio_snd_pcm_set_params *params)
 {
+VirtIOSoundPCMStream *stream;
 virtio_snd_pcm_set_params *st_params;
 
-if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) {
+if (stream_id >= s->snd_conf.streams) {
 /*
  * TODO: do we need to set DEVICE_NEEDS_RESET?
  */
@@ -274,7 +294,17 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
 return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
 }
 
-st_params = virtio_snd_pcm_get_params(s, stream_id);
+stream = virtio_snd_pcm_get_stream(s, stream_id);
+
+switch (stream->state) {
+case VSND_PCMSTREAM_STATE_UNINITIALIZED:
+case VSND_PCMSTREAM_STATE_PARAMS_SET:
+case VSND_PCMSTREAM_STATE_PREPARED:
+case VSND_PCMSTREAM_STATE_RELEASED:
+break;
+default:
+return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+}
 
 if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
 error_report("Number of channels is not supported.");
@@ -289

[PATCH 08/10] hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler

2024-01-04 Thread Volker Rümelin
With the involvement of a malicious guest, it's possible to reach
the error paths in the virtio_snd_handle_tx/rx_xfer handlers with
stream == NULL. This triggers a segmentation fault.

Move the queues for invalid messages from the stream structs to
the device struct and initialize the queues quite early so they
are always available to avoid this kind of issue.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 84 ---
 include/hw/audio/virtio-snd.h |  8 +++-
 2 files changed, 45 insertions(+), 47 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 16e8c49655..92b10287ad 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -531,7 +531,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 
 if (!(stream->state & VSND_PCMSTREAM_STATE_F_PREPARED)) {
 QSIMPLEQ_INIT(>queue);
-QSIMPLEQ_INIT(>invalid);
 }
 
 virtio_snd_pcm_open(stream);
@@ -677,9 +676,6 @@ static size_t 
virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
 QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
 count += 1;
 }
-QSIMPLEQ_FOREACH_SAFE(buffer, >invalid, entry, next) {
-count += 1;
-}
 return count;
 }
 
@@ -895,44 +891,38 @@ static void virtio_snd_handle_event(VirtIODevice *vdev, 
VirtQueue *vq)
 trace_virtio_snd_handle_event();
 }
 
-static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq)
+static void empty_invalid_queue(VirtIODevice *vdev, uint32_t queue_index)
 {
+VirtIOSound *s = VIRTIO_SND(vdev);
+VirtQueue *vq;
 VirtIOSoundPCMBuffer *buffer = NULL;
-VirtIOSoundPCMStream *stream = NULL;
+VirtIOSoundPCMBufferSimpleQueue *invalidq;
 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 = >streams[i];
-if (stream) {
-any = false;
-while (!QSIMPLEQ_EMPTY(>invalid)) {
-buffer = QSIMPLEQ_FIRST(>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,
- ,
- sizeof(virtio_snd_pcm_status));
-virtqueue_push(vq,
-   buffer->elem,
-   sizeof(virtio_snd_pcm_status));
-QSIMPLEQ_REMOVE_HEAD(>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);
-}
-}
+vq = s->queues[queue_index];
+invalidq = s->invalidq[queue_index];
+while (!QSIMPLEQ_EMPTY(invalidq)) {
+any = true;
+buffer = QSIMPLEQ_FIRST(invalidq);
+resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+iov_from_buf(buffer->elem->in_sg,
+ buffer->elem->in_num,
+ 0,
+ ,
+ sizeof(virtio_snd_pcm_status));
+virtqueue_push(vq,
+   buffer->elem,
+   sizeof(virtio_snd_pcm_status));
+QSIMPLEQ_REMOVE_HEAD(invalidq, 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);
 }
 }
 
@@ -953,8 +943,8 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 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.
+ * If any of the I/O messages are invalid, put them in
+ * s->invalidq[VIRTIO_SND_VQ_TX] and return them after the for loop.
  */
 bool must_empty_invalid_queue = false;
 
@@ -1005,11 +995,11 @@ tx_err:
 buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
 buffer->elem = elem;
 buffer->vq = vq;
-QSIMPLEQ_INSERT_TAIL(>invalid, buffer, entry);
+QSIMPLEQ_INSERT_TAIL(s->invalidq[VIRTIO_SND_VQ_TX], buffer, entry);
 }
 
 if (must_empty_invalid_queue) {
-empty_invalid_queue(vdev, vq);
+empty_invalid_queue(vdev, VIRTIO_SND_VQ_TX);
 }
 }
 
@@ -1030,8 +1020,8 @@ static void virtio_snd_handle_rx_

[PATCH 10/10] hw/audio/virtio-sound: add placeholder for buffer write position

2024-01-04 Thread Volker Rümelin
When a running audio stream is migrated, on average half of a
recording stream buffer is lost or half of a playback stream
buffer is played twice. Add a placeholder for the write position
of the current stream buffer to the migrated data. Additional
program code is required to resolve the above issues. However,
the placeholder makes it possible to add code in a backwards and
forwards compatible way.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 2 ++
 include/hw/audio/virtio-snd.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 328ee54808..71281967bf 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -83,6 +83,7 @@ static const VMStateDescription vmstate_virtio_snd_stream = {
 .name = "virtio-sound-stream",
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32(state, VirtIOSoundPCMStream),
+VMSTATE_UINT32(buf_wpos, VirtIOSoundPCMStream),
 VMSTATE_UINT32(info.hdr.hda_fn_nid, VirtIOSoundPCMStream),
 VMSTATE_UINT32(info.features, VirtIOSoundPCMStream),
 VMSTATE_UINT64(info.formats, VirtIOSoundPCMStream),
@@ -1434,6 +1435,7 @@ static int virtio_snd_post_load(VirtIODevice *vdev)
 virtio_snd_pcm_set_active(stream, true);
 }
 }
+stream->buf_wpos = 0;
 }
 
 for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index 141e60e23c..d46204967a 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -127,6 +127,8 @@ struct VirtIOSoundPCMStream {
 virtio_snd_pcm_set_params params;
 uint32_t id;
 uint32_t state;
+/* placeholder: write position in current VirtIOSoundPCMBuffer */
+uint32_t buf_wpos;
 /* channel position values (VIRTIO_SND_CHMAP_XXX) */
 uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
 VirtIOSound *s;
-- 
2.35.3




[PATCH 09/10] hw/audio/virtio-sound: add missing vmstate fields

2024-01-04 Thread Volker Rümelin
The virtio-sound device is currently not migratable. Add the
missing VMSTATE fields, enable migration and reconnect the audio
streams after migration.

The queue_inuse[] array variables mimic the inuse variable in
struct VirtQueue which is private. They are needed to restart
the virtio queues after migration.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 81 +++
 include/hw/audio/virtio-snd.h |  1 +
 2 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 92b10287ad..328ee54808 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -25,7 +25,6 @@
 #include "hw/audio/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 2
 #define VIRTIO_SOUND_CHMAP_DEFAULT 0
@@ -80,17 +79,40 @@ static uint32_t supported_rates = 
BIT(VIRTIO_SND_PCM_RATE_5512)
 | BIT(VIRTIO_SND_PCM_RATE_192000)
 | BIT(VIRTIO_SND_PCM_RATE_384000);
 
+static const VMStateDescription vmstate_virtio_snd_stream = {
+.name = "virtio-sound-stream",
+.fields = (const VMStateField[]) {
+VMSTATE_UINT32(state, VirtIOSoundPCMStream),
+VMSTATE_UINT32(info.hdr.hda_fn_nid, VirtIOSoundPCMStream),
+VMSTATE_UINT32(info.features, VirtIOSoundPCMStream),
+VMSTATE_UINT64(info.formats, VirtIOSoundPCMStream),
+VMSTATE_UINT64(info.rates, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.direction, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.channels_min, VirtIOSoundPCMStream),
+VMSTATE_UINT8(info.channels_max, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.buffer_bytes, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.period_bytes, VirtIOSoundPCMStream),
+VMSTATE_UINT32(params.features, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.channels, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.format, VirtIOSoundPCMStream),
+VMSTATE_UINT8(params.rate, VirtIOSoundPCMStream),
+VMSTATE_END_OF_LIST()
+},
+};
+
 static const VMStateDescription vmstate_virtio_snd_device = {
-.name = TYPE_VIRTIO_SND,
-.version_id = VIRTIO_SOUND_VM_VERSION,
-.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
+.name = "virtio-sound-device",
+.fields = (const VMStateField[]) {
+VMSTATE_UINT32_ARRAY(queue_inuse, VirtIOSound, VIRTIO_SND_VQ_MAX),
+VMSTATE_STRUCT_VARRAY_POINTER_UINT32(streams, VirtIOSound,
+snd_conf.streams,
+vmstate_virtio_snd_stream, VirtIOSoundPCMStream),
+VMSTATE_END_OF_LIST()
+},
 };
 
 static const VMStateDescription vmstate_virtio_snd = {
-.name = TYPE_VIRTIO_SND,
-.unmigratable = 1,
-.minimum_version_id = VIRTIO_SOUND_VM_VERSION,
-.version_id = VIRTIO_SOUND_VM_VERSION,
+.name = "virtio-sound",
 .fields = (const VMStateField[]) {
 VMSTATE_VIRTIO_DEVICE,
 VMSTATE_END_OF_LIST()
@@ -820,6 +842,7 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
  sizeof(virtio_snd_hdr));
 virtqueue_push(cmd->vq, cmd->elem,
sizeof(virtio_snd_hdr) + cmd->payload_size);
+s->queue_inuse[VIRTIO_SND_VQ_CONTROL] -= 1;
 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
 }
 
@@ -866,6 +889,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 
 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
 while (elem) {
+s->queue_inuse[VIRTIO_SND_VQ_CONTROL] += 1;
 cmd = g_new0(virtio_snd_ctrl_command, 1);
 cmd->elem = elem;
 cmd->vq = vq;
@@ -914,6 +938,7 @@ static void empty_invalid_queue(VirtIODevice *vdev, 
uint32_t queue_index)
 virtqueue_push(vq,
buffer->elem,
sizeof(virtio_snd_pcm_status));
+s->queue_inuse[queue_index] -= 1;
 QSIMPLEQ_REMOVE_HEAD(invalidq, entry);
 virtio_snd_pcm_buffer_free(buffer);
 }
@@ -958,6 +983,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 if (!elem) {
 break;
 }
+s->queue_inuse[VIRTIO_SND_VQ_TX] += 1;
 /* get the message hdr object */
 msg_sz = iov_to_buf(elem->out_sg,
 elem->out_num,
@@ -1035,6 +1061,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, 
VirtQueue *vq)
 if (!elem) {
 break;
 }
+s->queue_inuse[VIRTIO_SND_VQ_RX] += 1;
 /* get the message hdr object */
 msg_sz = iov_to_buf(elem->out_sg,
 elem->out_num,
@@ -1192,6 +1219,7 @@ static inline void return_tx_buffer(VirtIOSoundPCMStream 
*stream,
 virtqueue_push(buffer->vq,
buffer->elem,
  

[PATCH 03/10] hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()

2024-01-04 Thread Volker Rümelin
Split out virtio_snd_pcm_start_stop(). This is a preparation
for the next patch so that it doesn't become too big.

Signed-off-by: Volker Rümelin 
---
 hw/audio/trace-events |  3 ++-
 hw/audio/virtio-snd.c | 57 ---
 2 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index b1870ff224..7554bfcc60 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -50,7 +50,8 @@ 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
+virtio_snd_handle_pcm_start(uint32_t stream) "VIRTIO_SND_R_PCM_START called 
for stream %"PRIu32
+virtio_snd_handle_pcm_stop(uint32_t stream) "VIRTIO_SND_R_PCM_STOP 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"
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 36b1bb502c..040bc32ebe 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -534,7 +534,42 @@ static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
 }
 
 /*
- * Handles VIRTIO_SND_R_PCM_START.
+ * Starts/Stops a VirtIOSound card stream.
+ * Returns the response status code. (VIRTIO_SND_S_*).
+ *
+ * @s: VirtIOSound device
+ * @stream_id: stream id
+ * @start: whether to start or stop the stream
+ */
+static uint32_t virtio_snd_pcm_start_stop(VirtIOSound *s,
+  uint32_t stream_id,
+  bool start)
+{
+VirtIOSoundPCMStream *stream;
+
+stream = virtio_snd_pcm_get_stream(s, stream_id);
+if (!stream) {
+return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+}
+
+if (start) {
+trace_virtio_snd_handle_pcm_start(stream_id);
+} else {
+trace_virtio_snd_handle_pcm_stop(stream_id);
+}
+
+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);
+}
+
+return cpu_to_le32(VIRTIO_SND_S_OK);
+}
+
+/*
+ * Handles VIRTIO_SND_R_PCM_START and VIRTIO_SND_R_PCM_STOP.
  *
  * @s: VirtIOSound device
  * @cmd: The request command queue element from VirtIOSound cmdq field
@@ -544,7 +579,6 @@ 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,
@@ -562,24 +596,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound 
*s,
 }
 
 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) {
-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;
+cmd->resp.code = virtio_snd_pcm_start_stop(s, stream_id, start);
 }
 
 /*
-- 
2.35.3




[PATCH 05/10] hw/audio/virtio-sound: return correct command response size

2024-01-04 Thread Volker Rümelin
The payload size returned by command VIRTIO_SND_R_PCM_INFO is
wrong. The code in process_cmd() assumes that all commands
return only a virtio_snd_hdr payload, but some commands like
VIRTIO_SND_R_PCM_INFO may return an additional payload.

Add a zero initialized payload_size variable to struct
virtio_snd_ctrl_command to allow for additional payloads.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 7 +--
 include/hw/audio/virtio-snd.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index a2817a64b5..9f3269d72b 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -262,12 +262,13 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
 memset(_info[i].padding, 0, 5);
 }
 
+cmd->payload_size = sizeof(virtio_snd_pcm_info) * count;
 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);
+ cmd->payload_size);
 }
 
 /*
@@ -805,7 +806,8 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
  0,
  >resp,
  sizeof(virtio_snd_hdr));
-virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
+virtqueue_push(cmd->vq, cmd->elem,
+   sizeof(virtio_snd_hdr) + cmd->payload_size);
 virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
 }
 
@@ -856,6 +858,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, 
VirtQueue *vq)
 cmd->elem = elem;
 cmd->vq = vq;
 cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
+/* implicit cmd->payload_size = 0; */
 QTAILQ_INSERT_TAIL(>cmdq, cmd, next);
 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
 }
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index d1a68444d0..d6e08bd30d 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -210,6 +210,7 @@ struct virtio_snd_ctrl_command {
 VirtQueue *vq;
 virtio_snd_hdr ctrl;
 virtio_snd_hdr resp;
+size_t payload_size;
 QTAILQ_ENTRY(virtio_snd_ctrl_command) next;
 };
 #endif
-- 
2.35.3




[PATCH 02/10] hw/audio/virtio-sound: allocate all streams in advance

2024-01-04 Thread Volker Rümelin
It is much easier to migrate an array of structs than individual
structs that are accessed via a pointer to a pointer to an array
of pointers to struct, where some pointers can also be NULL.

For this reason, the audio streams are already allocated during
the realization phase and all stream variables that are constant
at runtime are initialised immediately after allocation. This is
a step towards being able to migrate the audio streams of the
virtio sound device after the next few patches.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 35 ++-
 include/hw/audio/virtio-snd.h |  1 +
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 8344f61c64..36b1bb502c 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -447,11 +447,9 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
 if (stream == NULL) {
-stream = g_new0(VirtIOSoundPCMStream, 1);
+stream = >streams[stream_id];
 stream->active = false;
-stream->id = stream_id;
 stream->pcm = s->pcm;
-stream->s = s;
 QSIMPLEQ_INIT(>queue);
 QSIMPLEQ_INIT(>invalid);
 
@@ -463,14 +461,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 }
 
 virtio_snd_get_qemu_audsettings(, 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;
@@ -1074,6 +1064,24 @@ static void virtio_snd_realize(DeviceState *dev, Error 
**errp)
 vsnd->vmstate =
 qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
 
+vsnd->streams = g_new0(VirtIOSoundPCMStream, vsnd->snd_conf.streams);
+
+for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
+VirtIOSoundPCMStream *stream = >streams[i];
+
+stream->id = i;
+stream->s = vsnd;
+stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
+stream->info.features = 0;
+stream->info.formats = supported_formats;
+stream->info.rates = supported_rates;
+stream->info.direction =
+i < vsnd->snd_conf.streams / 2 + (vsnd->snd_conf.streams & 1)
+? VIRTIO_SND_D_OUTPUT : VIRTIO_SND_D_INPUT;
+stream->info.channels_min = 1;
+stream->info.channels_max = 2;
+}
+
 vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
 vsnd->pcm->snd = vsnd;
 vsnd->pcm->streams =
@@ -1314,14 +1322,13 @@ static void virtio_snd_unrealize(DeviceState *dev)
 qemu_del_vm_change_state_handler(vsnd->vmstate);
 trace_virtio_snd_unrealize(vsnd);
 
-if (vsnd->pcm) {
+if (vsnd->streams) {
 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);
@@ -1329,6 +1336,8 @@ static void virtio_snd_unrealize(DeviceState *dev)
 g_free(vsnd->pcm->pcm_params);
 g_free(vsnd->pcm);
 vsnd->pcm = NULL;
+g_free(vsnd->streams);
+vsnd->streams = NULL;
 }
 AUD_remove_card(>card);
 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
index ea6315f59b..05b4490488 100644
--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -216,6 +216,7 @@ struct VirtIOSound {
 VirtQueue *queues[VIRTIO_SND_VQ_MAX];
 uint64_t features;
 VirtIOSoundPCM *pcm;
+VirtIOSoundPCMStream *streams;
 QEMUSoundCard card;
 VMChangeStateEntry *vmstate;
 virtio_snd_config snd_conf;
-- 
2.35.3




[PATCH 06/10] hw/audio/virtio-sound: introduce virtio_snd_pcm_open()

2024-01-04 Thread Volker Rümelin
Split out the function virtio_snd_pcm_open() from
virtio_snd_pcm_prepare(). A later patch also needs
the new function. There is no functional change.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 57 +++
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 9f3269d72b..a1d2b3367e 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -443,6 +443,36 @@ static void virtio_snd_get_qemu_audsettings(audsettings 
*as,
 as->endianness = target_words_bigendian() ? 1 : 0;
 }
 
+/*
+ * Open a stream.
+ *
+ * @stream: VirtIOSoundPCMStream *stream
+ */
+static void virtio_snd_pcm_open(VirtIOSoundPCMStream *stream)
+{
+virtio_snd_get_qemu_audsettings(>as, >params);
+stream->positions[0] = VIRTIO_SND_CHMAP_FL;
+stream->positions[1] = VIRTIO_SND_CHMAP_FR;
+
+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 {
+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);
+}
+}
+
 /*
  * Close a stream and free all its resources.
  *
@@ -468,8 +498,6 @@ static void virtio_snd_pcm_close(VirtIOSoundPCMStream 
*stream)
  */
 static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
 {
-audsettings as;
-virtio_snd_pcm_set_params *params;
 VirtIOSoundPCMStream *stream;
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
@@ -491,30 +519,7 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 QSIMPLEQ_INIT(>invalid);
 }
 
-params = virtio_snd_pcm_get_params(s, stream_id);
-
-virtio_snd_get_qemu_audsettings(, 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(>card,
- stream->voice.out,
- "virtio-sound.out",
- stream,
- virtio_snd_pcm_out_cb,
- );
-AUD_set_volume_out(stream->voice.out, 0, 255, 255);
-} else {
-stream->voice.in = AUD_open_in(>card,
-stream->voice.in,
-"virtio-sound.in",
-stream,
-virtio_snd_pcm_in_cb,
-);
-AUD_set_volume_in(stream->voice.in, 0, 255, 255);
-}
+virtio_snd_pcm_open(stream);
 
 stream->state = VSND_PCMSTREAM_STATE_PREPARED;
 
-- 
2.35.3




[PATCH 01/10] hw/audio/virtio-sound: remove command and stream mutexes

2024-01-04 Thread Volker Rümelin
All code in virtio-snd.c runs with the BQL held. Remove the
command queue mutex and the stream queue mutexes. The qatomic
functions are also not needed.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 294 +++---
 include/hw/audio/virtio-snd.h |   3 -
 2 files changed, 130 insertions(+), 167 deletions(-)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index ea2aeaef14..8344f61c64 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -19,7 +19,6 @@
 #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"
@@ -453,7 +452,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, 
uint32_t stream_id)
 stream->id = stream_id;
 stream->pcm = s->pcm;
 stream->s = s;
-qemu_mutex_init(>queue_mutex);
 QSIMPLEQ_INIT(>queue);
 QSIMPLEQ_INIT(>invalid);
 
@@ -580,9 +578,7 @@ static void virtio_snd_handle_pcm_start_stop(VirtIOSound *s,
 
 stream = virtio_snd_pcm_get_stream(s, stream_id);
 if (stream) {
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-stream->active = start;
-}
+stream->active = start;
 if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
 AUD_set_active_out(stream->voice.out, start);
 } else {
@@ -606,13 +602,11 @@ static size_t 
virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
 VirtIOSoundPCMBuffer *buffer, *next;
 size_t count = 0;
 
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
-count += 1;
-}
-QSIMPLEQ_FOREACH_SAFE(buffer, >invalid, entry, next) {
-count += 1;
-}
+QSIMPLEQ_FOREACH_SAFE(buffer, >queue, entry, next) {
+count += 1;
+}
+QSIMPLEQ_FOREACH_SAFE(buffer, >invalid, entry, next) {
+count += 1;
 }
 return count;
 }
@@ -762,23 +756,15 @@ static void virtio_snd_process_cmdq(VirtIOSound *s)
 {
 virtio_snd_ctrl_command *cmd;
 
-if (unlikely(qatomic_read(>processing_cmdq))) {
-return;
-}
-
-WITH_QEMU_LOCK_GUARD(>cmdq_mutex) {
-qatomic_set(>processing_cmdq, true);
-while (!QTAILQ_EMPTY(>cmdq)) {
-cmd = QTAILQ_FIRST(>cmdq);
+while (!QTAILQ_EMPTY(>cmdq)) {
+cmd = QTAILQ_FIRST(>cmdq);
 
-/* process command */
-process_cmd(s, cmd);
+/* process command */
+process_cmd(s, cmd);
 
-QTAILQ_REMOVE(>cmdq, cmd, next);
+QTAILQ_REMOVE(>cmdq, cmd, next);
 
-virtio_snd_ctrl_cmd_free(cmd);
-}
-qatomic_set(>processing_cmdq, false);
+virtio_snd_ctrl_cmd_free(cmd);
 }
 }
 
@@ -840,32 +826,30 @@ static inline void empty_invalid_queue(VirtIODevice 
*vdev, VirtQueue *vq)
 stream = vsnd->pcm->streams[i];
 if (stream) {
 any = false;
-WITH_QEMU_LOCK_GUARD(>queue_mutex) {
-while (!QSIMPLEQ_EMPTY(>invalid)) {
-buffer = QSIMPLEQ_FIRST(>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,
- ,
- sizeof(virtio_snd_pcm_status));
-virtqueue_push(vq,
-   buffer->elem,
-   sizeof(virtio_snd_pcm_status));
-QSIMPLEQ_REMOVE_HEAD(>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);
+while (!QSIMPLEQ_EMPTY(>invalid)) {
+buffer = QSIMPLEQ_FIRST(>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,
+ ,
+ sizeof(virtio_snd_pcm_status));
+virtqueue_push(vq,
+   

[PATCH 00/10] virtio-sound migration part 1

2024-01-04 Thread Volker Rümelin
Here is the first part of my virtio-sound patches. Most of them are a
preparation to make migration work. Patch 09/10 enables migration of the
virtio-sound device.

The second part isn't finished yet and will have to do with virtio-sound
jack and channel maps configuration and migration.

Volker Rümelin (10):
  hw/audio/virtio-sound: remove command and stream mutexes
  hw/audio/virtio-sound: allocate all streams in advance
  hw/audio/virtio-sound: split out virtio_snd_pcm_start_stop()
  hw/audio/virtio-sound: add stream state variable
  hw/audio/virtio-sound: return correct command response size
  hw/audio/virtio-sound: introduce virtio_snd_pcm_open()
  hw/audio/virtio-sound: introduce virtio_snd_set_active()
  hw/audio/virtio-sound: fix segmentation fault in tx/rx xfer handler
  hw/audio/virtio-sound: add missing vmstate fields
  hw/audio/virtio-sound: add placeholder for buffer write position

 hw/audio/trace-events |   3 +-
 hw/audio/virtio-snd.c | 771 +++---
 include/hw/audio/virtio-snd.h |  36 +-
 3 files changed, 441 insertions(+), 369 deletions(-)

-- 
2.35.3



[PATCH] hw/vfio: fix iteration over global VFIODevice list

2023-12-29 Thread Volker Rümelin
Commit 3d779abafe ("vfio/common: Introduce a global VFIODevice list")
introduced a global VFIODevice list, but forgot to update the list
element field name when iterating over the new list. Change the code
to use the correct list element field.

Fixes: 3d779abafe ("vfio/common: Introduce a global VFIODevice list")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2061
Signed-off-by: Volker Rümelin 
---
 hw/vfio/common.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 08a3e57672..3ba892d7d3 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -74,7 +74,7 @@ bool vfio_mig_active(void)
 return false;
 }
 
-QLIST_FOREACH(vbasedev, _device_list, next) {
+QLIST_FOREACH(vbasedev, _device_list, global_next) {
 if (vbasedev->migration_blocker) {
 return false;
 }
@@ -95,7 +95,7 @@ static bool vfio_multiple_devices_migration_is_supported(void)
 unsigned int device_num = 0;
 bool all_support_p2p = true;
 
-QLIST_FOREACH(vbasedev, _device_list, next) {
+QLIST_FOREACH(vbasedev, _device_list, global_next) {
 if (vbasedev->migration) {
 device_num++;
 
@@ -1367,13 +1367,13 @@ void vfio_reset_handler(void *opaque)
 {
 VFIODevice *vbasedev;
 
-QLIST_FOREACH(vbasedev, _device_list, next) {
+QLIST_FOREACH(vbasedev, _device_list, global_next) {
 if (vbasedev->dev->realized) {
 vbasedev->ops->vfio_compute_needs_reset(vbasedev);
 }
 }
 
-QLIST_FOREACH(vbasedev, _device_list, next) {
+QLIST_FOREACH(vbasedev, _device_list, global_next) {
 if (vbasedev->dev->realized && vbasedev->needs_reset) {
 vbasedev->ops->vfio_hot_reset_multi(vbasedev);
 }
-- 
2.35.3




Re: [PATCH for 8.2] hw/audio/virtio-sound: mark the device as unmigratable

2023-12-03 Thread Volker Rümelin
Am 04.12.23 um 08:28 schrieb Volker Rümelin:

> The virtio-sound device is currently not migratable. QEMU crashes
> on the source machine at some point during the migration with a
> segmentation fault.
>
> Even with this bug fixed, the virtio-sound device doesn't migrate
> the state of the audio streams. For example, running streams leave
> the device on the destination machine in a broken condition.
>
> Mark the device as unmigratable until these issues have been fixed.
>
> Signed-off-by: Volker Rümelin 
> ---
>  hw/audio/virtio-snd.c | 1 +
>  1 file changed, 1 insertion(+)

I already have a working patch series with 6 patches to fix these
issues. I wrote them in the last two days, which means they are not yet
in a reviewable state and the series is too big for 8.2. I think I need
another weekend or two before I send them to the qemu-devel mailing list.

With best regards,
Volker

> diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> index 2fe966e311..b10fad1228 100644
> --- a/hw/audio/virtio-snd.c
> +++ b/hw/audio/virtio-snd.c
> @@ -68,6 +68,7 @@ static const VMStateDescription vmstate_virtio_snd_device = 
> {
>  
>  static const VMStateDescription vmstate_virtio_snd = {
>  .name = TYPE_VIRTIO_SND,
> +.unmigratable = 1,
>  .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
>  .version_id = VIRTIO_SOUND_VM_VERSION,
>  .fields = (VMStateField[]) {




[PATCH for 8.2] hw/audio/virtio-sound: mark the device as unmigratable

2023-12-03 Thread Volker Rümelin
The virtio-sound device is currently not migratable. QEMU crashes
on the source machine at some point during the migration with a
segmentation fault.

Even with this bug fixed, the virtio-sound device doesn't migrate
the state of the audio streams. For example, running streams leave
the device on the destination machine in a broken condition.

Mark the device as unmigratable until these issues have been fixed.

Signed-off-by: Volker Rümelin 
---
 hw/audio/virtio-snd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 2fe966e311..b10fad1228 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -68,6 +68,7 @@ static const VMStateDescription vmstate_virtio_snd_device = {
 
 static const VMStateDescription vmstate_virtio_snd = {
 .name = TYPE_VIRTIO_SND,
+.unmigratable = 1,
 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
 .version_id = VIRTIO_SOUND_VM_VERSION,
 .fields = (VMStateField[]) {
-- 
2.35.3




Re: [PATCH for 8.2] ui/gtk-egl: move function calls back to regular code path

2023-12-03 Thread Volker Rümelin
Am 13.11.23 um 09:26 schrieb Marc-André Lureau:
> Hi
>
> On Sat, Nov 11, 2023 at 2:40 PM Volker Rümelin  wrote:
>> Commit 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing
>> scanout") introduced a regression when QEMU is running with a
>> virtio-gpu-gl-device on a host under X11. After the guest has
>> initialized the virtio-gpu-gl-device, the guest screen only
>> shows "Display output is not active.".
>>
>> Commit 6f189a08c1 moved all function calls in
>> gd_egl_scanout_texture() to a code path which is only called
>> once after gd_egl_init() succeeds in gd_egl_scanout_texture().
>> Move all function calls in gd_egl_scanout_texture() back to
>> the regular code path so they get always called if one of the
>> gd_egl_init() calls was successful.
>>
>> Fixes: 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing scanout")
>> Signed-off-by: Volker Rümelin 
> Reviewed-by: Marc-André Lureau 

Hi Marc-André,

as the de facto maintainer of the ui directory, could you please send a
pull request for this patch for 8.2-rc3?

With best regards,
Volker

>> ---
>>  ui/gtk-egl.c | 12 ++--
>>  1 file changed, 6 insertions(+), 6 deletions(-)
>>
>> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
>> index cd2f176502..3af5ac5bcf 100644
>> --- a/ui/gtk-egl.c
>> +++ b/ui/gtk-egl.c
>> @@ -249,14 +249,14 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
>>  if (!vc->gfx.esurface) {
>>  return;
>>  }
>> +}
>>
>> -eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>> -   vc->gfx.esurface, vc->gfx.ectx);
>> +eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>> +   vc->gfx.esurface, vc->gfx.ectx);
>>
>> -gtk_egl_set_scanout_mode(vc, true);
>> -egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
>> backing_height,
>> - backing_id, false);
>> -}
>> +gtk_egl_set_scanout_mode(vc, true);
>> +egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
>> + backing_id, false);
>>  }
>>
>>  void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
>> --
>> 2.35.3
>>




pending hw/audio patches for 8.2

2023-11-26 Thread Volker Rümelin
Hi,

there are five pending reviewed hw/audio patches for 8.2. They are all
bug fixes. It would be good if someone could send a pull request for
rc2. I don't think Gerd will send it.

The five patches are:

("hw/audio/hda-codec: fix multiplication overflow")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg00828.html

("hw/audio/hda-codec: reenable the audio mixer")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg00827.html

("hw/audio/virtio-snd-pci: fix the PCI class code")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg02084.html

("virtio-snd: check AUD_register_card return value")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg02545.html

("virtio-sound: add realize() error cleanup path")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg03878.html

IIRC the last patch needs a rebase.

I omitted another reviewed patch, which is a variant of
("hw/audio/hda-codec: reenable the audio mixer").
("hw/audio: Fix logic error in hda audio")
https://lists.nongnu.org/archive/html/qemu-devel/2023-11/msg03951.html

I have a repository at https://gitlab.com/volker.ruemelin/qemu.git. The
five rebased patches are in the hw-audio-fixes-for-8.2 branch.

With best regards,
Volker




virtio-sound segmentation fault

2023-11-15 Thread Volker Rümelin
Cc: qemu-devel

Hi Manos,

it's easy to trigger a segmentation fault with the virtio-sound device.
The basic problem is that in function virtio_snd_realize() there is no
code in the errror paths to undo the previous steps.

To reproduce the segmentation fault start QEMU with an empty PCIe root
port. The necessary command line options are

-device
pcie-root-port,port=224,chassis=1,id=pcie.1,addr=0x1c,multifunction=on
-audiodev pipewire,id=audio0

Then hotplug a virtio-sound device with the compat monitor. Please note
the missing audiodev argument so that AUD_register_card() in
virtio_snd_realize() fails. It's also necessary to apply your
"virtio-snd: check AUD_register_card return value" patch, otherwise the
device_add command fails immediately with a segmentation fault.

QEMU 8.1.90 monitor - type 'help' for more information
(qemu) device_add virtio-sound,bus=pcie.1
Error: no default audio driver available
Perhaps you wanted to use -audio or set audiodev=audio0?
(qemu) device_add virtio-sound,bus=pcie.1,audiodev=audio0
(qemu)

Now shutdown the guest. Most of the time QEMU will dump core because
there is no qemu_del_vm_change_state_handler() in the
virtio_snd_realize() error path.

Core was generated by `./qemu-system-x86_64 -machine
q35,usb=off,vmport=off,hpet=off,dump-guest-core=o'.
Program terminated with signal SIGSEGV, Segmentation fault.
(gdb) bt
#0  0x5649d3aa70d2 in object_dynamic_cast_assert
    (obj=obj@entry=0x5649d6da73d0,
typename=typename@entry=0x5649d3d944a5 "device",
file=file@entry=0x5649d3c9b8e0
"/home/ruemelin/rpmbuild/BUILD/qemu-master/include/hw/qdev-core.h",
line=line@entry=77, func=func@entry=0x5649d3e89d45 <__func__.16> "DEVICE")
    at ../qemu-master/qom/object.c:887
#1  0x5649d3a1521f in DEVICE (obj=0x5649d6da73d0) at
/home/ruemelin/rpmbuild/BUILD/qemu-master/include/hw/qdev-core.h:77
#2  virtio_vmstate_change (opaque=0x5649d6da73d0, running=, state=)
    at ../qemu-master/hw/virtio/virtio.c:3188
#3  0x5649d387fdc0 in vm_state_notify (running=running@entry=false,
state=state@entry=RUN_STATE_SHUTDOWN)
    at ../qemu-master/system/runstate.c:381
#4  0x5649d3876de0 in do_vm_stop (send_stop=false,
state=RUN_STATE_SHUTDOWN) at ../qemu-master/system/cpus.c:270
#5  vm_shutdown () at ../qemu-master/system/cpus.c:288
#6  0x5649d3880908 in qemu_cleanup (status=status@entry=0) at
../qemu-master/system/runstate.c:857
#7  0x5649d366dc91 in qemu_default_main () at
../qemu-master/system/main.c:38
#8  0x7f1bc4e3e24d in __libc_start_main () at /lib64/libc.so.6
#9  0x5649d366dbba in _start () at ../sysdeps/x86_64/start.S:120

With best regards,
Volker



Re: [PATCH] Fix Windows 2000 and XP HDAudio Support

2023-11-12 Thread Volker Rümelin
Am 12.11.23 um 01:37 schrieb Christopher Lentocha:
> So wait, you want me to add it as another device name? Because 
> it is going to be the same exact way as the 1af4 device
> just with a number change. Ok, work it is then ...
> (Sorry about not getting back sooner also)
>
> Christopher

Hi Christopher,

why do you want the device to be exactly the same as the generic hda
codec? A new device gives you the opportunity to model it closer to the
specs in the ALC885 datasheet. This could improve compatibility with the
old guest drivers.

With best regards,
Volker

> On 11/8/23 6:12 AM, Gerd Hoffmann wrote:
>> On Wed, Nov 08, 2023 at 11:02:06AM +0100, Philippe Mathieu-Daudé wrote:
>>> Thanks Christopher for your patch,
>>>
>>> I'm Cc'ing Volker and Gerd who know better this hardware model.
>>>
>>> On 7/11/23 20:27, Christopher Lentocha wrote:
 Change the ID to be a Realtek ALC885 so that both
>> No.  Rewriting the existing codecs is clearly a non-starter.
>>
>> You can add a 'hda-realtek-alc885' variant which tries to
>> mimic the realtek coded close enough to make old guests
>> without generic hda driver happy.
>>
 +#define QEMU_HDA_ID 0x10EC0885
>> Nope.  Somemething like 'REALTEK_ALC885_ID' please.
>>
>> [ remaining bits of the patch snipped, needs major rework ]
>>
>> take care,
>>   Gerd
>>




Re: disable-pie build

2023-11-11 Thread Volker Rümelin
Am 11.11.23 um 17:09 schrieb Paolo Bonzini:
> On Sat, Nov 11, 2023 at 3:40 AM Michael Tokarev  wrote:
>> Hi!
>>
>> It looks like --disable-pie configure, which uses -fno-pie -no-pie flags
>> for the compiler, is broken: it does not not tell the *linker* about the
>> option, so the link fails (at least on debian bookworm):
> Looks good, if you can send a patch perhaps Stefan can apply it (or
> someone else can handle it in my stead, because I'm away next week).
>
> Paolo

No, this doesn't look good. This patch again breaks the native Windows
build with MSYS2 and mingw64 cross compile probably too.

See

https://gitlab.com/qemu-project/qemu/-/issues/1664

https://lore.kernel.org/qemu-devel/20230522080816.66320-1-pbonz...@redhat.com/
https://lore.kernel.org/qemu-devel/20230523073029.19549-1-pbonz...@redhat.com/

and the big comment above the changed lines in meson.build.

With best regards,
Volker

>> /usr/bin/ld: libcommon.fa.p/hw_core_cpu-common.c.o: relocation R_X86_64_32 
>> against `.rodata' can not be used when making a PIE object; recompile with
>> -fPIE
>> /usr/bin/ld: failed to set dynamic section sizes: bad value
>>
>> This is failing for *all* executables, including tests, qemu-img, etc.
>>
>> The following change fixes it:
>>
>> diff --git a/meson.build b/meson.build
>> index a9c4f28247..0b7ca45d48 100644
>> --- a/meson.build
>> +++ b/meson.build
>> @@ -278,7 +278,8 @@ endif
>>   # tries to build an executable instead of a shared library and fails.  So
>>   # don't add -no-pie anywhere and cross fingers. :(
>>   if not get_option('b_pie')
>> -  qemu_common_flags += cc.get_supported_arguments('-fno-pie', '-no-pie')
>> +  qemu_common_flags += cc.get_supported_arguments('-fno-pie')
>> +  qemu_ldflags += cc.get_supported_arguments('-no-pie')
>>   endif
>>
>>   if not get_option('stack_protector').disabled()



Re: [PATCH] hw/audio/es1370: Clean up comment

2023-11-11 Thread Volker Rümelin
Am 10.11.23 um 17:43 schrieb Peter Maydell:
> Replace a sweary comment with one that's a bit more helpful to
> future readers of the code.
>
> Signed-off-by: Peter Maydell 

Reviewed-by: Volker Rümelin 

> ---
>  hw/audio/es1370.c | 9 +++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
> index 91c47330ad3..fad55412119 100644
> --- a/hw/audio/es1370.c
> +++ b/hw/audio/es1370.c
> @@ -670,8 +670,13 @@ static void es1370_transfer_audio (ES1370State *s, 
> struct chan *d, int loop_sel,
>  cnt += (transferred + d->leftover) >> 2;
>  
>  if (s->sctl & loop_sel) {
> -/* Bah, how stupid is that having a 0 represent true value?
> -   i just spent few hours on this shit */
> +/*
> + * loop_sel tells us which bit in the SCTL register to look at
> + * (either P1_LOOP_SEL, P2_LOOP_SEL or R1_LOOP_SEL). The sense
> + * of these bits is 0 for loop mode (set interrupt and keep recording
> + * when the sample count reaches zero) or 1 for stop mode (set
> + * interrupt and stop recording).
> + */
>  AUD_log ("es1370: warning", "non looping mode\n");
>  } else {
>  d->frame_cnt = size;




Re: [PATCH for 8.2] ui/gtk-egl: move function calls back to regular code path

2023-11-11 Thread Volker Rümelin
Cc: Antonio

> Commit 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing
> scanout") introduced a regression when QEMU is running with a
> virtio-gpu-gl-device on a host under X11. After the guest has
> initialized the virtio-gpu-gl-device, the guest screen only
> shows "Display output is not active.".
>
> Commit 6f189a08c1 moved all function calls in
> gd_egl_scanout_texture() to a code path which is only called
> once after gd_egl_init() succeeds in gd_egl_scanout_texture().
> Move all function calls in gd_egl_scanout_texture() back to
> the regular code path so they get always called if one of the
> gd_egl_init() calls was successful.
>
> Fixes: 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing scanout")
> Signed-off-by: Volker Rümelin 
> ---
>  ui/gtk-egl.c | 12 ++--
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> index cd2f176502..3af5ac5bcf 100644
> --- a/ui/gtk-egl.c
> +++ b/ui/gtk-egl.c
> @@ -249,14 +249,14 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
>  if (!vc->gfx.esurface) {
>  return;
>  }
> +}
>  
> -eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> -   vc->gfx.esurface, vc->gfx.ectx);
> +eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +   vc->gfx.esurface, vc->gfx.ectx);
>  
> -gtk_egl_set_scanout_mode(vc, true);
> -egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
> backing_height,
> - backing_id, false);
> -}
> +gtk_egl_set_scanout_mode(vc, true);
> +egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
> + backing_id, false);
>  }
>  
>  void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,




[PATCH for 8.2] ui/gtk-egl: move function calls back to regular code path

2023-11-11 Thread Volker Rümelin
Commit 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing
scanout") introduced a regression when QEMU is running with a
virtio-gpu-gl-device on a host under X11. After the guest has
initialized the virtio-gpu-gl-device, the guest screen only
shows "Display output is not active.".

Commit 6f189a08c1 moved all function calls in
gd_egl_scanout_texture() to a code path which is only called
once after gd_egl_init() succeeds in gd_egl_scanout_texture().
Move all function calls in gd_egl_scanout_texture() back to
the regular code path so they get always called if one of the
gd_egl_init() calls was successful.

Fixes: 6f189a08c1 ("ui/gtk-egl: Check EGLSurface before doing scanout")
Signed-off-by: Volker Rümelin 
---
 ui/gtk-egl.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index cd2f176502..3af5ac5bcf 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -249,14 +249,14 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
 if (!vc->gfx.esurface) {
 return;
 }
+}
 
-eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
-   vc->gfx.esurface, vc->gfx.ectx);
+eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+   vc->gfx.esurface, vc->gfx.ectx);
 
-gtk_egl_set_scanout_mode(vc, true);
-egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
- backing_id, false);
-}
+gtk_egl_set_scanout_mode(vc, true);
+egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
+ backing_id, false);
 }
 
 void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
-- 
2.35.3




Re: [PULL 2/5] ui/gtk-egl: Check EGLSurface before doing scanout

2023-11-10 Thread Volker Rümelin
>> From: Antonio Caggiano 
>>
>> The first time gd_egl_scanout_texture() is called, there's a possibility
>> that the GTK drawing area might not be realized yet, in which case its
>> associated GdkWindow is NULL. This means gd_egl_init() was also skipped
>> and the EGLContext and EGLSurface stored in the VirtualGfxConsole are
>> not valid yet.
>>
>> Continuing with the scanout in this conditions would result in hitting
>> an assert in libepoxy: "Couldn't find current GLX or EGL context".
>>
>> A possible workaround is to just ignore the scanout request, giving the
>> the GTK drawing area some time to finish its realization. At that point,
>> the gd_egl_init() will succeed and the EGLContext and EGLSurface stored
>> in the VirtualGfxConsole will be valid.
>>
>> Signed-off-by: Antonio Caggiano 
>> Reviewed-by: Marc-André Lureau 
>> Message-Id: <20231016123215.2699269-1-quic_acagg...@quicinc.com>
>> ---
>>  ui/gtk-egl.c | 17 -
>>  1 file changed, 12 insertions(+), 5 deletions(-)
> Hi Antonio,
>
> this patch breaks the QEMU guest display on my system. QEMU was started
> with ./qemu-system-x86_64 -machine q35 -device
> virtio-vga-gl,xres=1280,yres=768 -display gtk,zoom-to-fit=off,gl=on. I
> can see the OVMF boot screen and then GRUB. After Linux was started,
> plymouth normally shows the OVMF boot logo and a rotating spinner. With
> your patch the guest screen is black and shows 'Display output is not
> active.'. It seems the guest works without issues. I can use ssh to log
> in and I can't find any obvious errors in the guest log files. The host
> uses a GNOME desktop under X11.
>
> If I revert this patch everything works as expected.
>
> With best regards,
> Volker
>
> Cc: Michael Tokarev
> This will affect Stable-7.2.7 and Stable-8.1.3.
>
>> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
>> index a1060fd80f..3e8d1c1d02 100644
>> --- a/ui/gtk-egl.c
>> +++ b/ui/gtk-egl.c
>> @@ -243,12 +243,19 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
>>  vc->gfx.h = h;
>>  vc->gfx.y0_top = backing_y_0_top;
>>  
>> -eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>> -   vc->gfx.esurface, vc->gfx.ectx);
>> +if (!vc->gfx.esurface) {
>> +gd_egl_init(vc);
>> +if (!vc->gfx.esurface) {
>> +return;
>> +}
>> +
>> +eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
>> +   vc->gfx.esurface, vc->gfx.ectx);
>>  
>> -gtk_egl_set_scanout_mode(vc, true);
>> -egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
>> - backing_id, false);
>> +gtk_egl_set_scanout_mode(vc, true);
>> +egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
>> backing_height,
>> + backing_id, false);
>> +}
>>  }
>>  
>>  void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,

I can see the mistake. I'll write a patch to fix it.

With best regards,
Volker






Re: [PULL 2/5] ui/gtk-egl: Check EGLSurface before doing scanout

2023-11-09 Thread Volker Rümelin
> From: Antonio Caggiano 
>
> The first time gd_egl_scanout_texture() is called, there's a possibility
> that the GTK drawing area might not be realized yet, in which case its
> associated GdkWindow is NULL. This means gd_egl_init() was also skipped
> and the EGLContext and EGLSurface stored in the VirtualGfxConsole are
> not valid yet.
>
> Continuing with the scanout in this conditions would result in hitting
> an assert in libepoxy: "Couldn't find current GLX or EGL context".
>
> A possible workaround is to just ignore the scanout request, giving the
> the GTK drawing area some time to finish its realization. At that point,
> the gd_egl_init() will succeed and the EGLContext and EGLSurface stored
> in the VirtualGfxConsole will be valid.
>
> Signed-off-by: Antonio Caggiano 
> Reviewed-by: Marc-André Lureau 
> Message-Id: <20231016123215.2699269-1-quic_acagg...@quicinc.com>
> ---
>  ui/gtk-egl.c | 17 -
>  1 file changed, 12 insertions(+), 5 deletions(-)

Hi Antonio,

this patch breaks the QEMU guest display on my system. QEMU was started
with ./qemu-system-x86_64 -machine q35 -device
virtio-vga-gl,xres=1280,yres=768 -display gtk,zoom-to-fit=off,gl=on. I
can see the OVMF boot screen and then GRUB. After Linux was started,
plymouth normally shows the OVMF boot logo and a rotating spinner. With
your patch the guest screen is black and shows 'Display output is not
active.'. It seems the guest works without issues. I can use ssh to log
in and I can't find any obvious errors in the guest log files. The host
uses a GNOME desktop under X11.

If I revert this patch everything works as expected.

With best regards,
Volker

Cc: Michael Tokarev
This will affect Stable-7.2.7 and Stable-8.1.3.

> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> index a1060fd80f..3e8d1c1d02 100644
> --- a/ui/gtk-egl.c
> +++ b/ui/gtk-egl.c
> @@ -243,12 +243,19 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
>  vc->gfx.h = h;
>  vc->gfx.y0_top = backing_y_0_top;
>  
> -eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> -   vc->gfx.esurface, vc->gfx.ectx);
> +if (!vc->gfx.esurface) {
> +gd_egl_init(vc);
> +if (!vc->gfx.esurface) {
> +return;
> +}
> +
> +eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +   vc->gfx.esurface, vc->gfx.ectx);
>  
> -gtk_egl_set_scanout_mode(vc, true);
> -egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
> - backing_id, false);
> +gtk_egl_set_scanout_mode(vc, true);
> +egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
> backing_height,
> + backing_id, false);
> +}
>  }
>  
>  void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,




[PATCH] hw/audio/virtio-snd-pci: fix the PCI class code

2023-11-07 Thread Volker Rümelin
The virtio sound device is currently an unclassified PCI device.

~> sudo lspci -s '00:02.0' -v -nn | head -n 2
00:02.0 Unclassified device [00ff]:
 Red Hat, Inc. Device [1af4:1059] (rev 01)
Subsystem: Red Hat, Inc. Device [1af4:1100]

Set the correct PCI class code to change the device to a
multimedia audio controller.

~> sudo lspci -s '00:02.0' -v -nn | head -n 2
00:02.0 Multimedia audio controller [0401]:
 Red Hat, Inc. Device [1af4:1059] (rev 01)
Subsystem: Red Hat, Inc. Device [1af4:1100]

Signed-off-by: Volker Rümelin 
---
The two additional lines have been lost between v6 and v7 of
the "Add VIRTIO sound card" patch series.

 hw/audio/virtio-snd-pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/audio/virtio-snd-pci.c b/hw/audio/virtio-snd-pci.c
index 0f92e0752b..ab58c6410e 100644
--- a/hw/audio/virtio-snd-pci.c
+++ b/hw/audio/virtio-snd-pci.c
@@ -47,12 +47,14 @@ static void virtio_snd_pci_class_init(ObjectClass *klass, 
void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
 VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
+PCIDeviceClass *pcidevklass = PCI_DEVICE_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;
+pcidevklass->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
 }
 
 static void virtio_snd_pci_instance_init(Object *obj)
-- 
2.35.3




Re: [PATCH 0/2] hw/audio/hda-codec bug fixes

2023-11-06 Thread Volker Rümelin
Am 06.11.23 um 20:54 schrieb Michael Tokarev:
> 05.11.2023 20:23, Volker Rümelin :
>> Patch 1/2 fixes a bug that was reported and correctly diagnosed on the
>> QEMU devel mailing list.
>> https://lists.nongnu.org/archive/html/qemu-devel/2023-08/msg02539.html
>> There was another patch to fix this bug, but I had an objection.
>> https://lists.nongnu.org/archive/html/qemu-devel/2023-08/msg02925.html
>>
>> Patch 2/2 corrects the sense of hda codec property mixer during
>> initialization. It was inverted not too long ago.
>
> It looks like -stable material, is it not?
>

Patch 1/2 ("hw/audio/hda-codec: fix multiplication overflow") is stable
material. Sorry, I forgot to cc qemu-stable.

With best regards,
Volker




[PATCH 2/2] hw/audio/hda-codec: reenable the audio mixer

2023-11-05 Thread Volker Rümelin
Commit b7639b7dd0 ("hw/audio: Simplify hda audio init") inverted
the sense of hda codec property mixer during initialization.
Change the code so that mixer=on enables the hda mixer emulation
and mixer=off disables the hda mixer emulation.

With this change audio playback and recording streams don't start
muted by default.

Fixes: b7639b7dd0 ("hw/audio: Simplify hda audio init")
Signed-off-by: Volker Rümelin 
---
 hw/audio/hda-codec.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index f756e419bb..0bc20d49f6 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -868,10 +868,10 @@ static Property hda_audio_properties[] = {
 static void hda_audio_init_output(HDACodecDevice *hda, Error **errp)
 {
 HDAAudioState *a = HDA_AUDIO(hda);
-const struct desc_codec *desc = _nomixemu;
+const struct desc_codec *desc = _mixemu;
 
 if (!a->mixer) {
-desc = _mixemu;
+desc = _nomixemu;
 }
 
 hda_audio_init(hda, desc, errp);
@@ -880,10 +880,10 @@ static void hda_audio_init_output(HDACodecDevice *hda, 
Error **errp)
 static void hda_audio_init_duplex(HDACodecDevice *hda, Error **errp)
 {
 HDAAudioState *a = HDA_AUDIO(hda);
-const struct desc_codec *desc = _nomixemu;
+const struct desc_codec *desc = _mixemu;
 
 if (!a->mixer) {
-desc = _mixemu;
+desc = _nomixemu;
 }
 
 hda_audio_init(hda, desc, errp);
@@ -892,10 +892,10 @@ static void hda_audio_init_duplex(HDACodecDevice *hda, 
Error **errp)
 static void hda_audio_init_micro(HDACodecDevice *hda, Error **errp)
 {
 HDAAudioState *a = HDA_AUDIO(hda);
-const struct desc_codec *desc = _nomixemu;
+const struct desc_codec *desc = _mixemu;
 
 if (!a->mixer) {
-desc = _mixemu;
+desc = _nomixemu;
 }
 
 hda_audio_init(hda, desc, errp);
-- 
2.35.3




[PATCH 1/2] hw/audio/hda-codec: fix multiplication overflow

2023-11-05 Thread Volker Rümelin
After a relatively short time, there is an multiplication overflow
when multiplying (now - buft_start) with hda_bytes_per_second().
While the uptime now - buft_start only overflows after 2**63 ns
= 292.27 years, this happens hda_bytes_per_second() times faster
with the multiplication. At 44100 samples/s * 2 channels
* 2 bytes/channel = 176400 bytes/s that is 14.52 hours. After the
multiplication overflow the affected audio stream stalls.

Replace the multiplication and following division with muldiv64()
to prevent a multiplication overflow.

Fixes: 280c1e1cdb ("audio/hda: create millisecond timers that handle IO")
Reported-by: M_O_Bz 
Signed-off-by: Volker Rümelin 
---
 hw/audio/hda-codec.c | 29 +
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index b9ad1f4c39..f756e419bb 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -22,6 +22,7 @@
 #include "hw/qdev-properties.h"
 #include "intel-hda.h"
 #include "migration/vmstate.h"
+#include "qemu/host-utils.h"
 #include "qemu/module.h"
 #include "intel-hda-defs.h"
 #include "audio/audio.h"
@@ -189,9 +190,9 @@ struct HDAAudioState {
 bool use_timer;
 };
 
-static inline int64_t hda_bytes_per_second(HDAAudioStream *st)
+static inline uint32_t hda_bytes_per_second(HDAAudioStream *st)
 {
-return 2LL * st->as.nchannels * st->as.freq;
+return 2 * (uint32_t)st->as.nchannels * (uint32_t)st->as.freq;
 }
 
 static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t 
target_pos)
@@ -222,12 +223,18 @@ static void hda_audio_input_timer(void *opaque)
 
 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
-int64_t buft_start = st->buft_start;
+int64_t uptime = now - st->buft_start;
 int64_t wpos = st->wpos;
 int64_t rpos = st->rpos;
+int64_t wanted_rpos;
 
-int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start)
-  / NANOSECONDS_PER_SECOND;
+if (uptime <= 0) {
+/* wanted_rpos <= 0 */
+goto out_timer;
+}
+
+wanted_rpos = muldiv64(uptime, hda_bytes_per_second(st),
+   NANOSECONDS_PER_SECOND);
 wanted_rpos &= -4; /* IMPORTANT! clip to frames */
 
 if (wanted_rpos <= rpos) {
@@ -286,12 +293,18 @@ static void hda_audio_output_timer(void *opaque)
 
 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
-int64_t buft_start = st->buft_start;
+int64_t uptime = now - st->buft_start;
 int64_t wpos = st->wpos;
 int64_t rpos = st->rpos;
+int64_t wanted_wpos;
+
+if (uptime <= 0) {
+/* wanted_wpos <= 0 */
+goto out_timer;
+}
 
-int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start)
-  / NANOSECONDS_PER_SECOND;
+wanted_wpos = muldiv64(uptime, hda_bytes_per_second(st),
+   NANOSECONDS_PER_SECOND);
 wanted_wpos &= -4; /* IMPORTANT! clip to frames */
 
 if (wanted_wpos <= wpos) {
-- 
2.35.3




[PATCH 0/2] hw/audio/hda-codec bug fixes

2023-11-05 Thread Volker Rümelin
Patch 1/2 fixes a bug that was reported and correctly diagnosed on the
QEMU devel mailing list.
https://lists.nongnu.org/archive/html/qemu-devel/2023-08/msg02539.html
There was another patch to fix this bug, but I had an objection.
https://lists.nongnu.org/archive/html/qemu-devel/2023-08/msg02925.html

Patch 2/2 corrects the sense of hda codec property mixer during
initialization. It was inverted not too long ago.

I guess Gerd is still busy with other projects. Another maintainer
probably will have to take these patches.

Volker Rümelin (2):
  hw/audio/hda-codec: fix multiplication overflow
  hw/audio/hda-codec: reenable the audio mixer

 hw/audio/hda-codec.c | 41 +++--
 1 file changed, 27 insertions(+), 14 deletions(-)

-- 
2.35.3




Re: [PATCH v12 02/11] Add virtio-sound-pci device

2023-10-22 Thread Volker Rümelin
Am 22.10.23 um 11:58 schrieb Manos Pitsidianakis:
> Hello Volker,
>
> On Sat, 21 Oct 2023 12:07, Volker Rümelin  wrote:
>> the virtio-sound device alias doesn't work.
>
> Yes, there's no virtio-sound alias hence why it does not work.

Sorry, I don't understand your last sentence. You add this alias with
the following line in patch 02/11, so there is a virtio-sound alias.
This alias doesn't work because there is a device with the same name.

+    { "virtio-sound-pci", "virtio-sound", QEMU_ARCH_VIRTIO_PCI},

With best regards,
Volker

>
> I will wait a bit before spinning a new version of the series because
> the goal post keeps moving forward everytime there's a new version
> while there is still stuff to address. If this is the only change I'd
> like to hear from Gerd if this is ok to merge otherwise, and perhaps I
> can send a new version of this patch only?
>
> Manos




Re: [PATCH v2 11/13] migration: Use vmstate_register_any() for audio

2023-10-21 Thread Volker Rümelin
Am 20.10.23 um 11:07 schrieb Juan Quintela:
> We can have more than one audio card.

Hi Juan,

I wouldn't use the term "audio card" here. In QEMU speak, Audiodev is an
"audio backend".

With best regards,
Volker

>
> void audio_init_audiodevs(void)
> {
> AudiodevListEntry *e;
>
> QSIMPLEQ_FOREACH(e, , next) {
> audio_init(e->dev, _fatal);
> }
> }
>
> Reviewed-by: Stefan Berger 
> Signed-off-by: Juan Quintela 
> ---
>  audio/audio.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index e9815d6812..f91e05b72c 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -1781,7 +1781,7 @@ static AudioState *audio_init(Audiodev *dev, Error 
> **errp)
>  
>  QTAILQ_INSERT_TAIL(_states, s, list);
>  QLIST_INIT (>card_head);
> -vmstate_register (NULL, 0, _audio, s);
> +vmstate_register_any(NULL, _audio, s);
>  return s;
>  
>  out:




Re: [PATCH v12 02/11] Add virtio-sound-pci device

2023-10-21 Thread Volker Rümelin
Am 19.10.23 um 12:03 schrieb 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 
> ---
>  MAINTAINERS   |  1 +
>  hw/audio/meson.build  |  1 +
>  hw/audio/virtio-snd-pci.c | 93 +++
>  system/qdev-monitor.c |  1 +
>  4 files changed, 96 insertions(+)
>  create mode 100644 hw/audio/virtio-snd-pci.c


> diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
> index 1b8005ae55..f007ee6953 100644
> --- a/system/qdev-monitor.c
> +++ b/system/qdev-monitor.c
> @@ -111,6 +111,7 @@ static const QDevAlias qdev_alias_table[] = {
>  { "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},

Hi Manos,

the virtio-sound device alias doesn't work.

> ./qemu-system-x86_64 -machine q35 -device virtio-sound,audiodev=audio0
-audiodev pipewire,id=audio0
qemu-system-x86_64: -device virtio-sound,audiodev=audio0: No
'virtio-bus' bus found for device 'virtio-sound'

This can be fixed if you change

--- a/include/hw/audio/virtio-snd.h
+++ b/include/hw/audio/virtio-snd.h
@@ -21,7 +21,7 @@
 #include "standard-headers/linux/virtio_ids.h"
 #include "standard-headers/linux/virtio_snd.h"
 
-#define TYPE_VIRTIO_SND "virtio-sound"
+#define TYPE_VIRTIO_SND "virtio-sound-device"
 #define VIRTIO_SND(obj) \
 OBJECT_CHECK(VirtIOSound, (obj), TYPE_VIRTIO_SND)
 
in patch 01/11.  The other virtio devices also have a device suffix in
their type name. Additionally I would insert this line

+    { "virtio-sound-device", "virtio-sound", QEMU_ARCH_VIRTIO_MMIO},

here.

With best regards,
Volker

> +{ "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 },




Re: [PATCH 2/3] hw/pci-host: Add emulation of Mai Logic Articia S

2023-10-06 Thread Volker Rümelin
Am 06.10.23 um 00:13 schrieb BALATON Zoltan:
> The Articia S is a generic chipset supporting several different CPUs
> that were used on some PPC boards. This is a minimal emulation of the
> parts needed for emulating the AmigaOne board.
>
> Signed-off-by: BALATON Zoltan 
> ---
>  hw/pci-host/Kconfig   |   5 +
>  hw/pci-host/articia.c | 266 ++
>  hw/pci-host/meson.build   |   2 +
>  include/hw/pci-host/articia.h |  17 +++
>  4 files changed, 290 insertions(+)
>  create mode 100644 hw/pci-host/articia.c
>  create mode 100644 include/hw/pci-host/articia.h
> diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c
> new file mode 100644
> index 00..80558e1c47
> --- /dev/null
> +++ b/hw/pci-host/articia.c
> @@ -0,0 +1,266 @@
> +/*
> + * Mai Logic Articia S emulation
> + *
> + * Copyright (c) 2023 BALATON Zoltan
> + *
> + * This work is licensed under the GNU GPL license version 2 or later.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qapi/error.h"
> +#include "hw/pci/pci_device.h"
> +#include "hw/pci/pci_host.h"
> +#include "hw/irq.h"
> +#include "hw/i2c/bitbang_i2c.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/pci-host/articia.h"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(ArticiaState, ARTICIA)
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(ArticiaHostState, ARTICIA_PCI_HOST)
> +struct ArticiaHostState {
> +PCIDevice parent_obj;
> +
> +ArticiaState *as;
> +};
> +
> +/* TYPE_ARTICIA */
> +
> +struct ArticiaState {
> +PCIHostState parent_obj;
> +
> +qemu_irq irq[PCI_NUM_PINS];
> +MemoryRegion io;
> +MemoryRegion mem;
> +MemoryRegion reg;
> +
> +bitbang_i2c_interface smbus;
> +uint32_t gpio; /* bits 0-7 in, 8-15 out, 16-23 direction (0 in, 1 out) */
> +hwaddr gpio_base;
> +MemoryRegion gpio_reg;
> +};
> +
> +static uint64_t articia_gpio_read(void *opaque, hwaddr addr, unsigned int 
> size)
> +{
> +ArticiaState *s = opaque;
> +
> +return (s->gpio >> (addr * 8)) & 0xff;
> +}
> +
> +static void articia_gpio_write(void *opaque, hwaddr addr, uint64_t val,
> +   unsigned int size)
> +{
> +ArticiaState *s = opaque;
> +uint32_t sh = addr * 8;
> +
> +if (addr == 0) {
> +/* in bits read only? */
> +return;
> +}
> +
> +if ((s->gpio & (0xff << sh)) != (val & 0xff) << sh) {
> +s->gpio &= ~(0xff << sh | 0xff);
> +s->gpio |= (val & 0xff) << sh;
> +s->gpio |= bitbang_i2c_set(>smbus, BITBANG_I2C_SDA,
> +   s->gpio & BIT(16) ?
> +   !!(s->gpio & BIT(8)) : 1);
> +if ((s->gpio & BIT(17))) {
> +s->gpio &= ~BIT(0);
> +s->gpio |= bitbang_i2c_set(>smbus, BITBANG_I2C_SCL,
> +   !!(s->gpio & BIT(9)));
> +}
> +}
> +}
> +
> +static const MemoryRegionOps articia_gpio_ops = {
> +.read = articia_gpio_read,
> +.write = articia_gpio_write,
> +.valid.min_access_size = 1,
> +.valid.max_access_size = 1,
> +.endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static uint64_t articia_reg_read(void *opaque, hwaddr addr, unsigned int 
> size)
> +{
> +ArticiaState *s = opaque;
> +uint64_t ret = UINT_MAX;
> +
> +switch (addr) {
> +case 0xc00cf8:
> +ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(s), 0, size);
> +break;
> +case 0xe00cfc ... 0xe00cff:
> +ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(s), addr - 0xe00cfc, 
> size);
> +break;
> +case 0xf0:
> +ret = pic_read_irq(isa_pic);
> +break;
> +default:
> +qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register read 0x%"
> +  HWADDR_PRIx " %d\n", __func__, addr, size);
> +break;
> +}
> +return ret;
> +}
> +
> +static void articia_reg_write(void *opaque, hwaddr addr, uint64_t val,
> +  unsigned int size)
> +{
> +ArticiaState *s = opaque;
> +
> +switch (addr) {
> +case 0xc00cf8:
> +pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(s), 0, val, size);
> +break;
> +case 0xe00cfc ... 0xe00cff:
> +pci_host_data_le_ops.write(PCI_HOST_BRIDGE(s), addr, val, size);
> +break;
> +default:
> +qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register write 0x%"
> +  HWADDR_PRIx " %d <- %"PRIx64"\n", __func__, addr, 
> size, val);
> +break;
> +}
> +}
> +
> +static const MemoryRegionOps articia_reg_ops = {
> +.read = articia_reg_read,
> +.write = articia_reg_write,
> +.valid.min_access_size = 1,
> +.valid.max_access_size = 4,
> +.endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void articia_pcihost_set_irq(void *opaque, int n, int level)
> +{
> +ArticiaState *s = opaque;
> +qemu_set_irq(s->irq[n], level);
> +}
> +
> +static void articia_realize(DeviceState *dev, Error **errp)
> +{
> +   

Re: [PATCH v2 07/20] audio: add Apple Sound Chip (ASC) emulation

2023-09-23 Thread Volker Rümelin
Am 20.09.23 um 17:39 schrieb Mark Cave-Ayland:
> On 14/09/2023 08:06, Volker Rümelin wrote:
>
>> Am 09.09.23 um 11:48 schrieb Mark Cave-Ayland:
>>> The Apple Sound Chip was primarily used by the Macintosh II to
>>> generate sound
>>> in hardware which was previously handled by the toolbox ROM with
>>> software
>>> interrupts.
>>>
>>> Implement both the standard ASC and also the enhanced ASC (EASC)
>>> functionality
>>> which is used in the Quadra 800.
>>>
>>> Note that whilst real ASC hardware uses AUDIO_FORMAT_S8, this
>>> implementation uses
>>> AUDIO_FORMAT_U8 instead because AUDIO_FORMAT_S8 is rarely used and
>>> not supported
>>> by some audio backends like PulseAudio and DirectSound when played
>>> directly with
>>> -audiodev out.mixing-engine=off.
>>>
>>> Co-developed-by: Laurent Vivier 
>>> Co-developed-by: Volker Rümelin 
>>> Signed-off-by: Mark Cave-Ayland 
>>> ---
>>>   MAINTAINERS    |   2 +
>>>   hw/audio/Kconfig   |   3 +
>>>   hw/audio/asc.c | 699
>>> +
>>>   hw/audio/meson.build   |   1 +
>>>   hw/audio/trace-events  |  10 +
>>>   hw/m68k/Kconfig    |   1 +
>>>   include/hw/audio/asc.h |  84 +
>>>   7 files changed, 800 insertions(+)
>>>   create mode 100644 hw/audio/asc.c
>>>   create mode 100644 include/hw/audio/asc.h
>>
>> Hi Mark,
>>
>> the function generate_fifo() has four issues. Only the first one
>> is noticeable.
>>
>> 1. The calculation of the variable limit assumes generate_fifo()
>> generates one output sample from every input byte. This is correct
>> for the raw mode, but not for the CD-XA BRR mode. This mode
>> generates 28 output samples from 15 input bytes. This is the
>> reason for the stuttering end of a CD-XA BRR mode sound. Every
>> generate_fifo() call generates approximately only half of the
>> possible samples when the fifo bytes are running low.
>>
>> 2. generate_fifo() doesn't generate the last output sample from
>> a CD-XA BRR mode sound. The last sample is generated from internal
>> state and the code will not be called without at least one byte
>> in the fifo.
>>
>> 3. It's not necessary to wait for a complete 15 byte packet in
>> CD-XA BRR mode. Audio playback devices should write all
>> requested samples immediately if possible.
>>
>> 4. The saturation function in CD-XA BRR mode works with 16 bit
>> integers. It should saturate at +32767 and -32768.
>>
>> Since I think a few lines of code explain the issues better
>> than my words, I've attached a patch below.
>>
>> With best regards,
>> Volker
>
> Hi Volker,
>
> Thanks for detailed explanation above - everything makes sense based
> upon previous discussions. My only question is in comment 3 where you
> say "Audio playback devices should write all requested samples
> immediately if possible": can you clarify does this mean that the
> supplied length to the audio callback represents a *required* rather
> than a *maximum* number of samples?
>

Hi Mark,

the supplied length is the number of bytes needed to fill the downstream
audio buffer completely or as fast as possible. An incompletely filled
buffer increases the probability of dropouts. The supplied length is
also the maximum number of bytes AUD_write() will write.

So it's better to write as many bytes as possible, but if you can't it
won't cause audio problems immediately in most cases.

With best regards,
Volker

> Regardless of this I've had some time to test on Windows this
> afternoon, and I can confirm that your changes fix the outstanding
> audio issues. I've squashed your changes locally and I'll included
> them in the next revision of the series, although I'll likely wait a
> bit first to see if any more reviews are forthcoming.
>
>
> Many thanks,
>
> Mark.
>




Re: [PATCH 2/2] seabios: remove PCI drivers from bios.bin

2023-09-23 Thread Volker Rümelin
Am 21.09.23 um 14:10 schrieb Paolo Bonzini:
> bios.bin is now used only by ISA PC, so PCI drivers are not necessary.
>
> Signed-off-by: Paolo Bonzini 
> ---
>  pc-bios/bios.bin | Bin 131072 -> 131072 bytes
>  roms/config.seabios-128k |  30 ++
>  2 files changed, 22 insertions(+), 8 deletions(-)
> diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k
> index d18c802c46e..06f4ba35bbe 100644
> --- a/roms/config.seabios-128k
> +++ b/roms/config.seabios-128k
> @@ -1,21 +1,35 @@
> -# for qemu machine types 1.7 + older
> -# need to turn off features (xhci,uas) to make it fit into 128k
> +# SeaBIOS Configuration for -M isapc
> +
> +#
> +# General Features
> +#
>  CONFIG_QEMU=y
>  CONFIG_ROM_SIZE=128
>  CONFIG_ATA_DMA=n
>  CONFIG_BOOTSPLASH=n
>  CONFIG_XEN=n
> -CONFIG_USB_OHCI=n
> -CONFIG_USB_XHCI=n
> -CONFIG_USB_UAS=n
> +CONFIG_ATA_PIO32=n
> +CONFIG_AHCI=n
>  CONFIG_SDCARD=n
>  CONFIG_TCGBIOS=n
> -CONFIG_MPT_SCSI=n
> -CONFIG_ESP_SCSI=n
> -CONFIG_MEGASAS=n
> +CONFIG_VIRTIO_BLK=n
> +CONFIG_VIRTIO_SCSI=n
>  CONFIG_PVSCSI=n
> +CONFIG_ESP_SCSI=n
> +CONFIG_LSI_SCSI=n
> +CONFIG_MEGASAS=n
> +CONFIG_MPT_SCSI=n
>  CONFIG_NVME=n
>  CONFIG_USE_SMM=n
>  CONFIG_VGAHOOKS=n
>  CONFIG_HOST_BIOS_GEOMETRY=n
> +CONFIG_PS2PORT=n

Hi Paolo,

CONFIG_PS2PORT shouldn't be disabled. Otherwise FreeDOS and other
programs don't have a working keyboard.

With best regards,
Volker

> +CONFIG_USB=n
> +CONFIG_PMTIMER=n
> +CONFIG_PCIBIOS=n
> +CONFIG_DISABLE_A20=n
> +CONFIG_WRITABLE_UPPERMEMORY=n
> +CONFIG_ACPI=n
>  CONFIG_ACPI_PARSE=n
> +CONFIG_DEBUG_SERIAL=n
> +CONFIG_DEBUG_SERIAL_MMIO=n




Re: [PATCH v9 11/12] virtio-sound: implement audio capture (RX)

2023-09-19 Thread Volker Rümelin
Am 13.09.23 um 09:33 schrieb 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 
> ---
>  hw/virtio/trace-events |   3 +-
>  hw/virtio/virtio-snd.c | 233 +
>  2 files changed, 213 insertions(+), 23 deletions(-)

> diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c
> index 6fe03f9790..1d3a001371 100644
> --- a/hw/virtio/virtio-snd.c
> +++ b/hw/virtio/virtio-snd.c
> @@ -1048,26 +1131,133 @@ static void virtio_snd_pcm_out_cb(void *data, int 
> available)
>  }
>  
>  /*
> - * Flush all buffer data from this stream's queue into the driver's virtual
> - * queue.
> + * AUD_* input callback.
>   *
> - * @stream: VirtIOSoundPCMStream *stream
> + * @data: VirtIOSoundPCMStream stream
> + * @available: number of bytes that can be read with AUD_read()
>   */
> -static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
> +static void virtio_snd_pcm_in_cb(void *data, int available)
>  {
> +VirtIOSoundPCMStream *stream = data;
>  VirtIOSoundPCMBlock *block;
> -VirtIOSoundPCMBlock *next;
> +virtio_snd_pcm_status resp = { 0 };
> +size_t size;
>  
>  WITH_QEMU_LOCK_GUARD(>queue_mutex) {
> -QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
> -AUD_write(stream->voice.out, block->data + block->offset, 
> block->size);
> -virtqueue_push(block->vq, block->elem, sizeof(block->elem));
> -virtio_notify(VIRTIO_DEVICE(stream->s), block->vq);
> -QSIMPLEQ_REMOVE(>queue, block, VirtIOSoundPCMBlock, 
> entry);
> +while (!QSIMPLEQ_EMPTY(>queue)) {
> +block = QSIMPLEQ_FIRST(>queue);
> +
> +for (;;) {
> +size = AUD_read(stream->voice.in,
> +block->data + block->size,
> +MIN(available, (stream->params.period_bytes - 
> block->size)));
> +if (!size) {
> +available = 0;
> +break;
> +}
> +block->size += size;
> +available -= size;
> +if (block->size >= stream->params.period_bytes) {
> +resp.status = cpu_to_le32(VIRTIO_SND_S_OK);
> +resp.latency_bytes = 0;
> +/* Copy data -if any- to guest */
> +iov_from_buf(block->elem->in_sg,
> + block->elem->in_num,
> + 0,
> + block->data,
> + stream->params.period_bytes);
> +iov_from_buf(block->elem->in_sg,
> + block->elem->in_num,
> + block->size,
> + ,
> + sizeof(resp));
> +virtqueue_push(block->vq,
> +   block->elem,
> +   sizeof(block->elem));

Hi Manos,

if I'm not completely mistaken, the third argument of a virtqueue_push()
call is the size of the message copied into the virtio ring buffer, not
the size of a pointer. As I wrote for the v8 series, the other
virtqueue_push() calls also don't look right.

With best regards,
Volker

> +virtio_notify(VIRTIO_DEVICE(stream->s),
> +  block->vq);
> +QSIMPLEQ_REMOVE_HEAD(>queue, entry);
> +virtio_snd_pcm_block_free(block);
> +break;
> +}
> +if (!available) {
> +break;
> +}
> +}
> +if (!available) {
> +break;
> +}
>  }
>  }
>  }
>

[PATCH 3/8] hw/audio/es1370: remove unused dolog macro

2023-09-17 Thread Volker Rümelin
The dolog macro is unused. Remove the macro and use the now unused
ES1370_VERBOSE macro to replace its inverse ES1370_SILENT macro.

Tested-by: Rene Engel 
Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 7 ---
 1 file changed, 7 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 0b9fdc8f41..f66feb5bb0 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -24,7 +24,6 @@
 
 /* #define DEBUG_ES1370 */
 /* #define VERBOSE_ES1370 */
-#define SILENT_ES1370
 
 #include "qemu/osdep.h"
 #include "hw/audio/soundhw.h"
@@ -243,12 +242,6 @@ static void print_sctl (uint32_t val)
 #endif
 
 #ifdef VERBOSE_ES1370
-#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#ifndef SILENT_ES1370
 #define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
 #else
 #define lwarn(...)
-- 
2.35.3




[PATCH 2/8] hw/audio/es1370: replace bit-rotted code with tracepoints

2023-09-17 Thread Volker Rümelin
It seems that nobody has enabled the debug code of the ES1370
device for a long time. Since then, the code has bit-rotted.
Replace the bit-rotten code with tracepoints.

Tested-by: Rene Engel 
Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 55 ++-
 hw/audio/trace-events | 10 
 2 files changed, 28 insertions(+), 37 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 9a8e29c39c..0b9fdc8f41 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -34,6 +34,7 @@
 #include "qemu/module.h"
 #include "sysemu/dma.h"
 #include "qom/object.h"
+#include "trace.h"
 
 /* Missing stuff:
SCTRL_P[12](END|ST)INC
@@ -166,8 +167,6 @@ static void es1370_adc_callback (void *opaque, int avail);
 
 #ifdef DEBUG_ES1370
 
-#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
-
 static void print_ctl (uint32_t val)
 {
 char buf[1024];
@@ -239,7 +238,6 @@ static void print_sctl (uint32_t val)
 );
 }
 #else
-#define ldebug(...)
 #define print_ctl(...)
 #define print_sctl(...)
 #endif
@@ -411,12 +409,9 @@ static void es1370_update_voices (ES1370State *s, uint32_t 
ctl, uint32_t sctl)
 
 if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
 d->shift = (new_fmt & 1) + (new_fmt >> 1);
-ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
-i,
-new_freq,
-1 << (new_fmt & 1),
-(new_fmt & 2) ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8,
-d->shift);
+trace_es1370_stream_format(i, new_freq,
+new_fmt & 2 ? "s16" : "u8", new_fmt & 1 ? "stereo" : "mono",
+d->shift);
 if (new_freq) {
 struct audsettings as;
 
@@ -503,8 +498,8 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 case ES1370_REG_ADC_SCOUNT:
 d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
 d->scount = (val & 0x) << 16 | (val & 0x);
-ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
-d - >chan[0], val >> 16, (val & 0x));
+trace_es1370_sample_count_wr(d - >chan[0],
+d->scount >> 16, d->scount & 0x);
 break;
 
 case ES1370_REG_ADC_FRAMEADR:
@@ -515,7 +510,7 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
 frameadr:
 d->frame_addr = val;
-ldebug ("chan %td frame address %#x\n", d - >chan[0], val);
+trace_es1370_frame_address_wr(d - >chan[0], d->frame_addr);
 break;
 
 case ES1370_REG_PHANTOM_FRAMECNT:
@@ -534,8 +529,8 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 framecnt:
 d->frame_cnt = val;
 d->leftover = 0;
-ldebug ("chan %td frame count %d, buffer size %d\n",
-d - >chan[0], val >> 16, val & 0x);
+trace_es1370_frame_count_wr(d - >chan[0],
+d->frame_cnt >> 16, d->frame_cnt & 0x);
 break;
 
 default:
@@ -573,17 +568,9 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, 
unsigned size)
 case ES1370_REG_DAC2_SCOUNT:
 case ES1370_REG_ADC_SCOUNT:
 d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
+trace_es1370_sample_count_rd(d - >chan[0],
+d->scount >> 16, d->scount & 0x);
 val = d->scount;
-#ifdef DEBUG_ES1370
-{
-uint32_t curr_count = d->scount >> 16;
-uint32_t count = d->scount & 0x;
-
-curr_count <<= d->shift;
-count <<= d->shift;
-dolog ("read scount curr %d, total %d\n", curr_count, count);
-}
-#endif
 break;
 
 case ES1370_REG_ADC_FRAMECNT:
@@ -593,17 +580,9 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, 
unsigned size)
 case ES1370_REG_DAC2_FRAMECNT:
 d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
 framecnt:
+trace_es1370_frame_count_rd(d - >chan[0],
+d->frame_cnt >> 16, d->frame_cnt & 0x);
 val = d->frame_cnt;
-#ifdef DEBUG_ES1370
-{
-uint32_t size = ((d->frame_cnt & 0x) + 1) << 2;
-uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
-if (curr > size) {
-dolog ("read framecnt curr %d, size %d %d\n", curr, size,
-   curr > size);
-}
-}
-#endif
 break;
 
 case ES1370_REG_A

[PATCH 6/8] hw/audio/es1370: block structure coding style fixes

2023-09-17 Thread Volker Rümelin
Change the block structure according to the QEMU Coding Style
documentation.

Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 36 
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index e1ca6a4cd5..86a869d4da 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -309,8 +309,7 @@ static void es1370_update_status (ES1370State *s, uint32_t 
new_status)
 
 if (level) {
 s->status = new_status | STAT_INTR;
-}
-else {
+} else {
 s->status = new_status & ~STAT_INTR;
 }
 pci_set_irq(>dev, !!level);
@@ -333,8 +332,7 @@ static void es1370_reset (ES1370State *s)
 if (i == ADC_CHANNEL) {
 AUD_close_in (>card, s->adc_voice);
 s->adc_voice = NULL;
-}
-else {
+} else {
 AUD_close_out (>card, s->dac_voice[i]);
 s->dac_voice[i] = NULL;
 }
@@ -421,8 +419,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t 
ctl, uint32_t sctl)
 es1370_adc_callback,
 
 );
-}
-else {
+} else {
 s->dac_voice[i] =
 AUD_open_out (
 >card,
@@ -442,8 +439,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t 
ctl, uint32_t sctl)
 
 if (i == ADC_CHANNEL) {
 AUD_set_active_in (s->adc_voice, on);
-}
-else {
+} else {
 AUD_set_active_out (s->dac_voice[i], on);
 }
 }
@@ -456,8 +452,9 @@ static void es1370_update_voices (ES1370State *s, uint32_t 
ctl, uint32_t sctl)
 static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
 {
 addr &= 0xff;
-if (addr >= 0x30 && addr <= 0x3f)
+if (addr >= 0x30 && addr <= 0x3f) {
 addr |= s->mempage << 8;
+}
 return addr;
 }
 
@@ -630,8 +627,9 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 
 to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
 acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
-if (!acquired)
+if (!acquired) {
 break;
+}
 
 pci_dma_write (>dev, addr, tmpbuf, acquired);
 
@@ -639,8 +637,7 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 addr += acquired;
 transferred += acquired;
 }
-}
-else {
+} else {
 SWVoiceOut *voice = s->dac_voice[index];
 
 while (temp > 0) {
@@ -649,8 +646,9 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
 pci_dma_read (>dev, addr, tmpbuf, to_copy);
 copied = AUD_write (voice, tmpbuf, to_copy);
-if (!copied)
+if (!copied) {
 break;
+}
 temp -= copied;
 addr += copied;
 transferred += copied;
@@ -660,8 +658,7 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 if (csc_bytes == transferred) {
 *irq = 1;
 d->scount = sc | (sc << 16);
-}
-else {
+} else {
 *irq = 0;
 d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
 }
@@ -672,12 +669,12 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 /* Bah, how stupid is that having a 0 represent true value?
i just spent few hours on this shit */
 AUD_log ("es1370: warning", "non looping mode\n");
-}
-else {
+} else {
 d->frame_cnt = size;
 
-if ((uint32_t) cnt <= d->frame_cnt)
+if ((uint32_t) cnt <= d->frame_cnt) {
 d->frame_cnt |= cnt << 16;
+}
 }
 
 d->leftover = (transferred + d->leftover) & 3;
@@ -778,8 +775,7 @@ static int es1370_post_load (void *opaque, int version_id)
 AUD_close_in (>card, s->adc_voice);
 s->adc_voice = NULL;
 }
-}
-else {
+} else {
 if (s->dac_voice[i]) {
 AUD_close_out (>card, s->dac_voice[i]);
 s->dac_voice[i] = NULL;
-- 
2.35.3




[PATCH 8/8] hw/audio/es1370: trace lost interrupts

2023-09-17 Thread Volker Rümelin
It turns out that there are drivers which assume that interrupts
can't be lost. E.g. the AROS sb128 driver is such a driver. Add
a lost interrupt tracepoint to debug this kind of issues.

Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 14 ++
 hw/audio/trace-events |  3 ++-
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 6d2aff57f2..4966f72ae6 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -602,7 +602,7 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, 
unsigned size)
 }
 
 static void es1370_transfer_audio (ES1370State *s, struct chan *d, int 
loop_sel,
-   int max, int *irq)
+   int max, bool *irq)
 {
 uint8_t tmpbuf[4096];
 size_t to_transfer;
@@ -657,10 +657,13 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 }
 
 if (csc_bytes == transferred) {
-*irq = 1;
+if (*irq) {
+trace_es1370_lost_interrupt(index);
+}
+*irq = true;
 d->scount = sc | (sc << 16);
 } else {
-*irq = 0;
+*irq = false;
 d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
 }
 
@@ -688,7 +691,8 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
 {
 uint32_t new_status = s->status;
-int max_bytes, irq;
+int max_bytes;
+bool irq;
 struct chan *d = >chan[chan];
 const struct chan_bits *b = _chan_bits[chan];
 
@@ -702,6 +706,8 @@ static void es1370_run_channel (ES1370State *s, size_t 
chan, int free_or_avail)
 return;
 }
 
+irq = s->sctl & b->sctl_inten && s->status & b->stat_int;
+
 es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, );
 
 if (irq) {
diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index 00f9e45158..ccbc8dabd5 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -11,10 +11,11 @@ es1370_frame_address_rd(int ch, uint32_t addr) "ch=%d 
addr=0x%08x"
 es1370_frame_address_wr(int ch, uint32_t addr) "ch=%d addr=0x%08x"
 es1370_frame_count_rd(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u 
BUF_SIZE=%u"
 es1370_frame_count_wr(int ch, uint32_t curr, uint32_t size) "ch=%d CURR_CT=%u 
BUF_SIZE=%u"
+es1370_lost_interrupt(int ch) "ch=%d lost interrupt"
 es1370_sample_count_rd(int ch, uint32_t curr, uint32_t num) "ch=%d 
CURR_SAMP_CT=%u SAMP_CT=%u"
 es1370_sample_count_wr(int ch, uint32_t curr, uint32_t num) "ch=%d 
CURR_SAMP_CT=%u SAMP_CT=%u"
 es1370_stream_format(int ch, uint32_t freq, const char *fmt, const char *mode, 
uint32_t shift) "ch=%d fmt=%u:%s:%s shift=%u"
-es1370_transfer_audio(int ch, uint32_t f_curr, uint32_t f_size, uint32_t 
s_curr, uint32_t s_num, uint32_t leftover, int irq) "ch=%d CURR_CT=%u 
BUF_SIZE=%u CURR_SAMP_CT=%u SAMP_CT=%u leftover=%u irq=%d"
+es1370_transfer_audio(int ch, uint32_t f_curr, uint32_t f_size, uint32_t 
s_curr, uint32_t s_num, uint32_t leftover, bool irq) "ch=%d CURR_CT=%u 
BUF_SIZE=%u CURR_SAMP_CT=%u SAMP_CT=%u leftover=%u irq=%d"
 
 # hda-codec.c
 hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run 
%d"
-- 
2.35.3




[PATCH 4/8] hw/audio/es1370: remove #ifdef ES1370_DEBUG to avoid bit rot

2023-09-17 Thread Volker Rümelin
Replace the #ifdef ES1370_DEBUG code with code that the compiler
can optimize away to avoid bit rot. While at it, replace strcat()
with pstrcat().

Tested-by: Rene Engel 
Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 135 +++---
 1 file changed, 66 insertions(+), 69 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index f66feb5bb0..839689bcb3 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -22,7 +22,7 @@
  * THE SOFTWARE.
  */
 
-/* #define DEBUG_ES1370 */
+#define DEBUG_ES1370 0
 /* #define VERBOSE_ES1370 */
 
 #include "qemu/osdep.h"
@@ -30,6 +30,7 @@
 #include "audio/audio.h"
 #include "hw/pci/pci_device.h"
 #include "migration/vmstate.h"
+#include "qemu/cutils.h"
 #include "qemu/module.h"
 #include "sysemu/dma.h"
 #include "qom/object.h"
@@ -164,82 +165,78 @@ static void es1370_dac1_callback (void *opaque, int free);
 static void es1370_dac2_callback (void *opaque, int free);
 static void es1370_adc_callback (void *opaque, int avail);
 
-#ifdef DEBUG_ES1370
-
-static void print_ctl (uint32_t val)
+static void print_ctl(uint32_t val)
 {
-char buf[1024];
-
-buf[0] = '\0';
-#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
-a (ADC_STOP);
-a (XCTL1);
-a (OPEN);
-a (MSFMTSEL);
-a (M_SBB);
-a (DAC_SYNC);
-a (CCB_INTRM);
-a (M_CB);
-a (XCTL0);
-a (BREQ);
-a (DAC1_EN);
-a (DAC2_EN);
-a (ADC_EN);
-a (UART_EN);
-a (JYSTK_EN);
-a (CDC_EN);
-a (SERR_DIS);
+if (DEBUG_ES1370) {
+char buf[1024];
+
+buf[0] = '\0';
+#define a(n) if (val & CTRL_##n) pstrcat(buf, sizeof(buf), " "#n)
+a(ADC_STOP);
+a(XCTL1);
+a(OPEN);
+a(MSFMTSEL);
+a(M_SBB);
+a(DAC_SYNC);
+a(CCB_INTRM);
+a(M_CB);
+a(XCTL0);
+a(BREQ);
+a(DAC1_EN);
+a(DAC2_EN);
+a(ADC_EN);
+a(UART_EN);
+a(JYSTK_EN);
+a(CDC_EN);
+a(SERR_DIS);
 #undef a
-AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
- (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
- DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
- buf);
+AUD_log("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
+(val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
+DAC2_DIVTOSR((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
+buf);
+}
 }
 
-static void print_sctl (uint32_t val)
+static void print_sctl(uint32_t val)
 {
-static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
-char buf[1024];
-
-buf[0] = '\0';
-
-#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
-#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
-b (R1LOOPSEL);
-b (P2LOOPSEL);
-b (P1LOOPSEL);
-a (P2PAUSE);
-a (P1PAUSE);
-a (R1INTEN);
-a (P2INTEN);
-a (P1INTEN);
-a (P1SCTRLD);
-a (P2DACSEN);
-if (buf[0]) {
-strcat (buf, "\n");
-}
-else {
-buf[0] = ' ';
-buf[1] = '\0';
-}
+if (DEBUG_ES1370) {
+static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
+char buf[1024];
+
+buf[0] = '\0';
+
+#define a(n) if (val & SCTRL_##n) pstrcat(buf, sizeof(buf), " "#n)
+#define b(n) if (!(val & SCTRL_##n)) pstrcat(buf, sizeof(buf), " "#n)
+b(R1LOOPSEL);
+b(P2LOOPSEL);
+b(P1LOOPSEL);
+a(P2PAUSE);
+a(P1PAUSE);
+a(R1INTEN);
+a(P2INTEN);
+a(P1INTEN);
+a(P1SCTRLD);
+a(P2DACSEN);
+if (buf[0]) {
+pstrcat(buf, sizeof(buf), "\n");
+} else {
+buf[0] = ' ';
+buf[1] = '\0';
+}
 #undef b
 #undef a
-AUD_log ("es1370",
- "%s"
- "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
- buf,
- (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
- (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
- fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
-);
+AUD_log("es1370",
+"%s p2_end_inc %d, p2_st_inc %d,"
+" r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
+buf,
+(val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
+(val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
+fmt_names[(val >> SCTRL_SH_R1FMT) & 3],
+fmt_names[(val >> SCTRL_SH_P2FMT) & 3],
+fmt_names[(val >> SCTRL_SH_P1FMT) & 3]);
+}
 }
-#else
-#define print_ctl(...)
-#define print_sctl(...)
-#endif
 
 #ifdef VERBOSE_ES1370
 #define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
-- 
2.35.3




[PATCH 7/8] hw/audio/es1370: change variable type and name

2023-09-17 Thread Volker Rümelin
Change the type of the variable temp to size_t to avoid a type
cast. While at it, rename the variable name to to_transfer. This
improves the readability of the code.

Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 86a869d4da..6d2aff57f2 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -605,6 +605,7 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
int max, int *irq)
 {
 uint8_t tmpbuf[4096];
+size_t to_transfer;
 uint32_t addr = d->frame_addr;
 int sc = d->scount & 0x;
 int csc = d->scount >> 16;
@@ -616,16 +617,16 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 }
 int left = ((size - cnt + 1) << 2) + d->leftover;
 int transferred = 0;
-int temp = MIN (max, MIN (left, csc_bytes));
 int index = d - >chan[0];
 
+to_transfer = MIN(max, MIN(left, csc_bytes));
 addr += (cnt << 2) + d->leftover;
 
 if (index == ADC_CHANNEL) {
-while (temp > 0) {
+while (to_transfer > 0) {
 int acquired, to_copy;
 
-to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
+to_copy = MIN(to_transfer, sizeof(tmpbuf));
 acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
 if (!acquired) {
 break;
@@ -633,23 +634,23 @@ static void es1370_transfer_audio (ES1370State *s, struct 
chan *d, int loop_sel,
 
 pci_dma_write (>dev, addr, tmpbuf, acquired);
 
-temp -= acquired;
+to_transfer -= acquired;
 addr += acquired;
 transferred += acquired;
 }
 } else {
 SWVoiceOut *voice = s->dac_voice[index];
 
-while (temp > 0) {
+while (to_transfer > 0) {
 int copied, to_copy;
 
-to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
+to_copy = MIN(to_transfer, sizeof(tmpbuf));
 pci_dma_read (>dev, addr, tmpbuf, to_copy);
 copied = AUD_write (voice, tmpbuf, to_copy);
 if (!copied) {
 break;
 }
-temp -= copied;
+to_transfer -= copied;
 addr += copied;
 transferred += copied;
 }
-- 
2.35.3




[PATCH 5/8] hw/audio/es1370: remove #ifdef ES1370_VERBOSE to avoid bit rot

2023-09-17 Thread Volker Rümelin
Replace the #ifdef ES1370_VERBOSE code with code that the compiler
can optimize away to avoid bit rot and fix the already rotten code.

Tested-by: Rene Engel 
Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 25 +
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 839689bcb3..e1ca6a4cd5 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -23,7 +23,7 @@
  */
 
 #define DEBUG_ES1370 0
-/* #define VERBOSE_ES1370 */
+#define VERBOSE_ES1370 0
 
 #include "qemu/osdep.h"
 #include "hw/audio/soundhw.h"
@@ -238,11 +238,12 @@ static void print_sctl(uint32_t val)
 }
 }
 
-#ifdef VERBOSE_ES1370
-#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
-#else
-#define lwarn(...)
-#endif
+#define lwarn(...) \
+do { \
+if (VERBOSE_ES1370) { \
+AUD_log("es1370: warning", __VA_ARGS__); \
+} \
+} while (0)
 
 #define TYPE_ES1370 "ES1370"
 OBJECT_DECLARE_SIMPLE_TYPE(ES1370State, ES1370)
@@ -504,10 +505,10 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 break;
 
 case ES1370_REG_PHANTOM_FRAMECNT:
-lwarn ("writing to phantom frame count %#x\n", val);
+lwarn("writing to phantom frame count 0x%" PRIx64 "\n", val);
 break;
 case ES1370_REG_PHANTOM_FRAMEADR:
-lwarn ("writing to phantom frame address %#x\n", val);
+lwarn("writing to phantom frame address 0x%" PRIx64 "\n", val);
 break;
 
 case ES1370_REG_ADC_FRAMECNT:
@@ -524,7 +525,7 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 break;
 
 default:
-lwarn ("writel %#x <- %#x\n", addr, val);
+lwarn("writel 0x%" PRIx64 " <- 0x%" PRIx64 "\n", addr, val);
 break;
 }
 }
@@ -588,16 +589,16 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, 
unsigned size)
 
 case ES1370_REG_PHANTOM_FRAMECNT:
 val = ~0U;
-lwarn ("reading from phantom frame count\n");
+lwarn("reading from phantom frame count\n");
 break;
 case ES1370_REG_PHANTOM_FRAMEADR:
 val = ~0U;
-lwarn ("reading from phantom frame address\n");
+lwarn("reading from phantom frame address\n");
 break;
 
 default:
 val = ~0U;
-lwarn ("readl %#x -> %#x\n", addr, val);
+lwarn("readl 0x%" PRIx64 " -> 0x%x\n", addr, val);
 break;
 }
 return val;
-- 
2.35.3




[PATCH 1/8] hw/audio/es1370: reset current sample counter

2023-09-17 Thread Volker Rümelin
Reset the current sample counter when writing the Channel Sample
Count Register. The Linux ens1370 driver and the AROS sb128
driver expect the current sample counter counts down from sample
count to 0 after a write to the Channel Sample Count Register.
Currently the current sample counter starts from 0 after a reset
or the last count when the counter was stopped.

The current sample counter is used to raise an interrupt whenever
a complete buffer was transferred. When the counter starts with a
value lower than the reload value, the interrupt triggeres before
the buffer was completly transferred. This may lead to corrupted
audio streams.

Tested-by: Rene Engel 
Signed-off-by: Volker Rümelin 
---
 hw/audio/es1370.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 4f738a0ad8..9a8e29c39c 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -502,7 +502,7 @@ static void es1370_write(void *opaque, hwaddr addr, 
uint64_t val, unsigned size)
 case ES1370_REG_DAC2_SCOUNT:
 case ES1370_REG_ADC_SCOUNT:
 d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
-d->scount = (val & 0x) | (d->scount & ~0x);
+d->scount = (val & 0x) << 16 | (val & 0x);
 ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
 d - >chan[0], val >> 16, (val & 0x));
 break;
-- 
2.35.3




[PATCH 0/8] hw/audio/es1370: bug fix

2023-09-17 Thread Volker Rümelin
Cc: qemu-stable. Patch 1/8 is a bug fix.
Cc: more people. The maintainer of hw/audio is busy with other projects.

Earlier this year I was asked if I could help to debug an audio playback
speed issue with the es1370 device. While debugging the playback speed
error, I noticed that the debug code of the ES1370 device has not been
compiled for a long time and has bit-rotted. This patch series fixes the
rotten code and also fixes a bug I found while debugging the code. The
bug fix is in patch 1/8 and prevents corrupted data streams. The
playback speed issue was caused by lost interrupts. Patch 8/8 helps to
debug this kind of issues.

Volker Rümelin (8):
  hw/audio/es1370: reset current sample counter
  hw/audio/es1370: replace bit-rotted code with tracepoints
  hw/audio/es1370: remove unused dolog macro
  hw/audio/es1370: remove #ifdef ES1370_DEBUG to avoid bit rot
  hw/audio/es1370: remove #ifdef ES1370_VERBOSE to avoid bit rot
  hw/audio/es1370: block structure coding style fixes
  hw/audio/es1370: change variable type and name
  hw/audio/es1370: trace lost interrupts

 hw/audio/es1370.c | 289 +++---
 hw/audio/trace-events |  11 ++
 2 files changed, 143 insertions(+), 157 deletions(-)

-- 
2.35.3



Re: [PATCH v2 08/20] asc: generate silence if FIFO empty but engine still running

2023-09-16 Thread Volker Rümelin
Am 14.09.23 um 09:56 schrieb Philippe Mathieu-Daudé:
>
> On 9/9/23 11:48, Mark Cave-Ayland wrote:
>> MacOS (un)helpfully leaves the FIFO engine running even when all the
>> samples have
>> been written to the hardware, and expects the FIFO status flags and
>> IRQ to be
>> updated continuously.
>>
>> There is an additional problem in that not all audio backends
>> guarantee an
>> all-zero output when there is no FIFO data available, in particular
>> the Windows
>> dsound backend which re-uses its internal circular buffer causing the
>> last played
>> sound to loop indefinitely.
>>
>> Whilst this is effectively a bug in the Windows dsound backend, work
>> around it
>> for now using a simple heuristic: if the FIFO remains empty for half
>> a cycle
>> (~23ms) then continuously fill the generated buffer with empty silence.
>>
>> Signed-off-by: Mark Cave-Ayland 
>> ---
>>   hw/audio/asc.c | 19 +++
>>   include/hw/audio/asc.h |  2 ++
>>   2 files changed, 21 insertions(+)
>>
>> diff --git a/hw/audio/asc.c b/hw/audio/asc.c
>> index 336ace0cd6..b01b285512 100644
>> --- a/hw/audio/asc.c
>> +++ b/hw/audio/asc.c
>> @@ -334,6 +334,21 @@ static void asc_out_cb(void *opaque, int free_b)
>>   }
>>     if (!generated) {
>> +    /* Workaround for audio underflow bug on Windows dsound
>> backend */
>> +    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    int silent_samples = muldiv64(now - s->fifo_empty_ns,
>> +  NANOSECONDS_PER_SECOND,
>> ASC_FREQ);
>> +
>> +    if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) {
>> +    /*
>> + * No new FIFO data within half a cycle time (~23ms) so
>> fill the
>> + * entire available buffer with silence. This prevents
>> an issue
>> + * with the Windows dsound backend whereby the sound
>> appears to
>> + * loop because the FIFO has run out of data, and the
>> driver
>> + * reuses the stale content in its circular audio buffer.
>> + */
>> +    AUD_write(s->voice, s->silentbuf, samples << s->shift);
>> +    }
>>   return;
>>   }
>
> What about having audio_callback_fn returning a boolean, and using
> a flag in backends for that silence case? Roughtly:
>

Hi Philippe,

I don't think there will be many audio devices that need this feature in
the future. It's probably better to keep the code in hw/audio/asc.c

I plan to change the buffer underflow behavior of the DirectSound
backend after these patches are commited. I already have a patch
available. This doesn't mean this patch is unnecessary after my patch.
It is a mistake when audio devices simply stop writing audio samples
without changing the status of the audio playback stream to deactivated.
At the moment the ASC device can't deactivate the audio stream.

With best regards,
Volker

> -- >8 --
> diff --git a/audio/audio.h b/audio/audio.h
> index 01bdc567fb..4844771c92 100644
> --- a/audio/audio.h
> +++ b/audio/audio.h
> @@ -30,7 +30,7 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/qdev-properties-system.h"
>
> -typedef void (*audio_callback_fn) (void *opaque, int avail);
> +typedef bool (*audio_callback_fn) (void *opaque, int avail);
>
>  #if HOST_BIG_ENDIAN
>  #define AUDIO_HOST_ENDIANNESS 1
> diff --git a/audio/audio.c b/audio/audio.c
> index 90c7c49d11..5b6e69fbd6 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -1178,8 +1178,11 @@ static void audio_run_out (AudioState *s)
>  if (free > sw->resample_buf.pos) {
>  free = MIN(free, sw->resample_buf.size)
>     - sw->resample_buf.pos;
> -    sw->callback.fn(sw->callback.opaque,
> -    free * sw->info.bytes_per_frame);
> +    if (!sw->callback.fn(sw->callback.opaque,
> + free *
> sw->info.bytes_per_frame)
> +    && unlikely(hw->silentbuf_required)) {
> +    /* write silence ... */
> +    }
>  }
>  }
>  }
> ---




Re: [PATCH v2 07/20] audio: add Apple Sound Chip (ASC) emulation

2023-09-14 Thread Volker Rümelin
Am 09.09.23 um 11:48 schrieb Mark Cave-Ayland:
> The Apple Sound Chip was primarily used by the Macintosh II to generate sound
> in hardware which was previously handled by the toolbox ROM with software
> interrupts.
>
> Implement both the standard ASC and also the enhanced ASC (EASC) functionality
> which is used in the Quadra 800.
>
> Note that whilst real ASC hardware uses AUDIO_FORMAT_S8, this implementation 
> uses
> AUDIO_FORMAT_U8 instead because AUDIO_FORMAT_S8 is rarely used and not 
> supported
> by some audio backends like PulseAudio and DirectSound when played directly 
> with
> -audiodev out.mixing-engine=off.
>
> Co-developed-by: Laurent Vivier 
> Co-developed-by: Volker Rümelin 
> Signed-off-by: Mark Cave-Ayland 
> ---
>  MAINTAINERS|   2 +
>  hw/audio/Kconfig   |   3 +
>  hw/audio/asc.c | 699 +
>  hw/audio/meson.build   |   1 +
>  hw/audio/trace-events  |  10 +
>  hw/m68k/Kconfig|   1 +
>  include/hw/audio/asc.h |  84 +
>  7 files changed, 800 insertions(+)
>  create mode 100644 hw/audio/asc.c
>  create mode 100644 include/hw/audio/asc.h

Hi Mark,

the function generate_fifo() has four issues. Only the first one
is noticeable.

1. The calculation of the variable limit assumes generate_fifo()
generates one output sample from every input byte. This is correct
for the raw mode, but not for the CD-XA BRR mode. This mode
generates 28 output samples from 15 input bytes. This is the
reason for the stuttering end of a CD-XA BRR mode sound. Every
generate_fifo() call generates approximately only half of the
possible samples when the fifo bytes are running low.

2. generate_fifo() doesn't generate the last output sample from
a CD-XA BRR mode sound. The last sample is generated from internal
state and the code will not be called without at least one byte
in the fifo.

3. It's not necessary to wait for a complete 15 byte packet in
CD-XA BRR mode. Audio playback devices should write all
requested samples immediately if possible.

4. The saturation function in CD-XA BRR mode works with 16 bit
integers. It should saturate at +32767 and -32768.

Since I think a few lines of code explain the issues better
than my words, I've attached a patch below.

With best regards,
Volker

> +static int generate_fifo(ASCState *s, int maxsamples)
> +{
> +int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +uint8_t *buf = s->mixbuf;
> +int i, limit, count = 0;
> +
> +limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
> +while (count < limit) {
> +uint8_t val;
> +int16_t d, f0, f1;
> +int32_t t;
> +int shift, filter;
> +bool hasdata = true;
> +
> +for (i = 0; i < 2; i++) {
> +ASCFIFOState *fs = >fifos[i];
> +
> +switch (fs->extregs[ASC_EXTREGS_FIFOCTRL] & 0x83) {
> +case 0x82:
> +/*
> + * CD-XA BRR mode: exit if there isn't enough data in the 
> FIFO
> + * for a complete 15 byte packet
> + */
> +if (fs->xa_cnt == -1 && fs->cnt < 15) {
> +hasdata = false;
> +continue;
> +}
> +
> +if (fs->xa_cnt == -1) {
> +/* Start of packet, get flags */
> +fs->xa_flags = asc_fifo_get(fs);
> +fs->xa_cnt = 0;
> +}
> +
> +shift = fs->xa_flags & 0xf;
> +filter = fs->xa_flags >> 4;
> +f0 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
> + (filter << 1) + 1];
> +f1 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT +
> + (filter << 1)];
> +if ((fs->xa_cnt & 1) == 0) {
> +fs->xa_val = asc_fifo_get(fs);
> +d = (fs->xa_val & 0xf) << 12;
> +} else {
> +d = (fs->xa_val & 0xf0) << 8;
> +}
> +t = (d >> shift) + (((fs->xa_last[0] * f0) +
> + (fs->xa_last[1] * f1) + 32) >> 6);
> +if (t < -32768) {
> +t = -32768;
> +} else if (t > 32768) {
> +t = 32768;
> +}
> +
> +/*
> + * CD-XA BRR generates 16-bit signed output, so convert to
> + * 8-bit before writing to buffer. Does real hardware do the
> + *

Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)

2023-09-09 Thread Volker Rümelin

Am 28.08.23 um 21:55 schrieb 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
---
  hw/virtio/trace-events |   3 +-
  hw/virtio/virtio-snd.c | 245 +++--
  2 files changed, 215 insertions(+), 33 deletions(-)

diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 3b95e745c2..9b7fbffedc 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 4859ce4bf6..70e8a73072 100644
--- a/hw/virtio/virtio-snd.c
+++ b/hw/virtio/virtio-snd.c



@@ -1002,26 +1073,119 @@ static void virtio_snd_pcm_out_cb(void *data, int 
available)
  }
  
  /*

- * Flush all buffer data from this stream's queue into the driver's virtual
- * queue.
+ * AUD_* input callback.
   *
- * @stream: VirtIOSoundPCMStream *stream
+ * @data: VirtIOSoundPCMStream stream
+ * @available: number of bytes that can be read with AUD_read()
   */
-static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
+static void virtio_snd_pcm_in_cb(void *data, int available)
  {
+VirtIOSoundPCMStream *stream = data;
  VirtIOSoundPCMBlock *block;
-VirtIOSoundPCMBlock *next;
+uint32_t sz;
+virtio_snd_pcm_status resp = { 0 };
+size_t size;
  
  WITH_QEMU_LOCK_GUARD(>queue_mutex) {

-QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
-AUD_write(stream->voice.out, block->data + block->offset, 
block->size);
-virtqueue_push(block->vq, block->elem, sizeof(block->elem));
-virtio_notify(VIRTIO_DEVICE(stream->s), block->vq);
-QSIMPLEQ_REMOVE(>queue, block, VirtIOSoundPCMBlock, entry);
+while (!QSIMPLEQ_EMPTY(>queue)) {
+block = QSIMPLEQ_FIRST(>queue);
+
+for (;;) {
+size = AUD_read(stream->voice.in,
+block->data + block->offset,
+MIN(stream->period_bytes - block->offset, available));
+block->offset += size;
+block->size += size;
+if (size == 0 || block->size >= stream->period_bytes) {
+resp.status = VIRTIO_SND_S_OK;


Hi Manos,

the type of resp.status is le32. I doubt that the virtio-sound device 
will work on a big endian host at the moment. There are more issues like 
this in virtio-snd.c.



+ sz = iov_from_buf(block->elem->in_sg,
+  block->elem->in_num,
+  0,
+  ,
+  sizeof(resp));
+
+/* Copy data -if any- to guest */
+if (block->size) {
+iov_from_buf(block->elem->in_sg,
+ block->elem->in_num,
+ sz,
+ block->data,
+ MIN(stream->period_bytes, block->size));
+}


The order of the parts of the PCM input stream message is wrong. The 
buffer comes first, then the status part. See virtio-v1.2-cs01 
5.14.6.8PCM I/O Messages. The correct order fixes the problem with the 
wrong audio frames every 25ms. The two wrong audio frames were the 
status part of the message.



+virtqueue_push(block->vq,
+block->elem,
+sizeof(block->elem));


sizeof(block->elem)? This is the size of a pointer. The PCM I/O Message 
is much larger. The other virtqueue_push() call sites also don't look right.


With best regards,
Volker


+virtio_notify(VIRTIO_DEVICE(stream->s),
+block->vq);
+QSIMPLEQ_REMOVE_HEAD(>queue, entry);
+g_free(block);
+available -= size;
+break;
+}
+
+available -= size;
+if (!available) {
+break;
+}
+}
+if (!available) {
+break;
+}
  }

Re: [PATCH v8 11/12] virtio-sound: implement audio capture (RX)

2023-09-08 Thread Volker Rümelin

Am 28.08.23 um 21:55 schrieb 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 
---
  hw/virtio/trace-events |   3 +-
  hw/virtio/virtio-snd.c | 245 +++--
  2 files changed, 215 insertions(+), 33 deletions(-)

diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 3b95e745c2..9b7fbffedc 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 4859ce4bf6..70e8a73072 100644
--- a/hw/virtio/virtio-snd.c
+++ b/hw/virtio/virtio-snd.c



@@ -1002,26 +1073,119 @@ static void virtio_snd_pcm_out_cb(void *data, int 
available)
  }
  
  /*

- * Flush all buffer data from this stream's queue into the driver's virtual
- * queue.
+ * AUD_* input callback.
   *
- * @stream: VirtIOSoundPCMStream *stream
+ * @data: VirtIOSoundPCMStream stream
+ * @available: number of bytes that can be read with AUD_read()
   */
-static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
+static void virtio_snd_pcm_in_cb(void *data, int available)
  {
+VirtIOSoundPCMStream *stream = data;
  VirtIOSoundPCMBlock *block;
-VirtIOSoundPCMBlock *next;
+uint32_t sz;
+virtio_snd_pcm_status resp = { 0 };
+size_t size;
  
  WITH_QEMU_LOCK_GUARD(>queue_mutex) {

-QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
-AUD_write(stream->voice.out, block->data + block->offset, 
block->size);
-virtqueue_push(block->vq, block->elem, sizeof(block->elem));
-virtio_notify(VIRTIO_DEVICE(stream->s), block->vq);
-QSIMPLEQ_REMOVE(>queue, block, VirtIOSoundPCMBlock, entry);
+while (!QSIMPLEQ_EMPTY(>queue)) {
+block = QSIMPLEQ_FIRST(>queue);
+
+for (;;) {
+size = AUD_read(stream->voice.in,
+block->data + block->offset,
+MIN(stream->period_bytes - block->offset, available));


For the -audiodev in.mixing-engine=off case, 'available' is much larger 
than the available bytes AUD_read() can actually read. 'size' is 0 when 
the upstream buffer is empty.


+    if (size == 0) {
+    available = 0;
+    break;
+    }

This fixes audio recording with -audiodev 
pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0. The issue 
with two wrong audio frames every 25ms remains.



+block->offset += size;
+block->size += size;
+if (size == 0 || block->size >= stream->period_bytes) {


-    if (size == 0 || block->size >= stream->period_bytes) {
+    if (block->size >= stream->period_bytes) {

With best regards,
Volker


+resp.status = VIRTIO_SND_S_OK;
+ sz = iov_from_buf(block->elem->in_sg,
+  block->elem->in_num,
+  0,
+  ,
+  sizeof(resp));
+
+/* Copy data -if any- to guest */
+if (block->size) {
+iov_from_buf(block->elem->in_sg,
+ block->elem->in_num,
+ sz,
+ block->data,
+ MIN(stream->period_bytes, block->size));
+}
+virtqueue_push(block->vq,
+block->elem,
+sizeof(block->elem));
+virtio_notify(VIRTIO_DEVICE(stream->s),
+block->vq);
+QSIMPLEQ_REMOVE_HEAD(>queue, entry);
+g_free(block);
+available -= size;
+break;
+}
+
+available -= size;
+if (!available) {
+break;
+}
+}
+if (!available) {
+break;
+}
  }
  }
  }
  




Re: [PATCH v8 10/12] virtio-sound: implement audio output (TX)

2023-09-05 Thread Volker Rümelin

Am 04.09.23 um 23:34 schrieb Volker Rümelin:

Am 04.09.23 um 12:34 schrieb Manos Pitsidianakis:
On Mon, 04 Sep 2023 13:26, Philippe Mathieu-Daudé  
wrote:



+/*
+ * 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;
+    VirtIOSoundPCMBlock *block;
+    VirtIOSoundPCMBlock *next;
+    size_t size;
+
+    WITH_QEMU_LOCK_GUARD(>queue_mutex) {
+    QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
+    for (;;) {
+    size = MIN(block->size, available);
+    size = AUD_write(stream->voice.out,
+    block->data + block->offset,
+    size);


If AUD_write() returns 0, is this an infinite loop?


Hm since we have available > 0 bytes this wouldn't theoretically 
happen, but I see there are code paths that return 0 on 
bugs/failures, I will add the check.


Before QEMU 8.0.0 it was possible that AUD_write() couldn't write the 
last audio frame and sometimes 'available' was just miscalculated. 
Since commit e1e6a6fcc9 ("audio: handle leftover audio frame from 
upsampling") AUD_write() writes all 'available' bytes.




I thought about this again. The error check is necessary.


With best regards,
Volker




+    block->size -= size;
+    block->offset += size;
+    if (!block->size) {
+    virtqueue_push(block->vq,
+    block->elem,
+    sizeof(block->elem));
+ virtio_notify(VIRTIO_DEVICE(stream->s),
+    block->vq);
+ QSIMPLEQ_REMOVE_HEAD(>queue, entry);
+    g_free(block);
+    available -= size;
+    break;
+    }
+
+    available -= size;
+    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 void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
+{
+    VirtIOSoundPCMBlock *block;
+    VirtIOSoundPCMBlock *next;
+
+    WITH_QEMU_LOCK_GUARD(>queue_mutex) {
+    QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
+    AUD_write(stream->voice.out, block->data + 
block->offset, block->size);









Re: [PATCH v8 00/12] Add VIRTIO sound card

2023-09-05 Thread Volker Rümelin

Am 04.09.23 um 12:01 schrieb Manos Pitsidianakis:

Hello Volker :)

On Mon, 04 Sep 2023 10:20, Volker Rümelin  wrote:

All qemu_log_mask() format strings need a trailing \n.


Thank you, will fix it!

I still hear a lot of playback dropouts. I had planned to look at the 
playback code, but I didn't have the time until now.


Compared to v6 audio recording has improved but there are bugs. When 
I start QEMU with -audiodev 
pipewire,out.frequency=48000,in.frequency=48000,id=audio0 there are 
two either uninitialized or stale samples every 25ms in the recorded 
audio stream.


To reproduce the issue start audacity on the host and generate a 2s 
square wave tone with 315Hz and an amplitude of 0.8. Use pavucontrol 
to select the monitor of your host playback device as QEMU recording 
device. In the guest start recording with audacity. Start playback of 
the generated square wave on the host. Stop recording in the guest 
and have a look at a 200ms sequence of the recorded square wave and 
notice the wrong samples every 25ms.


We've noticed this and decided to fix it in the future. I think the 
problem lies when PCM release is called from the guest. Quoting the spec:


 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.


When RELEASE is received, buffers are simply dropped. This is pure 
conjecture but I think creating an in-device buffer could solve this.
Unless the bug is found to be caused by something else, I settled on 
accepting it for this patch series because it is spec conformant.


When I start QEMU with -audiodev 
pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0 audio 
recording starts but the recorded stream immediately stalls.


Can you elaborate? Do you mean you repeat the same process as before, 
but the stall happens immediately? I personally rarely get any drops I 
could notice, only one or two for many minutes of playback / capture. 
I also could not reproduce exactly the same behavior you had in the 
previous version. The bugs *were* there but it was not as severe. 
Maybe it's a hardware performance issue? Can someone else test this 
too? It'd be helpful.


For this test I only start QEMU with the mixing engine disabled. When I 
start recording with audacity, audacity reports 'Recording' in the 
status line but it actually doesn't record. The recording marker in the 
tracks window stays a 0.


I don't think it's a hardware performance issue. Other QEMU audio 
devices don't show this behaviour.


With best regards,
Volker



Thank you very much for your help,
Manos





Re: [PATCH v8 00/12] Add VIRTIO sound card

2023-09-05 Thread Volker Rümelin

Am 04.09.23 um 14:11 schrieb Alex Bennée:

Manos Pitsidianakis  writes:


Hello Volker :)

On Mon, 04 Sep 2023 10:20, Volker Rümelin  wrote:

All qemu_log_mask() format strings need a trailing \n.

Thank you, will fix it!


I still hear a lot of playback dropouts. I had planned to look at
the playback code, but I didn't have the time until now.

Compared to v6 audio recording has improved but there are bugs. When
I start QEMU with -audiodev
pipewire,out.frequency=48000,in.frequency=48000,id=audio0 there are
two either uninitialized or stale samples every 25ms in the recorded
audio stream.

To reproduce the issue start audacity on the host and generate a 2s
square wave tone with 315Hz and an amplitude of 0.8. Use pavucontrol
to select the monitor of your host playback device as QEMU recording
device. In the guest start recording with audacity. Start playback
of the generated square wave on the host. Stop recording in the
guest and have a look at a 200ms sequence of the recorded square
wave and notice the wrong samples every 25ms.

We've noticed this and decided to fix it in the future. I think the
problem lies when PCM release is called from the guest. Quoting the
spec:

  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.

When RELEASE is received, buffers are simply dropped. This is pure
conjecture but I think creating an in-device buffer could solve this.
Unless the bug is found to be caused by something else, I settled on
accepting it for this patch series because it is spec conformant.

Volker,

Can you run with:

   -d trace:virtio_snd\*

to confirm you are seeing the same behaviour. The experience I had with
ogg123 in an emulated guest was it would work fine but then the next run
I would get audio corruption. You can see this if you see lots of
START/STOP/RELEASE messages constantly restarting things. If you are
getting corruption without this pattern that is something else which we
should investigate before merging.


Hi Alex,

I only see a START message when I start recording with audacity and a 
STOP message approximately 5s after I stop recording. This is when guest 
PulseAudio disables the virtio-sound device.


9881@1693892230.558732:virtio_snd_handle_ctrl snd 0x55ac9e6eb590: handle 
ctrl event for queue 0x55ac9e6f4160
9881@1693892230.558780:virtio_snd_handle_code ctrl code msg val = 257 == 
VIRTIO_SND_R_PCM_SET_PARAMS
9881@1693892230.558797:virtio_snd_handle_pcm_set_params 
VIRTIO_SND_PCM_SET_PARAMS called for stream 1
9881@1693892230.559132:virtio_snd_handle_ctrl snd 0x55ac9e6eb590: handle 
ctrl event for queue 0x55ac9e6f4160
9881@1693892230.559158:virtio_snd_handle_code ctrl code msg val = 258 == 
VIRTIO_SND_R_PCM_PREPARE

9881@1693892230.562202:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892230.562365:virtio_snd_handle_ctrl snd 0x55ac9e6eb590: handle 
ctrl event for queue 0x55ac9e6f4160
9881@1693892230.562395:virtio_snd_handle_code ctrl code msg val = 260 == 
VIRTIO_SND_R_PCM_START
9881@1693892230.562411:virtio_snd_handle_pcm_start_stop 
VIRTIO_SND_R_PCM_START called for stream 1

9881@1693892230.562557:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892230.810029:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892230.840194:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892230.860279:virtio_snd_handle_rx_xfer rx queue callback called

... a lot of 'virtio_snd_handle_rx_xfer rx queue callback called' 
messages every 20ms - 30ms


9881@1693892238.510774:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892238.530895:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892238.561123:virtio_snd_handle_rx_xfer rx queue callback called
9881@1693892238.566280:virtio_snd_handle_ctrl snd 0x55ac9e6eb590: handle 
ctrl event for queue 0x55ac9e6f4160
9881@1693892238.566290:virtio_snd_handle_code ctrl code msg val = 261 == 
VIRTIO_SND_R_PCM_STOP
9881@1693892238.566293:virtio_snd_handle_pcm_start_stop 
VIRTIO_SND_R_PCM_STOP called for stream 1
9881@1693892238.566415:virtio_snd_handle_ctrl snd 0x55ac9e6eb590: handle 
ctrl event for queue 0x55ac9e6f4160
9881@1693892238.566424:virtio_snd_handle_code ctrl code msg val = 259 == 
VIRTIO_SND_R_PCM_RELEASE
9881@1693892238.566428:virtio_snd_handle_pcm_release 
VIRTIO_SND_PCM_RELEASE called for stream 1


With best regards,
Volker


When I start QEMU with -audiodev
pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0 audio
recording starts but the recorded stream immediately stalls.

Can you elaborate? Do you mean you repeat the same process as before,
but the stall happens immediately? I personally rarely get any drops I
could notice, only one or two for many minutes of playback / capture.
I also could not reproduce exactly the same behavior you had in the
previous version. The bugs *were* there but it was not as severe.
Maybe it's

Re: [PATCH v8 10/12] virtio-sound: implement audio output (TX)

2023-09-04 Thread Volker Rümelin

Am 04.09.23 um 12:34 schrieb Manos Pitsidianakis:
On Mon, 04 Sep 2023 13:26, Philippe Mathieu-Daudé  
wrote:



+/*
+ * 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;
+    VirtIOSoundPCMBlock *block;
+    VirtIOSoundPCMBlock *next;
+    size_t size;
+
+    WITH_QEMU_LOCK_GUARD(>queue_mutex) {
+    QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
+    for (;;) {
+    size = MIN(block->size, available);
+    size = AUD_write(stream->voice.out,
+    block->data + block->offset,
+    size);


If AUD_write() returns 0, is this an infinite loop?


Hm since we have available > 0 bytes this wouldn't theoretically 
happen, but I see there are code paths that return 0 on bugs/failures, 
I will add the check.


Before QEMU 8.0.0 it was possible that AUD_write() couldn't write the 
last audio frame and sometimes 'available' was just miscalculated. Since 
commit e1e6a6fcc9 ("audio: handle leftover audio frame from upsampling") 
AUD_write() writes all 'available' bytes.


With best regards,
Volker




+    block->size -= size;
+    block->offset += size;
+    if (!block->size) {
+    virtqueue_push(block->vq,
+    block->elem,
+    sizeof(block->elem));
+ virtio_notify(VIRTIO_DEVICE(stream->s),
+    block->vq);
+ QSIMPLEQ_REMOVE_HEAD(>queue, entry);
+    g_free(block);
+    available -= size;
+    break;
+    }
+
+    available -= size;
+    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 void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream)
+{
+    VirtIOSoundPCMBlock *block;
+    VirtIOSoundPCMBlock *next;
+
+    WITH_QEMU_LOCK_GUARD(>queue_mutex) {
+    QSIMPLEQ_FOREACH_SAFE(block, >queue, entry, next) {
+    AUD_write(stream->voice.out, block->data + 
block->offset, block->size);







Re: [PATCH v8 02/12] Add virtio-sound-pci device

2023-09-04 Thread Volker Rümelin

Am 04.09.23 um 12:26 schrieb Manos Pitsidianakis:

On Mon, 04 Sep 2023 09:32, Volker Rümelin  wrote:

+static Property virtio_snd_pci_properties[] = {
+    DEFINE_AUDIO_PROPERTIES(VirtIOSoundPCI, vdev.card),


I think DEFINE_AUDIO_PROPERTIES should be moved back to virtio-snd.c. 
The audiodev property is a virtio-sound property and not a 
virtio-sound-pci property.


Hm, is it? Can you instantiate a virtio-sound device without the PCI 
wrapper? Under hw/audio, DEFINE_AUDIO_PROPERTIES is set in PCI devices 
as well (e.g. ac97)




Creating a virtio-sound device without the PCI wrapper is possible.
./qemu-system-x86_64 -M microvm -accel kvm -cpu host -m 512m -smp 2 
-serial stdio -device virtio-sound,audiodev=audio0 -audiodev 
pipewire,id=audio0 -display gtk
qemu-system-x86_64: -device virtio-sound,audiodev=audio0: Property 
'virtio-sound.audiodev' not found


If you move DEFINE_AUDIO_PROPERTIES to virtio-snd.c you don't see this 
error message and you can see a virtio-mmio sound device if you type 
info qtree in the QEMU compat monitor.


Now that you asked this question I wonder if this should be #define 
TYPE_VIRTIO_SND "virtio-sound-device". Other virtio devices have the 
-device suffix.


With best regards,
Volker




+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+   DEV_NVECTORS_UNSPECIFIED),
+    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(>vdev);
+
+    if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+    vpci_dev->nvectors = 2;
+    }


Why do you need that intermediate step with DEV_NVECTORS_UNSPECIFIED? 
Unlike e.g. virtio-scsi-pci and virtio-net-pci devices, the default 
value of nvectors is already known at compile time and can be 
specified in the property definition.


I did not think this through properly, you are correct. Thank you!

Manos





Re: [PATCH v8 00/12] Add VIRTIO sound card

2023-09-04 Thread Volker Rümelin

Am 28.08.23 um 21:54 schrieb Emmanouil Pitsidianakis:

This patch series adds an audio device implementing the recent virtio
sound spec (1.2) and a corresponding PCI wrapper device.


Hi Manos,

I have a few more general comments.

All qemu_log_mask() format strings need a trailing \n.

I still hear a lot of playback dropouts. I had planned to look at the 
playback code, but I didn't have the time until now.


Compared to v6 audio recording has improved but there are bugs. When I 
start QEMU with -audiodev 
pipewire,out.frequency=48000,in.frequency=48000,id=audio0 there are two 
either uninitialized or stale samples every 25ms in the recorded audio 
stream.


To reproduce the issue start audacity on the host and generate a 2s 
square wave tone with 315Hz and an amplitude of 0.8. Use pavucontrol to 
select the monitor of your host playback device as QEMU recording 
device. In the guest start recording with audacity. Start playback of 
the generated square wave on the host. Stop recording in the guest and 
have a look at a 200ms sequence of the recorded square wave and notice 
the wrong samples every 25ms.


When I start QEMU with -audiodev 
pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0 audio 
recording starts but the recorded stream immediately stalls.


With best regards,
Volker


v8 can be found online at:

https://gitlab.com/epilys/qemu/-/tree/virtio-snd-v8

Ref 69eb5f4fbae731f5fc05dea8a5f4b656e0de127f

Main differences with v7 patch series [^v7]
:

- Addressed [^v7] review comments.
   Functions that were called from more than one place for code re-use
   are not created until they are actually needed.
- Fixed cases where block->offset was not respected in Playback







Re: [PATCH v8 02/12] Add virtio-sound-pci device

2023-09-04 Thread Volker Rümelin

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 | 97 ++
  softmmu/qdev-monitor.c |  1 +
  3 files changed, 99 insertions(+)
  create mode 100644 hw/virtio/virtio-snd-pci.c



diff --git a/hw/virtio/virtio-snd-pci.c b/hw/virtio/virtio-snd-pci.c
new file mode 100644
index 00..a6a530d161
--- /dev/null
+++ b/hw/virtio/virtio-snd-pci.c
@@ -0,0 +1,97 @@
+/*
+ * 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 "qapi/error.h"


Hi Manos,

the macro definition of DECLARE_INSTANCE_CHECKER is in the qom/object.h 
header file. It's better to include it directly than to rely on another 
header file to include it.



+#include "hw/audio/soundhw.h"
+#include "hw/virtio/virtio-pci.h"
+#include "hw/virtio/virtio-snd.h"
+
+typedef struct VirtIOSoundPCI VirtIOSoundPCI;
+
+/*
+ * virtio-snd-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SND_PCI "virtio-sound-pci"
+DECLARE_INSTANCE_CHECKER(VirtIOSoundPCI, VIRTIO_SND_PCI,
+ TYPE_VIRTIO_SND_PCI)
+
+struct VirtIOSoundPCI {
+VirtIOPCIProxy parent;
+VirtIOSound vdev;
+};
+
+static Property virtio_snd_pci_properties[] = {
+DEFINE_AUDIO_PROPERTIES(VirtIOSoundPCI, vdev.card),


I think DEFINE_AUDIO_PROPERTIES should be moved back to virtio-snd.c. 
The audiodev property is a virtio-sound property and not a 
virtio-sound-pci property.



+DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+   DEV_NVECTORS_UNSPECIFIED),
+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(>vdev);
+
+if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+vpci_dev->nvectors = 2;
+}


Why do you need that intermediate step with DEV_NVECTORS_UNSPECIFIED? 
Unlike e.g. virtio-scsi-pci and virtio-net-pci devices, the default 
value of nvectors is already known at compile time and can be specified 
in the property definition.


With best regards,
Volker


+
+virtio_pci_force_virtio_1(vpci_dev);
+qdev_realize(vdev, BUS(_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, >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 *dev;
+
+dev = qdev_new(TYPE_VIRTIO_SND_PCI);
+qdev_prop_set_string(dev, "audiodev", audiodev);
+qdev_realize_and_unref(dev, BUS(bus), _fatal);
+return 0;
+}
+
+static void virtio_snd_pci_register(void)
+{
+virtio_pci_types_register(_snd_pci_info);
+pci_register_soundhw("virtio", "Virtio Sound", virtio_snd_pci_init);
+}
+
+type_init(virtio_snd_pci_register);
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 74f4e41338..2e9835ad88 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ 

Re: [PATCH v6 00/12] Add VIRTIO sound card

2023-08-21 Thread Volker Rümelin

Am 21.08.23 um 08:10 schrieb Manos Pitsidianakis:

Hello Volker,

On Sun, 20 Aug 2023 14:46, Volker Rümelin  wrote:
I tested the virtio-sound-pci device. It seems the device works 
unreliably. Audio playback has a lot of dropouts. I can actually hear 
my mouse moving around. Audio recording with audacity doesn't work. 
Either recording stops with an error or the recorded stream is silent.


I'll see if I can change the code so audio playback works reliably. I 
don't think it makes sense to review the current code as it is. I 
will of course report any issues I find.


have you been having this bad performance with pulseaudio/pipewire? 
Are you using alsa for playback/recording in the guest?


I am asking because this was my setup and I was wondering if it 
affected the code I ended up with. For me I had normal playback, 
except for a short delay at first (maybe something to do with alsa 
buffer lengths, I am not familiar with ALSA much).


If you can share your guest and host setup you used for this I can try 
replicating it.




Hi Manos,

on the host I use pipewire. The audio device used for playback and 
recording is a Intel HDA device. I also tested recording from the 
playback monitor of the HDA device. The important command line arguments 
are: ./qemu-system-x86_64 -machine q35 -device 
virtio-vga-gl,xres=1280,yres=768,bus=pcie.0 -display 
gtk,zoom-to-fit=off,gl=on -machine pcspk-audiodev=audio0 -device 
virtio-sound-pci,bus=pcie.0,audiodev=audio0 -audiodev 
pipewire,out.frequency=48000,in.frequency=48000,id=audio0


The guest is Linux OpenSUSE 15.5 system. The guest uses PulseAudio. This 
means audacity ALSA audio recording was routed through PulseAudio. 
Audacity doesn't really start recording but after a few seconds it 
reports 'Wait timed out' and 'Error opening sound device. Try changing 
the audio host, recording device and the project sample rate'.


When I start QEMU with -audiodev 
pipewire,out.mixing-engine=off,in.mixing-engine=off,id=audio0 audacity 
only records silence.


For playback I use Rhythmbox or Audacity. If you don't immediately hear 
dropouts try activating and deactivating the QEMU gtk window in quick 
succession. A slightly increased processor load like moving the mouse 
around also increases the dropout rate.


With best regards,
Volker




Re: [PATCH v6 01/12] Add virtio-sound device stub

2023-08-21 Thread Volker Rümelin

Am 21.08.23 um 08:06 schrieb Manos Pitsidianakis:

Hello Volker!

On Sun, 20 Aug 2023 12:33, Volker Rümelin  wrote:
I think the virtio-snd.c code, the trace events and the Kconfig 
VIRTIO_SND should be moved to hw/audio. The code for nearly all audio 
devices is in this directory. This would be similar to other virtio 
devices. E.g. the virtio-scsi code is in hw/scsi and the virtio-net 
code is in hw/net.


This was where it was initially but in previous patchset versions it 
was recommended to move them to hw/virtio. I don't mind either 
approach though.


Hi Manos,

Ok, then don't change the directory. I guess I will have to discuss this 
with Alex first.


With best regards,
Volker

Re: [PATCH v6 00/12] Add VIRTIO sound card

2023-08-20 Thread Volker Rümelin

Hi Manos,

I tested the virtio-sound-pci device. It seems the device works 
unreliably. Audio playback has a lot of dropouts. I can actually hear my 
mouse moving around. Audio recording with audacity doesn't work. Either 
recording stops with an error or the recorded stream is silent.


I'll see if I can change the code so audio playback works reliably. I 
don't think it makes sense to review the current code as it is. I will 
of course report any issues I find.


With best regards,
Volker


This patch series adds an audio device implementing the recent virtio
sound spec (1.2) and a corresponding PCI wrapper device.

https://github.com/epilys/qemu-virtio-snd/tree/virtio-snd-v6

Main differences with v5 patch series [^v5]
:

- Free any existing PCM stream resources before allocating a new one.
- Add docs.

[^v5]:
https://lore.kernel.org/qemu-devel/cover.1690626150.git.manos.pitsidiana...@linaro.org/

Previously:

[^v4]:
https://lore.kernel.org/qemu-devel/cover.1689857559.git.manos.pitsidiana...@linaro.org/
[^v3]:
https://lore.kernel.org/qemu-devel/cover.1689692765.git.manos.pitsidiana...@linaro.org/


Emmanouil Pitsidianakis (12):
   Add virtio-sound device stub
   Add virtio-sound-pci device
   virtio-sound: handle control messages and streams
   virtio-sound: set PCM stream parameters
   virtio-sound: handle VIRTIO_SND_R_PCM_INFO request
   virtio-sound: handle VIRTIO_SND_R_PCM_{START,STOP}
   virtio-sound: handle VIRTIO_SND_PCM_SET_PARAMS
   virtio-sound: handle VIRTIO_SND_R_PCM_PREPARE
   virtio-sound: handle VIRTIO_SND_PCM_RELEASE
   virtio-sound: implement audio output (TX)
   virtio-sound: implement audio capture (RX)
   docs/system: add basic virtio-snd documentation

  MAINTAINERS|6 +
  docs/system/device-emulation.rst   |1 +
  docs/system/devices/virtio-snd.rst |   36 +
  hw/virtio/Kconfig  |5 +
  hw/virtio/meson.build  |2 +
  hw/virtio/trace-events |   20 +
  hw/virtio/virtio-snd-pci.c |   91 ++
  hw/virtio/virtio-snd.c | 1308 
  include/hw/pci/pci.h   |1 +
  include/hw/virtio/virtio-snd.h |  158 
  softmmu/qdev-monitor.c |1 +
  11 files changed, 1629 insertions(+)
  create mode 100644 docs/system/devices/virtio-snd.rst
  create mode 100644 hw/virtio/virtio-snd-pci.c
  create mode 100644 hw/virtio/virtio-snd.c
  create mode 100644 include/hw/virtio/virtio-snd.h


Re: [PATCH v6 01/12] Add virtio-sound device stub

2023-08-20 Thread Volker Rümelin

Hi Manos,


Add a new VIRTIO device for the virtio sound device id. Functionality
will be added in the following commits.


I think the virtio-snd.c code, the trace events and the Kconfig 
VIRTIO_SND should be moved to hw/audio. The code for nearly all audio 
devices is in this directory. This would be similar to other virtio 
devices. E.g. the virtio-scsi code is in hw/scsi and the virtio-net code 
is in hw/net.


With best regards,
Volker


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 | 231 +
  include/hw/virtio/virtio-snd.h |  80 
  6 files changed, 332 insertions(+)
  create mode 100644 hw/virtio/virtio-snd.c
  create mode 100644 include/hw/virtio/virtio-snd.h







Re: [PATCH v6 02/12] Add virtio-sound-pci device

2023-08-20 Thread Volker Rümelin

Hi Manos,

I see a core dump with this code on my host. I don't use the -audio 
command line argument and the audiodev_id variable is NULL. You can't 
use a global audiodev_id variable because each guest can have more than 
one virtio-sound-pci device and each virtio-sound-pci device may be 
connected to a different audio backend device.


(gdb) r
Starting program: 
/home/ruemelin/rpmbuild/BUILD/qemu-8.0.50-build/qemu-system-x86_64 
-machine q35 -device virtio-sound-pci,audiodev=audio0 -audiodev 
pipewire,out.frequency=48000,in.frequency=48000,id=audio0


Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
0x71987dd1 in __strlen_avx2 () from /lib64/libc.so.6

(gdb) bt
#0  0x71987dd1 in __strlen_avx2 () at /lib64/libc.so.6
#1  0x55e19afd in qstring_from_str (str=0x0) at 
../qemu-master/qobject/qstring.c:50

#2  0x55cb254c in object_property_set_str
    (obj=obj@entry=0x57d3db30, name=name@entry=0x55fea6b9 
"audiodev", value=, errp=0x567b4580 ) at 
../qemu-master/qom/object.c:1427

#3  0x55caa84c in qdev_prop_set_string
    (dev=dev@entry=0x57d3db30, name=name@entry=0x55fea6b9 
"audiodev", value=)

    at ../qemu-master/hw/core/qdev-properties.c:729
#4  0x55c3e8d1 in virtio_snd_pci_realize 
(vpci_dev=0x57d35760, errp=0x7fffd750)

    at ../qemu-master/hw/virtio/virtio-snd-pci.c:48
#5  0x559d0549 in pci_qdev_realize (qdev=, 
errp=) at ../qemu-master/hw/pci/pci.c:2124
#6  0x55cabad3 in device_set_realized (obj=, 
value=, errp=0x7fffd980)

    at ../qemu-master/hw/core/qdev.c:510
#7  0x55caf4f6 in property_set_bool
    (obj=0x57d35760, v=, name=, 
opaque=0x5690f5f0, errp=0x7fffd980)

    at ../qemu-master/qom/object.c:2285
#8  0x55cb2124 in object_property_set
 (obj=obj@entry=0x57d35760, name=name@entry=0x55f9d929 
"realized", v=v@entry=0x57d3fdc0, errp=errp@entry=0x7fffd980) at 
../qemu-master/qom/object.c:1420

#9  0x55cb5370 in object_property_set_qobject
    (obj=obj@entry=0x57d35760, name=name@entry=0x55f9d929 
"realized", value=value@entry=0x57d3ec50, 
errp=errp@entry=0x7fffd980) at ../qemu-master/qom/qom-qobject.c:28

#10 0x55cb2705 in object_property_set_bool
    (obj=obj@entry=0x57d35760, name=name@entry=0x55f9d929 
"realized", value=value@entry=true, errp=errp@entry=0x7fffd980--) at 
../qemu-master/qom/object.c:1489
#11 0x55cac42e in qdev_realize (dev=dev@entry=0x57d35760, 
bus=bus@entry=0x56d96610, errp=errp@entry=0x7fffd980) at 
../qemu-master/hw/core/qdev.c:292
#12 0x55a89917 in qdev_device_add_from_qdict 
(opts=opts@entry=0x57d34740, from_json=from_json@entry=false, 
errp=0x7fffd980, errp@entry=0x567b4578 ) at 
../qemu-master/softmmu/qdev-monitor.c:715
#13 0x55a89a42 in qdev_device_add (opts=0x5690bb80, 
errp=errp@entry=0x567b4578 ) at 
../qemu-master/softmmu/qdev-monitor.c:734
#14 0x55a8e0ef in device_init_func (opaque=, 
opts=, errp=0x567b4578 ) at 
../qemu-master/softmmu/vl.c:1153
#15 0x55e2d6f2 in qemu_opts_foreach (list=, 
func=func@entry=0x55a8e0e0 , 
opaque=opaque@entry=0x0, errp=errp@entry=0x567b4578 ) 
at ../qemu-master/util/qemu-option.c:1135
#16 0x55a9087a in qemu_create_cli_devices () at 
../qemu-master/softmmu/vl.c:2577
#17 qmp_x_exit_preconfig (errp=) at 
../qemu-master/softmmu/vl.c:2645
#18 0x55a9433b in qmp_x_exit_preconfig (errp=) at 
../qemu-master/softmmu/vl.c:2639
#19 qemu_init (argc=, argv=) at 
../qemu-master/softmmu/vl.c:3663
#20 0x55888959 in main (argc=, argv=out>) at ../qemu-master/softmmu/main.c:47



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:

   -device virtio-sound-pci,disable-legacy=on


virtio-legacy should be disabled in the virtio-snd-pci.c code.


And an audio backend listed with `-audio driver=help` that works on
your host machine, e.g.:

Pulseaudio:
   -audio driver=pa,model=virtio-sound
   or
   -audio driver=pa,model=virtio-sound,server=/run/user/1000/pulse/native
sdl:
   -audio driver=sdl,model=virtio-sound
coreaudio (macos/darwin):
   -audio driver=coreaudio,model=virtio-sound
etc.

Signed-off-by: Emmanouil Pitsidianakis
---
  hw/virtio/meson.build  |  1 +
  hw/virtio/virtio-snd-pci.c | 91 ++
  include/hw/pci/pci.h   |  1 +
  softmmu/qdev-monitor.c |  1 +
  4 files changed, 94 insertions(+)
  create mode 100644 hw/virtio/virtio-snd-pci.c

diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 120d4bfa0a..5e5a83a4ee 100644

Re: [PATCH] HDA codec: Fix wanted_r/w position overflow

2023-08-17 Thread Volker Rümelin

Hi,


From: zeroway 

when the duration now - buft_start reach to some kind of value,
which will get the multiply hda_bytes_per_second(st) * (now - buft_start) 
overflow,
instead of calculate the wanted_r/wpos from start time to current time,
here calculate the each timer tick delta data first in wanted_r/wpos_delta,
and sum it all to wanted_r/wpos to avoid the overflow


you could avoid the multiplication overflow with the following code

#include "qemu/host-utils.h"

    int64_t wanted_rpos = muldiv64(now - buft_start, 
hda_bytes_per_second(st),

   NANOSECONDS_PER_SECOND);

and

    int64_t wanted_wpos = muldiv64(now - buft_start, 
hda_bytes_per_second(st),

   NANOSECONDS_PER_SECOND);

This would be a less intrusive change. The wanted_pos with your code 
will grow slower than with the original code because you sum up 
truncated results from the division by NANOSECONDS_PER_SECONDS rounded 
down to next multiple of 4.


With best regards,
Volker



Signed-off-by: zeroway 
---
  hw/audio/hda-codec.c | 24 
  1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index c51d8ba617..747188221a 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -169,6 +169,8 @@ struct HDAAudioStream {
  uint8_t buf[8192]; /* size must be power of two */
  int64_t rpos;
  int64_t wpos;
+int64_t wanted_rpos;
+int64_t wanted_wpos;
  QEMUTimer *buft;
  int64_t buft_start;
  };
@@ -226,16 +228,18 @@ static void hda_audio_input_timer(void *opaque)
  int64_t wpos = st->wpos;
  int64_t rpos = st->rpos;
  
-int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start)

+int64_t wanted_rpos_delta = hda_bytes_per_second(st) * (now - buft_start)
/ NANOSECONDS_PER_SECOND;
-wanted_rpos &= -4; /* IMPORTANT! clip to frames */
+st->wanted_rpos += wanted_rpos_delta;
+st->wanted_rpos &= -4; /* IMPORTANT! clip to frames */
  
-if (wanted_rpos <= rpos) {

+st->buft_start = now;
+if (st->wanted_rpos <= rpos) {
  /* we already transmitted the data */
  goto out_timer;
  }
  
-int64_t to_transfer = MIN(wpos - rpos, wanted_rpos - rpos);

+int64_t to_transfer = MIN(wpos - rpos, st->wanted_rpos - rpos);
  while (to_transfer) {
  uint32_t start = (rpos & B_MASK);
  uint32_t chunk = MIN(B_SIZE - start, to_transfer);
@@ -290,16 +294,18 @@ static void hda_audio_output_timer(void *opaque)
  int64_t wpos = st->wpos;
  int64_t rpos = st->rpos;
  
-int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start)

+int64_t wanted_wpos_delta = hda_bytes_per_second(st) * (now - buft_start)
/ NANOSECONDS_PER_SECOND;
-wanted_wpos &= -4; /* IMPORTANT! clip to frames */
+st->wanted_wpos += wanted_wpos_delta;
+st->wanted_wpos &= -4; /* IMPORTANT! clip to frames */
  
-if (wanted_wpos <= wpos) {

+st->buft_start = now;
+if (st->wanted_wpos <= wpos) {
  /* we already received the data */
  goto out_timer;
  }
  
-int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos);

+int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), st->wanted_wpos - wpos);
  while (to_transfer) {
  uint32_t start = (wpos & B_MASK);
  uint32_t chunk = MIN(B_SIZE - start, to_transfer);
@@ -420,6 +426,8 @@ static void hda_audio_set_running(HDAAudioStream *st, bool 
running)
  int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  st->rpos = 0;
  st->wpos = 0;
+st->wanted_rpos = 0;
+st->wanted_wpos = 0;
  st->buft_start = now;
  timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS);
  } else {





Re: hda codec issue

2023-08-16 Thread Volker Rümelin

Cc: qemu-devel@nongnu.org


cc Volker Rümelin

==

so I was curious about:
1. why using wpos, rpos which will increasing along the time, which 
may overflow in the feature time?


wpos and rpos are 64 bit integers. At a sample rate of 96kHz and with 32 
bit stereo audio frames they overflow after 2^63 bytes / (8 bytes/frame 
* 96000 frames/s) = 1.2E13 s = 380561.23 years. I don't think you will 
notice an overflow.


But you're right anyway. The wanted_rpos and wanted_wpos calculation 
overflows quite early. At a sample rate of 44100kHz and with 16 bit 
stereo samples the multiplication hda_bytes_per_second(st) * (now - 
buft_start) overflows after 2^63 bytes / 176400 bytes/ns = 5,23E13 ns = 
14.58 hours.


I don't think your fix below is correct. There are certainly ways to 
prevent the overflow without resetting the buffer.


2. how to fix the wanted_wpos or wanted_rpos, I current don't 
understand the  wanted_pos mean and how it work to optimize the codec


This is a jitter-buffer implementation to decouple the audio backend 
updates from the hda device updates. The code splits large  >10ms sized 
audio packets into 1ms sized audio packets.


With best regards,
Volker


===

Currently  I got Playback and Capture issue

I test Playing and recoding for a very long time, Playback issue is 
hard to reproduce, Capture issue is easy to reproduce for recording 
about 14 hours


Playback issue current can only be found on qemu 2.11, which I found 
the code below (remove some unnecessary)


wanted_wpos overflow, and is always little then the wpos,(current wpos 
- rpos = 0) so qemu will no long get data from vm, as a result


static void hda_audio_output_timer(void *opaque)
{
.

    int64_t wanted_wpos = hda_bytes_per_second(st) * (now - 
buft_start) > overflow here

                          / NANOSECONDS_PER_SECOND;
    wanted_wpos &= -4; /* IMPORTANT! clip to frames */

    if (wanted_wpos <= wpos) {
        /* we already received the data */
        goto out_timer;
    }
}


Capture issue: Just record all the time
(i using qemu 6.0 to test) I add code below to the input callback 
function like below, the issue dispear

hda_audio_input_cb
    if (wpos - rpos == B_SIZE) {
        /* drop buffer, reset timer adjust */
        st->rpos = 0;
        st->wpos = 0;
        st->buft_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
        error_report("input drop buffer, reset timer adjust\n");
        return;
    }











Re: [PULL 06/19] ui/gtk: set scanout-mode right before scheduling draw

2023-07-24 Thread Volker Rümelin

Am 24.07.23 um 06:47 schrieb Kim, Dongwon:

Hi there,

I guess removing this line would have been causing the problem. Can 
you add this line back and test it?


diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index eee821d73a..98b3a116bf 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -242,7 +242,6 @@ void gd_egl_scanout_texture(DisplayChangeListener 
*dcl,

  eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
 vc->gfx.esurface, vc->gfx.ectx);
  -    gtk_egl_set_scanout_mode(vc, true);
  egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
backing_height,

   backing_id, false);
  }

Thanks!



Adding back this line fixes the black guest screen when running the host 
under X11. For Wayland I had to add back the similar line in 
ui/gtk-gl-area.c.


With best regards,
Volker


On 7/20/2023 11:53 PM, Volker Rümelin wrote:

Am 17.07.23 um 14:45 schrieb marcandre.lur...@redhat.com:

From: Dongwon Kim

Setting scanout mode is better to be done very last minute
right because the mode can be reset anytime after it is set in
dpy_gl_scanout_texture by any asynchronouse dpy_refresh call,
which eventually cancels drawing of the guest scanout texture.


Hi Dongwon,

this patch breaks the QEMU guest display on my system. QEMU was 
started with ./qemu-system-x86_64 -machine q35 -device 
virtio-vga-gl,xres=1280,yres=768 -display gtk,zoom-to-fit=off,gl=on. 
I can see the OVMF boot screen and then GRUB. After Linux was 
started, plymouth normally shows the OVMF boot logo and a rotating 
spinner. With your patch the guest screen stays black and I see a 
text cursor in the upper left corner. It seems the guest works 
without issues. I can use ssh to log in and I can't find any obvious 
errors in the guest log files. I tested on a host GNOME desktop under 
X11 and again under Wayland. In both cases the result is a black 
guest screen.


With best regards,
Volker


Cc: Gerd Hoffmann
Cc: Marc-André Lureau
Cc: Vivek Kasireddy
Signed-off-by: Dongwon Kim
Acked-by: Marc-André Lureau
Message-ID:<20230706183355.29361-1-dongwon@intel.com>
---
  ui/gtk-egl.c | 2 +-
  ui/gtk-gl-area.c | 2 +-
  2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index eee821d73a..98b3a116bf 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -242,7 +242,6 @@ void 
gd_egl_scanout_texture(DisplayChangeListener *dcl,

  eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
 vc->gfx.esurface, vc->gfx.ectx);
  -    gtk_egl_set_scanout_mode(vc, true);
  egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
backing_height,

   backing_id, false);
  }
@@ -353,6 +352,7 @@ void gd_egl_flush(DisplayChangeListener *dcl,
  if (vc->gfx.guest_fb.dmabuf && 
!vc->gfx.guest_fb.dmabuf->draw_submitted) {

  graphic_hw_gl_block(vc->gfx.dcl.con, true);
  vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+    gtk_egl_set_scanout_mode(vc, true);
  gtk_widget_queue_draw_area(area, x, y, w, h);
  return;
  }
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 4513d3d059..28d9e49888 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -264,7 +264,6 @@ void 
gd_gl_area_scanout_texture(DisplayChangeListener *dcl,

  return;
  }
  -    gtk_gl_area_set_scanout_mode(vc, true);
  egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, 
backing_height,

   backing_id, false);
  }
@@ -284,6 +283,7 @@ void 
gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
  if (vc->gfx.guest_fb.dmabuf && 
!vc->gfx.guest_fb.dmabuf->draw_submitted) {

  graphic_hw_gl_block(vc->gfx.dcl.con, true);
  vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+    gtk_gl_area_set_scanout_mode(vc, true);
  }
gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
  }







Re: [PULL 06/19] ui/gtk: set scanout-mode right before scheduling draw

2023-07-21 Thread Volker Rümelin

Am 17.07.23 um 14:45 schrieb marcandre.lur...@redhat.com:

From: Dongwon Kim

Setting scanout mode is better to be done very last minute
right because the mode can be reset anytime after it is set in
dpy_gl_scanout_texture by any asynchronouse dpy_refresh call,
which eventually cancels drawing of the guest scanout texture.


Hi Dongwon,

this patch breaks the QEMU guest display on my system. QEMU was started 
with ./qemu-system-x86_64 -machine q35 -device 
virtio-vga-gl,xres=1280,yres=768 -display gtk,zoom-to-fit=off,gl=on. I 
can see the OVMF boot screen and then GRUB. After Linux was started, 
plymouth normally shows the OVMF boot logo and a rotating spinner. With 
your patch the guest screen stays black and I see a text cursor in the 
upper left corner. It seems the guest works without issues. I can use 
ssh to log in and I can't find any obvious errors in the guest log 
files. I tested on a host GNOME desktop under X11 and again under 
Wayland. In both cases the result is a black guest screen.


With best regards,
Volker


Cc: Gerd Hoffmann
Cc: Marc-André Lureau
Cc: Vivek Kasireddy
Signed-off-by: Dongwon Kim
Acked-by: Marc-André Lureau
Message-ID:<20230706183355.29361-1-dongwon@intel.com>
---
  ui/gtk-egl.c | 2 +-
  ui/gtk-gl-area.c | 2 +-
  2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index eee821d73a..98b3a116bf 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -242,7 +242,6 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
  eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
 vc->gfx.esurface, vc->gfx.ectx);
  
-gtk_egl_set_scanout_mode(vc, true);

  egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
   backing_id, false);
  }
@@ -353,6 +352,7 @@ void gd_egl_flush(DisplayChangeListener *dcl,
  if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
  graphic_hw_gl_block(vc->gfx.dcl.con, true);
  vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+gtk_egl_set_scanout_mode(vc, true);
  gtk_widget_queue_draw_area(area, x, y, w, h);
  return;
  }
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 4513d3d059..28d9e49888 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -264,7 +264,6 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
  return;
  }
  
-gtk_gl_area_set_scanout_mode(vc, true);

  egl_fb_setup_for_tex(>gfx.guest_fb, backing_width, backing_height,
   backing_id, false);
  }
@@ -284,6 +283,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
  if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
  graphic_hw_gl_block(vc->gfx.dcl.con, true);
  vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+gtk_gl_area_set_scanout_mode(vc, true);
  }
  gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
  }





Re: [PATCH 08/21] asc: generate silence if FIFO empty but engine still running

2023-07-07 Thread Volker Rümelin

MacOS (un)helpfully leaves the FIFO engine running even when all the samples 
have
been written to the hardware, and expects the FIFO status flags and IRQ to be
updated continuously.

Since not all audio backends guarantee an all-zero output when no data is
provided, explicitly generate at least one full output buffer of all-zero output
when the FIFO is disabled and continuously if the FIFO is empty. Otherwise some
audio backends such as Windows re-use their internal buffers causing the last
played sound to loop indefinitely.

Signed-off-by: Mark Cave-Ayland 
---
  hw/audio/asc.c | 43 --
  include/hw/audio/asc.h |  1 +
  2 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index ebcb8a97a6..f9bfae5168 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -148,6 +148,20 @@ static uint8_t asc_fifo_get(ASCFIFOState *fs)
  return val;
  }


Hi Mark,

I don't understand why the flush_zero_samples variable is necessary at all.

  
+static int generate_silence(ASCState *s, int maxsamples)

+{
+uint8_t *buf = s->mixbuf;
+
+if (s->flush_zero_samples) {
+memset(buf, 0x80, maxsamples << s->shift);
+s->flush_zero_samples -= MIN(maxsamples, s->flush_zero_samples);
+
+return maxsamples;
+}
+
+return 0;
+}
+
  static int generate_fifo(ASCState *s, int maxsamples)
  {
  uint8_t *buf = s->mixbuf;
@@ -156,18 +170,26 @@ static int generate_fifo(ASCState *s, int maxsamples)
  limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
  
  /*

- * If starting a new run with no FIFO data present, update the IRQ and
- * continue
+ * MacOS (un)helpfully leaves the FIFO engine running even when it has
+ * finished writing out samples. Since not all audio backends guarantee an
+ * all-zero output when no data is provided, zero out the sample buffer
+ * and then update the FIFO flags and IRQ as normal and continue
   */
-if (limit == 0 && s->fifos[0].int_status == 0 &&
-s->fifos[1].int_status == 0) {
-s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL |
-  ASC_FIFO_STATUS_FULL_EMPTY;
-s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
-  ASC_FIFO_STATUS_FULL_EMPTY;
+if (limit == 0) {
+if (s->fifos[0].int_status == 0 && s->fifos[1].int_status == 0) {
+s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL |
+  ASC_FIFO_STATUS_FULL_EMPTY;
+s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
+  ASC_FIFO_STATUS_FULL_EMPTY;
+}
+
+if (s->flush_zero_samples == 0) {
+s->flush_zero_samples = s->samples;
+}


At this point s->flush_zero_samples is != 0 and generate_silence() 
always generates maxsamples silent audio frames.


  
+generate_silence(s, maxsamples);

  asc_raise_irq(s);
-return 0;
+return maxsamples;
  }
  
  while (count < limit) {

@@ -309,7 +331,7 @@ static void asc_out_cb(void *opaque, int free_b)
  switch (s->regs[ASC_MODE] & 3) {
  default:
  /* Off */


This code will not be called for s->regs[ASC_MODE] & 3 == 0 because in 
asc_write() AUD_set_active_out(s->voice, 0) was called before.


For s->regs[ASC_MODE] & 3 == 3 the code in asc_write() clears 
s->flush_zero_samples and generate_silence() always returns 0. The audio 
subsystem is running and expects new audio frames here.


With best regards,
Volker


-samples = 0;
+samples = generate_silence(s, samples);
  break;
  case 1:
  /* FIFO mode */
@@ -437,6 +459,7 @@ static void asc_write(void *opaque, hwaddr addr, uint64_t 
value,
  asc_lower_irq(s);
  if (value != 0) {
  AUD_set_active_out(s->voice, 1);
+s->flush_zero_samples = 0;
  } else {
  AUD_set_active_out(s->voice, 0);
  }
diff --git a/include/hw/audio/asc.h b/include/hw/audio/asc.h
index 41c6cba8fa..918f6ac582 100644
--- a/include/hw/audio/asc.h
+++ b/include/hw/audio/asc.h
@@ -65,6 +65,7 @@ struct ASCState {
  uint8_t *mixbuf;
  int samples;
  int shift;
+uint32_t flush_zero_samples;
  
  qemu_irq irq;
  





Re: [PATCH 07/21] audio: add Apple Sound Chip (ASC) emulation

2023-07-06 Thread Volker Rümelin

The Apple Sound Chip was primarily used by the Macintosh II to generate sound
in hardware which was previously handled by the toolbox ROM with software
interrupts.

Implement both the standard ASC and also the enhanced ASC (EASC) functionality
which is used in the Quadra 800.

Note that whilst real ASC hardware uses AUDIO_FORMAT_S8, this implementation 
uses
AUDIO_FORMAT_U8 instead because AUDIO_FORMAT_S8 is rarely used and not supported
by some audio backends like PulseAudio and DirectSound when played directly with
-audiodev out.mixing-engine=off.

Co-developed-by: Laurent Vivier 
Co-developed-by: Volker Rümelin 
Signed-off-by: Mark Cave-Ayland 
---
  MAINTAINERS|   2 +
  hw/audio/Kconfig   |   3 +
  hw/audio/asc.c | 685 +
  hw/audio/meson.build   |   1 +
  hw/audio/trace-events  |  10 +
  hw/m68k/Kconfig|   1 +
  include/hw/audio/asc.h |  79 +
  7 files changed, 781 insertions(+)
  create mode 100644 hw/audio/asc.c
  create mode 100644 include/hw/audio/asc.h


Reviewed-by: Volker Rümelin 


diff --git a/MAINTAINERS b/MAINTAINERS
index 88db6540ae..5ab23de2a6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1233,6 +1233,7 @@ F: hw/display/macfb.c
  F: hw/block/swim.c
  F: hw/misc/djmemc.c
  F: hw/misc/iosb.c
+F: hw/audio/asc.c
  F: hw/m68k/bootinfo.h
  F: include/standard-headers/asm-m68k/bootinfo.h
  F: include/standard-headers/asm-m68k/bootinfo-mac.h
@@ -1244,6 +1245,7 @@ F: include/hw/m68k/q800.h
  F: include/hw/m68k/q800-glue.h
  F: include/hw/misc/djmemc.h
  F: include/hw/misc/iosb.h
+F: include/hw/audio/asc.h
  
  virt

  M: Laurent Vivier 
diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig
index e76c69ca7e..d0993514a1 100644
--- a/hw/audio/Kconfig
+++ b/hw/audio/Kconfig
@@ -47,3 +47,6 @@ config PL041
  
  config CS4231

  bool
+
+config ASC
+bool
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
new file mode 100644
index 00..ebcb8a97a6
--- /dev/null
+++ b/hw/audio/asc.c
@@ -0,0 +1,685 @@
+/*
+ * QEMU Apple Sound Chip emulation
+ *
+ * Apple Sound Chip (ASC) 344S0063
+ * Enhanced Apple Sound Chip (EASC) 343S1063
+ *
+ * Copyright (c) 2012-2018 Laurent Vivier 
+ * Copyright (c) 2022 Mark Cave-Ayland 
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "audio/audio.h"
+#include "hw/audio/asc.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+/*
+ * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c
+ * and arch/m68k/include/asm/mac_asc.h
+ *
+ * best information is coming from MAME:
+ *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h
+ *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp
+ *   Emulation by R. Belmont
+ * or MESS:
+ *   http://mess.redump.net/mess/driver_info/easc
+ *
+ * 0x800: VERSION
+ * 0x801: MODE
+ *1=FIFO mode,
+ *2=wavetable mode
+ * 0x802: CONTROL
+ *bit 0=analog or PWM output,
+ *1=stereo/mono,
+ *7=processing time exceeded
+ * 0x803: FIFO MODE
+ *bit 7=clear FIFO,
+ *bit 1="non-ROM companding",
+ *bit 0="ROM companding")
+ * 0x804: FIFO IRQ STATUS
+ *bit 0=ch A 1/2 full,
+ *1=ch A full,
+ *2=ch B 1/2 full,
+ *3=ch B full)
+ * 0x805: WAVETABLE CONTROL
+ *bits 0-3 wavetables 0-3 start
+ * 0x806: VOLUME
+ *bits 2-4 = 3 bit internal ASC volume,
+ *bits 5-7 = volume control sent to Sony sound chip
+ * 0x807: CLOCK RATE
+ *0 = Mac 22257 Hz,
+ *1 = undefined,
+ *2 = 22050 Hz,
+ *3 = 44100 Hz
+ * 0x80a: PLAY REC A
+ * 0x80f: TEST
+ *bits 6-7 = digital test,
+ *bits 4-5 = analog test
+ * 0x810: WAVETABLE 0 PHASE
+ *big-endian 9.15 fixed-point, only 24 bits valid
+ * 0x814: WAVETABLE 0 INCREMENT
+ *big-endian 9.15 fixed-point, only 24 bits valid
+ * 0x818: WAVETABLE 1 PHASE
+ * 0x81C: WAVETABLE 1 INCREMENT
+ * 0x820: WAVETABLE 2 PHASE
+ * 0x824: WAVETABLE 2 INCREMENT
+ * 0x828: WAVETABLE 3 PHASE
+ * 0x82C: WAVETABLE 3 INCREMENT
+ * 0x830: UNKNOWN START
+ *NetBSD writes Wavetable data here (are there more
+ *wavetables/channels than we know about?)
+ * 0x857: UNKNOWN END
+ */
+
+#define ASC_SIZE   0x2000
+
+enum {
+ASC_VERSION = 0x00,
+ASC_MODE= 0x01,
+ASC_CONTROL = 0x02,
+ASC_FIFOMODE= 0x03,
+ASC_FIFOIRQ = 0x04,
+ASC_WAVECTRL= 0x05,
+ASC_VOLUME  = 0x06,
+ASC_CLOCK   = 0x07,
+ASC_PLAYRECA= 0x0a,
+ASC_TEST= 0x0f,
+ASC_WAVETABL

Re: [PATCH 14/30] audio: add Apple Sound Chip (ASC) emulation

2023-05-29 Thread Volker Rümelin

The Apple Sound Chip was primarily used by the Macintosh II to generate sound
in hardware which was previously handled by the toolbox ROM with software
interrupts.

Implement both the standard ASC and also the enhanced ASC (EASC) functionality
which is used in the Quadra 800.

Note that whilst real ASC hardware uses AUDIO_FORMAT_S8, this implementation 
uses
AUDIO_FORMAT_U8 instead because AUDIO_FORMAT_S8 is rarely used and not supported
by some audio backends like PulseAudio and DirectSound when played directly with
-audiodev out.mixing-engine=off.

Co-developed-by: Laurent Vivier 
Co-developed-by: Volker Rümelin 
Signed-off-by: Mark Cave-Ayland 
---
  MAINTAINERS|   2 +
  hw/audio/Kconfig   |   3 +
  hw/audio/asc.c | 688 +
  hw/audio/meson.build   |   1 +
  hw/audio/trace-events  |  10 +
  hw/m68k/Kconfig|   1 +
  include/hw/audio/asc.h |  75 +
  7 files changed, 780 insertions(+)
  create mode 100644 hw/audio/asc.c
  create mode 100644 include/hw/audio/asc.h


Reviewed-by: Volker Rümelin 


diff --git a/MAINTAINERS b/MAINTAINERS
index f151aaf99f..1b79ab7965 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1229,6 +1229,7 @@ F: hw/display/macfb.c
  F: hw/block/swim.c
  F: hw/misc/djmemc.c
  F: hw/misc/iosb.c
+F: hw/audio/asc.c
  F: hw/m68k/bootinfo.h
  F: include/standard-headers/asm-m68k/bootinfo.h
  F: include/standard-headers/asm-m68k/bootinfo-mac.h
@@ -1239,6 +1240,7 @@ F: include/hw/block/swim.h
  F: include/hw/m68k/q800.h
  F: include/hw/misc/djmemc.c
  F: include/hw/misc/iosb.c
+F: include/hw/audio/asc.h
  
  virt

  M: Laurent Vivier 
diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig
index e76c69ca7e..d0993514a1 100644
--- a/hw/audio/Kconfig
+++ b/hw/audio/Kconfig
@@ -47,3 +47,6 @@ config PL041
  
  config CS4231

  bool
+
+config ASC
+bool
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
new file mode 100644
index 00..04194b1e43
--- /dev/null
+++ b/hw/audio/asc.c
@@ -0,0 +1,688 @@
+/*
+ *  QEMU Apple Sound Chip emulation
+ *
+ *  Apple Sound Chip (ASC) 344S0063
+ *  Enhanced Apple Sound Chip (EASC) 343S1063
+ *
+ *  Copyright (c) 2012-2018 Laurent Vivier 
+ *  Copyright (c) 2022 Mark Cave-Ayland 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "audio/audio.h"
+#include "hw/audio/asc.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+/*
+ * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c
+ * and arch/m68k/include/asm/mac_asc.h
+ *
+ * best information is coming from MAME:
+ *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h
+ *   https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp
+ *   Emulation by R. Belmont
+ * or MESS:
+ *   http://mess.redump.net/mess/driver_info/easc
+ *
+ * 0x800: VERSION
+ * 0x801: MODE
+ *1=FIFO mode,
+ *2=wavetable mode
+ * 0x802: CONTROL
+ *bit 0=analog or PWM output,
+ *1=stereo/mono,
+ *7=processing time exceeded
+ * 0x803: FIFO MODE
+ *bit 7=clear FIFO,
+ *bit 1="non-ROM companding",
+ *bit 0="ROM companding")
+ * 0x804: FIFO IRQ STATUS
+ *bit 0=ch A 1/2 full,
+ *1=ch A full,
+ *2=ch B 1/2 full,
+ *3=ch B full)
+ * 0x805: WAVETABLE CONTROL
+ *bits 0-3 wavetables 0-3 start
+ * 0x806: VOLUME
+ *bits 2-4 = 3 bit internal ASC volume,
+ *bits 5-7 = volume control sent to Sony sound chip
+ * 0x807: CLOCK RATE
+ *0 = Mac 22257 Hz,
+ *1 = undefined,
+ *2 = 22050 Hz,
+ *3 = 44100 Hz
+ * 0x80a: PLAY REC A
+ * 0x80f: TEST
+ *bits 6-7 = digital test,
+ *bits 4-5 = analog test
+ * 0x810: WAVETABLE 0 PHASE
+ *big-endian 9.15 fixed-point, only 24 bits valid
+ * 0x814: WAVETABLE 0 INCREMENT
+ *big-endian 9.15 fixed-point, only 24 bits valid
+ * 0x818: WAVETABLE 1 PHASE
+ * 0x81C: WAVETABLE 1 INCREMENT
+ * 0x820: WAVETABLE 2 PHASE
+ * 0x824: WAVETABLE 2 INCREMENT
+ * 0x828: WAVETABLE 3 PHASE
+ * 0x82C: WAVETABLE 3 INCREMENT
+ * 0x830: UNKNOWN START
+ *NetBSD writes Wavetable data here (are there more
+ *wavetables/channels than we know about?)
+ * 0x857: UNKNOWN END
+ */
+
+#define ASC_SIZE   0x2000
+
+enum {
+ASC_VERSION = 0x00,
+ASC_MODE= 0x01,
+ASC_CONTROL = 0x02,
+ASC_FIFOMODE= 0x03,
+ASC_FIFOIRQ = 0x04,
+ASC_WAVECTRL= 0x05,
+ASC_VOLUME  = 0x06,
+ASC_CLOCK

Re: [PATCH 15/30] asc: generate silence if FIFO empty but engine still running

2023-05-29 Thread Volker Rümelin

MacOS (un)helpfully leaves the FIFO engine running even when all the samples 
have
been written to the hardware, and expects the FIFO status flags and IRQ to be
updated continuously.

Since not all audio backends guarantee an all-zero output when no data is
provided, explicitly generate an all-zero output when this condition occurs to
avoid the audio backends re-using their internal buffers and looping audio once
the FIFOs are empty.

Signed-off-by: Mark Cave-Ayland 
---
  hw/audio/asc.c | 9 ++---
  1 file changed, 6 insertions(+), 3 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 04194b1e43..c5173a8d35 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -158,8 +158,10 @@ static int generate_fifo(ASCState *s, int maxsamples)
  limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
  
  /*

- * If starting a new run with no FIFO data present, update the IRQ and
- * continue
+ * MacOS (un)helpfully leaves the FIFO engine running even when it has
+ * finished writing out samples. Since not all audio backends guarantee an
+ * all-zero output when no data is provided, zero out the sample buffer
+ * and then update the FIFO flags and IRQ as normal and continue
   */
  if (limit == 0 && s->fifos[0].int_status == 0 &&
  s->fifos[1].int_status == 0) {
@@ -168,8 +170,9 @@ static int generate_fifo(ASCState *s, int maxsamples)
  s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
ASC_FIFO_STATUS_FULL_EMPTY;
  
+memset(buf, 0x80, maxsamples << s->shift);

  asc_raise_irq(s);
-return 0;
+return maxsamples;
  }
  
  while (count < limit) {





Re: [PATCH v2] meson: move -no-pie from linker to compiler

2023-05-24 Thread Volker Rümelin

Am 23.05.23 um 09:30 schrieb Paolo Bonzini:

The large comment in the patch says it all; the -no-pie flag is broken and
this is why it was not included in QEMU_LDFLAGS before commit a988b4c5614
("build: move remaining compiler flag tests to meson", 2023-05-18).  And
some distros made things even worse, so we have to add it to the compiler
command line.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1664
Signed-off-by: Paolo Bonzini 
---
  meson.build | 19 ++-
  1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/meson.build b/meson.build
index 0a5cdefd4d3d..20accae99281 100644
--- a/meson.build
+++ b/meson.build
@@ -265,12 +265,21 @@ endif
  
  # Meson currently only handles pie as a boolean for now, so if the user

  # has explicitly disabled PIE we need to extend our cflags.
+#
+# -no-pie is supposedly a linker flag that has no effect on the compiler
+# command line, but some distros, that didn't quite know what they were
+# doing, made local changes to gcc's specs file that turned it into
+# a compiler command-line flag.
+#
+# What about linker flags?  For a static build, no PIE is implied by -static
+# which we added above (and if it's not because of the same specs patching,
+# there's nothing we can do: compilation will fail, report a bug to your
+# distro and do not use --disable-pie in the meanwhile).  For dynamic linking,
+# instead, we can't add -no-pie because it overrides -shared: the linker then
+# tries to build an executable instead of a shared library and fails.  So
+# don't add -no-pie anywhere and cross fingers. :(
  if not get_option('b_pie')
-  qemu_common_flags += cc.get_supported_arguments('-fno-pie')
-  if not get_option('prefer_static')
-# No PIE is implied by -static which we added above.
-qemu_ldflags += cc.get_supported_link_arguments('-no-pie')
-  endif
+  qemu_common_flags += cc.get_supported_arguments('-fno-pie', '-no-pie')
  endif
  
  if not get_option('stack_protector').disabled()


I tested that QEMU builds on Windows with MSYS2 mingw64.

One unrelated note: The DLL loader doesn't find the libslirp-0.dll when 
QEMU was built with libslirp from the subprojects folder and started 
from the build folder. It's necessary to copy this library to a folder 
in the DLL search path.


Tested-by: Volker Rümelin 



Re: [PATCH] meson: remove -no-pie linker flag

2023-05-22 Thread Volker Rümelin

Am 22.05.23 um 10:08 schrieb Paolo Bonzini:

The large comment in the patch says it all; the -no-pie flag is broken and
this is why it was not included in QEMU_LDFLAGS before commit a988b4c5614
("build: move remaining compiler flag tests to meson", 2023-05-18).

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1664
Signed-off-by: Paolo Bonzini 
---
  meson.build | 13 +
  1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/meson.build b/meson.build
index 0a5cdefd4d3d..6733b2917081 100644
--- a/meson.build
+++ b/meson.build
@@ -267,10 +267,15 @@ endif
  # has explicitly disabled PIE we need to extend our cflags.
  if not get_option('b_pie')
qemu_common_flags += cc.get_supported_arguments('-fno-pie')
-  if not get_option('prefer_static')
-# No PIE is implied by -static which we added above.
-qemu_ldflags += cc.get_supported_link_arguments('-no-pie')
-  endif
+  # What about linker flags?  For a static build, no PIE is implied by -static
+  # which we added above.  For dynamic linking, adding -no-pie is messy because
+  # it overrides -shared: the linker then wants to build an executable instead
+  # of a shared library and the build fails.  Before moving this code to Meson,
+  # we went through a dozen different commits affecting the usage of -no-pie,
+  # ultimately settling for a completely broken one that added -no-pie to the
+  # compiler flags together with -fno-pie... except that -no-pie is a linker
+  # flag that has no effect on the compiler command line.  So, don't add
+  # -no-pie anywhere and cross fingers.
  endif
  
  if not get_option('stack_protector').disabled()


QEMU builds again on Windows with MSYS2 mingw64.

I also tried to build QEMU on Windows with libslirp from the subproject 
folder. The issue reported in 
https://gitlab.com/qemu-project/qemu/-/issues/1664 is fixed, but it now 
fails with a different error. This is a libslirp bug. See 
https://gitlab.freedesktop.org/slirp/libslirp/-/issues/68. The revision 
in subprojects/slirp.wrap should be at least 
fc5eaaf6f68d5cff76468c63984c33c4fb51506d.


Building QEMU on my Linux system works fine.

Tested-by: Volker Rümelin 



[PATCH v2] tests/qtest/ac97-test: add up-/downsampling tests

2023-05-20 Thread Volker Rümelin
Test if the audio subsystem can handle extreme up- and down-
sampling ratios like 44100/1 and 1/44100. For some time these
used to trigger QEMU aborts. The test was taken from
https://gitlab.com/qemu-project/qemu/-/issues/71 where it was
used to demonstrate a very different issue.

Suggested-by: Marc-André Lureau 
Signed-off-by: Volker Rümelin 
---
v2:
Cosmetic changes to the comments. The promised improved commit
message appeared in commit b9ae74e2e4 ("audio: log unimplemented
audio device sample rates").

 tests/qtest/ac97-test.c | 40 +++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/ac97-test.c b/tests/qtest/ac97-test.c
index 74103efdfa..b71bd60a8a 100644
--- a/tests/qtest/ac97-test.c
+++ b/tests/qtest/ac97-test.c
@@ -42,16 +42,54 @@ static void *ac97_create(void *pci_bus, QGuestAllocator 
*alloc, void *addr)
 return >obj;
 }
 
+/*
+ * This is rather a test of the audio subsystem and not an AC97 test. Test if
+ * the audio subsystem can handle a 44100/1 upsample ratio. For some time this
+ * used to trigger QEMU aborts.
+ */
+static void ac97_playback_upsample(void *obj, void *data, QGuestAllocator 
*alloc)
+{
+QAC97 *ac97 = obj;
+QPCIDevice *dev = >dev;
+QPCIBar bar0;
+
+qpci_device_enable(dev);
+bar0 = qpci_iomap(dev, 0, NULL);
+/* IOBAR0 offset 0x2c: PCM Front DAC Rate */
+qpci_io_writew(dev, bar0, 0x2c, 0x1);
+}
+
+/*
+ * This test is similar to the playback upsample test. QEMU shouldn't abort if
+ * asked for a 1/44100 downsample ratio.
+ */
+static void ac97_record_downsample(void *obj, void *data, QGuestAllocator 
*alloc)
+{
+QAC97 *ac97 = obj;
+QPCIDevice *dev = >dev;
+QPCIBar bar0;
+
+qpci_device_enable(dev);
+bar0 = qpci_iomap(dev, 0, NULL);
+/* IOBAR0 offset 0x32: PCM L/R ADC Rate */
+qpci_io_writew(dev, bar0, 0x32, 0x1);
+}
+
 static void ac97_register_nodes(void)
 {
 QOSGraphEdgeOptions opts = {
-.extra_device_opts = "addr=04.0",
+.extra_device_opts = "addr=04.0,audiodev=snd0",
+.after_cmd_line = "-audiodev none,id=snd0"
+  ",out.frequency=44100,in.frequency=44100",
 };
 add_qpci_address(, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
 qos_node_create_driver("AC97", ac97_create);
 qos_node_produces("AC97", "pci-device");
 qos_node_consumes("AC97", "pci-bus", );
+
+qos_add_test("playback_upsample", "AC97", ac97_playback_upsample, NULL);
+qos_add_test("record_downsample", "AC97", ac97_record_downsample, NULL);
 }
 
 libqos_init(ac97_register_nodes);
-- 
2.35.3




Re: [PATCH 10/12] audio/pw: simplify error reporting in stream creation

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau

create_stream() now reports on all error paths.

Signed-off-by: Marc-André Lureau
---
  audio/pwaudio.c | 12 +---
  1 file changed, 1 insertion(+), 11 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 5c706a9fde..38905f5be2 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -486,8 +486,6 @@ static int
  qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
 const char *name, enum spa_direction dir)
  {
-int r;
-
  switch (v->info.channels) {
  case 8:
  v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
@@ -540,13 +538,7 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char 
*stream_name,
  }
  
  /* create a new unconnected pwstream */

-r = create_stream(c, v, stream_name, name, dir);
-if (r < 0) {
-AUD_log(AUDIO_CAP, "Failed to create stream.");
-return -1;
-}
-
-return r;
+return create_stream(c, v, stream_name, name, dir);
  }
  
  static int

@@ -577,7 +569,6 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void 
*drv_opaque)
  r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
 ppdo->name, SPA_DIRECTION_OUTPUT);
  if (r < 0) {
-error_report("qpw_stream_new for playback failed");
  pw_thread_loop_unlock(c->thread_loop);
  return -1;
  }
@@ -621,7 +612,6 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void 
*drv_opaque)
  r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
 ppdo->name, SPA_DIRECTION_INPUT);
  if (r < 0) {
-error_report("qpw_stream_new for recording failed");
  pw_thread_loop_unlock(c->thread_loop);
  return -1;
  }





Re: [PATCH 09/12] audio/pw: add more error reporting

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau

Signed-off-by: Marc-André Lureau
---
  audio/pwaudio.c | 7 ++-
  1 file changed, 6 insertions(+), 1 deletion(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 67df53948c..5c706a9fde 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -429,6 +429,10 @@ create_stream(pwaudio *c, PWVoice *v, const char 
*stream_name,
  struct pw_properties *props;
  
  props = pw_properties_new(NULL, NULL);

+if (!props) {
+error_report("Failed to create PW properties: %s", g_strerror(errno));
+return -1;
+}
  
  /* 75% of the timer period for faster updates */

  buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
@@ -441,8 +445,8 @@ create_stream(pwaudio *c, PWVoice *v, const char 
*stream_name,
  pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
  }
  v->stream = pw_stream_new(c->core, stream_name, props);
-
  if (v->stream == NULL) {
+error_report("Failed to create PW stream: %s", g_strerror(errno));
  return -1;
  }
  
@@ -470,6 +474,7 @@ create_stream(pwaudio *c, PWVoice *v, const char *stream_name,

  PW_STREAM_FLAG_MAP_BUFFERS |
  PW_STREAM_FLAG_RT_PROCESS, params, n_params);
  if (res < 0) {
+error_report("Failed to connect PW stream: %s", g_strerror(errno));
  pw_stream_destroy(v->stream);
  return -1;
  }





Re: [PATCH 07/12] audio/pw: add more details on error

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau

PipeWire uses errno to report error details.

Signed-off-by: Marc-André Lureau
---
  audio/pwaudio.c | 7 ---
  1 file changed, 4 insertions(+), 3 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 2b12b40934..d0bc4680a6 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -750,6 +750,7 @@ static int wait_resync(pwaudio *pw)
  }
  return 0;
  }
+
  static void
  on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
  {
@@ -793,19 +794,19 @@ qpw_audio_init(Audiodev *dev)
  pw->dev = dev;
  pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
  if (pw->thread_loop == NULL) {
-error_report("Could not create PipeWire loop");
+error_report("Could not create PipeWire loop: %s", g_strerror(errno));
  goto fail;
  }
  
  pw->context =

  pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
  if (pw->context == NULL) {
-error_report("Could not create PipeWire context");
+error_report("Could not create PipeWire context: %s", 
g_strerror(errno));
  goto fail;
  }
  
  if (pw_thread_loop_start(pw->thread_loop) < 0) {

-error_report("Could not start PipeWire loop");
+error_report("Could not start PipeWire loop: %s", g_strerror(errno));
  goto fail;
  }
  





Re: [PATCH 12/12] audio/pw: improve channel position code

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

Follow PulseAudio backend comment and code, and only implement the
channels QEMU actually supports at this point, and add the same comment
about limits and future mappings. Simplify a bit the code.

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 75 +
  1 file changed, 26 insertions(+), 49 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index f74d506ec6..062610a704 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -417,8 +417,8 @@ pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
  }
  
  static int

-create_stream(pwaudio *c, PWVoice *v, const char *stream_name,
-  const char *name, enum spa_direction dir)
+qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
+   const char *name, enum spa_direction dir)
  {
  int res;
  uint32_t n_params;
@@ -482,62 +482,37 @@ create_stream(pwaudio *c, PWVoice *v, const char 
*stream_name,
  return 0;
  }
  
-static int

-qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
-   const char *name, enum spa_direction dir)
+static void
+qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
  {
-switch (v->info.channels) {
+memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { 
SPA_AUDIO_CHANNEL_UNKNOWN, },
+   sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
+/*
+ * TODO: This currently expects the only frontend supporting more than 2
+ * channels is the usb-audio.  We will need some means to set channel
+ * order when a new frontend gains multi-channel support.
+ */
+switch (channels) {
  case 8:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
-v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
-v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
-v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
-v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
-v->info.position[6] = SPA_AUDIO_CHANNEL_SL;
-v->info.position[7] = SPA_AUDIO_CHANNEL_SR;
-break;
+position[6] = SPA_AUDIO_CHANNEL_SL;
+position[7] = SPA_AUDIO_CHANNEL_SR;
+/* fallthrough */
  case 6:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
-v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
-v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
-v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
-v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
-break;
-case 5:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
-v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
-v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
-v->info.position[4] = SPA_AUDIO_CHANNEL_RC;
-break;
-case 4:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
-v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
-v->info.position[3] = SPA_AUDIO_CHANNEL_RC;
-break;
-case 3:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
-v->info.position[2] = SPA_AUDIO_CHANNEL_LFE;
-break;
+position[2] = SPA_AUDIO_CHANNEL_FC;
+position[3] = SPA_AUDIO_CHANNEL_LFE;
+position[4] = SPA_AUDIO_CHANNEL_RL;
+position[5] = SPA_AUDIO_CHANNEL_RR;
+/* fallthrough */
  case 2:
-v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
-v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
+position[0] = SPA_AUDIO_CHANNEL_FL;
+position[1] = SPA_AUDIO_CHANNEL_FR;
  break;
  case 1:
-v->info.position[0] = SPA_AUDIO_CHANNEL_MONO;
+position[0] = SPA_AUDIO_CHANNEL_MONO;
  break;
  default:
-for (size_t i = 0; i < v->info.channels; i++) {
-v->info.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
-}
-break;
+dolog("Internal error: unsupported channel count %d\n", channels);
  }
-
-return create_stream(c, v, stream_name, name, dir);
  }
  
  static int

@@ -555,6 +530,7 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void 
*drv_opaque)
  
  v->info.format = audfmt_to_pw(as->fmt, as->endianness);

  v->info.channels = as->nchannels;
+qpw_set_position(as->nchannels, v->info.position);
  v->info.rate = as->freq;
  
  obt_as.fmt =

@@ -601,6 +577,7 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void 
*drv_opaque)
  
  v->info.format = audfmt_to_pw(as->fmt, as->endianness);

  v->info.channels = as->nchannels;
+qpw_set_position(as->nchannels, v->info.position);
  v->info.rate = as->freq;
  
  obt_as.fmt =





Re: [PATCH 11/12] audio/pw: remove wrong comment

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

The stream is actually created connected.

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 1 -
  1 file changed, 1 deletion(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 38905f5be2..f74d506ec6 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -537,7 +537,6 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char 
*stream_name,
  break;
  }
  
-/* create a new unconnected pwstream */

  return create_stream(c, v, stream_name, name, dir);
  }
  





Re: [PATCH 08/12] audio/pw: factorize some common code

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 85 -
  1 file changed, 34 insertions(+), 51 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index d0bc4680a6..67df53948c 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -66,6 +66,9 @@ typedef struct PWVoiceIn {
  PWVoice v;
  } PWVoiceIn;
  
+#define PW_VOICE_IN(v) ((PWVoiceIn*)v)

+#define PW_VOICE_OUT(v) ((PWVoiceOut*)v)
+
  static void
  stream_destroy(void *data)
  {
@@ -630,62 +633,55 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void 
*drv_opaque)
  }
  
  static void

-qpw_fini_out(HWVoiceOut *hw)
+qpw_voice_fini(PWVoice *v)
  {
-PWVoiceOut *pw = (PWVoiceOut *) hw;
-PWVoice *v = >v;
+pwaudio *c = v->g;
  
-if (v->stream) {

-pwaudio *c = v->g;
-pw_thread_loop_lock(c->thread_loop);
-pw_stream_destroy(v->stream);
-v->stream = NULL;
-pw_thread_loop_unlock(c->thread_loop);
+if (!v->stream) {
+return;
  }
+pw_thread_loop_lock(c->thread_loop);
+pw_stream_destroy(v->stream);
+v->stream = NULL;
+pw_thread_loop_unlock(c->thread_loop);
  }
  
  static void

-qpw_fini_in(HWVoiceIn *hw)
+qpw_fini_out(HWVoiceOut *hw)
  {
-PWVoiceIn *pw = (PWVoiceIn *) hw;
-PWVoice *v = >v;
+qpw_voice_fini(_VOICE_OUT(hw)->v);
+}
  
-if (v->stream) {

-pwaudio *c = v->g;
-pw_thread_loop_lock(c->thread_loop);
-pw_stream_destroy(v->stream);
-v->stream = NULL;
-pw_thread_loop_unlock(c->thread_loop);
-}
+static void
+qpw_fini_in(HWVoiceIn *hw)
+{
+qpw_voice_fini(_VOICE_IN(hw)->v);
  }
  
  static void

-qpw_enable_out(HWVoiceOut *hw, bool enable)
+qpw_voice_set_enabled(PWVoice *v, bool enable)
  {
-PWVoiceOut *po = (PWVoiceOut *) hw;
-PWVoice *v = >v;
  pwaudio *c = v->g;
  pw_thread_loop_lock(c->thread_loop);
  pw_stream_set_active(v->stream, enable);
  pw_thread_loop_unlock(c->thread_loop);
  }
  
+static void

+qpw_enable_out(HWVoiceOut *hw, bool enable)
+{
+qpw_voice_set_enabled(_VOICE_OUT(hw)->v, enable);
+}
+
  static void
  qpw_enable_in(HWVoiceIn *hw, bool enable)
  {
-PWVoiceIn *pi = (PWVoiceIn *) hw;
-PWVoice *v = >v;
-pwaudio *c = v->g;
-pw_thread_loop_lock(c->thread_loop);
-pw_stream_set_active(v->stream, enable);
-pw_thread_loop_unlock(c->thread_loop);
+qpw_voice_set_enabled(_VOICE_IN(hw)->v, enable);
  }
  
  static void

-qpw_volume_out(HWVoiceOut *hw, Volume *vol)
+qpw_voice_set_volume(PWVoice *v, Volume *vol)
  {
-PWVoiceOut *pw = (PWVoiceOut *) hw;
-PWVoice *v = >v;
  pwaudio *c = v->g;
  int i, ret;
  
@@ -707,28 +703,15 @@ qpw_volume_out(HWVoiceOut *hw, Volume *vol)

  }
  
  static void

-qpw_volume_in(HWVoiceIn *hw, Volume *vol)
+qpw_volume_out(HWVoiceOut *hw, Volume *vol)
  {
-PWVoiceIn *pw = (PWVoiceIn *) hw;
-PWVoice *v = >v;
-pwaudio *c = v->g;
-int i, ret;
-
-pw_thread_loop_lock(c->thread_loop);
-v->volume.channels = vol->channels;
-
-for (i = 0; i < vol->channels; ++i) {
-v->volume.values[i] = (float)vol->vol[i] / 255;
-}
-
-ret = pw_stream_set_control(v->stream,
-SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
-trace_pw_vol(ret == 0 ? "success" : "failed");
+qpw_voice_set_volume(_VOICE_OUT(hw)->v, vol);
+}
  
-v->muted = vol->mute;

-float val = v->muted ? 1.f : 0.f;
-ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, , 0);
-pw_thread_loop_unlock(c->thread_loop);
+static void
+qpw_volume_in(HWVoiceIn *hw, Volume *vol)
+{
+qpw_voice_set_volume(_VOICE_IN(hw)->v, vol);
  }
  
  static int wait_resync(pwaudio *pw)





Re: [PATCH 06/12] audio/pw: trace during init before calling pipewire API

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 6ca4ef4f62..2b12b40934 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -784,10 +784,11 @@ static void *
  qpw_audio_init(Audiodev *dev)
  {
  g_autofree pwaudio *pw = g_new0(pwaudio, 1);
-pw_init(NULL, NULL);
  
-trace_pw_audio_init();

  assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
+trace_pw_audio_init();
+
+pw_init(NULL, NULL);
  
  pw->dev = dev;

  pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);





Re: [PATCH 05/12] audio/pw: needless check for NULL

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

g_clear_pointer() already checks for NULL.

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 8 ++--
  1 file changed, 2 insertions(+), 6 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 51cfc0b052..6ca4ef4f62 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -834,12 +834,8 @@ fail:
  if (pw->thread_loop) {
  pw_thread_loop_stop(pw->thread_loop);
  }
-if (pw->context) {
-g_clear_pointer(>context, pw_context_destroy);
-}
-if (pw->thread_loop) {
-g_clear_pointer(>thread_loop, pw_thread_loop_destroy);
-}
+g_clear_pointer(>context, pw_context_destroy);
+g_clear_pointer(>thread_loop, pw_thread_loop_destroy);
  return NULL;
  }
  





Re: [PATCH 04/12] audio/pw: drop needless case statement

2023-05-07 Thread Volker Rümelin

From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
  audio/pwaudio.c | 10 --
  1 file changed, 10 deletions(-)


Reviewed-by: Volker Rümelin 


diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 9eb69bfd18..51cfc0b052 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -197,16 +197,6 @@ on_stream_state_changed(void *data, enum pw_stream_state 
old,
  
  trace_pw_state_changed(pw_stream_get_node_id(v->stream),

 pw_stream_state_as_string(state));
-
-switch (state) {
-case PW_STREAM_STATE_ERROR:
-case PW_STREAM_STATE_UNCONNECTED:
-break;
-case PW_STREAM_STATE_PAUSED:
-case PW_STREAM_STATE_CONNECTING:
-case PW_STREAM_STATE_STREAMING:
-break;
-}
  }
  
  static const struct pw_stream_events capture_stream_events = {





  1   2   3   4   5   6   >