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