1
2
3
4
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
22
23
24
25
26
27
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
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
50
51
52
53
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 }
68}
69
70
71
72
73
74
75
76
77
78
79static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
80{
81 struct virtio_snd *snd = vqueue->vdev->priv;
82 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
83 struct virtio_snd_event *event;
84 u32 length;
85 unsigned long flags;
86
87 spin_lock_irqsave(&queue->lock, flags);
88 do {
89 virtqueue_disable_cb(vqueue);
90 while ((event = virtqueue_get_buf(vqueue, &length))) {
91 virtsnd_event_dispatch(snd, event);
92 virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
93 }
94 if (unlikely(virtqueue_is_broken(vqueue)))
95 break;
96 } while (!virtqueue_enable_cb(vqueue));
97 spin_unlock_irqrestore(&queue->lock, flags);
98}
99
100
101
102
103
104
105
106
107
108
109static int virtsnd_find_vqs(struct virtio_snd *snd)
110{
111 struct virtio_device *vdev = snd->vdev;
112 static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = {
113 [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb,
114 [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb,
115 [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb,
116 [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb
117 };
118 static const char *names[VIRTIO_SND_VQ_MAX] = {
119 [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl",
120 [VIRTIO_SND_VQ_EVENT] = "virtsnd-event",
121 [VIRTIO_SND_VQ_TX] = "virtsnd-tx",
122 [VIRTIO_SND_VQ_RX] = "virtsnd-rx"
123 };
124 struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 };
125 unsigned int i;
126 unsigned int n;
127 int rc;
128
129 rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names,
130 NULL);
131 if (rc) {
132 dev_err(&vdev->dev, "failed to initialize virtqueues\n");
133 return rc;
134 }
135
136 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
137 snd->queues[i].vqueue = vqs[i];
138
139
140 virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]);
141
142 n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]);
143
144 snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs),
145 GFP_KERNEL);
146 if (!snd->event_msgs)
147 return -ENOMEM;
148
149 for (i = 0; i < n; ++i)
150 virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT],
151 &snd->event_msgs[i], false, GFP_KERNEL);
152
153 return 0;
154}
155
156
157
158
159
160
161
162static void virtsnd_enable_event_vq(struct virtio_snd *snd)
163{
164 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
165
166 if (!virtqueue_enable_cb(queue->vqueue))
167 virtsnd_event_notify_cb(queue->vqueue);
168}
169
170
171
172
173
174
175
176static void virtsnd_disable_event_vq(struct virtio_snd *snd)
177{
178 struct virtio_snd_queue *queue = virtsnd_event_queue(snd);
179 struct virtio_snd_event *event;
180 u32 length;
181 unsigned long flags;
182
183 if (queue->vqueue) {
184 spin_lock_irqsave(&queue->lock, flags);
185 virtqueue_disable_cb(queue->vqueue);
186 while ((event = virtqueue_get_buf(queue->vqueue, &length)))
187 virtsnd_event_dispatch(snd, event);
188 spin_unlock_irqrestore(&queue->lock, flags);
189 }
190}
191
192
193
194
195
196
197
198
199static int virtsnd_build_devs(struct virtio_snd *snd)
200{
201 struct virtio_device *vdev = snd->vdev;
202 struct device *dev = &vdev->dev;
203 int rc;
204
205 rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
206 THIS_MODULE, 0, &snd->card);
207 if (rc < 0)
208 return rc;
209
210 snd->card->private_data = snd;
211
212 strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER,
213 sizeof(snd->card->driver));
214 strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME,
215 sizeof(snd->card->shortname));
216 if (dev->parent->bus)
217 snprintf(snd->card->longname, sizeof(snd->card->longname),
218 VIRTIO_SND_CARD_NAME " at %s/%s/%s",
219 dev->parent->bus->name, dev_name(dev->parent),
220 dev_name(dev));
221 else
222 snprintf(snd->card->longname, sizeof(snd->card->longname),
223 VIRTIO_SND_CARD_NAME " at %s/%s",
224 dev_name(dev->parent), dev_name(dev));
225
226 rc = virtsnd_jack_parse_cfg(snd);
227 if (rc)
228 return rc;
229
230 rc = virtsnd_pcm_parse_cfg(snd);
231 if (rc)
232 return rc;
233
234 rc = virtsnd_chmap_parse_cfg(snd);
235 if (rc)
236 return rc;
237
238 if (snd->njacks) {
239 rc = virtsnd_jack_build_devs(snd);
240 if (rc)
241 return rc;
242 }
243
244 if (snd->nsubstreams) {
245 rc = virtsnd_pcm_build_devs(snd);
246 if (rc)
247 return rc;
248 }
249
250 if (snd->nchmaps) {
251 rc = virtsnd_chmap_build_devs(snd);
252 if (rc)
253 return rc;
254 }
255
256 return snd_card_register(snd->card);
257}
258
259
260
261
262
263
264
265
266static int virtsnd_validate(struct virtio_device *vdev)
267{
268 if (!vdev->config->get) {
269 dev_err(&vdev->dev, "configuration access disabled\n");
270 return -EINVAL;
271 }
272
273 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
274 dev_err(&vdev->dev,
275 "device does not comply with spec version 1.x\n");
276 return -EINVAL;
277 }
278
279 if (!virtsnd_msg_timeout_ms) {
280 dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n");
281 return -EINVAL;
282 }
283
284 if (virtsnd_pcm_validate(vdev))
285 return -EINVAL;
286
287 return 0;
288}
289
290
291
292
293
294
295
296
297static int virtsnd_probe(struct virtio_device *vdev)
298{
299 struct virtio_snd *snd;
300 unsigned int i;
301 int rc;
302
303 snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL);
304 if (!snd)
305 return -ENOMEM;
306
307 snd->vdev = vdev;
308 INIT_LIST_HEAD(&snd->ctl_msgs);
309 INIT_LIST_HEAD(&snd->pcm_list);
310
311 vdev->priv = snd;
312
313 for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
314 spin_lock_init(&snd->queues[i].lock);
315
316 rc = virtsnd_find_vqs(snd);
317 if (rc)
318 goto on_exit;
319
320 virtio_device_ready(vdev);
321
322 rc = virtsnd_build_devs(snd);
323 if (rc)
324 goto on_exit;
325
326 virtsnd_enable_event_vq(snd);
327
328on_exit:
329 if (rc)
330 virtsnd_remove(vdev);
331
332 return rc;
333}
334
335
336
337
338
339
340
341static void virtsnd_remove(struct virtio_device *vdev)
342{
343 struct virtio_snd *snd = vdev->priv;
344 unsigned int i;
345
346 virtsnd_disable_event_vq(snd);
347 virtsnd_ctl_msg_cancel_all(snd);
348
349 if (snd->card)
350 snd_card_free(snd->card);
351
352 vdev->config->del_vqs(vdev);
353 vdev->config->reset(vdev);
354
355 for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
356 struct virtio_pcm_substream *vss = &snd->substreams[i];
357
358 cancel_work_sync(&vss->elapsed_period);
359 virtsnd_pcm_msg_free(vss);
360 }
361
362 kfree(snd->event_msgs);
363}
364
365#ifdef CONFIG_PM_SLEEP
366
367
368
369
370
371
372
373static int virtsnd_freeze(struct virtio_device *vdev)
374{
375 struct virtio_snd *snd = vdev->priv;
376 unsigned int i;
377
378 virtsnd_disable_event_vq(snd);
379 virtsnd_ctl_msg_cancel_all(snd);
380
381 vdev->config->del_vqs(vdev);
382 vdev->config->reset(vdev);
383
384 for (i = 0; i < snd->nsubstreams; ++i)
385 cancel_work_sync(&snd->substreams[i].elapsed_period);
386
387 kfree(snd->event_msgs);
388 snd->event_msgs = NULL;
389
390 return 0;
391}
392
393
394
395
396
397
398
399
400static int virtsnd_restore(struct virtio_device *vdev)
401{
402 struct virtio_snd *snd = vdev->priv;
403 int rc;
404
405 rc = virtsnd_find_vqs(snd);
406 if (rc)
407 return rc;
408
409 virtio_device_ready(vdev);
410
411 virtsnd_enable_event_vq(snd);
412
413 return 0;
414}
415#endif
416
417static const struct virtio_device_id id_table[] = {
418 { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID },
419 { 0 },
420};
421
422static struct virtio_driver virtsnd_driver = {
423 .driver.name = KBUILD_MODNAME,
424 .driver.owner = THIS_MODULE,
425 .id_table = id_table,
426 .validate = virtsnd_validate,
427 .probe = virtsnd_probe,
428 .remove = virtsnd_remove,
429#ifdef CONFIG_PM_SLEEP
430 .freeze = virtsnd_freeze,
431 .restore = virtsnd_restore,
432#endif
433};
434
435module_virtio_driver(virtsnd_driver);
436
437MODULE_DEVICE_TABLE(virtio, id_table);
438MODULE_DESCRIPTION("Virtio sound card driver");
439MODULE_LICENSE("GPL");
440