1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * virtio-snd: Virtio sound device
4 * Copyright (C) 2021 OpenSynergy GmbH
5 */
6#include <linux/module.h>
7#include <linux/moduleparam.h>
8#include <linux/virtio_config.h>
9#include <sound/initval.h>
10#include <uapi/linux/virtio_ids.h>
11
12#include "virtio_card.h"
13
14u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC;
15module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644);
16MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
17
18static void virtsnd_remove(struct virtio_device *vdev);
19
20/**
21 * virtsnd_event_send() - Add an event to the event queue.
22 * @vqueue: Underlying event virtqueue.
23 * @event: Event.
24 * @notify: Indicates whether or not to send a notification to the device.
25 * @gfp: Kernel flags for memory allocation.
26 *
27 * Context: Any context.
28 */
29static void virtsnd_event_send(struct virtqueue *vqueue,
30 struct virtio_snd_event *event, bool notify,
31 gfp_t gfp)
32{
33 struct scatterlist sg;
34 struct scatterlist *psgs[1] = { &sg };
35
36 /* reset event content */
37 memset(event, 0, sizeof(*event));
38
39 sg_init_one(&sg, event, sizeof(*event));
40
41 if (virtqueue_add_sgs(vq: vqueue, sgs: psgs, out_sgs: 0, in_sgs: 1, data: event, gfp) || !notify)
42 return;
43
44 if (virtqueue_kick_prepare(vq: vqueue))
45 virtqueue_notify(vq: vqueue);
46}
47
48/**
49 * virtsnd_event_dispatch() - Dispatch an event from the device side.
50 * @snd: VirtIO sound device.
51 * @event: VirtIO sound event.
52 *
53 * Context: Any context.
54 */
55static void virtsnd_event_dispatch(struct virtio_snd *snd,
56 struct virtio_snd_event *event)
57{
58 switch (le32_to_cpu(event->hdr.code)) {
59 case VIRTIO_SND_EVT_JACK_CONNECTED:
60 case VIRTIO_SND_EVT_JACK_DISCONNECTED:
61 virtsnd_jack_event(snd, event);
62 break;
63 case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED:
64 case VIRTIO_SND_EVT_PCM_XRUN:
65 virtsnd_pcm_event(snd, event);
66 break;
67 case VIRTIO_SND_EVT_CTL_NOTIFY:
68 virtsnd_kctl_event(snd, event);
69 break;
70 }
71}
72
73/**
74 * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue.
75 * @vqueue: Underlying event virtqueue.
76 *
77 * This callback function is called upon a vring interrupt request from the
78 * device.
79 *
80 * Context: Interrupt context.
81 */
82static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
83{
84 struct virtio_snd *snd = vqueue->vdev->priv;
85 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
86 struct virtio_snd_event *event;
87 u32 length;
88 unsigned long flags;
89
90 spin_lock_irqsave(&queue->lock, flags);
91 do {
92 virtqueue_disable_cb(vq: vqueue);
93 while ((event = virtqueue_get_buf(vq: vqueue, len: &length))) {
94 virtsnd_event_dispatch(snd, event);
95 virtsnd_event_send(vqueue, event, notify: true, GFP_ATOMIC);
96 }
97 } while (!virtqueue_enable_cb(vq: vqueue));
98 spin_unlock_irqrestore(lock: &queue->lock, flags);
99}
100
101/**
102 * virtsnd_find_vqs() - Enumerate and initialize all virtqueues.
103 * @snd: VirtIO sound device.
104 *
105 * After calling this function, the event queue is disabled.
106 *
107 * Context: Any context.
108 * Return: 0 on success, -errno on failure.
109 */
110static int virtsnd_find_vqs(struct virtio_snd *snd)
111{
112 struct virtio_device *vdev = snd->vdev;
113 static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
114 [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
115 [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb,
116 [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb,
117 [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb
118 };
119 static const char *names[VIRTIO_SND_VQ_MAX] = {
120 [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
121 [VIRTIO_SND_VQ_EVENT] = "virtsnd-event",
122 [VIRTIO_SND_VQ_TX] = "virtsnd-tx",
123 [VIRTIO_SND_VQ_RX] = "virtsnd-rx"
124 };
125 struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
126 unsigned int i;
127 unsigned int n;
128 int rc;
129
130 rc = virtio_find_vqs(vdev, nvqs: VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
131 NULL);
132 if (rc) {
133 dev_err(&vdev->dev, "failed to initialize virtqueues\n");
134 return rc;
135 }
136
137 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
138 snd->queues[i].vqueue = vqs[i];
139
140 /* Allocate events and populate the event queue */
141 virtqueue_disable_cb(vq: vqs[VIRTIO_SND_VQ_EVENT]);
142
143 n = virtqueue_get_vring_size(vq: vqs[VIRTIO_SND_VQ_EVENT]);
144
145 snd->event_msgs = kmalloc_array(n, size: sizeof(*snd->event_msgs),
146 GFP_KERNEL);
147 if (!snd->event_msgs)
148 return -ENOMEM;
149
150 for (i = 0; i < n; ++i)
151 virtsnd_event_send(vqueue: vqs[VIRTIO_SND_VQ_EVENT],
152 event: &snd->event_msgs[i], notify: false, GFP_KERNEL);
153
154 return 0;
155}
156
157/**
158 * virtsnd_enable_event_vq() - Enable the event virtqueue.
159 * @snd: VirtIO sound device.
160 *
161 * Context: Any context.
162 */
163static void virtsnd_enable_event_vq(struct virtio_snd *snd)
164{
165 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
166
167 if (!virtqueue_enable_cb(vq: queue->vqueue))
168 virtsnd_event_notify_cb(vqueue: queue->vqueue);
169}
170
171/**
172 * virtsnd_disable_event_vq() - Disable the event virtqueue.
173 * @snd: VirtIO sound device.
174 *
175 * Context: Any context.
176 */
177static void virtsnd_disable_event_vq(struct virtio_snd *snd)
178{
179 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
180 struct virtio_snd_event *event;
181 u32 length;
182 unsigned long flags;
183
184 if (queue->vqueue) {
185 spin_lock_irqsave(&queue->lock, flags);
186 virtqueue_disable_cb(vq: queue->vqueue);
187 while ((event = virtqueue_get_buf(vq: queue->vqueue, len: &length)))
188 virtsnd_event_dispatch(snd, event);
189 spin_unlock_irqrestore(lock: &queue->lock, flags);
190 }
191}
192
193/**
194 * virtsnd_build_devs() - Read configuration and build ALSA devices.
195 * @snd: VirtIO sound device.
196 *
197 * Context: Any context that permits to sleep.
198 * Return: 0 on success, -errno on failure.
199 */
200static int virtsnd_build_devs(struct virtio_snd *snd)
201{
202 struct virtio_device *vdev = snd->vdev;
203 struct device *dev = &vdev->dev;
204 int rc;
205
206 rc = snd_card_new(parent: dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
207 THIS_MODULE, extra_size: 0, card_ret: &snd->card);
208 if (rc < 0)
209 return rc;
210
211 snd->card->private_data = snd;
212
213 strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
214 sizeof(snd->card->driver));
215 strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
216 sizeof(snd->card->shortname));
217 if (dev->parent->bus)
218 snprintf(buf: snd->card->longname, size: sizeof(snd->card->longname),
219 VIRTIO_SND_CARD_NAME " at %s/%s/%s",
220 dev->parent->bus->name, dev_name(dev: dev->parent),
221 dev_name(dev));
222 else
223 snprintf(buf: snd->card->longname, size: sizeof(snd->card->longname),
224 VIRTIO_SND_CARD_NAME " at %s/%s",
225 dev_name(dev: dev->parent), dev_name(dev));
226
227 rc = virtsnd_jack_parse_cfg(snd);
228 if (rc)
229 return rc;
230
231 rc = virtsnd_pcm_parse_cfg(snd);
232 if (rc)
233 return rc;
234
235 rc = virtsnd_chmap_parse_cfg(snd);
236 if (rc)
237 return rc;
238
239 if (virtio_has_feature(vdev, fbit: VIRTIO_SND_F_CTLS)) {
240 rc = virtsnd_kctl_parse_cfg(snd);
241 if (rc)
242 return rc;
243 }
244
245 if (snd->njacks) {
246 rc = virtsnd_jack_build_devs(snd);
247 if (rc)
248 return rc;
249 }
250
251 if (snd->nsubstreams) {
252 rc = virtsnd_pcm_build_devs(snd);
253 if (rc)
254 return rc;
255 }
256
257 if (snd->nchmaps) {
258 rc = virtsnd_chmap_build_devs(snd);
259 if (rc)
260 return rc;
261 }
262
263 if (snd->nkctls) {
264 rc = virtsnd_kctl_build_devs(snd);
265 if (rc)
266 return rc;
267 }
268
269 return snd_card_register(card: snd->card);
270}
271
272/**
273 * virtsnd_validate() - Validate if the device can be started.
274 * @vdev: VirtIO parent device.
275 *
276 * Context: Any context.
277 * Return: 0 on success, -EINVAL on failure.
278 */
279static int virtsnd_validate(struct virtio_device *vdev)
280{
281 if (!vdev->config->get) {
282 dev_err(&vdev->dev, "configuration access disabled\n");
283 return -EINVAL;
284 }
285
286 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
287 dev_err(&vdev->dev,
288 "device does not comply with spec version 1.x\n");
289 return -EINVAL;
290 }
291
292 if (!virtsnd_msg_timeout_ms) {
293 dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
294 return -EINVAL;
295 }
296
297 if (virtsnd_pcm_validate(vdev))
298 return -EINVAL;
299
300 return 0;
301}
302
303/**
304 * virtsnd_probe() - Create and initialize the device.
305 * @vdev: VirtIO parent device.
306 *
307 * Context: Any context that permits to sleep.
308 * Return: 0 on success, -errno on failure.
309 */
310static int virtsnd_probe(struct virtio_device *vdev)
311{
312 struct virtio_snd *snd;
313 unsigned int i;
314 int rc;
315
316 snd = devm_kzalloc(dev: &vdev->dev, size: sizeof(*snd), GFP_KERNEL);
317 if (!snd)
318 return -ENOMEM;
319
320 snd->vdev = vdev;
321 INIT_LIST_HEAD(list: &snd->ctl_msgs);
322 INIT_LIST_HEAD(list: &snd->pcm_list);
323
324 vdev->priv = snd;
325
326 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
327 spin_lock_init(&snd->queues[i].lock);
328
329 rc = virtsnd_find_vqs(snd);
330 if (rc)
331 goto on_exit;
332
333 virtio_device_ready(dev: vdev);
334
335 rc = virtsnd_build_devs(snd);
336 if (rc)
337 goto on_exit;
338
339 virtsnd_enable_event_vq(snd);
340
341on_exit:
342 if (rc)
343 virtsnd_remove(vdev);
344
345 return rc;
346}
347
348/**
349 * virtsnd_remove() - Remove VirtIO and ALSA devices.
350 * @vdev: VirtIO parent device.
351 *
352 * Context: Any context that permits to sleep.
353 */
354static void virtsnd_remove(struct virtio_device *vdev)
355{
356 struct virtio_snd *snd = vdev->priv;
357 unsigned int i;
358
359 virtsnd_disable_event_vq(snd);
360 virtsnd_ctl_msg_cancel_all(snd);
361
362 if (snd->card)
363 snd_card_free(card: snd->card);
364
365 vdev->config->del_vqs(vdev);
366 virtio_reset_device(dev: vdev);
367
368 for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
369 struct virtio_pcm_substream *vss = &snd->substreams[i];
370
371 cancel_work_sync(work: &vss->elapsed_period);
372 virtsnd_pcm_msg_free(vss);
373 }
374
375 kfree(objp: snd->event_msgs);
376}
377
378#ifdef CONFIG_PM_SLEEP
379/**
380 * virtsnd_freeze() - Suspend device.
381 * @vdev: VirtIO parent device.
382 *
383 * Context: Any context.
384 * Return: 0 on success, -errno on failure.
385 */
386static int virtsnd_freeze(struct virtio_device *vdev)
387{
388 struct virtio_snd *snd = vdev->priv;
389 unsigned int i;
390
391 virtsnd_disable_event_vq(snd);
392 virtsnd_ctl_msg_cancel_all(snd);
393
394 vdev->config->del_vqs(vdev);
395 virtio_reset_device(dev: vdev);
396
397 for (i = 0; i < snd->nsubstreams; ++i)
398 cancel_work_sync(work: &snd->substreams[i].elapsed_period);
399
400 kfree(objp: snd->event_msgs);
401 snd->event_msgs = NULL;
402
403 return 0;
404}
405
406/**
407 * virtsnd_restore() - Resume device.
408 * @vdev: VirtIO parent device.
409 *
410 * Context: Any context.
411 * Return: 0 on success, -errno on failure.
412 */
413static int virtsnd_restore(struct virtio_device *vdev)
414{
415 struct virtio_snd *snd = vdev->priv;
416 int rc;
417
418 rc = virtsnd_find_vqs(snd);
419 if (rc)
420 return rc;
421
422 virtio_device_ready(dev: vdev);
423
424 virtsnd_enable_event_vq(snd);
425
426 return 0;
427}
428#endif /* CONFIG_PM_SLEEP */
429
430static const struct virtio_device_id id_table[] = {
431 { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
432 { 0 },
433};
434
435static unsigned int features[] = {
436 VIRTIO_SND_F_CTLS
437};
438
439static struct virtio_driver virtsnd_driver = {
440 .driver.name = KBUILD_MODNAME,
441 .driver.owner = THIS_MODULE,
442 .id_table = id_table,
443 .feature_table = features,
444 .feature_table_size = ARRAY_SIZE(features),
445 .validate = virtsnd_validate,
446 .probe = virtsnd_probe,
447 .remove = virtsnd_remove,
448#ifdef CONFIG_PM_SLEEP
449 .freeze = virtsnd_freeze,
450 .restore = virtsnd_restore,
451#endif
452};
453
454module_virtio_driver(virtsnd_driver);
455
456MODULE_DEVICE_TABLE(virtio, id_table);
457MODULE_DESCRIPTION("Virtio sound card driver");
458MODULE_LICENSE("GPL");
459

source code of linux/sound/virtio/virtio_card.c