Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pci/ctxfi/ctpcm.c
10820 views
1
/**
2
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
3
*
4
* This source file is released under GPL v2 license (no other versions).
5
* See the COPYING file included in the main directory of this source
6
* distribution for the license terms and conditions.
7
*
8
* @File ctpcm.c
9
*
10
* @Brief
11
* This file contains the definition of the pcm device functions.
12
*
13
* @Author Liu Chun
14
* @Date Apr 2 2008
15
*
16
*/
17
18
#include "ctpcm.h"
19
#include "cttimer.h"
20
#include <linux/slab.h>
21
#include <sound/pcm.h>
22
23
/* Hardware descriptions for playback */
24
static struct snd_pcm_hardware ct_pcm_playback_hw = {
25
.info = (SNDRV_PCM_INFO_MMAP |
26
SNDRV_PCM_INFO_INTERLEAVED |
27
SNDRV_PCM_INFO_BLOCK_TRANSFER |
28
SNDRV_PCM_INFO_MMAP_VALID |
29
SNDRV_PCM_INFO_PAUSE),
30
.formats = (SNDRV_PCM_FMTBIT_U8 |
31
SNDRV_PCM_FMTBIT_S16_LE |
32
SNDRV_PCM_FMTBIT_S24_3LE |
33
SNDRV_PCM_FMTBIT_S32_LE |
34
SNDRV_PCM_FMTBIT_FLOAT_LE),
35
.rates = (SNDRV_PCM_RATE_CONTINUOUS |
36
SNDRV_PCM_RATE_8000_192000),
37
.rate_min = 8000,
38
.rate_max = 192000,
39
.channels_min = 1,
40
.channels_max = 2,
41
.buffer_bytes_max = (128*1024),
42
.period_bytes_min = (64),
43
.period_bytes_max = (128*1024),
44
.periods_min = 2,
45
.periods_max = 1024,
46
.fifo_size = 0,
47
};
48
49
static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
50
.info = (SNDRV_PCM_INFO_MMAP |
51
SNDRV_PCM_INFO_INTERLEAVED |
52
SNDRV_PCM_INFO_BLOCK_TRANSFER |
53
SNDRV_PCM_INFO_MMAP_VALID |
54
SNDRV_PCM_INFO_PAUSE),
55
.formats = SNDRV_PCM_FMTBIT_S16_LE,
56
.rates = (SNDRV_PCM_RATE_48000 |
57
SNDRV_PCM_RATE_44100 |
58
SNDRV_PCM_RATE_32000),
59
.rate_min = 32000,
60
.rate_max = 48000,
61
.channels_min = 2,
62
.channels_max = 2,
63
.buffer_bytes_max = (128*1024),
64
.period_bytes_min = (64),
65
.period_bytes_max = (128*1024),
66
.periods_min = 2,
67
.periods_max = 1024,
68
.fifo_size = 0,
69
};
70
71
/* Hardware descriptions for capture */
72
static struct snd_pcm_hardware ct_pcm_capture_hw = {
73
.info = (SNDRV_PCM_INFO_MMAP |
74
SNDRV_PCM_INFO_INTERLEAVED |
75
SNDRV_PCM_INFO_BLOCK_TRANSFER |
76
SNDRV_PCM_INFO_PAUSE |
77
SNDRV_PCM_INFO_MMAP_VALID),
78
.formats = (SNDRV_PCM_FMTBIT_U8 |
79
SNDRV_PCM_FMTBIT_S16_LE |
80
SNDRV_PCM_FMTBIT_S24_3LE |
81
SNDRV_PCM_FMTBIT_S32_LE |
82
SNDRV_PCM_FMTBIT_FLOAT_LE),
83
.rates = (SNDRV_PCM_RATE_CONTINUOUS |
84
SNDRV_PCM_RATE_8000_96000),
85
.rate_min = 8000,
86
.rate_max = 96000,
87
.channels_min = 1,
88
.channels_max = 2,
89
.buffer_bytes_max = (128*1024),
90
.period_bytes_min = (384),
91
.period_bytes_max = (64*1024),
92
.periods_min = 2,
93
.periods_max = 1024,
94
.fifo_size = 0,
95
};
96
97
static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
98
{
99
struct ct_atc_pcm *apcm = atc_pcm;
100
101
if (!apcm->substream)
102
return;
103
104
snd_pcm_period_elapsed(apcm->substream);
105
}
106
107
static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
108
{
109
struct ct_atc_pcm *apcm = runtime->private_data;
110
struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
111
112
atc->pcm_release_resources(atc, apcm);
113
ct_timer_instance_free(apcm->timer);
114
kfree(apcm);
115
runtime->private_data = NULL;
116
}
117
118
/* pcm playback operations */
119
static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
120
{
121
struct ct_atc *atc = snd_pcm_substream_chip(substream);
122
struct snd_pcm_runtime *runtime = substream->runtime;
123
struct ct_atc_pcm *apcm;
124
int err;
125
126
apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
127
if (!apcm)
128
return -ENOMEM;
129
130
apcm->substream = substream;
131
apcm->interrupt = ct_atc_pcm_interrupt;
132
if (IEC958 == substream->pcm->device) {
133
runtime->hw = ct_spdif_passthru_playback_hw;
134
atc->spdif_out_passthru(atc, 1);
135
} else {
136
runtime->hw = ct_pcm_playback_hw;
137
if (FRONT == substream->pcm->device)
138
runtime->hw.channels_max = 8;
139
}
140
141
err = snd_pcm_hw_constraint_integer(runtime,
142
SNDRV_PCM_HW_PARAM_PERIODS);
143
if (err < 0) {
144
kfree(apcm);
145
return err;
146
}
147
err = snd_pcm_hw_constraint_minmax(runtime,
148
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
149
1024, UINT_MAX);
150
if (err < 0) {
151
kfree(apcm);
152
return err;
153
}
154
155
apcm->timer = ct_timer_instance_new(atc->timer, apcm);
156
if (!apcm->timer) {
157
kfree(apcm);
158
return -ENOMEM;
159
}
160
runtime->private_data = apcm;
161
runtime->private_free = ct_atc_pcm_free_substream;
162
163
return 0;
164
}
165
166
static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
167
{
168
struct ct_atc *atc = snd_pcm_substream_chip(substream);
169
170
/* TODO: Notify mixer inactive. */
171
if (IEC958 == substream->pcm->device)
172
atc->spdif_out_passthru(atc, 0);
173
174
/* The ct_atc_pcm object will be freed by runtime->private_free */
175
176
return 0;
177
}
178
179
static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
180
struct snd_pcm_hw_params *hw_params)
181
{
182
struct ct_atc *atc = snd_pcm_substream_chip(substream);
183
struct ct_atc_pcm *apcm = substream->runtime->private_data;
184
int err;
185
186
err = snd_pcm_lib_malloc_pages(substream,
187
params_buffer_bytes(hw_params));
188
if (err < 0)
189
return err;
190
/* clear previous resources */
191
atc->pcm_release_resources(atc, apcm);
192
return err;
193
}
194
195
static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
196
{
197
struct ct_atc *atc = snd_pcm_substream_chip(substream);
198
struct ct_atc_pcm *apcm = substream->runtime->private_data;
199
200
/* clear previous resources */
201
atc->pcm_release_resources(atc, apcm);
202
/* Free snd-allocated pages */
203
return snd_pcm_lib_free_pages(substream);
204
}
205
206
207
static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
208
{
209
int err;
210
struct ct_atc *atc = snd_pcm_substream_chip(substream);
211
struct snd_pcm_runtime *runtime = substream->runtime;
212
struct ct_atc_pcm *apcm = runtime->private_data;
213
214
if (IEC958 == substream->pcm->device)
215
err = atc->spdif_passthru_playback_prepare(atc, apcm);
216
else
217
err = atc->pcm_playback_prepare(atc, apcm);
218
219
if (err < 0) {
220
printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
221
return err;
222
}
223
224
return 0;
225
}
226
227
static int
228
ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
229
{
230
struct ct_atc *atc = snd_pcm_substream_chip(substream);
231
struct snd_pcm_runtime *runtime = substream->runtime;
232
struct ct_atc_pcm *apcm = runtime->private_data;
233
234
switch (cmd) {
235
case SNDRV_PCM_TRIGGER_START:
236
case SNDRV_PCM_TRIGGER_RESUME:
237
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
238
atc->pcm_playback_start(atc, apcm);
239
break;
240
case SNDRV_PCM_TRIGGER_STOP:
241
case SNDRV_PCM_TRIGGER_SUSPEND:
242
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
243
atc->pcm_playback_stop(atc, apcm);
244
break;
245
default:
246
break;
247
}
248
249
return 0;
250
}
251
252
static snd_pcm_uframes_t
253
ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
254
{
255
unsigned long position;
256
struct ct_atc *atc = snd_pcm_substream_chip(substream);
257
struct snd_pcm_runtime *runtime = substream->runtime;
258
struct ct_atc_pcm *apcm = runtime->private_data;
259
260
/* Read out playback position */
261
position = atc->pcm_playback_position(atc, apcm);
262
position = bytes_to_frames(runtime, position);
263
if (position >= runtime->buffer_size)
264
position = 0;
265
return position;
266
}
267
268
/* pcm capture operations */
269
static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
270
{
271
struct ct_atc *atc = snd_pcm_substream_chip(substream);
272
struct snd_pcm_runtime *runtime = substream->runtime;
273
struct ct_atc_pcm *apcm;
274
int err;
275
276
apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
277
if (!apcm)
278
return -ENOMEM;
279
280
apcm->started = 0;
281
apcm->substream = substream;
282
apcm->interrupt = ct_atc_pcm_interrupt;
283
runtime->hw = ct_pcm_capture_hw;
284
runtime->hw.rate_max = atc->rsr * atc->msr;
285
286
err = snd_pcm_hw_constraint_integer(runtime,
287
SNDRV_PCM_HW_PARAM_PERIODS);
288
if (err < 0) {
289
kfree(apcm);
290
return err;
291
}
292
err = snd_pcm_hw_constraint_minmax(runtime,
293
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
294
1024, UINT_MAX);
295
if (err < 0) {
296
kfree(apcm);
297
return err;
298
}
299
300
apcm->timer = ct_timer_instance_new(atc->timer, apcm);
301
if (!apcm->timer) {
302
kfree(apcm);
303
return -ENOMEM;
304
}
305
runtime->private_data = apcm;
306
runtime->private_free = ct_atc_pcm_free_substream;
307
308
return 0;
309
}
310
311
static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
312
{
313
/* The ct_atc_pcm object will be freed by runtime->private_free */
314
/* TODO: Notify mixer inactive. */
315
return 0;
316
}
317
318
static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
319
{
320
int err;
321
struct ct_atc *atc = snd_pcm_substream_chip(substream);
322
struct snd_pcm_runtime *runtime = substream->runtime;
323
struct ct_atc_pcm *apcm = runtime->private_data;
324
325
err = atc->pcm_capture_prepare(atc, apcm);
326
if (err < 0) {
327
printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
328
return err;
329
}
330
331
return 0;
332
}
333
334
static int
335
ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
336
{
337
struct ct_atc *atc = snd_pcm_substream_chip(substream);
338
struct snd_pcm_runtime *runtime = substream->runtime;
339
struct ct_atc_pcm *apcm = runtime->private_data;
340
341
switch (cmd) {
342
case SNDRV_PCM_TRIGGER_START:
343
atc->pcm_capture_start(atc, apcm);
344
break;
345
case SNDRV_PCM_TRIGGER_STOP:
346
atc->pcm_capture_stop(atc, apcm);
347
break;
348
default:
349
atc->pcm_capture_stop(atc, apcm);
350
break;
351
}
352
353
return 0;
354
}
355
356
static snd_pcm_uframes_t
357
ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
358
{
359
unsigned long position;
360
struct ct_atc *atc = snd_pcm_substream_chip(substream);
361
struct snd_pcm_runtime *runtime = substream->runtime;
362
struct ct_atc_pcm *apcm = runtime->private_data;
363
364
/* Read out playback position */
365
position = atc->pcm_capture_position(atc, apcm);
366
position = bytes_to_frames(runtime, position);
367
if (position >= runtime->buffer_size)
368
position = 0;
369
return position;
370
}
371
372
/* PCM operators for playback */
373
static struct snd_pcm_ops ct_pcm_playback_ops = {
374
.open = ct_pcm_playback_open,
375
.close = ct_pcm_playback_close,
376
.ioctl = snd_pcm_lib_ioctl,
377
.hw_params = ct_pcm_hw_params,
378
.hw_free = ct_pcm_hw_free,
379
.prepare = ct_pcm_playback_prepare,
380
.trigger = ct_pcm_playback_trigger,
381
.pointer = ct_pcm_playback_pointer,
382
.page = snd_pcm_sgbuf_ops_page,
383
};
384
385
/* PCM operators for capture */
386
static struct snd_pcm_ops ct_pcm_capture_ops = {
387
.open = ct_pcm_capture_open,
388
.close = ct_pcm_capture_close,
389
.ioctl = snd_pcm_lib_ioctl,
390
.hw_params = ct_pcm_hw_params,
391
.hw_free = ct_pcm_hw_free,
392
.prepare = ct_pcm_capture_prepare,
393
.trigger = ct_pcm_capture_trigger,
394
.pointer = ct_pcm_capture_pointer,
395
.page = snd_pcm_sgbuf_ops_page,
396
};
397
398
/* Create ALSA pcm device */
399
int ct_alsa_pcm_create(struct ct_atc *atc,
400
enum CTALSADEVS device,
401
const char *device_name)
402
{
403
struct snd_pcm *pcm;
404
int err;
405
int playback_count, capture_count;
406
407
playback_count = (IEC958 == device) ? 1 : 8;
408
capture_count = (FRONT == device) ? 1 : 0;
409
err = snd_pcm_new(atc->card, "ctxfi", device,
410
playback_count, capture_count, &pcm);
411
if (err < 0) {
412
printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
413
return err;
414
}
415
416
pcm->private_data = atc;
417
pcm->info_flags = 0;
418
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
419
strlcpy(pcm->name, device_name, sizeof(pcm->name));
420
421
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
422
423
if (FRONT == device)
424
snd_pcm_set_ops(pcm,
425
SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
426
427
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
428
snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
429
430
#ifdef CONFIG_PM
431
atc->pcms[device] = pcm;
432
#endif
433
434
return 0;
435
}
436
437