diff options
Diffstat (limited to 'sound/pci/ctxfi/ctatc.c')
-rw-r--r-- | sound/pci/ctxfi/ctatc.c | 1713 |
1 files changed, 1713 insertions, 0 deletions
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c new file mode 100644 index 000000000000..a49c76647307 --- /dev/null +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -0,0 +1,1713 @@ | |||
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 ctatc.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of the device resource management | ||
12 | * object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date Mar 28 2008 | ||
16 | */ | ||
17 | |||
18 | #include "ctatc.h" | ||
19 | #include "ctpcm.h" | ||
20 | #include "ctmixer.h" | ||
21 | #include "cthardware.h" | ||
22 | #include "ctsrc.h" | ||
23 | #include "ctamixer.h" | ||
24 | #include "ctdaio.h" | ||
25 | #include "cttimer.h" | ||
26 | #include <linux/delay.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/control.h> | ||
29 | #include <sound/asoundef.h> | ||
30 | |||
31 | #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ | ||
32 | #define DAIONUM 7 | ||
33 | #define MAX_MULTI_CHN 8 | ||
34 | |||
35 | #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ | ||
36 | | IEC958_AES0_CON_NOT_COPYRIGHT) \ | ||
37 | | ((IEC958_AES1_CON_MIXER \ | ||
38 | | IEC958_AES1_CON_ORIGINAL) << 8) \ | ||
39 | | (0x10 << 16) \ | ||
40 | | ((IEC958_AES3_CON_FS_48000) << 24)) | ||
41 | |||
42 | static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { | ||
43 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), | ||
44 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), | ||
45 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), | ||
46 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), | ||
47 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, | ||
48 | "UAA", CTUAA), | ||
49 | { } /* terminator */ | ||
50 | }; | ||
51 | |||
52 | static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { | ||
53 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, | ||
54 | "SB0760", CTSB0760), | ||
55 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, | ||
56 | "SB0880", CTSB0880), | ||
57 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, | ||
58 | "SB0880", CTSB0880), | ||
59 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, | ||
60 | "SB0880", CTSB0880), | ||
61 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, | ||
62 | PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", | ||
63 | CTHENDRIX), | ||
64 | { } /* terminator */ | ||
65 | }; | ||
66 | |||
67 | static const char *ct_subsys_name[NUM_CTCARDS] = { | ||
68 | /* 20k1 models */ | ||
69 | [CTSB055X] = "SB055x", | ||
70 | [CTSB073X] = "SB073x", | ||
71 | [CTUAA] = "UAA", | ||
72 | [CT20K1_UNKNOWN] = "Unknown", | ||
73 | /* 20k2 models */ | ||
74 | [CTSB0760] = "SB076x", | ||
75 | [CTHENDRIX] = "Hendrix", | ||
76 | [CTSB0880] = "SB0880", | ||
77 | [CT20K2_UNKNOWN] = "Unknown", | ||
78 | }; | ||
79 | |||
80 | static struct { | ||
81 | int (*create)(struct ct_atc *atc, | ||
82 | enum CTALSADEVS device, const char *device_name); | ||
83 | int (*destroy)(void *alsa_dev); | ||
84 | const char *public_name; | ||
85 | } alsa_dev_funcs[NUM_CTALSADEVS] = { | ||
86 | [FRONT] = { .create = ct_alsa_pcm_create, | ||
87 | .destroy = NULL, | ||
88 | .public_name = "Front/WaveIn"}, | ||
89 | [SURROUND] = { .create = ct_alsa_pcm_create, | ||
90 | .destroy = NULL, | ||
91 | .public_name = "Surround"}, | ||
92 | [CLFE] = { .create = ct_alsa_pcm_create, | ||
93 | .destroy = NULL, | ||
94 | .public_name = "Center/LFE"}, | ||
95 | [SIDE] = { .create = ct_alsa_pcm_create, | ||
96 | .destroy = NULL, | ||
97 | .public_name = "Side"}, | ||
98 | [IEC958] = { .create = ct_alsa_pcm_create, | ||
99 | .destroy = NULL, | ||
100 | .public_name = "IEC958 Non-audio"}, | ||
101 | |||
102 | [MIXER] = { .create = ct_alsa_mix_create, | ||
103 | .destroy = NULL, | ||
104 | .public_name = "Mixer"} | ||
105 | }; | ||
106 | |||
107 | typedef int (*create_t)(void *, void **); | ||
108 | typedef int (*destroy_t)(void *); | ||
109 | |||
110 | static struct { | ||
111 | int (*create)(void *hw, void **rmgr); | ||
112 | int (*destroy)(void *mgr); | ||
113 | } rsc_mgr_funcs[NUM_RSCTYP] = { | ||
114 | [SRC] = { .create = (create_t)src_mgr_create, | ||
115 | .destroy = (destroy_t)src_mgr_destroy }, | ||
116 | [SRCIMP] = { .create = (create_t)srcimp_mgr_create, | ||
117 | .destroy = (destroy_t)srcimp_mgr_destroy }, | ||
118 | [AMIXER] = { .create = (create_t)amixer_mgr_create, | ||
119 | .destroy = (destroy_t)amixer_mgr_destroy }, | ||
120 | [SUM] = { .create = (create_t)sum_mgr_create, | ||
121 | .destroy = (destroy_t)sum_mgr_destroy }, | ||
122 | [DAIO] = { .create = (create_t)daio_mgr_create, | ||
123 | .destroy = (destroy_t)daio_mgr_destroy } | ||
124 | }; | ||
125 | |||
126 | static int | ||
127 | atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
128 | |||
129 | /* * | ||
130 | * Only mono and interleaved modes are supported now. | ||
131 | * Always allocates a contiguous channel block. | ||
132 | * */ | ||
133 | |||
134 | static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
135 | { | ||
136 | struct snd_pcm_runtime *runtime; | ||
137 | struct ct_vm *vm; | ||
138 | |||
139 | if (NULL == apcm->substream) | ||
140 | return 0; | ||
141 | |||
142 | runtime = apcm->substream->runtime; | ||
143 | vm = atc->vm; | ||
144 | |||
145 | apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); | ||
146 | |||
147 | if (NULL == apcm->vm_block) | ||
148 | return -ENOENT; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
154 | { | ||
155 | struct ct_vm *vm; | ||
156 | |||
157 | if (NULL == apcm->vm_block) | ||
158 | return; | ||
159 | |||
160 | vm = atc->vm; | ||
161 | |||
162 | vm->unmap(vm, apcm->vm_block); | ||
163 | |||
164 | apcm->vm_block = NULL; | ||
165 | } | ||
166 | |||
167 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) | ||
168 | { | ||
169 | struct ct_vm *vm; | ||
170 | void *kvirt_addr; | ||
171 | unsigned long phys_addr; | ||
172 | |||
173 | vm = atc->vm; | ||
174 | kvirt_addr = vm->get_ptp_virt(vm, index); | ||
175 | if (kvirt_addr == NULL) | ||
176 | phys_addr = (~0UL); | ||
177 | else | ||
178 | phys_addr = virt_to_phys(kvirt_addr); | ||
179 | |||
180 | return phys_addr; | ||
181 | } | ||
182 | |||
183 | static unsigned int convert_format(snd_pcm_format_t snd_format) | ||
184 | { | ||
185 | switch (snd_format) { | ||
186 | case SNDRV_PCM_FORMAT_U8: | ||
187 | return SRC_SF_U8; | ||
188 | case SNDRV_PCM_FORMAT_S16_LE: | ||
189 | return SRC_SF_S16; | ||
190 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
191 | return SRC_SF_S24; | ||
192 | case SNDRV_PCM_FORMAT_S32_LE: | ||
193 | return SRC_SF_S32; | ||
194 | case SNDRV_PCM_FORMAT_FLOAT_LE: | ||
195 | return SRC_SF_F32; | ||
196 | default: | ||
197 | printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", | ||
198 | snd_format); | ||
199 | return SRC_SF_S16; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static unsigned int | ||
204 | atc_get_pitch(unsigned int input_rate, unsigned int output_rate) | ||
205 | { | ||
206 | unsigned int pitch; | ||
207 | int b; | ||
208 | |||
209 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
210 | pitch = (input_rate / output_rate) << 24; | ||
211 | input_rate %= output_rate; | ||
212 | input_rate /= 100; | ||
213 | output_rate /= 100; | ||
214 | for (b = 31; ((b >= 0) && !(input_rate >> b)); ) | ||
215 | b--; | ||
216 | |||
217 | if (b >= 0) { | ||
218 | input_rate <<= (31 - b); | ||
219 | input_rate /= output_rate; | ||
220 | b = 24 - (31 - b); | ||
221 | if (b >= 0) | ||
222 | input_rate <<= b; | ||
223 | else | ||
224 | input_rate >>= -b; | ||
225 | |||
226 | pitch |= input_rate; | ||
227 | } | ||
228 | |||
229 | return pitch; | ||
230 | } | ||
231 | |||
232 | static int select_rom(unsigned int pitch) | ||
233 | { | ||
234 | if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) { | ||
235 | /* 0.26 <= pitch <= 1.72 */ | ||
236 | return 1; | ||
237 | } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) { | ||
238 | /* pitch == 1.8375 */ | ||
239 | return 2; | ||
240 | } else if (0x02000000 == pitch) { | ||
241 | /* pitch == 2 */ | ||
242 | return 3; | ||
243 | } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) { | ||
244 | /* 0 <= pitch <= 8 */ | ||
245 | return 0; | ||
246 | } else { | ||
247 | return -ENOENT; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
252 | { | ||
253 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
254 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
255 | struct src_desc desc = {0}; | ||
256 | struct amixer_desc mix_dsc = {0}; | ||
257 | struct src *src; | ||
258 | struct amixer *amixer; | ||
259 | int err; | ||
260 | int n_amixer = apcm->substream->runtime->channels, i = 0; | ||
261 | int device = apcm->substream->pcm->device; | ||
262 | unsigned int pitch; | ||
263 | |||
264 | /* first release old resources */ | ||
265 | atc_pcm_release_resources(atc, apcm); | ||
266 | |||
267 | /* Get SRC resource */ | ||
268 | desc.multi = apcm->substream->runtime->channels; | ||
269 | desc.msr = atc->msr; | ||
270 | desc.mode = MEMRD; | ||
271 | err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); | ||
272 | if (err) | ||
273 | goto error1; | ||
274 | |||
275 | pitch = atc_get_pitch(apcm->substream->runtime->rate, | ||
276 | (atc->rsr * atc->msr)); | ||
277 | src = apcm->src; | ||
278 | src->ops->set_pitch(src, pitch); | ||
279 | src->ops->set_rom(src, select_rom(pitch)); | ||
280 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
281 | src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); | ||
282 | |||
283 | /* Get AMIXER resource */ | ||
284 | n_amixer = (n_amixer < 2) ? 2 : n_amixer; | ||
285 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
286 | if (NULL == apcm->amixers) { | ||
287 | err = -ENOMEM; | ||
288 | goto error1; | ||
289 | } | ||
290 | mix_dsc.msr = atc->msr; | ||
291 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
292 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
293 | (struct amixer **)&apcm->amixers[i]); | ||
294 | if (err) | ||
295 | goto error1; | ||
296 | |||
297 | apcm->n_amixer++; | ||
298 | } | ||
299 | |||
300 | /* Set up device virtual mem map */ | ||
301 | err = ct_map_audio_buffer(atc, apcm); | ||
302 | if (err < 0) | ||
303 | goto error1; | ||
304 | |||
305 | /* Connect resources */ | ||
306 | src = apcm->src; | ||
307 | for (i = 0; i < n_amixer; i++) { | ||
308 | amixer = apcm->amixers[i]; | ||
309 | mutex_lock(&atc->atc_mutex); | ||
310 | amixer->ops->setup(amixer, &src->rsc, | ||
311 | INIT_VOL, atc->pcm[i+device*2]); | ||
312 | mutex_unlock(&atc->atc_mutex); | ||
313 | src = src->ops->next_interleave(src); | ||
314 | if (NULL == src) | ||
315 | src = apcm->src; | ||
316 | } | ||
317 | |||
318 | ct_timer_prepare(apcm->timer); | ||
319 | |||
320 | return 0; | ||
321 | |||
322 | error1: | ||
323 | atc_pcm_release_resources(atc, apcm); | ||
324 | return err; | ||
325 | } | ||
326 | |||
327 | static int | ||
328 | atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
329 | { | ||
330 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
331 | struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
332 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
333 | struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; | ||
334 | struct srcimp *srcimp; | ||
335 | int i; | ||
336 | |||
337 | if (NULL != apcm->srcimps) { | ||
338 | for (i = 0; i < apcm->n_srcimp; i++) { | ||
339 | srcimp = apcm->srcimps[i]; | ||
340 | srcimp->ops->unmap(srcimp); | ||
341 | srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); | ||
342 | apcm->srcimps[i] = NULL; | ||
343 | } | ||
344 | kfree(apcm->srcimps); | ||
345 | apcm->srcimps = NULL; | ||
346 | } | ||
347 | |||
348 | if (NULL != apcm->srccs) { | ||
349 | for (i = 0; i < apcm->n_srcc; i++) { | ||
350 | src_mgr->put_src(src_mgr, apcm->srccs[i]); | ||
351 | apcm->srccs[i] = NULL; | ||
352 | } | ||
353 | kfree(apcm->srccs); | ||
354 | apcm->srccs = NULL; | ||
355 | } | ||
356 | |||
357 | if (NULL != apcm->amixers) { | ||
358 | for (i = 0; i < apcm->n_amixer; i++) { | ||
359 | amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); | ||
360 | apcm->amixers[i] = NULL; | ||
361 | } | ||
362 | kfree(apcm->amixers); | ||
363 | apcm->amixers = NULL; | ||
364 | } | ||
365 | |||
366 | if (NULL != apcm->mono) { | ||
367 | sum_mgr->put_sum(sum_mgr, apcm->mono); | ||
368 | apcm->mono = NULL; | ||
369 | } | ||
370 | |||
371 | if (NULL != apcm->src) { | ||
372 | src_mgr->put_src(src_mgr, apcm->src); | ||
373 | apcm->src = NULL; | ||
374 | } | ||
375 | |||
376 | if (NULL != apcm->vm_block) { | ||
377 | /* Undo device virtual mem map */ | ||
378 | ct_unmap_audio_buffer(atc, apcm); | ||
379 | apcm->vm_block = NULL; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
386 | { | ||
387 | unsigned int max_cisz; | ||
388 | struct src *src = apcm->src; | ||
389 | |||
390 | if (apcm->started) | ||
391 | return 0; | ||
392 | apcm->started = 1; | ||
393 | |||
394 | max_cisz = src->multi * src->rsc.msr; | ||
395 | max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); | ||
396 | |||
397 | src->ops->set_sa(src, apcm->vm_block->addr); | ||
398 | src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); | ||
399 | src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); | ||
400 | src->ops->set_cisz(src, max_cisz); | ||
401 | |||
402 | src->ops->set_bm(src, 1); | ||
403 | src->ops->set_state(src, SRC_STATE_INIT); | ||
404 | src->ops->commit_write(src); | ||
405 | |||
406 | ct_timer_start(apcm->timer); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
411 | { | ||
412 | struct src *src; | ||
413 | int i; | ||
414 | |||
415 | ct_timer_stop(apcm->timer); | ||
416 | |||
417 | src = apcm->src; | ||
418 | src->ops->set_bm(src, 0); | ||
419 | src->ops->set_state(src, SRC_STATE_OFF); | ||
420 | src->ops->commit_write(src); | ||
421 | |||
422 | if (NULL != apcm->srccs) { | ||
423 | for (i = 0; i < apcm->n_srcc; i++) { | ||
424 | src = apcm->srccs[i]; | ||
425 | src->ops->set_bm(src, 0); | ||
426 | src->ops->set_state(src, SRC_STATE_OFF); | ||
427 | src->ops->commit_write(src); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | apcm->started = 0; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int | ||
437 | atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
438 | { | ||
439 | struct src *src = apcm->src; | ||
440 | u32 size, max_cisz; | ||
441 | int position; | ||
442 | |||
443 | if (!src) | ||
444 | return 0; | ||
445 | position = src->ops->get_ca(src); | ||
446 | |||
447 | size = apcm->vm_block->size; | ||
448 | max_cisz = src->multi * src->rsc.msr; | ||
449 | max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); | ||
450 | |||
451 | return (position + size - max_cisz - apcm->vm_block->addr) % size; | ||
452 | } | ||
453 | |||
454 | struct src_node_conf_t { | ||
455 | unsigned int pitch; | ||
456 | unsigned int msr:8; | ||
457 | unsigned int mix_msr:8; | ||
458 | unsigned int imp_msr:8; | ||
459 | unsigned int vo:1; | ||
460 | }; | ||
461 | |||
462 | static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, | ||
463 | struct src_node_conf_t *conf, int *n_srcc) | ||
464 | { | ||
465 | unsigned int pitch; | ||
466 | |||
467 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
468 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
469 | apcm->substream->runtime->rate); | ||
470 | *n_srcc = 0; | ||
471 | |||
472 | if (1 == atc->msr) { | ||
473 | *n_srcc = apcm->substream->runtime->channels; | ||
474 | conf[0].pitch = pitch; | ||
475 | conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; | ||
476 | conf[0].vo = 1; | ||
477 | } else if (2 == atc->msr) { | ||
478 | if (0x8000000 < pitch) { | ||
479 | /* Need two-stage SRCs, SRCIMPs and | ||
480 | * AMIXERs for converting format */ | ||
481 | conf[0].pitch = (atc->msr << 24); | ||
482 | conf[0].msr = conf[0].mix_msr = 1; | ||
483 | conf[0].imp_msr = atc->msr; | ||
484 | conf[0].vo = 0; | ||
485 | conf[1].pitch = atc_get_pitch(atc->rsr, | ||
486 | apcm->substream->runtime->rate); | ||
487 | conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; | ||
488 | conf[1].vo = 1; | ||
489 | *n_srcc = apcm->substream->runtime->channels * 2; | ||
490 | } else if (0x1000000 < pitch) { | ||
491 | /* Need one-stage SRCs, SRCIMPs and | ||
492 | * AMIXERs for converting format */ | ||
493 | conf[0].pitch = pitch; | ||
494 | conf[0].msr = conf[0].mix_msr | ||
495 | = conf[0].imp_msr = atc->msr; | ||
496 | conf[0].vo = 1; | ||
497 | *n_srcc = apcm->substream->runtime->channels; | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static int | ||
503 | atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
504 | { | ||
505 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
506 | struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
507 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
508 | struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; | ||
509 | struct src_desc src_dsc = {0}; | ||
510 | struct src *src; | ||
511 | struct srcimp_desc srcimp_dsc = {0}; | ||
512 | struct srcimp *srcimp; | ||
513 | struct amixer_desc mix_dsc = {0}; | ||
514 | struct sum_desc sum_dsc = {0}; | ||
515 | unsigned int pitch; | ||
516 | int multi, err, i; | ||
517 | int n_srcimp, n_amixer, n_srcc, n_sum; | ||
518 | struct src_node_conf_t src_node_conf[2] = {{0} }; | ||
519 | |||
520 | /* first release old resources */ | ||
521 | atc_pcm_release_resources(atc, apcm); | ||
522 | |||
523 | /* The numbers of converting SRCs and SRCIMPs should be determined | ||
524 | * by pitch value. */ | ||
525 | |||
526 | multi = apcm->substream->runtime->channels; | ||
527 | |||
528 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
529 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
530 | apcm->substream->runtime->rate); | ||
531 | |||
532 | setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); | ||
533 | n_sum = (1 == multi) ? 1 : 0; | ||
534 | n_amixer = n_sum * 2 + n_srcc; | ||
535 | n_srcimp = n_srcc; | ||
536 | if ((multi > 1) && (0x8000000 >= pitch)) { | ||
537 | /* Need extra AMIXERs and SRCIMPs for special treatment | ||
538 | * of interleaved recording of conjugate channels */ | ||
539 | n_amixer += multi * atc->msr; | ||
540 | n_srcimp += multi * atc->msr; | ||
541 | } else { | ||
542 | n_srcimp += multi; | ||
543 | } | ||
544 | |||
545 | if (n_srcc) { | ||
546 | apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); | ||
547 | if (NULL == apcm->srccs) | ||
548 | return -ENOMEM; | ||
549 | } | ||
550 | if (n_amixer) { | ||
551 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
552 | if (NULL == apcm->amixers) { | ||
553 | err = -ENOMEM; | ||
554 | goto error1; | ||
555 | } | ||
556 | } | ||
557 | apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); | ||
558 | if (NULL == apcm->srcimps) { | ||
559 | err = -ENOMEM; | ||
560 | goto error1; | ||
561 | } | ||
562 | |||
563 | /* Allocate SRCs for sample rate conversion if needed */ | ||
564 | src_dsc.multi = 1; | ||
565 | src_dsc.mode = ARCRW; | ||
566 | for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { | ||
567 | src_dsc.msr = src_node_conf[i/multi].msr; | ||
568 | err = src_mgr->get_src(src_mgr, &src_dsc, | ||
569 | (struct src **)&apcm->srccs[i]); | ||
570 | if (err) | ||
571 | goto error1; | ||
572 | |||
573 | src = apcm->srccs[i]; | ||
574 | pitch = src_node_conf[i/multi].pitch; | ||
575 | src->ops->set_pitch(src, pitch); | ||
576 | src->ops->set_rom(src, select_rom(pitch)); | ||
577 | src->ops->set_vo(src, src_node_conf[i/multi].vo); | ||
578 | |||
579 | apcm->n_srcc++; | ||
580 | } | ||
581 | |||
582 | /* Allocate AMIXERs for routing SRCs of conversion if needed */ | ||
583 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
584 | if (i < (n_sum*2)) | ||
585 | mix_dsc.msr = atc->msr; | ||
586 | else if (i < (n_sum*2+n_srcc)) | ||
587 | mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; | ||
588 | else | ||
589 | mix_dsc.msr = 1; | ||
590 | |||
591 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
592 | (struct amixer **)&apcm->amixers[i]); | ||
593 | if (err) | ||
594 | goto error1; | ||
595 | |||
596 | apcm->n_amixer++; | ||
597 | } | ||
598 | |||
599 | /* Allocate a SUM resource to mix all input channels together */ | ||
600 | sum_dsc.msr = atc->msr; | ||
601 | err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); | ||
602 | if (err) | ||
603 | goto error1; | ||
604 | |||
605 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
606 | apcm->substream->runtime->rate); | ||
607 | /* Allocate SRCIMP resources */ | ||
608 | for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { | ||
609 | if (i < (n_srcc)) | ||
610 | srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; | ||
611 | else if (1 == multi) | ||
612 | srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; | ||
613 | else | ||
614 | srcimp_dsc.msr = 1; | ||
615 | |||
616 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); | ||
617 | if (err) | ||
618 | goto error1; | ||
619 | |||
620 | apcm->srcimps[i] = srcimp; | ||
621 | apcm->n_srcimp++; | ||
622 | } | ||
623 | |||
624 | /* Allocate a SRC for writing data to host memory */ | ||
625 | src_dsc.multi = apcm->substream->runtime->channels; | ||
626 | src_dsc.msr = 1; | ||
627 | src_dsc.mode = MEMWR; | ||
628 | err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); | ||
629 | if (err) | ||
630 | goto error1; | ||
631 | |||
632 | src = apcm->src; | ||
633 | src->ops->set_pitch(src, pitch); | ||
634 | |||
635 | /* Set up device virtual mem map */ | ||
636 | err = ct_map_audio_buffer(atc, apcm); | ||
637 | if (err < 0) | ||
638 | goto error1; | ||
639 | |||
640 | return 0; | ||
641 | |||
642 | error1: | ||
643 | atc_pcm_release_resources(atc, apcm); | ||
644 | return err; | ||
645 | } | ||
646 | |||
647 | static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
648 | { | ||
649 | struct src *src; | ||
650 | struct amixer *amixer; | ||
651 | struct srcimp *srcimp; | ||
652 | struct ct_mixer *mixer = atc->mixer; | ||
653 | struct sum *mono; | ||
654 | struct rsc *out_ports[8] = {NULL}; | ||
655 | int err, i, j, n_sum, multi; | ||
656 | unsigned int pitch; | ||
657 | int mix_base = 0, imp_base = 0; | ||
658 | |||
659 | atc_pcm_release_resources(atc, apcm); | ||
660 | |||
661 | /* Get needed resources. */ | ||
662 | err = atc_pcm_capture_get_resources(atc, apcm); | ||
663 | if (err) | ||
664 | return err; | ||
665 | |||
666 | /* Connect resources */ | ||
667 | mixer->get_output_ports(mixer, MIX_PCMO_FRONT, | ||
668 | &out_ports[0], &out_ports[1]); | ||
669 | |||
670 | multi = apcm->substream->runtime->channels; | ||
671 | if (1 == multi) { | ||
672 | mono = apcm->mono; | ||
673 | for (i = 0; i < 2; i++) { | ||
674 | amixer = apcm->amixers[i]; | ||
675 | amixer->ops->setup(amixer, out_ports[i], | ||
676 | MONO_SUM_SCALE, mono); | ||
677 | } | ||
678 | out_ports[0] = &mono->rsc; | ||
679 | n_sum = 1; | ||
680 | mix_base = n_sum * 2; | ||
681 | } | ||
682 | |||
683 | for (i = 0; i < apcm->n_srcc; i++) { | ||
684 | src = apcm->srccs[i]; | ||
685 | srcimp = apcm->srcimps[imp_base+i]; | ||
686 | amixer = apcm->amixers[mix_base+i]; | ||
687 | srcimp->ops->map(srcimp, src, out_ports[i%multi]); | ||
688 | amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); | ||
689 | out_ports[i%multi] = &amixer->rsc; | ||
690 | } | ||
691 | |||
692 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
693 | apcm->substream->runtime->rate); | ||
694 | |||
695 | if ((multi > 1) && (pitch <= 0x8000000)) { | ||
696 | /* Special connection for interleaved | ||
697 | * recording with conjugate channels */ | ||
698 | for (i = 0; i < multi; i++) { | ||
699 | out_ports[i]->ops->master(out_ports[i]); | ||
700 | for (j = 0; j < atc->msr; j++) { | ||
701 | amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; | ||
702 | amixer->ops->set_input(amixer, out_ports[i]); | ||
703 | amixer->ops->set_scale(amixer, INIT_VOL); | ||
704 | amixer->ops->set_sum(amixer, NULL); | ||
705 | amixer->ops->commit_raw_write(amixer); | ||
706 | out_ports[i]->ops->next_conj(out_ports[i]); | ||
707 | |||
708 | srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; | ||
709 | srcimp->ops->map(srcimp, apcm->src, | ||
710 | &amixer->rsc); | ||
711 | } | ||
712 | } | ||
713 | } else { | ||
714 | for (i = 0; i < multi; i++) { | ||
715 | srcimp = apcm->srcimps[apcm->n_srcc+i]; | ||
716 | srcimp->ops->map(srcimp, apcm->src, out_ports[i]); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | ct_timer_prepare(apcm->timer); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
726 | { | ||
727 | struct src *src; | ||
728 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
729 | int i, multi; | ||
730 | |||
731 | if (apcm->started) | ||
732 | return 0; | ||
733 | |||
734 | apcm->started = 1; | ||
735 | multi = apcm->substream->runtime->channels; | ||
736 | /* Set up converting SRCs */ | ||
737 | for (i = 0; i < apcm->n_srcc; i++) { | ||
738 | src = apcm->srccs[i]; | ||
739 | src->ops->set_pm(src, ((i%multi) != (multi-1))); | ||
740 | src_mgr->src_disable(src_mgr, src); | ||
741 | } | ||
742 | |||
743 | /* Set up recording SRC */ | ||
744 | src = apcm->src; | ||
745 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
746 | src->ops->set_sa(src, apcm->vm_block->addr); | ||
747 | src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); | ||
748 | src->ops->set_ca(src, apcm->vm_block->addr); | ||
749 | src_mgr->src_disable(src_mgr, src); | ||
750 | |||
751 | /* Disable relevant SRCs firstly */ | ||
752 | src_mgr->commit_write(src_mgr); | ||
753 | |||
754 | /* Enable SRCs respectively */ | ||
755 | for (i = 0; i < apcm->n_srcc; i++) { | ||
756 | src = apcm->srccs[i]; | ||
757 | src->ops->set_state(src, SRC_STATE_RUN); | ||
758 | src->ops->commit_write(src); | ||
759 | src_mgr->src_enable_s(src_mgr, src); | ||
760 | } | ||
761 | src = apcm->src; | ||
762 | src->ops->set_bm(src, 1); | ||
763 | src->ops->set_state(src, SRC_STATE_RUN); | ||
764 | src->ops->commit_write(src); | ||
765 | src_mgr->src_enable_s(src_mgr, src); | ||
766 | |||
767 | /* Enable relevant SRCs synchronously */ | ||
768 | src_mgr->commit_write(src_mgr); | ||
769 | |||
770 | ct_timer_start(apcm->timer); | ||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static int | ||
775 | atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
776 | { | ||
777 | struct src *src = apcm->src; | ||
778 | |||
779 | if (!src) | ||
780 | return 0; | ||
781 | return src->ops->get_ca(src) - apcm->vm_block->addr; | ||
782 | } | ||
783 | |||
784 | static int spdif_passthru_playback_get_resources(struct ct_atc *atc, | ||
785 | struct ct_atc_pcm *apcm) | ||
786 | { | ||
787 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
788 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
789 | struct src_desc desc = {0}; | ||
790 | struct amixer_desc mix_dsc = {0}; | ||
791 | struct src *src; | ||
792 | int err; | ||
793 | int n_amixer = apcm->substream->runtime->channels, i; | ||
794 | unsigned int pitch, rsr = atc->pll_rate; | ||
795 | |||
796 | /* first release old resources */ | ||
797 | atc_pcm_release_resources(atc, apcm); | ||
798 | |||
799 | /* Get SRC resource */ | ||
800 | desc.multi = apcm->substream->runtime->channels; | ||
801 | desc.msr = 1; | ||
802 | while (apcm->substream->runtime->rate > (rsr * desc.msr)) | ||
803 | desc.msr <<= 1; | ||
804 | |||
805 | desc.mode = MEMRD; | ||
806 | err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); | ||
807 | if (err) | ||
808 | goto error1; | ||
809 | |||
810 | pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); | ||
811 | src = apcm->src; | ||
812 | src->ops->set_pitch(src, pitch); | ||
813 | src->ops->set_rom(src, select_rom(pitch)); | ||
814 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
815 | src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); | ||
816 | src->ops->set_bp(src, 1); | ||
817 | |||
818 | /* Get AMIXER resource */ | ||
819 | n_amixer = (n_amixer < 2) ? 2 : n_amixer; | ||
820 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
821 | if (NULL == apcm->amixers) { | ||
822 | err = -ENOMEM; | ||
823 | goto error1; | ||
824 | } | ||
825 | mix_dsc.msr = desc.msr; | ||
826 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
827 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
828 | (struct amixer **)&apcm->amixers[i]); | ||
829 | if (err) | ||
830 | goto error1; | ||
831 | |||
832 | apcm->n_amixer++; | ||
833 | } | ||
834 | |||
835 | /* Set up device virtual mem map */ | ||
836 | err = ct_map_audio_buffer(atc, apcm); | ||
837 | if (err < 0) | ||
838 | goto error1; | ||
839 | |||
840 | return 0; | ||
841 | |||
842 | error1: | ||
843 | atc_pcm_release_resources(atc, apcm); | ||
844 | return err; | ||
845 | } | ||
846 | |||
847 | static int atc_pll_init(struct ct_atc *atc, int rate) | ||
848 | { | ||
849 | struct hw *hw = atc->hw; | ||
850 | int err; | ||
851 | err = hw->pll_init(hw, rate); | ||
852 | atc->pll_rate = err ? 0 : rate; | ||
853 | return err; | ||
854 | } | ||
855 | |||
856 | static int | ||
857 | spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
858 | { | ||
859 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
860 | unsigned int rate = apcm->substream->runtime->rate; | ||
861 | unsigned int status; | ||
862 | int err = 0; | ||
863 | unsigned char iec958_con_fs; | ||
864 | |||
865 | switch (rate) { | ||
866 | case 48000: | ||
867 | iec958_con_fs = IEC958_AES3_CON_FS_48000; | ||
868 | break; | ||
869 | case 44100: | ||
870 | iec958_con_fs = IEC958_AES3_CON_FS_44100; | ||
871 | break; | ||
872 | case 32000: | ||
873 | iec958_con_fs = IEC958_AES3_CON_FS_32000; | ||
874 | break; | ||
875 | default: | ||
876 | return -ENOENT; | ||
877 | } | ||
878 | |||
879 | mutex_lock(&atc->atc_mutex); | ||
880 | dao->ops->get_spos(dao, &status); | ||
881 | if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { | ||
882 | status &= ((~IEC958_AES3_CON_FS) << 24); | ||
883 | status |= (iec958_con_fs << 24); | ||
884 | dao->ops->set_spos(dao, status); | ||
885 | dao->ops->commit_write(dao); | ||
886 | } | ||
887 | if ((rate != atc->pll_rate) && (32000 != rate)) | ||
888 | err = atc_pll_init(atc, rate); | ||
889 | mutex_unlock(&atc->atc_mutex); | ||
890 | |||
891 | return err; | ||
892 | } | ||
893 | |||
894 | static int | ||
895 | spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
896 | { | ||
897 | struct src *src; | ||
898 | struct amixer *amixer; | ||
899 | struct dao *dao; | ||
900 | int err; | ||
901 | int i; | ||
902 | |||
903 | atc_pcm_release_resources(atc, apcm); | ||
904 | |||
905 | /* Configure SPDIFOO and PLL to passthrough mode; | ||
906 | * determine pll_rate. */ | ||
907 | err = spdif_passthru_playback_setup(atc, apcm); | ||
908 | if (err) | ||
909 | return err; | ||
910 | |||
911 | /* Get needed resources. */ | ||
912 | err = spdif_passthru_playback_get_resources(atc, apcm); | ||
913 | if (err) | ||
914 | return err; | ||
915 | |||
916 | /* Connect resources */ | ||
917 | src = apcm->src; | ||
918 | for (i = 0; i < apcm->n_amixer; i++) { | ||
919 | amixer = apcm->amixers[i]; | ||
920 | amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); | ||
921 | src = src->ops->next_interleave(src); | ||
922 | if (NULL == src) | ||
923 | src = apcm->src; | ||
924 | } | ||
925 | /* Connect to SPDIFOO */ | ||
926 | mutex_lock(&atc->atc_mutex); | ||
927 | dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
928 | amixer = apcm->amixers[0]; | ||
929 | dao->ops->set_left_input(dao, &amixer->rsc); | ||
930 | amixer = apcm->amixers[1]; | ||
931 | dao->ops->set_right_input(dao, &amixer->rsc); | ||
932 | mutex_unlock(&atc->atc_mutex); | ||
933 | |||
934 | ct_timer_prepare(apcm->timer); | ||
935 | |||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | static int atc_select_line_in(struct ct_atc *atc) | ||
940 | { | ||
941 | struct hw *hw = atc->hw; | ||
942 | struct ct_mixer *mixer = atc->mixer; | ||
943 | struct src *src; | ||
944 | |||
945 | if (hw->is_adc_source_selected(hw, ADC_LINEIN)) | ||
946 | return 0; | ||
947 | |||
948 | mixer->set_input_left(mixer, MIX_MIC_IN, NULL); | ||
949 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | ||
950 | |||
951 | hw->select_adc_source(hw, ADC_LINEIN); | ||
952 | |||
953 | src = atc->srcs[2]; | ||
954 | mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); | ||
955 | src = atc->srcs[3]; | ||
956 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static int atc_select_mic_in(struct ct_atc *atc) | ||
962 | { | ||
963 | struct hw *hw = atc->hw; | ||
964 | struct ct_mixer *mixer = atc->mixer; | ||
965 | struct src *src; | ||
966 | |||
967 | if (hw->is_adc_source_selected(hw, ADC_MICIN)) | ||
968 | return 0; | ||
969 | |||
970 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | ||
971 | mixer->set_input_right(mixer, MIX_LINE_IN, NULL); | ||
972 | |||
973 | hw->select_adc_source(hw, ADC_MICIN); | ||
974 | |||
975 | src = atc->srcs[2]; | ||
976 | mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); | ||
977 | src = atc->srcs[3]; | ||
978 | mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); | ||
979 | |||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | static int atc_have_digit_io_switch(struct ct_atc *atc) | ||
984 | { | ||
985 | struct hw *hw = atc->hw; | ||
986 | |||
987 | return hw->have_digit_io_switch(hw); | ||
988 | } | ||
989 | |||
990 | static int atc_select_digit_io(struct ct_atc *atc) | ||
991 | { | ||
992 | struct hw *hw = atc->hw; | ||
993 | |||
994 | if (hw->is_adc_source_selected(hw, ADC_NONE)) | ||
995 | return 0; | ||
996 | |||
997 | hw->select_adc_source(hw, ADC_NONE); | ||
998 | |||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) | ||
1003 | { | ||
1004 | struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; | ||
1005 | |||
1006 | if (state) | ||
1007 | daio_mgr->daio_enable(daio_mgr, atc->daios[type]); | ||
1008 | else | ||
1009 | daio_mgr->daio_disable(daio_mgr, atc->daios[type]); | ||
1010 | |||
1011 | daio_mgr->commit_write(daio_mgr); | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | static int | ||
1017 | atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) | ||
1018 | { | ||
1019 | struct dao *dao = container_of(atc->daios[type], struct dao, daio); | ||
1020 | return dao->ops->get_spos(dao, status); | ||
1021 | } | ||
1022 | |||
1023 | static int | ||
1024 | atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) | ||
1025 | { | ||
1026 | struct dao *dao = container_of(atc->daios[type], struct dao, daio); | ||
1027 | |||
1028 | dao->ops->set_spos(dao, status); | ||
1029 | dao->ops->commit_write(dao); | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) | ||
1034 | { | ||
1035 | return atc_daio_unmute(atc, state, LINEO1); | ||
1036 | } | ||
1037 | |||
1038 | static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) | ||
1039 | { | ||
1040 | return atc_daio_unmute(atc, state, LINEO4); | ||
1041 | } | ||
1042 | |||
1043 | static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) | ||
1044 | { | ||
1045 | return atc_daio_unmute(atc, state, LINEO3); | ||
1046 | } | ||
1047 | |||
1048 | static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) | ||
1049 | { | ||
1050 | return atc_daio_unmute(atc, state, LINEO2); | ||
1051 | } | ||
1052 | |||
1053 | static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) | ||
1054 | { | ||
1055 | return atc_daio_unmute(atc, state, LINEIM); | ||
1056 | } | ||
1057 | |||
1058 | static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) | ||
1059 | { | ||
1060 | return atc_daio_unmute(atc, state, SPDIFOO); | ||
1061 | } | ||
1062 | |||
1063 | static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) | ||
1064 | { | ||
1065 | return atc_daio_unmute(atc, state, SPDIFIO); | ||
1066 | } | ||
1067 | |||
1068 | static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) | ||
1069 | { | ||
1070 | return atc_dao_get_status(atc, status, SPDIFOO); | ||
1071 | } | ||
1072 | |||
1073 | static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) | ||
1074 | { | ||
1075 | return atc_dao_set_status(atc, status, SPDIFOO); | ||
1076 | } | ||
1077 | |||
1078 | static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) | ||
1079 | { | ||
1080 | struct dao_desc da_dsc = {0}; | ||
1081 | struct dao *dao; | ||
1082 | int err; | ||
1083 | struct ct_mixer *mixer = atc->mixer; | ||
1084 | struct rsc *rscs[2] = {NULL}; | ||
1085 | unsigned int spos = 0; | ||
1086 | |||
1087 | mutex_lock(&atc->atc_mutex); | ||
1088 | dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
1089 | da_dsc.msr = state ? 1 : atc->msr; | ||
1090 | da_dsc.passthru = state ? 1 : 0; | ||
1091 | err = dao->ops->reinit(dao, &da_dsc); | ||
1092 | if (state) { | ||
1093 | spos = IEC958_DEFAULT_CON; | ||
1094 | } else { | ||
1095 | mixer->get_output_ports(mixer, MIX_SPDIF_OUT, | ||
1096 | &rscs[0], &rscs[1]); | ||
1097 | dao->ops->set_left_input(dao, rscs[0]); | ||
1098 | dao->ops->set_right_input(dao, rscs[1]); | ||
1099 | /* Restore PLL to atc->rsr if needed. */ | ||
1100 | if (atc->pll_rate != atc->rsr) | ||
1101 | err = atc_pll_init(atc, atc->rsr); | ||
1102 | } | ||
1103 | dao->ops->set_spos(dao, spos); | ||
1104 | dao->ops->commit_write(dao); | ||
1105 | mutex_unlock(&atc->atc_mutex); | ||
1106 | |||
1107 | return err; | ||
1108 | } | ||
1109 | |||
1110 | static int atc_release_resources(struct ct_atc *atc) | ||
1111 | { | ||
1112 | int i; | ||
1113 | struct daio_mgr *daio_mgr = NULL; | ||
1114 | struct dao *dao = NULL; | ||
1115 | struct dai *dai = NULL; | ||
1116 | struct daio *daio = NULL; | ||
1117 | struct sum_mgr *sum_mgr = NULL; | ||
1118 | struct src_mgr *src_mgr = NULL; | ||
1119 | struct srcimp_mgr *srcimp_mgr = NULL; | ||
1120 | struct srcimp *srcimp = NULL; | ||
1121 | struct ct_mixer *mixer = NULL; | ||
1122 | |||
1123 | /* disconnect internal mixer objects */ | ||
1124 | if (NULL != atc->mixer) { | ||
1125 | mixer = atc->mixer; | ||
1126 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | ||
1127 | mixer->set_input_right(mixer, MIX_LINE_IN, NULL); | ||
1128 | mixer->set_input_left(mixer, MIX_MIC_IN, NULL); | ||
1129 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | ||
1130 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); | ||
1131 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); | ||
1132 | } | ||
1133 | |||
1134 | if (NULL != atc->daios) { | ||
1135 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; | ||
1136 | for (i = 0; i < atc->n_daio; i++) { | ||
1137 | daio = atc->daios[i]; | ||
1138 | if (daio->type < LINEIM) { | ||
1139 | dao = container_of(daio, struct dao, daio); | ||
1140 | dao->ops->clear_left_input(dao); | ||
1141 | dao->ops->clear_right_input(dao); | ||
1142 | } else { | ||
1143 | dai = container_of(daio, struct dai, daio); | ||
1144 | /* some thing to do for dai ... */ | ||
1145 | } | ||
1146 | daio_mgr->put_daio(daio_mgr, daio); | ||
1147 | } | ||
1148 | kfree(atc->daios); | ||
1149 | atc->daios = NULL; | ||
1150 | } | ||
1151 | |||
1152 | if (NULL != atc->pcm) { | ||
1153 | sum_mgr = atc->rsc_mgrs[SUM]; | ||
1154 | for (i = 0; i < atc->n_pcm; i++) | ||
1155 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); | ||
1156 | |||
1157 | kfree(atc->pcm); | ||
1158 | atc->pcm = NULL; | ||
1159 | } | ||
1160 | |||
1161 | if (NULL != atc->srcs) { | ||
1162 | src_mgr = atc->rsc_mgrs[SRC]; | ||
1163 | for (i = 0; i < atc->n_src; i++) | ||
1164 | src_mgr->put_src(src_mgr, atc->srcs[i]); | ||
1165 | |||
1166 | kfree(atc->srcs); | ||
1167 | atc->srcs = NULL; | ||
1168 | } | ||
1169 | |||
1170 | if (NULL != atc->srcimps) { | ||
1171 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
1172 | for (i = 0; i < atc->n_srcimp; i++) { | ||
1173 | srcimp = atc->srcimps[i]; | ||
1174 | srcimp->ops->unmap(srcimp); | ||
1175 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); | ||
1176 | } | ||
1177 | kfree(atc->srcimps); | ||
1178 | atc->srcimps = NULL; | ||
1179 | } | ||
1180 | |||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | static int ct_atc_destroy(struct ct_atc *atc) | ||
1185 | { | ||
1186 | int i = 0; | ||
1187 | |||
1188 | if (NULL == atc) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (atc->timer) { | ||
1192 | ct_timer_free(atc->timer); | ||
1193 | atc->timer = NULL; | ||
1194 | } | ||
1195 | |||
1196 | atc_release_resources(atc); | ||
1197 | |||
1198 | /* Destroy internal mixer objects */ | ||
1199 | if (NULL != atc->mixer) | ||
1200 | ct_mixer_destroy(atc->mixer); | ||
1201 | |||
1202 | for (i = 0; i < NUM_RSCTYP; i++) { | ||
1203 | if ((NULL != rsc_mgr_funcs[i].destroy) && | ||
1204 | (NULL != atc->rsc_mgrs[i])) | ||
1205 | rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); | ||
1206 | |||
1207 | } | ||
1208 | |||
1209 | if (NULL != atc->hw) | ||
1210 | destroy_hw_obj((struct hw *)atc->hw); | ||
1211 | |||
1212 | /* Destroy device virtual memory manager object */ | ||
1213 | if (NULL != atc->vm) { | ||
1214 | ct_vm_destroy(atc->vm); | ||
1215 | atc->vm = NULL; | ||
1216 | } | ||
1217 | |||
1218 | kfree(atc); | ||
1219 | |||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | static int atc_dev_free(struct snd_device *dev) | ||
1224 | { | ||
1225 | struct ct_atc *atc = dev->device_data; | ||
1226 | return ct_atc_destroy(atc); | ||
1227 | } | ||
1228 | |||
1229 | static int __devinit atc_identify_card(struct ct_atc *atc) | ||
1230 | { | ||
1231 | const struct snd_pci_quirk *p; | ||
1232 | const struct snd_pci_quirk *list; | ||
1233 | |||
1234 | switch (atc->chip_type) { | ||
1235 | case ATC20K1: | ||
1236 | atc->chip_name = "20K1"; | ||
1237 | list = subsys_20k1_list; | ||
1238 | break; | ||
1239 | case ATC20K2: | ||
1240 | atc->chip_name = "20K2"; | ||
1241 | list = subsys_20k2_list; | ||
1242 | break; | ||
1243 | default: | ||
1244 | return -ENOENT; | ||
1245 | } | ||
1246 | p = snd_pci_quirk_lookup(atc->pci, list); | ||
1247 | if (p) { | ||
1248 | if (p->value < 0) { | ||
1249 | printk(KERN_ERR "ctxfi: " | ||
1250 | "Device %04x:%04x is black-listed\n", | ||
1251 | atc->pci->subsystem_vendor, | ||
1252 | atc->pci->subsystem_device); | ||
1253 | return -ENOENT; | ||
1254 | } | ||
1255 | atc->model = p->value; | ||
1256 | } else { | ||
1257 | if (atc->chip_type == ATC20K1) | ||
1258 | atc->model = CT20K1_UNKNOWN; | ||
1259 | else | ||
1260 | atc->model = CT20K2_UNKNOWN; | ||
1261 | } | ||
1262 | atc->model_name = ct_subsys_name[atc->model]; | ||
1263 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", | ||
1264 | atc->chip_name, atc->model_name, | ||
1265 | atc->pci->subsystem_vendor, | ||
1266 | atc->pci->subsystem_device); | ||
1267 | return 0; | ||
1268 | } | ||
1269 | |||
1270 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) | ||
1271 | { | ||
1272 | enum CTALSADEVS i; | ||
1273 | int err; | ||
1274 | |||
1275 | alsa_dev_funcs[MIXER].public_name = atc->chip_name; | ||
1276 | |||
1277 | for (i = 0; i < NUM_CTALSADEVS; i++) { | ||
1278 | if (NULL == alsa_dev_funcs[i].create) | ||
1279 | continue; | ||
1280 | |||
1281 | err = alsa_dev_funcs[i].create(atc, i, | ||
1282 | alsa_dev_funcs[i].public_name); | ||
1283 | if (err) { | ||
1284 | printk(KERN_ERR "ctxfi: " | ||
1285 | "Creating alsa device %d failed!\n", i); | ||
1286 | return err; | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static int __devinit atc_create_hw_devs(struct ct_atc *atc) | ||
1294 | { | ||
1295 | struct hw *hw; | ||
1296 | struct card_conf info = {0}; | ||
1297 | int i, err; | ||
1298 | |||
1299 | err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); | ||
1300 | if (err) { | ||
1301 | printk(KERN_ERR "Failed to create hw obj!!!\n"); | ||
1302 | return err; | ||
1303 | } | ||
1304 | atc->hw = hw; | ||
1305 | |||
1306 | /* Initialize card hardware. */ | ||
1307 | info.rsr = atc->rsr; | ||
1308 | info.msr = atc->msr; | ||
1309 | info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); | ||
1310 | err = hw->card_init(hw, &info); | ||
1311 | if (err < 0) | ||
1312 | return err; | ||
1313 | |||
1314 | for (i = 0; i < NUM_RSCTYP; i++) { | ||
1315 | if (NULL == rsc_mgr_funcs[i].create) | ||
1316 | continue; | ||
1317 | |||
1318 | err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); | ||
1319 | if (err) { | ||
1320 | printk(KERN_ERR "ctxfi: " | ||
1321 | "Failed to create rsc_mgr %d!!!\n", i); | ||
1322 | return err; | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | return 0; | ||
1327 | } | ||
1328 | |||
1329 | static int atc_get_resources(struct ct_atc *atc) | ||
1330 | { | ||
1331 | struct daio_desc da_desc = {0}; | ||
1332 | struct daio_mgr *daio_mgr; | ||
1333 | struct src_desc src_dsc = {0}; | ||
1334 | struct src_mgr *src_mgr; | ||
1335 | struct srcimp_desc srcimp_dsc = {0}; | ||
1336 | struct srcimp_mgr *srcimp_mgr; | ||
1337 | struct sum_desc sum_dsc = {0}; | ||
1338 | struct sum_mgr *sum_mgr; | ||
1339 | int err, i; | ||
1340 | |||
1341 | atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); | ||
1342 | if (NULL == atc->daios) | ||
1343 | return -ENOMEM; | ||
1344 | |||
1345 | atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | ||
1346 | if (NULL == atc->srcs) | ||
1347 | return -ENOMEM; | ||
1348 | |||
1349 | atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | ||
1350 | if (NULL == atc->srcimps) | ||
1351 | return -ENOMEM; | ||
1352 | |||
1353 | atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); | ||
1354 | if (NULL == atc->pcm) | ||
1355 | return -ENOMEM; | ||
1356 | |||
1357 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; | ||
1358 | da_desc.msr = atc->msr; | ||
1359 | for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { | ||
1360 | da_desc.type = i; | ||
1361 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | ||
1362 | (struct daio **)&atc->daios[i]); | ||
1363 | if (err) { | ||
1364 | printk(KERN_ERR "ctxfi: Failed to get DAIO " | ||
1365 | "resource %d!!!\n", i); | ||
1366 | return err; | ||
1367 | } | ||
1368 | atc->n_daio++; | ||
1369 | } | ||
1370 | if (atc->model == CTSB073X) | ||
1371 | da_desc.type = SPDIFI1; | ||
1372 | else | ||
1373 | da_desc.type = SPDIFIO; | ||
1374 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | ||
1375 | (struct daio **)&atc->daios[i]); | ||
1376 | if (err) { | ||
1377 | printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); | ||
1378 | return err; | ||
1379 | } | ||
1380 | atc->n_daio++; | ||
1381 | |||
1382 | src_mgr = atc->rsc_mgrs[SRC]; | ||
1383 | src_dsc.multi = 1; | ||
1384 | src_dsc.msr = atc->msr; | ||
1385 | src_dsc.mode = ARCRW; | ||
1386 | for (i = 0, atc->n_src = 0; i < (2*2); i++) { | ||
1387 | err = src_mgr->get_src(src_mgr, &src_dsc, | ||
1388 | (struct src **)&atc->srcs[i]); | ||
1389 | if (err) | ||
1390 | return err; | ||
1391 | |||
1392 | atc->n_src++; | ||
1393 | } | ||
1394 | |||
1395 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
1396 | srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ | ||
1397 | for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { | ||
1398 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | ||
1399 | (struct srcimp **)&atc->srcimps[i]); | ||
1400 | if (err) | ||
1401 | return err; | ||
1402 | |||
1403 | atc->n_srcimp++; | ||
1404 | } | ||
1405 | srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ | ||
1406 | for (i = 0; i < (2*1); i++) { | ||
1407 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | ||
1408 | (struct srcimp **)&atc->srcimps[2*1+i]); | ||
1409 | if (err) | ||
1410 | return err; | ||
1411 | |||
1412 | atc->n_srcimp++; | ||
1413 | } | ||
1414 | |||
1415 | sum_mgr = atc->rsc_mgrs[SUM]; | ||
1416 | sum_dsc.msr = atc->msr; | ||
1417 | for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { | ||
1418 | err = sum_mgr->get_sum(sum_mgr, &sum_dsc, | ||
1419 | (struct sum **)&atc->pcm[i]); | ||
1420 | if (err) | ||
1421 | return err; | ||
1422 | |||
1423 | atc->n_pcm++; | ||
1424 | } | ||
1425 | |||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | static void | ||
1430 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | ||
1431 | struct src **srcs, struct srcimp **srcimps) | ||
1432 | { | ||
1433 | struct rsc *rscs[2] = {NULL}; | ||
1434 | struct src *src; | ||
1435 | struct srcimp *srcimp; | ||
1436 | int i = 0; | ||
1437 | |||
1438 | rscs[0] = &dai->daio.rscl; | ||
1439 | rscs[1] = &dai->daio.rscr; | ||
1440 | for (i = 0; i < 2; i++) { | ||
1441 | src = srcs[i]; | ||
1442 | srcimp = srcimps[i]; | ||
1443 | srcimp->ops->map(srcimp, src, rscs[i]); | ||
1444 | src_mgr->src_disable(src_mgr, src); | ||
1445 | } | ||
1446 | |||
1447 | src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ | ||
1448 | |||
1449 | src = srcs[0]; | ||
1450 | src->ops->set_pm(src, 1); | ||
1451 | for (i = 0; i < 2; i++) { | ||
1452 | src = srcs[i]; | ||
1453 | src->ops->set_state(src, SRC_STATE_RUN); | ||
1454 | src->ops->commit_write(src); | ||
1455 | src_mgr->src_enable_s(src_mgr, src); | ||
1456 | } | ||
1457 | |||
1458 | dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); | ||
1459 | dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); | ||
1460 | |||
1461 | dai->ops->set_enb_src(dai, 1); | ||
1462 | dai->ops->set_enb_srt(dai, 1); | ||
1463 | dai->ops->commit_write(dai); | ||
1464 | |||
1465 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ | ||
1466 | } | ||
1467 | |||
1468 | static void atc_connect_resources(struct ct_atc *atc) | ||
1469 | { | ||
1470 | struct dai *dai; | ||
1471 | struct dao *dao; | ||
1472 | struct src *src; | ||
1473 | struct sum *sum; | ||
1474 | struct ct_mixer *mixer; | ||
1475 | struct rsc *rscs[2] = {NULL}; | ||
1476 | int i, j; | ||
1477 | |||
1478 | mixer = atc->mixer; | ||
1479 | |||
1480 | for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { | ||
1481 | mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); | ||
1482 | dao = container_of(atc->daios[j], struct dao, daio); | ||
1483 | dao->ops->set_left_input(dao, rscs[0]); | ||
1484 | dao->ops->set_right_input(dao, rscs[1]); | ||
1485 | } | ||
1486 | |||
1487 | dai = container_of(atc->daios[LINEIM], struct dai, daio); | ||
1488 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | ||
1489 | (struct src **)&atc->srcs[2], | ||
1490 | (struct srcimp **)&atc->srcimps[2]); | ||
1491 | src = atc->srcs[2]; | ||
1492 | mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); | ||
1493 | src = atc->srcs[3]; | ||
1494 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); | ||
1495 | |||
1496 | dai = container_of(atc->daios[SPDIFIO], struct dai, daio); | ||
1497 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | ||
1498 | (struct src **)&atc->srcs[0], | ||
1499 | (struct srcimp **)&atc->srcimps[0]); | ||
1500 | |||
1501 | src = atc->srcs[0]; | ||
1502 | mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); | ||
1503 | src = atc->srcs[1]; | ||
1504 | mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); | ||
1505 | |||
1506 | for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { | ||
1507 | sum = atc->pcm[j]; | ||
1508 | mixer->set_input_left(mixer, i, &sum->rsc); | ||
1509 | sum = atc->pcm[j+1]; | ||
1510 | mixer->set_input_right(mixer, i, &sum->rsc); | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1514 | #ifdef CONFIG_PM | ||
1515 | static int atc_suspend(struct ct_atc *atc, pm_message_t state) | ||
1516 | { | ||
1517 | int i; | ||
1518 | struct hw *hw = atc->hw; | ||
1519 | |||
1520 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); | ||
1521 | |||
1522 | for (i = FRONT; i < NUM_PCMS; i++) { | ||
1523 | if (!atc->pcms[i]) | ||
1524 | continue; | ||
1525 | |||
1526 | snd_pcm_suspend_all(atc->pcms[i]); | ||
1527 | } | ||
1528 | |||
1529 | atc_release_resources(atc); | ||
1530 | |||
1531 | hw->suspend(hw, state); | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | static int atc_hw_resume(struct ct_atc *atc) | ||
1537 | { | ||
1538 | struct hw *hw = atc->hw; | ||
1539 | struct card_conf info = {0}; | ||
1540 | |||
1541 | /* Re-initialize card hardware. */ | ||
1542 | info.rsr = atc->rsr; | ||
1543 | info.msr = atc->msr; | ||
1544 | info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); | ||
1545 | return hw->resume(hw, &info); | ||
1546 | } | ||
1547 | |||
1548 | static int atc_resources_resume(struct ct_atc *atc) | ||
1549 | { | ||
1550 | struct ct_mixer *mixer; | ||
1551 | int err = 0; | ||
1552 | |||
1553 | /* Get resources */ | ||
1554 | err = atc_get_resources(atc); | ||
1555 | if (err < 0) { | ||
1556 | atc_release_resources(atc); | ||
1557 | return err; | ||
1558 | } | ||
1559 | |||
1560 | /* Build topology */ | ||
1561 | atc_connect_resources(atc); | ||
1562 | |||
1563 | mixer = atc->mixer; | ||
1564 | mixer->resume(mixer); | ||
1565 | |||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int atc_resume(struct ct_atc *atc) | ||
1570 | { | ||
1571 | int err = 0; | ||
1572 | |||
1573 | /* Do hardware resume. */ | ||
1574 | err = atc_hw_resume(atc); | ||
1575 | if (err < 0) { | ||
1576 | printk(KERN_ERR "ctxfi: pci_enable_device failed, " | ||
1577 | "disabling device\n"); | ||
1578 | snd_card_disconnect(atc->card); | ||
1579 | return err; | ||
1580 | } | ||
1581 | |||
1582 | err = atc_resources_resume(atc); | ||
1583 | if (err < 0) | ||
1584 | return err; | ||
1585 | |||
1586 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); | ||
1587 | |||
1588 | return 0; | ||
1589 | } | ||
1590 | #endif | ||
1591 | |||
1592 | static struct ct_atc atc_preset __devinitdata = { | ||
1593 | .map_audio_buffer = ct_map_audio_buffer, | ||
1594 | .unmap_audio_buffer = ct_unmap_audio_buffer, | ||
1595 | .pcm_playback_prepare = atc_pcm_playback_prepare, | ||
1596 | .pcm_release_resources = atc_pcm_release_resources, | ||
1597 | .pcm_playback_start = atc_pcm_playback_start, | ||
1598 | .pcm_playback_stop = atc_pcm_stop, | ||
1599 | .pcm_playback_position = atc_pcm_playback_position, | ||
1600 | .pcm_capture_prepare = atc_pcm_capture_prepare, | ||
1601 | .pcm_capture_start = atc_pcm_capture_start, | ||
1602 | .pcm_capture_stop = atc_pcm_stop, | ||
1603 | .pcm_capture_position = atc_pcm_capture_position, | ||
1604 | .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, | ||
1605 | .get_ptp_phys = atc_get_ptp_phys, | ||
1606 | .select_line_in = atc_select_line_in, | ||
1607 | .select_mic_in = atc_select_mic_in, | ||
1608 | .select_digit_io = atc_select_digit_io, | ||
1609 | .line_front_unmute = atc_line_front_unmute, | ||
1610 | .line_surround_unmute = atc_line_surround_unmute, | ||
1611 | .line_clfe_unmute = atc_line_clfe_unmute, | ||
1612 | .line_rear_unmute = atc_line_rear_unmute, | ||
1613 | .line_in_unmute = atc_line_in_unmute, | ||
1614 | .spdif_out_unmute = atc_spdif_out_unmute, | ||
1615 | .spdif_in_unmute = atc_spdif_in_unmute, | ||
1616 | .spdif_out_get_status = atc_spdif_out_get_status, | ||
1617 | .spdif_out_set_status = atc_spdif_out_set_status, | ||
1618 | .spdif_out_passthru = atc_spdif_out_passthru, | ||
1619 | .have_digit_io_switch = atc_have_digit_io_switch, | ||
1620 | #ifdef CONFIG_PM | ||
1621 | .suspend = atc_suspend, | ||
1622 | .resume = atc_resume, | ||
1623 | #endif | ||
1624 | }; | ||
1625 | |||
1626 | /** | ||
1627 | * ct_atc_create - create and initialize a hardware manager | ||
1628 | * @card: corresponding alsa card object | ||
1629 | * @pci: corresponding kernel pci device object | ||
1630 | * @ratc: return created object address in it | ||
1631 | * | ||
1632 | * Creates and initializes a hardware manager. | ||
1633 | * | ||
1634 | * Creates kmallocated ct_atc structure. Initializes hardware. | ||
1635 | * Returns 0 if suceeds, or negative error code if fails. | ||
1636 | */ | ||
1637 | |||
1638 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | ||
1639 | unsigned int rsr, unsigned int msr, | ||
1640 | int chip_type, struct ct_atc **ratc) | ||
1641 | { | ||
1642 | struct ct_atc *atc; | ||
1643 | static struct snd_device_ops ops = { | ||
1644 | .dev_free = atc_dev_free, | ||
1645 | }; | ||
1646 | int err; | ||
1647 | |||
1648 | *ratc = NULL; | ||
1649 | |||
1650 | atc = kzalloc(sizeof(*atc), GFP_KERNEL); | ||
1651 | if (NULL == atc) | ||
1652 | return -ENOMEM; | ||
1653 | |||
1654 | /* Set operations */ | ||
1655 | *atc = atc_preset; | ||
1656 | |||
1657 | atc->card = card; | ||
1658 | atc->pci = pci; | ||
1659 | atc->rsr = rsr; | ||
1660 | atc->msr = msr; | ||
1661 | atc->chip_type = chip_type; | ||
1662 | |||
1663 | mutex_init(&atc->atc_mutex); | ||
1664 | |||
1665 | /* Find card model */ | ||
1666 | err = atc_identify_card(atc); | ||
1667 | if (err < 0) { | ||
1668 | printk(KERN_ERR "ctatc: Card not recognised\n"); | ||
1669 | goto error1; | ||
1670 | } | ||
1671 | |||
1672 | /* Set up device virtual memory management object */ | ||
1673 | err = ct_vm_create(&atc->vm); | ||
1674 | if (err < 0) | ||
1675 | goto error1; | ||
1676 | |||
1677 | /* Create all atc hw devices */ | ||
1678 | err = atc_create_hw_devs(atc); | ||
1679 | if (err < 0) | ||
1680 | goto error1; | ||
1681 | |||
1682 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1683 | if (err) { | ||
1684 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1685 | goto error1; | ||
1686 | } | ||
1687 | |||
1688 | /* Get resources */ | ||
1689 | err = atc_get_resources(atc); | ||
1690 | if (err < 0) | ||
1691 | goto error1; | ||
1692 | |||
1693 | /* Build topology */ | ||
1694 | atc_connect_resources(atc); | ||
1695 | |||
1696 | atc->timer = ct_timer_new(atc); | ||
1697 | if (!atc->timer) | ||
1698 | goto error1; | ||
1699 | |||
1700 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); | ||
1701 | if (err < 0) | ||
1702 | goto error1; | ||
1703 | |||
1704 | snd_card_set_dev(card, &pci->dev); | ||
1705 | |||
1706 | *ratc = atc; | ||
1707 | return 0; | ||
1708 | |||
1709 | error1: | ||
1710 | ct_atc_destroy(atc); | ||
1711 | printk(KERN_ERR "ctxfi: Something wrong!!!\n"); | ||
1712 | return err; | ||
1713 | } | ||