xref: /linux/sound/virtio/virtio_card.c (revision 29b96bf50ba958eb5f097cdc3fbd4c1acf9547a2)
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  */
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  */
55 static void virtsnd_event_dispatch(struct virtio_snd *snd,
56 				   struct virtio_snd_event *event)
57 {
58 }
59 
60 /**
61  * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue.
62  * @vqueue: Underlying event virtqueue.
63  *
64  * This callback function is called upon a vring interrupt request from the
65  * device.
66  *
67  * Context: Interrupt context.
68  */
69 static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
70 {
71 	struct virtio_snd *snd = vqueue->vdev->priv;
72 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
73 	struct virtio_snd_event *event;
74 	u32 length;
75 	unsigned long flags;
76 
77 	spin_lock_irqsave(&queue->lock, flags);
78 	do {
79 		virtqueue_disable_cb(vqueue);
80 		while ((event = virtqueue_get_buf(vqueue, &length))) {
81 			virtsnd_event_dispatch(snd, event);
82 			virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
83 		}
84 		if (unlikely(virtqueue_is_broken(vqueue)))
85 			break;
86 	} while (!virtqueue_enable_cb(vqueue));
87 	spin_unlock_irqrestore(&queue->lock, flags);
88 }
89 
90 /**
91  * virtsnd_find_vqs() - Enumerate and initialize all virtqueues.
92  * @snd: VirtIO sound device.
93  *
94  * After calling this function, the event queue is disabled.
95  *
96  * Context: Any context.
97  * Return: 0 on success, -errno on failure.
98  */
99 static int virtsnd_find_vqs(struct virtio_snd *snd)
100 {
101 	struct virtio_device *vdev = snd->vdev;
102 	static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
103 		[VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
104 		[VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb
105 	};
106 	static const char *names[VIRTIO_SND_VQ_MAX] = {
107 		[VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
108 		[VIRTIO_SND_VQ_EVENT] = "virtsnd-event"
109 	};
110 	struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
111 	unsigned int i;
112 	unsigned int n;
113 	int rc;
114 
115 	rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
116 			     NULL);
117 	if (rc) {
118 		dev_err(&vdev->dev, "failed to initialize virtqueues\n");
119 		return rc;
120 	}
121 
122 	for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
123 		snd->queues[i].vqueue = vqs[i];
124 
125 	/* Allocate events and populate the event queue */
126 	virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]);
127 
128 	n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]);
129 
130 	snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs),
131 					GFP_KERNEL);
132 	if (!snd->event_msgs)
133 		return -ENOMEM;
134 
135 	for (i = 0; i < n; ++i)
136 		virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT],
137 				   &snd->event_msgs[i], false, GFP_KERNEL);
138 
139 	return 0;
140 }
141 
142 /**
143  * virtsnd_enable_event_vq() - Enable the event virtqueue.
144  * @snd: VirtIO sound device.
145  *
146  * Context: Any context.
147  */
148 static void virtsnd_enable_event_vq(struct virtio_snd *snd)
149 {
150 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
151 
152 	if (!virtqueue_enable_cb(queue->vqueue))
153 		virtsnd_event_notify_cb(queue->vqueue);
154 }
155 
156 /**
157  * virtsnd_disable_event_vq() - Disable the event virtqueue.
158  * @snd: VirtIO sound device.
159  *
160  * Context: Any context.
161  */
162 static void virtsnd_disable_event_vq(struct virtio_snd *snd)
163 {
164 	struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
165 	struct virtio_snd_event *event;
166 	u32 length;
167 	unsigned long flags;
168 
169 	if (queue->vqueue) {
170 		spin_lock_irqsave(&queue->lock, flags);
171 		virtqueue_disable_cb(queue->vqueue);
172 		while ((event = virtqueue_get_buf(queue->vqueue, &length)))
173 			virtsnd_event_dispatch(snd, event);
174 		spin_unlock_irqrestore(&queue->lock, flags);
175 	}
176 }
177 
178 /**
179  * virtsnd_build_devs() - Read configuration and build ALSA devices.
180  * @snd: VirtIO sound device.
181  *
182  * Context: Any context that permits to sleep.
183  * Return: 0 on success, -errno on failure.
184  */
185 static int virtsnd_build_devs(struct virtio_snd *snd)
186 {
187 	struct virtio_device *vdev = snd->vdev;
188 	struct device *dev = &vdev->dev;
189 	int rc;
190 
191 	rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
192 			  THIS_MODULE, 0, &snd->card);
193 	if (rc < 0)
194 		return rc;
195 
196 	snd->card->private_data = snd;
197 
198 	strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
199 		sizeof(snd->card->driver));
200 	strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
201 		sizeof(snd->card->shortname));
202 	if (dev->parent->bus)
203 		snprintf(snd->card->longname, sizeof(snd->card->longname),
204 			 VIRTIO_SND_CARD_NAME " at %s/%s/%s",
205 			 dev->parent->bus->name, dev_name(dev->parent),
206 			 dev_name(dev));
207 	else
208 		snprintf(snd->card->longname, sizeof(snd->card->longname),
209 			 VIRTIO_SND_CARD_NAME " at %s/%s",
210 			 dev_name(dev->parent), dev_name(dev));
211 
212 	rc = virtsnd_pcm_parse_cfg(snd);
213 	if (rc)
214 		return rc;
215 
216 	if (snd->nsubstreams) {
217 		rc = virtsnd_pcm_build_devs(snd);
218 		if (rc)
219 			return rc;
220 	}
221 
222 	return snd_card_register(snd->card);
223 }
224 
225 /**
226  * virtsnd_validate() - Validate if the device can be started.
227  * @vdev: VirtIO parent device.
228  *
229  * Context: Any context.
230  * Return: 0 on success, -EINVAL on failure.
231  */
232 static int virtsnd_validate(struct virtio_device *vdev)
233 {
234 	if (!vdev->config->get) {
235 		dev_err(&vdev->dev, "configuration access disabled\n");
236 		return -EINVAL;
237 	}
238 
239 	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
240 		dev_err(&vdev->dev,
241 			"device does not comply with spec version 1.x\n");
242 		return -EINVAL;
243 	}
244 
245 	if (!virtsnd_msg_timeout_ms) {
246 		dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
247 		return -EINVAL;
248 	}
249 
250 	if (virtsnd_pcm_validate(vdev))
251 		return -EINVAL;
252 
253 	return 0;
254 }
255 
256 /**
257  * virtsnd_probe() - Create and initialize the device.
258  * @vdev: VirtIO parent device.
259  *
260  * Context: Any context that permits to sleep.
261  * Return: 0 on success, -errno on failure.
262  */
263 static int virtsnd_probe(struct virtio_device *vdev)
264 {
265 	struct virtio_snd *snd;
266 	unsigned int i;
267 	int rc;
268 
269 	snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL);
270 	if (!snd)
271 		return -ENOMEM;
272 
273 	snd->vdev = vdev;
274 	INIT_LIST_HEAD(&snd->ctl_msgs);
275 	INIT_LIST_HEAD(&snd->pcm_list);
276 
277 	vdev->priv = snd;
278 
279 	for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
280 		spin_lock_init(&snd->queues[i].lock);
281 
282 	rc = virtsnd_find_vqs(snd);
283 	if (rc)
284 		goto on_exit;
285 
286 	virtio_device_ready(vdev);
287 
288 	rc = virtsnd_build_devs(snd);
289 	if (rc)
290 		goto on_exit;
291 
292 	virtsnd_enable_event_vq(snd);
293 
294 on_exit:
295 	if (rc)
296 		virtsnd_remove(vdev);
297 
298 	return rc;
299 }
300 
301 /**
302  * virtsnd_remove() - Remove VirtIO and ALSA devices.
303  * @vdev: VirtIO parent device.
304  *
305  * Context: Any context that permits to sleep.
306  */
307 static void virtsnd_remove(struct virtio_device *vdev)
308 {
309 	struct virtio_snd *snd = vdev->priv;
310 	unsigned int i;
311 
312 	virtsnd_disable_event_vq(snd);
313 	virtsnd_ctl_msg_cancel_all(snd);
314 
315 	if (snd->card)
316 		snd_card_free(snd->card);
317 
318 	vdev->config->del_vqs(vdev);
319 	vdev->config->reset(vdev);
320 
321 	for (i = 0; snd->substreams && i < snd->nsubstreams; ++i)
322 		cancel_work_sync(&snd->substreams[i].elapsed_period);
323 
324 	kfree(snd->event_msgs);
325 }
326 
327 static const struct virtio_device_id id_table[] = {
328 	{ VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
329 	{ 0 },
330 };
331 
332 static struct virtio_driver virtsnd_driver = {
333 	.driver.name = KBUILD_MODNAME,
334 	.driver.owner = THIS_MODULE,
335 	.id_table = id_table,
336 	.validate = virtsnd_validate,
337 	.probe = virtsnd_probe,
338 	.remove = virtsnd_remove,
339 };
340 
341 static int __init init(void)
342 {
343 	return register_virtio_driver(&virtsnd_driver);
344 }
345 module_init(init);
346 
347 static void __exit fini(void)
348 {
349 	unregister_virtio_driver(&virtsnd_driver);
350 }
351 module_exit(fini);
352 
353 MODULE_DEVICE_TABLE(virtio, id_table);
354 MODULE_DESCRIPTION("Virtio sound card driver");
355 MODULE_LICENSE("GPL");
356