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
14 u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC;
15 module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644);
16 MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds");
17
18 static 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 */
virtsnd_event_send(struct virtqueue * vqueue,struct virtio_snd_event * event,bool notify,gfp_t gfp)29 static 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(vqueue, psgs, 0, 1, event, gfp) || !notify)
42 return;
43
44 if (virtqueue_kick_prepare(vqueue))
45 virtqueue_notify(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 */
virtsnd_event_dispatch(struct virtio_snd * snd,struct virtio_snd_event * event)55 static 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 */
virtsnd_event_notify_cb(struct virtqueue * vqueue)82 static 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(vqueue);
93 while ((event = virtqueue_get_buf(vqueue, &length))) {
94 virtsnd_event_dispatch(snd, event);
95 virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
96 }
97 } while (!virtqueue_enable_cb(vqueue));
98 spin_unlock_irqrestore(&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 */
virtsnd_find_vqs(struct virtio_snd * snd)110 static int virtsnd_find_vqs(struct virtio_snd *snd)
111 {
112 struct virtio_device *vdev = snd->vdev;
113 struct virtqueue_info vqs_info[VIRTIO_SND_VQ_MAX] = {
114 [VIRTIO_SND_VQ_CONTROL] = { "virtsnd-ctl",
115 virtsnd_ctl_notify_cb },
116 [VIRTIO_SND_VQ_EVENT] = { "virtsnd-event",
117 virtsnd_event_notify_cb },
118 [VIRTIO_SND_VQ_TX] = { "virtsnd-tx",
119 virtsnd_pcm_tx_notify_cb },
120 [VIRTIO_SND_VQ_RX] = { "virtsnd-rx",
121 virtsnd_pcm_rx_notify_cb },
122 };
123 struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
124 unsigned int i;
125 unsigned int n;
126 int rc;
127
128 rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, vqs_info, NULL);
129 if (rc) {
130 dev_err(&vdev->dev, "failed to initialize virtqueues\n");
131 return rc;
132 }
133
134 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
135 snd->queues[i].vqueue = vqs[i];
136
137 /* Allocate events and populate the event queue */
138 virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]);
139
140 n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]);
141
142 snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs),
143 GFP_KERNEL);
144 if (!snd->event_msgs)
145 return -ENOMEM;
146
147 for (i = 0; i < n; ++i)
148 virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT],
149 &snd->event_msgs[i], false, GFP_KERNEL);
150
151 return 0;
152 }
153
154 /**
155 * virtsnd_enable_event_vq() - Enable the event virtqueue.
156 * @snd: VirtIO sound device.
157 *
158 * Context: Any context.
159 */
virtsnd_enable_event_vq(struct virtio_snd * snd)160 static void virtsnd_enable_event_vq(struct virtio_snd *snd)
161 {
162 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
163
164 if (!virtqueue_enable_cb(queue->vqueue))
165 virtsnd_event_notify_cb(queue->vqueue);
166 }
167
168 /**
169 * virtsnd_disable_event_vq() - Disable the event virtqueue.
170 * @snd: VirtIO sound device.
171 *
172 * Context: Any context.
173 */
virtsnd_disable_event_vq(struct virtio_snd * snd)174 static void virtsnd_disable_event_vq(struct virtio_snd *snd)
175 {
176 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
177 struct virtio_snd_event *event;
178 u32 length;
179 unsigned long flags;
180
181 if (queue->vqueue) {
182 spin_lock_irqsave(&queue->lock, flags);
183 virtqueue_disable_cb(queue->vqueue);
184 while ((event = virtqueue_get_buf(queue->vqueue, &length)))
185 virtsnd_event_dispatch(snd, event);
186 spin_unlock_irqrestore(&queue->lock, flags);
187 }
188 }
189
190 /**
191 * virtsnd_build_devs() - Read configuration and build ALSA devices.
192 * @snd: VirtIO sound device.
193 *
194 * Context: Any context that permits to sleep.
195 * Return: 0 on success, -errno on failure.
196 */
virtsnd_build_devs(struct virtio_snd * snd)197 static int virtsnd_build_devs(struct virtio_snd *snd)
198 {
199 struct virtio_device *vdev = snd->vdev;
200 struct device *dev = &vdev->dev;
201 int rc;
202
203 rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
204 THIS_MODULE, 0, &snd->card);
205 if (rc < 0)
206 return rc;
207
208 snd->card->private_data = snd;
209
210 strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
211 sizeof(snd->card->driver));
212 strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
213 sizeof(snd->card->shortname));
214 if (dev->parent->bus)
215 snprintf(snd->card->longname, sizeof(snd->card->longname),
216 VIRTIO_SND_CARD_NAME " at %s/%s/%s",
217 dev->parent->bus->name, dev_name(dev->parent),
218 dev_name(dev));
219 else
220 snprintf(snd->card->longname, sizeof(snd->card->longname),
221 VIRTIO_SND_CARD_NAME " at %s/%s",
222 dev_name(dev->parent), dev_name(dev));
223
224 rc = virtsnd_jack_parse_cfg(snd);
225 if (rc)
226 return rc;
227
228 rc = virtsnd_pcm_parse_cfg(snd);
229 if (rc)
230 return rc;
231
232 rc = virtsnd_chmap_parse_cfg(snd);
233 if (rc)
234 return rc;
235
236 if (virtio_has_feature(vdev, VIRTIO_SND_F_CTLS)) {
237 rc = virtsnd_kctl_parse_cfg(snd);
238 if (rc)
239 return rc;
240 }
241
242 if (snd->njacks) {
243 rc = virtsnd_jack_build_devs(snd);
244 if (rc)
245 return rc;
246 }
247
248 if (snd->nsubstreams) {
249 rc = virtsnd_pcm_build_devs(snd);
250 if (rc)
251 return rc;
252 }
253
254 if (snd->nchmaps) {
255 rc = virtsnd_chmap_build_devs(snd);
256 if (rc)
257 return rc;
258 }
259
260 if (snd->nkctls) {
261 rc = virtsnd_kctl_build_devs(snd);
262 if (rc)
263 return rc;
264 }
265
266 return snd_card_register(snd->card);
267 }
268
269 /**
270 * virtsnd_validate() - Validate if the device can be started.
271 * @vdev: VirtIO parent device.
272 *
273 * Context: Any context.
274 * Return: 0 on success, -EINVAL on failure.
275 */
virtsnd_validate(struct virtio_device * vdev)276 static int virtsnd_validate(struct virtio_device *vdev)
277 {
278 if (!vdev->config->get) {
279 dev_err(&vdev->dev, "configuration access disabled\n");
280 return -EINVAL;
281 }
282
283 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
284 dev_err(&vdev->dev,
285 "device does not comply with spec version 1.x\n");
286 return -EINVAL;
287 }
288
289 if (!virtsnd_msg_timeout_ms) {
290 dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
291 return -EINVAL;
292 }
293
294 if (virtsnd_pcm_validate(vdev))
295 return -EINVAL;
296
297 return 0;
298 }
299
300 /**
301 * virtsnd_probe() - Create and initialize the device.
302 * @vdev: VirtIO parent device.
303 *
304 * Context: Any context that permits to sleep.
305 * Return: 0 on success, -errno on failure.
306 */
virtsnd_probe(struct virtio_device * vdev)307 static int virtsnd_probe(struct virtio_device *vdev)
308 {
309 struct virtio_snd *snd;
310 unsigned int i;
311 int rc;
312
313 snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL);
314 if (!snd)
315 return -ENOMEM;
316
317 snd->vdev = vdev;
318 INIT_LIST_HEAD(&snd->ctl_msgs);
319 INIT_LIST_HEAD(&snd->pcm_list);
320
321 vdev->priv = snd;
322
323 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
324 spin_lock_init(&snd->queues[i].lock);
325
326 rc = virtsnd_find_vqs(snd);
327 if (rc)
328 goto on_exit;
329
330 virtio_device_ready(vdev);
331
332 rc = virtsnd_build_devs(snd);
333 if (rc)
334 goto on_exit;
335
336 virtsnd_enable_event_vq(snd);
337
338 on_exit:
339 if (rc)
340 virtsnd_remove(vdev);
341
342 return rc;
343 }
344
345 /**
346 * virtsnd_remove() - Remove VirtIO and ALSA devices.
347 * @vdev: VirtIO parent device.
348 *
349 * Context: Any context that permits to sleep.
350 */
virtsnd_remove(struct virtio_device * vdev)351 static void virtsnd_remove(struct virtio_device *vdev)
352 {
353 struct virtio_snd *snd = vdev->priv;
354 unsigned int i;
355
356 virtsnd_disable_event_vq(snd);
357 virtsnd_ctl_msg_cancel_all(snd);
358
359 if (snd->card)
360 snd_card_free(snd->card);
361
362 vdev->config->del_vqs(vdev);
363 virtio_reset_device(vdev);
364
365 for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
366 struct virtio_pcm_substream *vss = &snd->substreams[i];
367
368 cancel_work_sync(&vss->elapsed_period);
369 virtsnd_pcm_msg_free(vss);
370 }
371
372 kfree(snd->event_msgs);
373 }
374
375 #ifdef CONFIG_PM_SLEEP
376 /**
377 * virtsnd_freeze() - Suspend device.
378 * @vdev: VirtIO parent device.
379 *
380 * Context: Any context.
381 * Return: 0 on success, -errno on failure.
382 */
virtsnd_freeze(struct virtio_device * vdev)383 static int virtsnd_freeze(struct virtio_device *vdev)
384 {
385 struct virtio_snd *snd = vdev->priv;
386 unsigned int i;
387
388 virtsnd_disable_event_vq(snd);
389 virtsnd_ctl_msg_cancel_all(snd);
390
391 vdev->config->del_vqs(vdev);
392 virtio_reset_device(vdev);
393
394 for (i = 0; i < snd->nsubstreams; ++i)
395 cancel_work_sync(&snd->substreams[i].elapsed_period);
396
397 kfree(snd->event_msgs);
398 snd->event_msgs = NULL;
399
400 return 0;
401 }
402
403 /**
404 * virtsnd_restore() - Resume device.
405 * @vdev: VirtIO parent device.
406 *
407 * Context: Any context.
408 * Return: 0 on success, -errno on failure.
409 */
virtsnd_restore(struct virtio_device * vdev)410 static int virtsnd_restore(struct virtio_device *vdev)
411 {
412 struct virtio_snd *snd = vdev->priv;
413 int rc;
414
415 rc = virtsnd_find_vqs(snd);
416 if (rc)
417 return rc;
418
419 virtio_device_ready(vdev);
420
421 virtsnd_enable_event_vq(snd);
422
423 return 0;
424 }
425 #endif /* CONFIG_PM_SLEEP */
426
427 static const struct virtio_device_id id_table[] = {
428 { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
429 { 0 },
430 };
431
432 static unsigned int features[] = {
433 VIRTIO_SND_F_CTLS
434 };
435
436 static struct virtio_driver virtsnd_driver = {
437 .driver.name = KBUILD_MODNAME,
438 .id_table = id_table,
439 .feature_table = features,
440 .feature_table_size = ARRAY_SIZE(features),
441 .validate = virtsnd_validate,
442 .probe = virtsnd_probe,
443 .remove = virtsnd_remove,
444 #ifdef CONFIG_PM_SLEEP
445 .freeze = virtsnd_freeze,
446 .restore = virtsnd_restore,
447 #endif
448 };
449
450 module_virtio_driver(virtsnd_driver);
451
452 MODULE_DEVICE_TABLE(virtio, id_table);
453 MODULE_DESCRIPTION("Virtio sound card driver");
454 MODULE_LICENSE("GPL");
455