]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License as published by | |
4 | * the Free Software Foundation; either version 2 of the License, or | |
5 | * (at your option) any later version. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU Library General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU General Public License | |
13 | * along with this program; if not, write to the Free Software | |
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
15 | */ | |
16 | ||
17 | /* | |
18 | * Vortex PCM ALSA driver. | |
19 | * | |
20 | * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet. | |
21 | * It remains stuck,and DMA transfers do not happen. | |
22 | */ | |
23 | #include <sound/asoundef.h> | |
1da177e4 LT |
24 | #include <linux/time.h> |
25 | #include <sound/core.h> | |
26 | #include <sound/pcm.h> | |
27 | #include <sound/pcm_params.h> | |
28 | #include "au88x0.h" | |
29 | ||
30 | #define VORTEX_PCM_TYPE(x) (x->name[40]) | |
31 | ||
32 | /* hardware definition */ | |
2fd16874 | 33 | static struct snd_pcm_hardware snd_vortex_playback_hw_adb = { |
1da177e4 | 34 | .info = |
41e4845c | 35 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
36 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
37 | SNDRV_PCM_INFO_MMAP_VALID), | |
38 | .formats = | |
39 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
40 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, | |
41 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | |
42 | .rate_min = 5000, | |
43 | .rate_max = 48000, | |
44 | .channels_min = 1, | |
1da177e4 | 45 | .channels_max = 2, |
1da177e4 LT |
46 | .buffer_bytes_max = 0x10000, |
47 | .period_bytes_min = 0x1, | |
48 | .period_bytes_max = 0x1000, | |
49 | .periods_min = 2, | |
50 | .periods_max = 32, | |
51 | }; | |
52 | ||
53 | #ifndef CHIP_AU8820 | |
2fd16874 | 54 | static struct snd_pcm_hardware snd_vortex_playback_hw_a3d = { |
1da177e4 | 55 | .info = |
41e4845c | 56 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
57 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
58 | SNDRV_PCM_INFO_MMAP_VALID), | |
59 | .formats = | |
60 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
61 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, | |
62 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | |
63 | .rate_min = 5000, | |
64 | .rate_max = 48000, | |
65 | .channels_min = 1, | |
66 | .channels_max = 1, | |
67 | .buffer_bytes_max = 0x10000, | |
68 | .period_bytes_min = 0x100, | |
69 | .period_bytes_max = 0x1000, | |
70 | .periods_min = 2, | |
71 | .periods_max = 64, | |
72 | }; | |
73 | #endif | |
2fd16874 | 74 | static struct snd_pcm_hardware snd_vortex_playback_hw_spdif = { |
1da177e4 | 75 | .info = |
41e4845c | 76 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
77 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
78 | SNDRV_PCM_INFO_MMAP_VALID), | |
79 | .formats = | |
80 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
81 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW | | |
82 | SNDRV_PCM_FMTBIT_A_LAW, | |
83 | .rates = | |
84 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | |
85 | .rate_min = 32000, | |
86 | .rate_max = 48000, | |
87 | .channels_min = 1, | |
88 | .channels_max = 2, | |
89 | .buffer_bytes_max = 0x10000, | |
90 | .period_bytes_min = 0x100, | |
91 | .period_bytes_max = 0x1000, | |
92 | .periods_min = 2, | |
93 | .periods_max = 64, | |
94 | }; | |
95 | ||
96 | #ifndef CHIP_AU8810 | |
2fd16874 | 97 | static struct snd_pcm_hardware snd_vortex_playback_hw_wt = { |
1da177e4 LT |
98 | .info = (SNDRV_PCM_INFO_MMAP | |
99 | SNDRV_PCM_INFO_INTERLEAVED | | |
100 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), | |
101 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
102 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000, | |
103 | .rate_min = 8000, | |
104 | .rate_max = 48000, | |
105 | .channels_min = 1, | |
106 | .channels_max = 2, | |
107 | .buffer_bytes_max = 0x10000, | |
108 | .period_bytes_min = 0x0400, | |
109 | .period_bytes_max = 0x1000, | |
110 | .periods_min = 2, | |
111 | .periods_max = 64, | |
112 | }; | |
113 | #endif | |
d9ab3443 RY |
114 | #ifdef CHIP_AU8830 |
115 | static unsigned int au8830_channels[3] = { | |
116 | 1, 2, 4, | |
117 | }; | |
118 | ||
119 | static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { | |
120 | .count = ARRAY_SIZE(au8830_channels), | |
121 | .list = au8830_channels, | |
122 | .mask = 0, | |
123 | }; | |
124 | #endif | |
1da177e4 | 125 | /* open callback */ |
2fd16874 | 126 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) |
1da177e4 LT |
127 | { |
128 | vortex_t *vortex = snd_pcm_substream_chip(substream); | |
2fd16874 | 129 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
130 | int err; |
131 | ||
132 | /* Force equal size periods */ | |
133 | if ((err = | |
134 | snd_pcm_hw_constraint_integer(runtime, | |
135 | SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | |
136 | return err; | |
137 | /* Avoid PAGE_SIZE boundary to fall inside of a period. */ | |
138 | if ((err = | |
139 | snd_pcm_hw_constraint_pow2(runtime, 0, | |
140 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) | |
141 | return err; | |
142 | ||
143 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
144 | #ifndef CHIP_AU8820 | |
145 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { | |
146 | runtime->hw = snd_vortex_playback_hw_a3d; | |
147 | } | |
148 | #endif | |
149 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { | |
150 | runtime->hw = snd_vortex_playback_hw_spdif; | |
151 | switch (vortex->spdif_sr) { | |
152 | case 32000: | |
153 | runtime->hw.rates = SNDRV_PCM_RATE_32000; | |
154 | break; | |
155 | case 44100: | |
156 | runtime->hw.rates = SNDRV_PCM_RATE_44100; | |
157 | break; | |
158 | case 48000: | |
159 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | |
160 | break; | |
161 | } | |
162 | } | |
163 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB | |
164 | || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) | |
165 | runtime->hw = snd_vortex_playback_hw_adb; | |
d9ab3443 RY |
166 | #ifdef CHIP_AU8830 |
167 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | |
168 | VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | |
169 | runtime->hw.channels_max = 4; | |
170 | snd_pcm_hw_constraint_list(runtime, 0, | |
171 | SNDRV_PCM_HW_PARAM_CHANNELS, | |
172 | &hw_constraints_au8830_channels); | |
173 | } | |
174 | #endif | |
1da177e4 LT |
175 | substream->runtime->private_data = NULL; |
176 | } | |
177 | #ifndef CHIP_AU8810 | |
178 | else { | |
179 | runtime->hw = snd_vortex_playback_hw_wt; | |
180 | substream->runtime->private_data = NULL; | |
181 | } | |
182 | #endif | |
183 | return 0; | |
184 | } | |
185 | ||
186 | /* close callback */ | |
2fd16874 | 187 | static int snd_vortex_pcm_close(struct snd_pcm_substream *substream) |
1da177e4 LT |
188 | { |
189 | //vortex_t *chip = snd_pcm_substream_chip(substream); | |
190 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
191 | ||
192 | // the hardware-specific codes will be here | |
193 | if (stream != NULL) { | |
194 | stream->substream = NULL; | |
195 | stream->nr_ch = 0; | |
196 | } | |
197 | substream->runtime->private_data = NULL; | |
198 | return 0; | |
199 | } | |
200 | ||
201 | /* hw_params callback */ | |
202 | static int | |
2fd16874 TI |
203 | snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, |
204 | struct snd_pcm_hw_params *hw_params) | |
1da177e4 LT |
205 | { |
206 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
207 | stream_t *stream = (stream_t *) (substream->runtime->private_data); | |
1da177e4 LT |
208 | int err; |
209 | ||
210 | // Alloc buffer memory. | |
211 | err = | |
212 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | |
213 | if (err < 0) { | |
214 | printk(KERN_ERR "Vortex: pcm page alloc failed!\n"); | |
215 | return err; | |
216 | } | |
1da177e4 LT |
217 | /* |
218 | printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), | |
219 | params_period_bytes(hw_params), params_channels(hw_params)); | |
220 | */ | |
221 | spin_lock_irq(&chip->lock); | |
222 | // Make audio routes and config buffer DMA. | |
223 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
224 | int dma, type = VORTEX_PCM_TYPE(substream->pcm); | |
225 | /* Dealloc any routes. */ | |
226 | if (stream != NULL) | |
227 | vortex_adb_allocroute(chip, stream->dma, | |
228 | stream->nr_ch, stream->dir, | |
229 | stream->type); | |
230 | /* Alloc routes. */ | |
231 | dma = | |
232 | vortex_adb_allocroute(chip, -1, | |
233 | params_channels(hw_params), | |
234 | substream->stream, type); | |
a278655f TI |
235 | if (dma < 0) { |
236 | spin_unlock_irq(&chip->lock); | |
1da177e4 | 237 | return dma; |
a278655f | 238 | } |
1da177e4 LT |
239 | stream = substream->runtime->private_data = &chip->dma_adb[dma]; |
240 | stream->substream = substream; | |
241 | /* Setup Buffers. */ | |
77a23f26 | 242 | vortex_adbdma_setbuffers(chip, dma, |
1da177e4 LT |
243 | params_period_bytes(hw_params), |
244 | params_periods(hw_params)); | |
245 | } | |
246 | #ifndef CHIP_AU8810 | |
247 | else { | |
248 | /* if (stream != NULL) | |
249 | vortex_wt_allocroute(chip, substream->number, 0); */ | |
250 | vortex_wt_allocroute(chip, substream->number, | |
251 | params_channels(hw_params)); | |
252 | stream = substream->runtime->private_data = | |
253 | &chip->dma_wt[substream->number]; | |
254 | stream->dma = substream->number; | |
255 | stream->substream = substream; | |
77a23f26 | 256 | vortex_wtdma_setbuffers(chip, substream->number, |
1da177e4 LT |
257 | params_period_bytes(hw_params), |
258 | params_periods(hw_params)); | |
259 | } | |
260 | #endif | |
261 | spin_unlock_irq(&chip->lock); | |
262 | return 0; | |
263 | } | |
264 | ||
265 | /* hw_free callback */ | |
2fd16874 | 266 | static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) |
1da177e4 LT |
267 | { |
268 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
269 | stream_t *stream = (stream_t *) (substream->runtime->private_data); | |
270 | ||
271 | spin_lock_irq(&chip->lock); | |
272 | // Delete audio routes. | |
273 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
274 | if (stream != NULL) | |
275 | vortex_adb_allocroute(chip, stream->dma, | |
276 | stream->nr_ch, stream->dir, | |
277 | stream->type); | |
278 | } | |
279 | #ifndef CHIP_AU8810 | |
280 | else { | |
281 | if (stream != NULL) | |
282 | vortex_wt_allocroute(chip, stream->dma, 0); | |
283 | } | |
284 | #endif | |
285 | substream->runtime->private_data = NULL; | |
286 | spin_unlock_irq(&chip->lock); | |
287 | ||
288 | return snd_pcm_lib_free_pages(substream); | |
289 | } | |
290 | ||
291 | /* prepare callback */ | |
2fd16874 | 292 | static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
293 | { |
294 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
2fd16874 | 295 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
296 | stream_t *stream = (stream_t *) substream->runtime->private_data; |
297 | int dma = stream->dma, fmt, dir; | |
298 | ||
299 | // set up the hardware with the current configuration. | |
300 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
301 | dir = 1; | |
302 | else | |
303 | dir = 0; | |
304 | fmt = vortex_alsafmt_aspfmt(runtime->format); | |
305 | spin_lock_irq(&chip->lock); | |
306 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
307 | vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ , | |
308 | 0); | |
309 | vortex_adbdma_setstartbuffer(chip, dma, 0); | |
310 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) | |
311 | vortex_adb_setsrc(chip, dma, runtime->rate, dir); | |
312 | } | |
313 | #ifndef CHIP_AU8810 | |
314 | else { | |
315 | vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0); | |
316 | // FIXME: Set rate (i guess using vortex_wt_writereg() somehow). | |
317 | vortex_wtdma_setstartbuffer(chip, dma, 0); | |
318 | } | |
319 | #endif | |
320 | spin_unlock_irq(&chip->lock); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | /* trigger callback */ | |
2fd16874 | 325 | static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
1da177e4 LT |
326 | { |
327 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
328 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
329 | int dma = stream->dma; | |
330 | ||
331 | spin_lock(&chip->lock); | |
332 | switch (cmd) { | |
333 | case SNDRV_PCM_TRIGGER_START: | |
334 | // do something to start the PCM engine | |
335 | //printk(KERN_INFO "vortex: start %d\n", dma); | |
336 | stream->fifo_enabled = 1; | |
337 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
338 | vortex_adbdma_resetup(chip, dma); | |
339 | vortex_adbdma_startfifo(chip, dma); | |
340 | } | |
341 | #ifndef CHIP_AU8810 | |
342 | else { | |
343 | printk(KERN_INFO "vortex: wt start %d\n", dma); | |
344 | vortex_wtdma_startfifo(chip, dma); | |
345 | } | |
346 | #endif | |
347 | break; | |
348 | case SNDRV_PCM_TRIGGER_STOP: | |
349 | // do something to stop the PCM engine | |
350 | //printk(KERN_INFO "vortex: stop %d\n", dma); | |
351 | stream->fifo_enabled = 0; | |
352 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
353 | vortex_adbdma_pausefifo(chip, dma); | |
354 | //vortex_adbdma_stopfifo(chip, dma); | |
355 | #ifndef CHIP_AU8810 | |
356 | else { | |
357 | printk(KERN_INFO "vortex: wt stop %d\n", dma); | |
358 | vortex_wtdma_stopfifo(chip, dma); | |
359 | } | |
360 | #endif | |
361 | break; | |
362 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
363 | //printk(KERN_INFO "vortex: pause %d\n", dma); | |
364 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
365 | vortex_adbdma_pausefifo(chip, dma); | |
366 | #ifndef CHIP_AU8810 | |
367 | else | |
368 | vortex_wtdma_pausefifo(chip, dma); | |
369 | #endif | |
370 | break; | |
371 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
372 | //printk(KERN_INFO "vortex: resume %d\n", dma); | |
373 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
374 | vortex_adbdma_resumefifo(chip, dma); | |
375 | #ifndef CHIP_AU8810 | |
376 | else | |
377 | vortex_wtdma_resumefifo(chip, dma); | |
378 | #endif | |
379 | break; | |
380 | default: | |
381 | spin_unlock(&chip->lock); | |
382 | return -EINVAL; | |
383 | } | |
384 | spin_unlock(&chip->lock); | |
385 | return 0; | |
386 | } | |
387 | ||
388 | /* pointer callback */ | |
2fd16874 | 389 | static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream) |
1da177e4 LT |
390 | { |
391 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
392 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
393 | int dma = stream->dma; | |
394 | snd_pcm_uframes_t current_ptr = 0; | |
395 | ||
396 | spin_lock(&chip->lock); | |
397 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
398 | current_ptr = vortex_adbdma_getlinearpos(chip, dma); | |
399 | #ifndef CHIP_AU8810 | |
400 | else | |
401 | current_ptr = vortex_wtdma_getlinearpos(chip, dma); | |
402 | #endif | |
403 | //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr); | |
404 | spin_unlock(&chip->lock); | |
405 | return (bytes_to_frames(substream->runtime, current_ptr)); | |
406 | } | |
407 | ||
1da177e4 | 408 | /* operators */ |
2fd16874 | 409 | static struct snd_pcm_ops snd_vortex_playback_ops = { |
1da177e4 LT |
410 | .open = snd_vortex_pcm_open, |
411 | .close = snd_vortex_pcm_close, | |
412 | .ioctl = snd_pcm_lib_ioctl, | |
413 | .hw_params = snd_vortex_pcm_hw_params, | |
414 | .hw_free = snd_vortex_pcm_hw_free, | |
415 | .prepare = snd_vortex_pcm_prepare, | |
416 | .trigger = snd_vortex_pcm_trigger, | |
417 | .pointer = snd_vortex_pcm_pointer, | |
418 | .page = snd_pcm_sgbuf_ops_page, | |
419 | }; | |
420 | ||
421 | /* | |
422 | * definitions of capture are omitted here... | |
423 | */ | |
424 | ||
425 | static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { | |
426 | "AU88x0 ADB", | |
427 | "AU88x0 SPDIF", | |
428 | "AU88x0 A3D", | |
429 | "AU88x0 WT", | |
430 | "AU88x0 I2S", | |
431 | }; | |
432 | static char *vortex_pcm_name[VORTEX_PCM_LAST] = { | |
433 | "adb", | |
434 | "spdif", | |
435 | "a3d", | |
436 | "wt", | |
437 | "i2s", | |
438 | }; | |
439 | ||
440 | /* SPDIF kcontrol */ | |
441 | ||
2fd16874 | 442 | static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
443 | { |
444 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
445 | uinfo->count = 1; | |
446 | return 0; | |
447 | } | |
448 | ||
2fd16874 | 449 | static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
450 | { |
451 | ucontrol->value.iec958.status[0] = 0xff; | |
452 | ucontrol->value.iec958.status[1] = 0xff; | |
453 | ucontrol->value.iec958.status[2] = 0xff; | |
454 | ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; | |
455 | return 0; | |
456 | } | |
457 | ||
2fd16874 | 458 | static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
459 | { |
460 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
461 | ucontrol->value.iec958.status[0] = 0x00; | |
462 | ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID; | |
463 | ucontrol->value.iec958.status[2] = 0x00; | |
464 | switch (vortex->spdif_sr) { | |
465 | case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break; | |
466 | case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break; | |
467 | case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break; | |
468 | } | |
469 | return 0; | |
470 | } | |
471 | ||
2fd16874 | 472 | static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
473 | { |
474 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
475 | int spdif_sr = 48000; | |
476 | switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) { | |
477 | case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break; | |
478 | case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break; | |
479 | case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break; | |
480 | } | |
481 | if (spdif_sr == vortex->spdif_sr) | |
482 | return 0; | |
483 | vortex->spdif_sr = spdif_sr; | |
484 | vortex_spdif_init(vortex, vortex->spdif_sr, 1); | |
485 | return 1; | |
486 | } | |
487 | ||
488 | /* spdif controls */ | |
2fd16874 | 489 | static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { |
1da177e4 LT |
490 | { |
491 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
492 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | |
493 | .info = snd_vortex_spdif_info, | |
494 | .get = snd_vortex_spdif_get, | |
495 | .put = snd_vortex_spdif_put, | |
496 | }, | |
497 | { | |
498 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
499 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
500 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), | |
501 | .info = snd_vortex_spdif_info, | |
502 | .get = snd_vortex_spdif_mask_get | |
503 | }, | |
504 | }; | |
505 | ||
506 | /* create a pcm device */ | |
3fa4a907 | 507 | static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
1da177e4 | 508 | { |
2fd16874 TI |
509 | struct snd_pcm *pcm; |
510 | struct snd_kcontrol *kctl; | |
1da177e4 LT |
511 | int i; |
512 | int err, nr_capt; | |
513 | ||
3fa4a907 | 514 | if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST) |
1da177e4 LT |
515 | return -ENODEV; |
516 | ||
517 | /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the | |
25985edc | 518 | * same dma engine. WT uses it own separate dma engine which can't capture. */ |
1da177e4 LT |
519 | if (idx == VORTEX_PCM_ADB) |
520 | nr_capt = nr; | |
521 | else | |
522 | nr_capt = 0; | |
3fa4a907 HH |
523 | err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, |
524 | nr_capt, &pcm); | |
525 | if (err < 0) | |
1da177e4 LT |
526 | return err; |
527 | strcpy(pcm->name, vortex_pcm_name[idx]); | |
528 | chip->pcm[idx] = pcm; | |
529 | // This is an evil hack, but it saves a lot of duplicated code. | |
530 | VORTEX_PCM_TYPE(pcm) = idx; | |
531 | pcm->private_data = chip; | |
532 | /* set operators */ | |
533 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
534 | &snd_vortex_playback_ops); | |
535 | if (idx == VORTEX_PCM_ADB) | |
536 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | |
537 | &snd_vortex_playback_ops); | |
538 | ||
539 | /* pre-allocation of Scatter-Gather buffers */ | |
540 | ||
541 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, | |
542 | snd_dma_pci_data(chip->pci_dev), | |
543 | 0x10000, 0x10000); | |
544 | ||
545 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { | |
546 | for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) { | |
547 | kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip); | |
548 | if (!kctl) | |
549 | return -ENOMEM; | |
550 | if ((err = snd_ctl_add(chip->card, kctl)) < 0) | |
551 | return err; | |
552 | } | |
553 | } | |
554 | return 0; | |
555 | } |