]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/audio/virtio-snd.c
Add virtio-sound-pci device
[thirdparty/qemu.git] / hw / audio / virtio-snd.c
CommitLineData
2880e676
MP
1/*
2 * VIRTIO Sound Device conforming to
3 *
4 * "Virtual I/O Device (VIRTIO) Version 1.2
5 * Committee Specification Draft 01
6 * 09 May 2022"
7 *
8 * <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-52900014>
9 *
10 * Copyright (c) 2023 Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
11 * Copyright (C) 2019 OpenSynergy GmbH
12 *
13 * This work is licensed under the terms of the GNU GPL, version 2 or
14 * (at your option) any later version. See the COPYING file in the
15 * top-level directory.
16 */
17
18#include "qemu/osdep.h"
19#include "qemu/iov.h"
20#include "qemu/log.h"
21#include "qemu/error-report.h"
22#include "include/qemu/lockable.h"
23#include "sysemu/runstate.h"
24#include "trace.h"
25#include "qapi/error.h"
26#include "hw/audio/virtio-snd.h"
27#include "hw/core/cpu.h"
28
29#define VIRTIO_SOUND_VM_VERSION 1
30#define VIRTIO_SOUND_JACK_DEFAULT 0
31#define VIRTIO_SOUND_STREAM_DEFAULT 1
32#define VIRTIO_SOUND_CHMAP_DEFAULT 0
33#define VIRTIO_SOUND_HDA_FN_NID 0
34
35static const VMStateDescription vmstate_virtio_snd_device = {
36 .name = TYPE_VIRTIO_SND,
37 .version_id = VIRTIO_SOUND_VM_VERSION,
38 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
39};
40
41static const VMStateDescription vmstate_virtio_snd = {
42 .name = TYPE_VIRTIO_SND,
43 .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
44 .version_id = VIRTIO_SOUND_VM_VERSION,
45 .fields = (VMStateField[]) {
46 VMSTATE_VIRTIO_DEVICE,
47 VMSTATE_END_OF_LIST()
48 },
49};
50
51static Property virtio_snd_properties[] = {
52 DEFINE_AUDIO_PROPERTIES(VirtIOSound, card),
53 DEFINE_PROP_UINT32("jacks", VirtIOSound, snd_conf.jacks,
54 VIRTIO_SOUND_JACK_DEFAULT),
55 DEFINE_PROP_UINT32("streams", VirtIOSound, snd_conf.streams,
56 VIRTIO_SOUND_STREAM_DEFAULT),
57 DEFINE_PROP_UINT32("chmaps", VirtIOSound, snd_conf.chmaps,
58 VIRTIO_SOUND_CHMAP_DEFAULT),
59 DEFINE_PROP_END_OF_LIST(),
60};
61
62static void
63virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
64{
65 VirtIOSound *s = VIRTIO_SND(vdev);
66 virtio_snd_config *sndconfig =
67 (virtio_snd_config *)config;
68 trace_virtio_snd_get_config(vdev,
69 s->snd_conf.jacks,
70 s->snd_conf.streams,
71 s->snd_conf.chmaps);
72
73 memcpy(sndconfig, &s->snd_conf, sizeof(s->snd_conf));
74 cpu_to_le32s(&sndconfig->jacks);
75 cpu_to_le32s(&sndconfig->streams);
76 cpu_to_le32s(&sndconfig->chmaps);
77
78}
79
80static void
81virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
82{
83 VirtIOSound *s = VIRTIO_SND(vdev);
84 const virtio_snd_config *sndconfig =
85 (const virtio_snd_config *)config;
86
87
88 trace_virtio_snd_set_config(vdev,
89 s->snd_conf.jacks,
90 sndconfig->jacks,
91 s->snd_conf.streams,
92 sndconfig->streams,
93 s->snd_conf.chmaps,
94 sndconfig->chmaps);
95
96 memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
97 le32_to_cpus(&s->snd_conf.jacks);
98 le32_to_cpus(&s->snd_conf.streams);
99 le32_to_cpus(&s->snd_conf.chmaps);
100
101}
102
103/*
104 * Queue handler stub.
105 *
106 * @vdev: VirtIOSound device
107 * @vq: virtqueue
108 */
109static void virtio_snd_handle_queue(VirtIODevice *vdev, VirtQueue *vq) {}
110
111static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
112 Error **errp)
113{
114 /*
115 * virtio-v1.2-csd01, 5.14.3,
116 * Feature Bits
117 * None currently defined.
118 */
119 VirtIOSound *s = VIRTIO_SND(vdev);
120 features |= s->features;
121
122 trace_virtio_snd_get_features(vdev, features);
123
124 return features;
125}
126
127static void
128virtio_snd_vm_state_change(void *opaque, bool running,
129 RunState state)
130{
131 if (running) {
132 trace_virtio_snd_vm_state_running();
133 } else {
134 trace_virtio_snd_vm_state_stopped();
135 }
136}
137
138static void virtio_snd_realize(DeviceState *dev, Error **errp)
139{
140 ERRP_GUARD();
141 VirtIOSound *vsnd = VIRTIO_SND(dev);
142 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
143
144 vsnd->vmstate =
145 qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);
146
147 trace_virtio_snd_realize(vsnd);
148
149 virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
150 virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
151
152 /* set number of jacks and streams */
153 if (vsnd->snd_conf.jacks > 8) {
154 error_setg(errp,
155 "Invalid number of jacks: %"PRIu32,
156 vsnd->snd_conf.jacks);
157 return;
158 }
159 if (vsnd->snd_conf.streams < 1 || vsnd->snd_conf.streams > 10) {
160 error_setg(errp,
161 "Invalid number of streams: %"PRIu32,
162 vsnd->snd_conf.streams);
163 return;
164 }
165
166 if (vsnd->snd_conf.chmaps > VIRTIO_SND_CHMAP_MAX_SIZE) {
167 error_setg(errp,
168 "Invalid number of channel maps: %"PRIu32,
169 vsnd->snd_conf.chmaps);
170 return;
171 }
172
173 AUD_register_card("virtio-sound", &vsnd->card, errp);
174
175 vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
176 virtio_add_queue(vdev, 64, virtio_snd_handle_queue);
177 vsnd->queues[VIRTIO_SND_VQ_EVENT] =
178 virtio_add_queue(vdev, 64, virtio_snd_handle_queue);
179 vsnd->queues[VIRTIO_SND_VQ_TX] =
180 virtio_add_queue(vdev, 64, virtio_snd_handle_queue);
181 vsnd->queues[VIRTIO_SND_VQ_RX] =
182 virtio_add_queue(vdev, 64, virtio_snd_handle_queue);
183}
184
185static void virtio_snd_unrealize(DeviceState *dev)
186{
187 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
188 VirtIOSound *vsnd = VIRTIO_SND(dev);
189
190 qemu_del_vm_change_state_handler(vsnd->vmstate);
191 trace_virtio_snd_unrealize(vsnd);
192
193 AUD_remove_card(&vsnd->card);
194 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
195 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_EVENT]);
196 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_TX]);
197 virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_RX]);
198 virtio_cleanup(vdev);
199}
200
201
202static void virtio_snd_reset(VirtIODevice *vdev) {}
203
204static void virtio_snd_class_init(ObjectClass *klass, void *data)
205{
206 DeviceClass *dc = DEVICE_CLASS(klass);
207 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
208
209
210 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
211 device_class_set_props(dc, virtio_snd_properties);
212
213 dc->vmsd = &vmstate_virtio_snd;
214 vdc->vmsd = &vmstate_virtio_snd_device;
215 vdc->realize = virtio_snd_realize;
216 vdc->unrealize = virtio_snd_unrealize;
217 vdc->get_config = virtio_snd_get_config;
218 vdc->set_config = virtio_snd_set_config;
219 vdc->get_features = get_features;
220 vdc->reset = virtio_snd_reset;
221 vdc->legacy_features = 0;
222}
223
224static const TypeInfo virtio_snd_types[] = {
225 {
226 .name = TYPE_VIRTIO_SND,
227 .parent = TYPE_VIRTIO_DEVICE,
228 .instance_size = sizeof(VirtIOSound),
229 .class_init = virtio_snd_class_init,
230 }
231};
232
233DEFINE_TYPES(virtio_snd_types)