Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
10817 views
1
/*
2
* Driver for Sound Core PDAudioCF soundcards
3
*
4
* PCM part
5
*
6
* Copyright (c) 2003 by Jaroslav Kysela <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*/
22
23
#include <linux/delay.h>
24
#include <sound/core.h>
25
#include <sound/asoundef.h>
26
#include "pdaudiocf.h"
27
28
29
/*
30
* clear the SRAM contents
31
*/
32
static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)
33
{
34
int max_loop = 64 * 1024;
35
36
while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
37
if (max_loop-- < 0)
38
return -EIO;
39
inw(chip->port + PDAUDIOCF_REG_MD);
40
}
41
return 0;
42
}
43
44
/*
45
* pdacf_pcm_trigger - trigger callback for capture
46
*/
47
static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
48
{
49
struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
50
struct snd_pcm_runtime *runtime = subs->runtime;
51
int inc, ret = 0, rate;
52
unsigned short mask, val, tmp;
53
54
if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
55
return -EBUSY;
56
57
switch (cmd) {
58
case SNDRV_PCM_TRIGGER_START:
59
chip->pcm_hwptr = 0;
60
chip->pcm_tdone = 0;
61
/* fall thru */
62
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
63
case SNDRV_PCM_TRIGGER_RESUME:
64
mask = 0;
65
val = PDAUDIOCF_RECORD;
66
inc = 1;
67
rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
68
break;
69
case SNDRV_PCM_TRIGGER_STOP:
70
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
71
case SNDRV_PCM_TRIGGER_SUSPEND:
72
mask = PDAUDIOCF_RECORD;
73
val = 0;
74
inc = -1;
75
rate = 0;
76
break;
77
default:
78
return -EINVAL;
79
}
80
spin_lock(&chip->reg_lock);
81
chip->pcm_running += inc;
82
tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
83
if (chip->pcm_running) {
84
if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
85
chip->pcm_running -= inc;
86
ret = -EIO;
87
goto __end;
88
}
89
}
90
tmp &= ~mask;
91
tmp |= val;
92
pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
93
__end:
94
spin_unlock(&chip->reg_lock);
95
snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
96
return ret;
97
}
98
99
/*
100
* pdacf_pcm_hw_params - hw_params callback for playback and capture
101
*/
102
static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs,
103
struct snd_pcm_hw_params *hw_params)
104
{
105
return snd_pcm_lib_alloc_vmalloc_32_buffer
106
(subs, params_buffer_bytes(hw_params));
107
}
108
109
/*
110
* pdacf_pcm_hw_free - hw_free callback for playback and capture
111
*/
112
static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs)
113
{
114
return snd_pcm_lib_free_vmalloc_buffer(subs);
115
}
116
117
/*
118
* pdacf_pcm_prepare - prepare callback for playback and capture
119
*/
120
static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)
121
{
122
struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
123
struct snd_pcm_runtime *runtime = subs->runtime;
124
u16 val, nval, aval;
125
126
if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
127
return -EBUSY;
128
129
chip->pcm_channels = runtime->channels;
130
131
chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
132
#ifdef SNDRV_LITTLE_ENDIAN
133
chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
134
#else
135
chip->pcm_swab = chip->pcm_little;
136
#endif
137
138
if (snd_pcm_format_unsigned(runtime->format))
139
chip->pcm_xor = 0x80008000;
140
141
if (pdacf_pcm_clear_sram(chip) < 0)
142
return -EIO;
143
144
val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
145
nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
146
switch (runtime->format) {
147
case SNDRV_PCM_FORMAT_S16_LE:
148
case SNDRV_PCM_FORMAT_S16_BE:
149
break;
150
default: /* 24-bit */
151
nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
152
break;
153
}
154
aval = 0;
155
chip->pcm_sample = 4;
156
switch (runtime->format) {
157
case SNDRV_PCM_FORMAT_S16_LE:
158
case SNDRV_PCM_FORMAT_S16_BE:
159
aval = AK4117_DIF_16R;
160
chip->pcm_frame = 2;
161
chip->pcm_sample = 2;
162
break;
163
case SNDRV_PCM_FORMAT_S24_3LE:
164
case SNDRV_PCM_FORMAT_S24_3BE:
165
chip->pcm_sample = 3;
166
/* fall through */
167
default: /* 24-bit */
168
aval = AK4117_DIF_24R;
169
chip->pcm_frame = 3;
170
chip->pcm_xor &= 0xffff0000;
171
break;
172
}
173
174
if (val != nval) {
175
snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
176
pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
177
}
178
179
val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER);
180
val &= ~(PDAUDIOCF_IRQLVLEN1);
181
val |= PDAUDIOCF_IRQLVLEN0;
182
pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
183
184
chip->pcm_size = runtime->buffer_size;
185
chip->pcm_period = runtime->period_size;
186
chip->pcm_area = runtime->dma_area;
187
188
return 0;
189
}
190
191
192
/*
193
* capture hw information
194
*/
195
196
static struct snd_pcm_hardware pdacf_pcm_capture_hw = {
197
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
198
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
199
SNDRV_PCM_INFO_MMAP_VALID |
200
SNDRV_PCM_INFO_BATCH),
201
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
202
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
203
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
204
.rates = SNDRV_PCM_RATE_32000 |
205
SNDRV_PCM_RATE_44100 |
206
SNDRV_PCM_RATE_48000 |
207
SNDRV_PCM_RATE_88200 |
208
SNDRV_PCM_RATE_96000 |
209
SNDRV_PCM_RATE_176400 |
210
SNDRV_PCM_RATE_192000,
211
.rate_min = 32000,
212
.rate_max = 192000,
213
.channels_min = 1,
214
.channels_max = 2,
215
.buffer_bytes_max = (512*1024),
216
.period_bytes_min = 8*1024,
217
.period_bytes_max = (64*1024),
218
.periods_min = 2,
219
.periods_max = 128,
220
.fifo_size = 0,
221
};
222
223
224
/*
225
* pdacf_pcm_capture_open - open callback for capture
226
*/
227
static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)
228
{
229
struct snd_pcm_runtime *runtime = subs->runtime;
230
struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
231
232
if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
233
return -EBUSY;
234
235
runtime->hw = pdacf_pcm_capture_hw;
236
runtime->private_data = chip;
237
chip->pcm_substream = subs;
238
239
return 0;
240
}
241
242
/*
243
* pdacf_pcm_capture_close - close callback for capture
244
*/
245
static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)
246
{
247
struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
248
249
if (!chip)
250
return -EINVAL;
251
pdacf_reinit(chip, 0);
252
chip->pcm_substream = NULL;
253
return 0;
254
}
255
256
257
/*
258
* pdacf_pcm_capture_pointer - pointer callback for capture
259
*/
260
static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)
261
{
262
struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
263
return chip->pcm_hwptr;
264
}
265
266
/*
267
* operators for PCM capture
268
*/
269
static struct snd_pcm_ops pdacf_pcm_capture_ops = {
270
.open = pdacf_pcm_capture_open,
271
.close = pdacf_pcm_capture_close,
272
.ioctl = snd_pcm_lib_ioctl,
273
.hw_params = pdacf_pcm_hw_params,
274
.hw_free = pdacf_pcm_hw_free,
275
.prepare = pdacf_pcm_prepare,
276
.trigger = pdacf_pcm_trigger,
277
.pointer = pdacf_pcm_capture_pointer,
278
.page = snd_pcm_lib_get_vmalloc_page,
279
.mmap = snd_pcm_lib_mmap_vmalloc,
280
};
281
282
283
/*
284
* snd_pdacf_pcm_new - create and initialize a pcm
285
*/
286
int snd_pdacf_pcm_new(struct snd_pdacf *chip)
287
{
288
struct snd_pcm *pcm;
289
int err;
290
291
err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
292
if (err < 0)
293
return err;
294
295
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
296
297
pcm->private_data = chip;
298
pcm->info_flags = 0;
299
strcpy(pcm->name, chip->card->shortname);
300
chip->pcm = pcm;
301
302
err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
303
if (err < 0)
304
return err;
305
306
return 0;
307
}
308
309