12880e676SManos Pitsidianakis /* 22880e676SManos Pitsidianakis * VIRTIO Sound Device conforming to 32880e676SManos Pitsidianakis * 42880e676SManos Pitsidianakis * "Virtual I/O Device (VIRTIO) Version 1.2 52880e676SManos Pitsidianakis * Committee Specification Draft 01 62880e676SManos Pitsidianakis * 09 May 2022" 72880e676SManos Pitsidianakis * 82880e676SManos Pitsidianakis * Copyright (c) 2023 Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org> 92880e676SManos Pitsidianakis * Copyright (C) 2019 OpenSynergy GmbH 102880e676SManos Pitsidianakis * 112880e676SManos Pitsidianakis * This work is licensed under the terms of the GNU GPL, version 2 or 122880e676SManos Pitsidianakis * (at your option) any later version. See the COPYING file in the 132880e676SManos Pitsidianakis * top-level directory. 142880e676SManos Pitsidianakis */ 152880e676SManos Pitsidianakis 162880e676SManos Pitsidianakis #ifndef QEMU_VIRTIO_SOUND_H 172880e676SManos Pitsidianakis #define QEMU_VIRTIO_SOUND_H 182880e676SManos Pitsidianakis 192880e676SManos Pitsidianakis #include "hw/virtio/virtio.h" 202880e676SManos Pitsidianakis #include "audio/audio.h" 212880e676SManos Pitsidianakis #include "standard-headers/linux/virtio_ids.h" 222880e676SManos Pitsidianakis #include "standard-headers/linux/virtio_snd.h" 232880e676SManos Pitsidianakis 242880e676SManos Pitsidianakis #define TYPE_VIRTIO_SND "virtio-sound-device" 252880e676SManos Pitsidianakis #define VIRTIO_SND(obj) \ 262880e676SManos Pitsidianakis OBJECT_CHECK(VirtIOSound, (obj), TYPE_VIRTIO_SND) 272880e676SManos Pitsidianakis 282880e676SManos Pitsidianakis /* CONFIGURATION SPACE */ 292880e676SManos Pitsidianakis 302880e676SManos Pitsidianakis typedef struct virtio_snd_config virtio_snd_config; 312880e676SManos Pitsidianakis 322880e676SManos Pitsidianakis /* COMMON DEFINITIONS */ 332880e676SManos Pitsidianakis 342880e676SManos Pitsidianakis /* common header for request/response*/ 352880e676SManos Pitsidianakis typedef struct virtio_snd_hdr virtio_snd_hdr; 362880e676SManos Pitsidianakis 372880e676SManos Pitsidianakis /* event notification */ 382880e676SManos Pitsidianakis typedef struct virtio_snd_event virtio_snd_event; 392880e676SManos Pitsidianakis 402880e676SManos Pitsidianakis /* common control request to query an item information */ 412880e676SManos Pitsidianakis typedef struct virtio_snd_query_info virtio_snd_query_info; 422880e676SManos Pitsidianakis 432880e676SManos Pitsidianakis /* JACK CONTROL MESSAGES */ 442880e676SManos Pitsidianakis 452880e676SManos Pitsidianakis typedef struct virtio_snd_jack_hdr virtio_snd_jack_hdr; 462880e676SManos Pitsidianakis 472880e676SManos Pitsidianakis /* jack information structure */ 482880e676SManos Pitsidianakis typedef struct virtio_snd_jack_info virtio_snd_jack_info; 492880e676SManos Pitsidianakis 502880e676SManos Pitsidianakis /* jack remapping control request */ 512880e676SManos Pitsidianakis typedef struct virtio_snd_jack_remap virtio_snd_jack_remap; 522880e676SManos Pitsidianakis 532880e676SManos Pitsidianakis /* 542880e676SManos Pitsidianakis * PCM CONTROL MESSAGES 552880e676SManos Pitsidianakis */ 562880e676SManos Pitsidianakis typedef struct virtio_snd_pcm_hdr virtio_snd_pcm_hdr; 572880e676SManos Pitsidianakis 582880e676SManos Pitsidianakis /* PCM stream info structure */ 592880e676SManos Pitsidianakis typedef struct virtio_snd_pcm_info virtio_snd_pcm_info; 602880e676SManos Pitsidianakis 612880e676SManos Pitsidianakis /* set PCM stream params */ 622880e676SManos Pitsidianakis typedef struct virtio_snd_pcm_set_params virtio_snd_pcm_set_params; 632880e676SManos Pitsidianakis 642880e676SManos Pitsidianakis /* I/O request header */ 652880e676SManos Pitsidianakis typedef struct virtio_snd_pcm_xfer virtio_snd_pcm_xfer; 662880e676SManos Pitsidianakis 672880e676SManos Pitsidianakis /* I/O request status */ 682880e676SManos Pitsidianakis typedef struct virtio_snd_pcm_status virtio_snd_pcm_status; 692880e676SManos Pitsidianakis 70*eb9ad377SManos Pitsidianakis /* device structs */ 71*eb9ad377SManos Pitsidianakis 72*eb9ad377SManos Pitsidianakis typedef struct VirtIOSound VirtIOSound; 73*eb9ad377SManos Pitsidianakis 74*eb9ad377SManos Pitsidianakis typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream; 75*eb9ad377SManos Pitsidianakis 76*eb9ad377SManos Pitsidianakis typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command; 77*eb9ad377SManos Pitsidianakis 78*eb9ad377SManos Pitsidianakis typedef struct VirtIOSoundPCM VirtIOSoundPCM; 79*eb9ad377SManos Pitsidianakis 80*eb9ad377SManos Pitsidianakis struct VirtIOSoundPCM { 81*eb9ad377SManos Pitsidianakis VirtIOSound *snd; 82*eb9ad377SManos Pitsidianakis /* 83*eb9ad377SManos Pitsidianakis * PCM parameters are a separate field instead of a VirtIOSoundPCMStream 84*eb9ad377SManos Pitsidianakis * field, because the operation of PCM control requests is first 85*eb9ad377SManos Pitsidianakis * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this 86*eb9ad377SManos Pitsidianakis * means that some times we get parameters without having an allocated 87*eb9ad377SManos Pitsidianakis * stream yet. 88*eb9ad377SManos Pitsidianakis */ 89*eb9ad377SManos Pitsidianakis virtio_snd_pcm_set_params *pcm_params; 90*eb9ad377SManos Pitsidianakis VirtIOSoundPCMStream **streams; 91*eb9ad377SManos Pitsidianakis }; 92*eb9ad377SManos Pitsidianakis 93*eb9ad377SManos Pitsidianakis struct VirtIOSoundPCMStream { 94*eb9ad377SManos Pitsidianakis VirtIOSoundPCM *pcm; 95*eb9ad377SManos Pitsidianakis virtio_snd_pcm_info info; 96*eb9ad377SManos Pitsidianakis virtio_snd_pcm_set_params params; 97*eb9ad377SManos Pitsidianakis uint32_t id; 98*eb9ad377SManos Pitsidianakis /* channel position values (VIRTIO_SND_CHMAP_XXX) */ 99*eb9ad377SManos Pitsidianakis uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE]; 100*eb9ad377SManos Pitsidianakis VirtIOSound *s; 101*eb9ad377SManos Pitsidianakis bool flushing; 102*eb9ad377SManos Pitsidianakis audsettings as; 103*eb9ad377SManos Pitsidianakis union { 104*eb9ad377SManos Pitsidianakis SWVoiceIn *in; 105*eb9ad377SManos Pitsidianakis SWVoiceOut *out; 106*eb9ad377SManos Pitsidianakis } voice; 107*eb9ad377SManos Pitsidianakis bool active; 108*eb9ad377SManos Pitsidianakis }; 109*eb9ad377SManos Pitsidianakis 110*eb9ad377SManos Pitsidianakis /* 111*eb9ad377SManos Pitsidianakis * PCM stream state machine. 112*eb9ad377SManos Pitsidianakis * ------------------------- 113*eb9ad377SManos Pitsidianakis * 114*eb9ad377SManos Pitsidianakis * 5.14.6.6.1 PCM Command Lifecycle 115*eb9ad377SManos Pitsidianakis * ================================ 116*eb9ad377SManos Pitsidianakis * 117*eb9ad377SManos Pitsidianakis * A PCM stream has the following command lifecycle: 118*eb9ad377SManos Pitsidianakis * - `SET PARAMETERS` 119*eb9ad377SManos Pitsidianakis * The driver negotiates the stream parameters (format, transport, etc) with 120*eb9ad377SManos Pitsidianakis * the device. 121*eb9ad377SManos Pitsidianakis * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. 122*eb9ad377SManos Pitsidianakis * - `PREPARE` 123*eb9ad377SManos Pitsidianakis * The device prepares the stream (allocates resources, etc). 124*eb9ad377SManos Pitsidianakis * Possible valid transitions: `SET PARAMETERS`, `PREPARE`, `START`, 125*eb9ad377SManos Pitsidianakis * `RELEASE`. Output only: the driver transfers data for pre-buffing. 126*eb9ad377SManos Pitsidianakis * - `START` 127*eb9ad377SManos Pitsidianakis * The device starts the stream (unmute, putting into running state, etc). 128*eb9ad377SManos Pitsidianakis * Possible valid transitions: `STOP`. 129*eb9ad377SManos Pitsidianakis * The driver transfers data to/from the stream. 130*eb9ad377SManos Pitsidianakis * - `STOP` 131*eb9ad377SManos Pitsidianakis * The device stops the stream (mute, putting into non-running state, etc). 132*eb9ad377SManos Pitsidianakis * Possible valid transitions: `START`, `RELEASE`. 133*eb9ad377SManos Pitsidianakis * - `RELEASE` 134*eb9ad377SManos Pitsidianakis * The device releases the stream (frees resources, etc). 135*eb9ad377SManos Pitsidianakis * Possible valid transitions: `SET PARAMETERS`, `PREPARE`. 136*eb9ad377SManos Pitsidianakis * 137*eb9ad377SManos Pitsidianakis * +---------------+ +---------+ +---------+ +-------+ +-------+ 138*eb9ad377SManos Pitsidianakis * | SetParameters | | Prepare | | Release | | Start | | Stop | 139*eb9ad377SManos Pitsidianakis * +---------------+ +---------+ +---------+ +-------+ +-------+ 140*eb9ad377SManos Pitsidianakis * |- | | | | 141*eb9ad377SManos Pitsidianakis * || | | | | 142*eb9ad377SManos Pitsidianakis * |< | | | | 143*eb9ad377SManos Pitsidianakis * |------------->| | | | 144*eb9ad377SManos Pitsidianakis * |<-------------| | | | 145*eb9ad377SManos Pitsidianakis * | |- | | | 146*eb9ad377SManos Pitsidianakis * | || | | | 147*eb9ad377SManos Pitsidianakis * | |< | | | 148*eb9ad377SManos Pitsidianakis * | |--------------------->| | 149*eb9ad377SManos Pitsidianakis * | |---------->| | | 150*eb9ad377SManos Pitsidianakis * | | | |-------->| 151*eb9ad377SManos Pitsidianakis * | | | |<--------| 152*eb9ad377SManos Pitsidianakis * | | |<-------------------| 153*eb9ad377SManos Pitsidianakis * |<-------------------------| | | 154*eb9ad377SManos Pitsidianakis * | |<----------| | | 155*eb9ad377SManos Pitsidianakis * 156*eb9ad377SManos Pitsidianakis * CTRL in the VirtIOSound device 157*eb9ad377SManos Pitsidianakis * ============================== 158*eb9ad377SManos Pitsidianakis * 159*eb9ad377SManos Pitsidianakis * The control messages that affect the state of a stream arrive in the 160*eb9ad377SManos Pitsidianakis * `virtio_snd_handle_ctrl()` queue callback and are of type `struct 161*eb9ad377SManos Pitsidianakis * virtio_snd_ctrl_command`. They are stored in a queue field in the device 162*eb9ad377SManos Pitsidianakis * type, `VirtIOSound`. This allows deferring the CTRL request completion if 163*eb9ad377SManos Pitsidianakis * it's not immediately possible due to locking/state reasons. 164*eb9ad377SManos Pitsidianakis * 165*eb9ad377SManos Pitsidianakis * The CTRL message is finally handled in `process_cmd()`. 166*eb9ad377SManos Pitsidianakis */ 167*eb9ad377SManos Pitsidianakis struct VirtIOSound { 1682880e676SManos Pitsidianakis VirtIODevice parent_obj; 1692880e676SManos Pitsidianakis 1702880e676SManos Pitsidianakis VirtQueue *queues[VIRTIO_SND_VQ_MAX]; 1712880e676SManos Pitsidianakis uint64_t features; 172*eb9ad377SManos Pitsidianakis VirtIOSoundPCM *pcm; 1732880e676SManos Pitsidianakis QEMUSoundCard card; 1742880e676SManos Pitsidianakis VMChangeStateEntry *vmstate; 1752880e676SManos Pitsidianakis virtio_snd_config snd_conf; 176*eb9ad377SManos Pitsidianakis QemuMutex cmdq_mutex; 177*eb9ad377SManos Pitsidianakis QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq; 178*eb9ad377SManos Pitsidianakis bool processing_cmdq; 179*eb9ad377SManos Pitsidianakis }; 180*eb9ad377SManos Pitsidianakis 181*eb9ad377SManos Pitsidianakis struct virtio_snd_ctrl_command { 182*eb9ad377SManos Pitsidianakis VirtQueueElement *elem; 183*eb9ad377SManos Pitsidianakis VirtQueue *vq; 184*eb9ad377SManos Pitsidianakis virtio_snd_hdr ctrl; 185*eb9ad377SManos Pitsidianakis virtio_snd_hdr resp; 186*eb9ad377SManos Pitsidianakis QTAILQ_ENTRY(virtio_snd_ctrl_command) next; 187*eb9ad377SManos Pitsidianakis }; 1882880e676SManos Pitsidianakis #endif 189