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