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