Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/virtio/virtio_pcm_ops.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
* virtio-snd: Virtio sound device
4
* Copyright (C) 2021 OpenSynergy GmbH
5
*/
6
#include <sound/pcm_params.h>
7
8
#include "virtio_card.h"
9
10
/*
11
* I/O messages lifetime
12
* ---------------------
13
*
14
* Allocation:
15
* Messages are initially allocated in the ops->hw_params() after the size and
16
* number of periods have been successfully negotiated.
17
*
18
* Freeing:
19
* Messages can be safely freed after the queue has been successfully flushed
20
* (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been
21
* called.
22
*
23
* When the substream stops, the ops->sync_stop() waits until the device has
24
* completed all pending messages. This wait can be interrupted either by a
25
* signal or due to a timeout. In this case, the device can still access
26
* messages even after calling ops->hw_free(). It can also issue an interrupt,
27
* and the interrupt handler will also try to access message structures.
28
*
29
* Therefore, freeing of already allocated messages occurs:
30
*
31
* - in ops->hw_params(), if this operator was called several times in a row,
32
* or if ops->hw_free() failed to free messages previously;
33
*
34
* - in ops->hw_free(), if the queue has been successfully flushed;
35
*
36
* - in dev->release().
37
*/
38
39
/* Map for converting ALSA format to VirtIO format. */
40
struct virtsnd_a2v_format {
41
snd_pcm_format_t alsa_bit;
42
unsigned int vio_bit;
43
};
44
45
static const struct virtsnd_a2v_format g_a2v_format_map[] = {
46
{ SNDRV_PCM_FORMAT_IMA_ADPCM, VIRTIO_SND_PCM_FMT_IMA_ADPCM },
47
{ SNDRV_PCM_FORMAT_MU_LAW, VIRTIO_SND_PCM_FMT_MU_LAW },
48
{ SNDRV_PCM_FORMAT_A_LAW, VIRTIO_SND_PCM_FMT_A_LAW },
49
{ SNDRV_PCM_FORMAT_S8, VIRTIO_SND_PCM_FMT_S8 },
50
{ SNDRV_PCM_FORMAT_U8, VIRTIO_SND_PCM_FMT_U8 },
51
{ SNDRV_PCM_FORMAT_S16_LE, VIRTIO_SND_PCM_FMT_S16 },
52
{ SNDRV_PCM_FORMAT_U16_LE, VIRTIO_SND_PCM_FMT_U16 },
53
{ SNDRV_PCM_FORMAT_S18_3LE, VIRTIO_SND_PCM_FMT_S18_3 },
54
{ SNDRV_PCM_FORMAT_U18_3LE, VIRTIO_SND_PCM_FMT_U18_3 },
55
{ SNDRV_PCM_FORMAT_S20_3LE, VIRTIO_SND_PCM_FMT_S20_3 },
56
{ SNDRV_PCM_FORMAT_U20_3LE, VIRTIO_SND_PCM_FMT_U20_3 },
57
{ SNDRV_PCM_FORMAT_S24_3LE, VIRTIO_SND_PCM_FMT_S24_3 },
58
{ SNDRV_PCM_FORMAT_U24_3LE, VIRTIO_SND_PCM_FMT_U24_3 },
59
{ SNDRV_PCM_FORMAT_S20_LE, VIRTIO_SND_PCM_FMT_S20 },
60
{ SNDRV_PCM_FORMAT_U20_LE, VIRTIO_SND_PCM_FMT_U20 },
61
{ SNDRV_PCM_FORMAT_S24_LE, VIRTIO_SND_PCM_FMT_S24 },
62
{ SNDRV_PCM_FORMAT_U24_LE, VIRTIO_SND_PCM_FMT_U24 },
63
{ SNDRV_PCM_FORMAT_S32_LE, VIRTIO_SND_PCM_FMT_S32 },
64
{ SNDRV_PCM_FORMAT_U32_LE, VIRTIO_SND_PCM_FMT_U32 },
65
{ SNDRV_PCM_FORMAT_FLOAT_LE, VIRTIO_SND_PCM_FMT_FLOAT },
66
{ SNDRV_PCM_FORMAT_FLOAT64_LE, VIRTIO_SND_PCM_FMT_FLOAT64 },
67
{ SNDRV_PCM_FORMAT_DSD_U8, VIRTIO_SND_PCM_FMT_DSD_U8 },
68
{ SNDRV_PCM_FORMAT_DSD_U16_LE, VIRTIO_SND_PCM_FMT_DSD_U16 },
69
{ SNDRV_PCM_FORMAT_DSD_U32_LE, VIRTIO_SND_PCM_FMT_DSD_U32 },
70
{ SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE,
71
VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME }
72
};
73
74
/* Map for converting ALSA frame rate to VirtIO frame rate. */
75
struct virtsnd_a2v_rate {
76
unsigned int rate;
77
unsigned int vio_bit;
78
};
79
80
static const struct virtsnd_a2v_rate g_a2v_rate_map[] = {
81
{ 5512, VIRTIO_SND_PCM_RATE_5512 },
82
{ 8000, VIRTIO_SND_PCM_RATE_8000 },
83
{ 11025, VIRTIO_SND_PCM_RATE_11025 },
84
{ 16000, VIRTIO_SND_PCM_RATE_16000 },
85
{ 22050, VIRTIO_SND_PCM_RATE_22050 },
86
{ 32000, VIRTIO_SND_PCM_RATE_32000 },
87
{ 44100, VIRTIO_SND_PCM_RATE_44100 },
88
{ 48000, VIRTIO_SND_PCM_RATE_48000 },
89
{ 64000, VIRTIO_SND_PCM_RATE_64000 },
90
{ 88200, VIRTIO_SND_PCM_RATE_88200 },
91
{ 96000, VIRTIO_SND_PCM_RATE_96000 },
92
{ 176400, VIRTIO_SND_PCM_RATE_176400 },
93
{ 192000, VIRTIO_SND_PCM_RATE_192000 }
94
};
95
96
static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream);
97
98
/**
99
* virtsnd_pcm_open() - Open the PCM substream.
100
* @substream: Kernel ALSA substream.
101
*
102
* Context: Process context.
103
* Return: 0 on success, -errno on failure.
104
*/
105
static int virtsnd_pcm_open(struct snd_pcm_substream *substream)
106
{
107
struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream);
108
struct virtio_pcm_stream *vs = &vpcm->streams[substream->stream];
109
struct virtio_pcm_substream *vss = vs->substreams[substream->number];
110
111
substream->runtime->hw = vss->hw;
112
substream->private_data = vss;
113
114
snd_pcm_hw_constraint_integer(substream->runtime,
115
SNDRV_PCM_HW_PARAM_PERIODS);
116
117
vss->stopped = !!virtsnd_pcm_msg_pending_num(vss);
118
vss->suspended = false;
119
120
/*
121
* If the substream has already been used, then the I/O queue may be in
122
* an invalid state. Just in case, we do a check and try to return the
123
* queue to its original state, if necessary.
124
*/
125
return virtsnd_pcm_sync_stop(substream);
126
}
127
128
/**
129
* virtsnd_pcm_close() - Close the PCM substream.
130
* @substream: Kernel ALSA substream.
131
*
132
* Context: Process context.
133
* Return: 0.
134
*/
135
static int virtsnd_pcm_close(struct snd_pcm_substream *substream)
136
{
137
return 0;
138
}
139
140
/**
141
* virtsnd_pcm_dev_set_params() - Set the parameters of the PCM substream on
142
* the device side.
143
* @vss: VirtIO PCM substream.
144
* @buffer_bytes: Size of the hardware buffer.
145
* @period_bytes: Size of the hardware period.
146
* @channels: Selected number of channels.
147
* @format: Selected sample format (SNDRV_PCM_FORMAT_XXX).
148
* @rate: Selected frame rate.
149
*
150
* Context: Any context that permits to sleep.
151
* Return: 0 on success, -errno on failure.
152
*/
153
static int virtsnd_pcm_dev_set_params(struct virtio_pcm_substream *vss,
154
unsigned int buffer_bytes,
155
unsigned int period_bytes,
156
unsigned int channels,
157
snd_pcm_format_t format,
158
unsigned int rate)
159
{
160
struct virtio_snd_msg *msg;
161
struct virtio_snd_pcm_set_params *request;
162
unsigned int i;
163
int vformat = -1;
164
int vrate = -1;
165
166
for (i = 0; i < ARRAY_SIZE(g_a2v_format_map); ++i)
167
if (g_a2v_format_map[i].alsa_bit == format) {
168
vformat = g_a2v_format_map[i].vio_bit;
169
170
break;
171
}
172
173
for (i = 0; i < ARRAY_SIZE(g_a2v_rate_map); ++i)
174
if (g_a2v_rate_map[i].rate == rate) {
175
vrate = g_a2v_rate_map[i].vio_bit;
176
177
break;
178
}
179
180
if (vformat == -1 || vrate == -1)
181
return -EINVAL;
182
183
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_SET_PARAMS,
184
GFP_KERNEL);
185
if (!msg)
186
return -ENOMEM;
187
188
request = virtsnd_ctl_msg_request(msg);
189
request->buffer_bytes = cpu_to_le32(buffer_bytes);
190
request->period_bytes = cpu_to_le32(period_bytes);
191
request->channels = channels;
192
request->format = vformat;
193
request->rate = vrate;
194
195
if (vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING))
196
request->features |=
197
cpu_to_le32(1U << VIRTIO_SND_PCM_F_MSG_POLLING);
198
199
if (vss->features & (1U << VIRTIO_SND_PCM_F_EVT_XRUNS))
200
request->features |=
201
cpu_to_le32(1U << VIRTIO_SND_PCM_F_EVT_XRUNS);
202
203
return virtsnd_ctl_msg_send_sync(vss->snd, msg);
204
}
205
206
/**
207
* virtsnd_pcm_hw_params() - Set the parameters of the PCM substream.
208
* @substream: Kernel ALSA substream.
209
* @hw_params: Hardware parameters.
210
*
211
* Context: Process context.
212
* Return: 0 on success, -errno on failure.
213
*/
214
static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream,
215
struct snd_pcm_hw_params *hw_params)
216
{
217
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
218
struct virtio_device *vdev = vss->snd->vdev;
219
int rc;
220
221
if (virtsnd_pcm_msg_pending_num(vss)) {
222
dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
223
vss->sid);
224
return -EBADFD;
225
}
226
227
rc = virtsnd_pcm_dev_set_params(vss, params_buffer_bytes(hw_params),
228
params_period_bytes(hw_params),
229
params_channels(hw_params),
230
params_format(hw_params),
231
params_rate(hw_params));
232
if (rc)
233
return rc;
234
235
/*
236
* Free previously allocated messages if ops->hw_params() is called
237
* several times in a row, or if ops->hw_free() failed to free messages.
238
*/
239
virtsnd_pcm_msg_free(vss);
240
241
return virtsnd_pcm_msg_alloc(vss, params_periods(hw_params),
242
params_period_bytes(hw_params));
243
}
244
245
/**
246
* virtsnd_pcm_hw_free() - Reset the parameters of the PCM substream.
247
* @substream: Kernel ALSA substream.
248
*
249
* Context: Process context.
250
* Return: 0
251
*/
252
static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream)
253
{
254
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
255
256
/* If the queue is flushed, we can safely free the messages here. */
257
if (!virtsnd_pcm_msg_pending_num(vss))
258
virtsnd_pcm_msg_free(vss);
259
260
return 0;
261
}
262
263
/**
264
* virtsnd_pcm_prepare() - Prepare the PCM substream.
265
* @substream: Kernel ALSA substream.
266
*
267
* Context: Process context.
268
* Return: 0 on success, -errno on failure.
269
*/
270
static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
271
{
272
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
273
struct virtio_device *vdev = vss->snd->vdev;
274
struct virtio_snd_msg *msg;
275
276
if (!vss->suspended) {
277
if (virtsnd_pcm_msg_pending_num(vss)) {
278
dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n",
279
vss->sid);
280
return -EBADFD;
281
}
282
283
vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
284
vss->hw_ptr = 0;
285
} else {
286
struct snd_pcm_runtime *runtime = substream->runtime;
287
unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
288
unsigned int period_bytes = snd_pcm_lib_period_bytes(substream);
289
int rc;
290
291
rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes,
292
runtime->channels,
293
runtime->format, runtime->rate);
294
if (rc)
295
return rc;
296
}
297
298
vss->xfer_xrun = false;
299
vss->suspended = false;
300
vss->msg_count = 0;
301
302
memset(&vss->pcm_indirect, 0, sizeof(vss->pcm_indirect));
303
vss->pcm_indirect.sw_buffer_size =
304
vss->pcm_indirect.hw_buffer_size =
305
snd_pcm_lib_buffer_bytes(substream);
306
307
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE,
308
GFP_KERNEL);
309
if (!msg)
310
return -ENOMEM;
311
312
return virtsnd_ctl_msg_send_sync(vss->snd, msg);
313
}
314
315
/**
316
* virtsnd_pcm_trigger() - Process command for the PCM substream.
317
* @substream: Kernel ALSA substream.
318
* @command: Substream command (SNDRV_PCM_TRIGGER_XXX).
319
*
320
* Context: Any context. Takes and releases the VirtIO substream spinlock.
321
* May take and release the tx/rx queue spinlock.
322
* Return: 0 on success, -errno on failure.
323
*/
324
static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command)
325
{
326
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
327
struct virtio_snd *snd = vss->snd;
328
struct virtio_snd_queue *queue;
329
struct virtio_snd_msg *msg;
330
unsigned long flags;
331
int rc = 0;
332
333
switch (command) {
334
case SNDRV_PCM_TRIGGER_START:
335
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
336
queue = virtsnd_pcm_queue(vss);
337
338
spin_lock_irqsave(&queue->lock, flags);
339
spin_lock(&vss->lock);
340
if (vss->direction == SNDRV_PCM_STREAM_CAPTURE)
341
rc = virtsnd_pcm_msg_send(vss, 0, vss->buffer_bytes);
342
if (!rc)
343
vss->xfer_enabled = true;
344
spin_unlock(&vss->lock);
345
spin_unlock_irqrestore(&queue->lock, flags);
346
if (rc)
347
return rc;
348
349
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START,
350
GFP_KERNEL);
351
if (!msg) {
352
spin_lock_irqsave(&vss->lock, flags);
353
vss->xfer_enabled = false;
354
spin_unlock_irqrestore(&vss->lock, flags);
355
356
return -ENOMEM;
357
}
358
359
return virtsnd_ctl_msg_send_sync(snd, msg);
360
case SNDRV_PCM_TRIGGER_SUSPEND:
361
vss->suspended = true;
362
fallthrough;
363
case SNDRV_PCM_TRIGGER_STOP:
364
vss->stopped = true;
365
fallthrough;
366
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
367
spin_lock_irqsave(&vss->lock, flags);
368
vss->xfer_enabled = false;
369
spin_unlock_irqrestore(&vss->lock, flags);
370
371
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP,
372
GFP_KERNEL);
373
if (!msg)
374
return -ENOMEM;
375
376
return virtsnd_ctl_msg_send_sync(snd, msg);
377
default:
378
return -EINVAL;
379
}
380
}
381
382
/**
383
* virtsnd_pcm_sync_stop() - Synchronous PCM substream stop.
384
* @substream: Kernel ALSA substream.
385
*
386
* The function can be called both from the upper level or from the driver
387
* itself.
388
*
389
* Context: Process context. Takes and releases the VirtIO substream spinlock.
390
* Return: 0 on success, -errno on failure.
391
*/
392
static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream)
393
{
394
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
395
struct virtio_snd *snd = vss->snd;
396
struct virtio_snd_msg *msg;
397
unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms);
398
int rc;
399
400
cancel_work_sync(&vss->elapsed_period);
401
402
if (!vss->stopped)
403
return 0;
404
405
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE,
406
GFP_KERNEL);
407
if (!msg)
408
return -ENOMEM;
409
410
rc = virtsnd_ctl_msg_send_sync(snd, msg);
411
if (rc)
412
return rc;
413
414
/*
415
* The spec states that upon receipt of the RELEASE command "the device
416
* MUST complete all pending I/O messages for the specified stream ID".
417
* Thus, we consider the absence of I/O messages in the queue as an
418
* indication that the substream has been released.
419
*/
420
rc = wait_event_interruptible_timeout(vss->msg_empty,
421
!virtsnd_pcm_msg_pending_num(vss),
422
js);
423
if (rc <= 0) {
424
dev_warn(&snd->vdev->dev, "SID %u: failed to flush I/O queue\n",
425
vss->sid);
426
427
return !rc ? -ETIMEDOUT : rc;
428
}
429
430
vss->stopped = false;
431
432
return 0;
433
}
434
435
/**
436
* virtsnd_pcm_pb_pointer() - Get the current hardware position for the PCM
437
* substream for playback.
438
* @substream: Kernel ALSA substream.
439
*
440
* Context: Any context.
441
* Return: Hardware position in frames inside [0 ... buffer_size) range.
442
*/
443
static snd_pcm_uframes_t
444
virtsnd_pcm_pb_pointer(struct snd_pcm_substream *substream)
445
{
446
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
447
448
return snd_pcm_indirect_playback_pointer(substream,
449
&vss->pcm_indirect,
450
vss->hw_ptr);
451
}
452
453
/**
454
* virtsnd_pcm_cp_pointer() - Get the current hardware position for the PCM
455
* substream for capture.
456
* @substream: Kernel ALSA substream.
457
*
458
* Context: Any context.
459
* Return: Hardware position in frames inside [0 ... buffer_size) range.
460
*/
461
static snd_pcm_uframes_t
462
virtsnd_pcm_cp_pointer(struct snd_pcm_substream *substream)
463
{
464
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
465
466
return snd_pcm_indirect_capture_pointer(substream,
467
&vss->pcm_indirect,
468
vss->hw_ptr);
469
}
470
471
static void virtsnd_pcm_trans_copy(struct snd_pcm_substream *substream,
472
struct snd_pcm_indirect *rec, size_t bytes)
473
{
474
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
475
476
virtsnd_pcm_msg_send(vss, rec->sw_data, bytes);
477
}
478
479
static int virtsnd_pcm_pb_ack(struct snd_pcm_substream *substream)
480
{
481
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
482
struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss);
483
unsigned long flags;
484
int rc;
485
486
spin_lock_irqsave(&queue->lock, flags);
487
spin_lock(&vss->lock);
488
489
rc = snd_pcm_indirect_playback_transfer(substream, &vss->pcm_indirect,
490
virtsnd_pcm_trans_copy);
491
492
spin_unlock(&vss->lock);
493
spin_unlock_irqrestore(&queue->lock, flags);
494
495
return rc;
496
}
497
498
static int virtsnd_pcm_cp_ack(struct snd_pcm_substream *substream)
499
{
500
struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
501
struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss);
502
unsigned long flags;
503
int rc;
504
505
spin_lock_irqsave(&queue->lock, flags);
506
spin_lock(&vss->lock);
507
508
rc = snd_pcm_indirect_capture_transfer(substream, &vss->pcm_indirect,
509
virtsnd_pcm_trans_copy);
510
511
spin_unlock(&vss->lock);
512
spin_unlock_irqrestore(&queue->lock, flags);
513
514
return rc;
515
}
516
517
/* PCM substream operators map. */
518
const struct snd_pcm_ops virtsnd_pcm_ops[] = {
519
{
520
.open = virtsnd_pcm_open,
521
.close = virtsnd_pcm_close,
522
.ioctl = snd_pcm_lib_ioctl,
523
.hw_params = virtsnd_pcm_hw_params,
524
.hw_free = virtsnd_pcm_hw_free,
525
.prepare = virtsnd_pcm_prepare,
526
.trigger = virtsnd_pcm_trigger,
527
.sync_stop = virtsnd_pcm_sync_stop,
528
.pointer = virtsnd_pcm_pb_pointer,
529
.ack = virtsnd_pcm_pb_ack,
530
},
531
{
532
.open = virtsnd_pcm_open,
533
.close = virtsnd_pcm_close,
534
.ioctl = snd_pcm_lib_ioctl,
535
.hw_params = virtsnd_pcm_hw_params,
536
.hw_free = virtsnd_pcm_hw_free,
537
.prepare = virtsnd_pcm_prepare,
538
.trigger = virtsnd_pcm_trigger,
539
.sync_stop = virtsnd_pcm_sync_stop,
540
.pointer = virtsnd_pcm_cp_pointer,
541
.ack = virtsnd_pcm_cp_ack,
542
},
543
};
544
545