blob: fac783f585fcee61a448c0ea4e45f76d43fde46d [file] [log] [blame]
Wai Yew CHAY8cc72362009-05-14 08:05:58 +02001/**
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 ctmixer.c
9 *
10 * @Brief
11 * This file contains the implementation of alsa mixer device functions.
12 *
13 * @Author Liu Chun
14 * @Date May 28 2008
15 *
16 */
17
18
19#include "ctmixer.h"
20#include "ctamixer.h"
21#include <sound/core.h>
22#include <sound/control.h>
23#include <sound/asoundef.h>
24#include <sound/pcm.h>
25#include <linux/slab.h>
26
27enum CT_SUM_CTL {
28 SUM_IN_F,
29 SUM_IN_R,
30 SUM_IN_C,
31 SUM_IN_S,
32 SUM_IN_F_C,
33
34 NUM_CT_SUMS
35};
36
37enum CT_AMIXER_CTL {
38 /* volume control mixers */
39 AMIXER_MASTER_F,
40 AMIXER_MASTER_R,
41 AMIXER_MASTER_C,
42 AMIXER_MASTER_S,
43 AMIXER_PCM_F,
44 AMIXER_PCM_R,
45 AMIXER_PCM_C,
46 AMIXER_PCM_S,
47 AMIXER_SPDIFI,
48 AMIXER_LINEIN,
49 AMIXER_MIC,
50 AMIXER_SPDIFO,
51 AMIXER_WAVE_F,
52 AMIXER_WAVE_R,
53 AMIXER_WAVE_C,
54 AMIXER_WAVE_S,
55 AMIXER_MASTER_F_C,
56 AMIXER_PCM_F_C,
57 AMIXER_SPDIFI_C,
58 AMIXER_LINEIN_C,
59 AMIXER_MIC_C,
60
61 /* this should always be the last one */
62 NUM_CT_AMIXERS
63};
64
65enum CTALSA_MIXER_CTL {
66 /* volume control mixers */
67 MIXER_MASTER_P,
68 MIXER_PCM_P,
69 MIXER_LINEIN_P,
70 MIXER_MIC_P,
71 MIXER_SPDIFI_P,
72 MIXER_SPDIFO_P,
73 MIXER_WAVEF_P,
74 MIXER_WAVER_P,
75 MIXER_WAVEC_P,
76 MIXER_WAVES_P,
77 MIXER_MASTER_C,
78 MIXER_PCM_C,
79 MIXER_LINEIN_C,
80 MIXER_MIC_C,
81 MIXER_SPDIFI_C,
82
83 /* switch control mixers */
84 MIXER_PCM_C_S,
85 MIXER_LINEIN_C_S,
86 MIXER_MIC_C_S,
87 MIXER_SPDIFI_C_S,
88 MIXER_LINEIN_P_S,
89 MIXER_SPDIFO_P_S,
90 MIXER_SPDIFI_P_S,
91 MIXER_WAVEF_P_S,
92 MIXER_WAVER_P_S,
93 MIXER_WAVEC_P_S,
94 MIXER_WAVES_P_S,
95 MIXER_DIGITAL_IO_S,
96 MIXER_IEC958_MASK,
97 MIXER_IEC958_DEFAULT,
98 MIXER_IEC958_STREAM,
99
100 /* this should always be the last one */
101 NUM_CTALSA_MIXERS
102};
103
104#define VOL_MIXER_START MIXER_MASTER_P
105#define VOL_MIXER_END MIXER_SPDIFI_C
106#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)
107#define SWH_MIXER_START MIXER_PCM_C_S
108#define SWH_MIXER_END MIXER_DIGITAL_IO_S
109#define SWH_CAPTURE_START MIXER_PCM_C_S
110#define SWH_CAPTURE_END MIXER_SPDIFI_C_S
111
112#define CHN_NUM 2
113
114struct ct_kcontrol_init {
115 unsigned char ctl;
116 char *name;
117};
118
119static struct ct_kcontrol_init
120ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
121 [MIXER_MASTER_P] = {
122 .ctl = 1,
123 .name = "Master Playback Volume",
124 },
125 [MIXER_MASTER_C] = {
126 .ctl = 1,
127 .name = "Master Capture Volume",
128 },
129 [MIXER_PCM_P] = {
130 .ctl = 1,
131 .name = "PCM Playback Volume",
132 },
133 [MIXER_PCM_C] = {
134 .ctl = 1,
135 .name = "PCM Capture Volume",
136 },
137 [MIXER_LINEIN_P] = {
138 .ctl = 1,
139 .name = "Line-in Playback Volume",
140 },
141 [MIXER_LINEIN_C] = {
142 .ctl = 1,
143 .name = "Line-in Capture Volume",
144 },
145 [MIXER_MIC_P] = {
146 .ctl = 1,
147 .name = "Mic Playback Volume",
148 },
149 [MIXER_MIC_C] = {
150 .ctl = 1,
151 .name = "Mic Capture Volume",
152 },
153 [MIXER_SPDIFI_P] = {
154 .ctl = 1,
155 .name = "S/PDIF-in Playback Volume",
156 },
157 [MIXER_SPDIFI_C] = {
158 .ctl = 1,
159 .name = "S/PDIF-in Capture Volume",
160 },
161 [MIXER_SPDIFO_P] = {
162 .ctl = 1,
163 .name = "S/PDIF-out Playback Volume",
164 },
165 [MIXER_WAVEF_P] = {
166 .ctl = 1,
167 .name = "Front Playback Volume",
168 },
169 [MIXER_WAVES_P] = {
170 .ctl = 1,
Takashi Iwai6585db92009-06-02 14:17:27 +0200171 .name = "Side Playback Volume",
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200172 },
173 [MIXER_WAVEC_P] = {
174 .ctl = 1,
175 .name = "Center/LFE Playback Volume",
176 },
177 [MIXER_WAVER_P] = {
178 .ctl = 1,
Takashi Iwai6585db92009-06-02 14:17:27 +0200179 .name = "Surround Playback Volume",
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200180 },
181
182 [MIXER_PCM_C_S] = {
183 .ctl = 1,
184 .name = "PCM Capture Switch",
185 },
186 [MIXER_LINEIN_C_S] = {
187 .ctl = 1,
188 .name = "Line-in Capture Switch",
189 },
190 [MIXER_MIC_C_S] = {
191 .ctl = 1,
192 .name = "Mic Capture Switch",
193 },
194 [MIXER_SPDIFI_C_S] = {
195 .ctl = 1,
196 .name = "S/PDIF-in Capture Switch",
197 },
198 [MIXER_LINEIN_P_S] = {
199 .ctl = 1,
200 .name = "Line-in Playback Switch",
201 },
202 [MIXER_SPDIFO_P_S] = {
203 .ctl = 1,
204 .name = "S/PDIF-out Playback Switch",
205 },
206 [MIXER_SPDIFI_P_S] = {
207 .ctl = 1,
208 .name = "S/PDIF-in Playback Switch",
209 },
210 [MIXER_WAVEF_P_S] = {
211 .ctl = 1,
212 .name = "Front Playback Switch",
213 },
214 [MIXER_WAVES_P_S] = {
215 .ctl = 1,
Takashi Iwai6585db92009-06-02 14:17:27 +0200216 .name = "Side Playback Switch",
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200217 },
218 [MIXER_WAVEC_P_S] = {
219 .ctl = 1,
220 .name = "Center/LFE Playback Switch",
221 },
222 [MIXER_WAVER_P_S] = {
223 .ctl = 1,
Takashi Iwai6585db92009-06-02 14:17:27 +0200224 .name = "Surround Playback Switch",
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200225 },
226 [MIXER_DIGITAL_IO_S] = {
227 .ctl = 0,
228 .name = "Digit-IO Playback Switch",
229 },
230};
231
232static void
233ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
234
235static void
236ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
237
238static struct snd_kcontrol *kctls[2] = {NULL};
239
240static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
241{
242 switch (alsa_index) {
243 case MIXER_MASTER_P: return AMIXER_MASTER_F;
244 case MIXER_MASTER_C: return AMIXER_MASTER_F_C;
245 case MIXER_PCM_P: return AMIXER_PCM_F;
246 case MIXER_PCM_C:
247 case MIXER_PCM_C_S: return AMIXER_PCM_F_C;
248 case MIXER_LINEIN_P: return AMIXER_LINEIN;
249 case MIXER_LINEIN_C:
250 case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C;
251 case MIXER_MIC_P: return AMIXER_MIC;
252 case MIXER_MIC_C:
253 case MIXER_MIC_C_S: return AMIXER_MIC_C;
254 case MIXER_SPDIFI_P: return AMIXER_SPDIFI;
255 case MIXER_SPDIFI_C:
256 case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C;
257 case MIXER_SPDIFO_P: return AMIXER_SPDIFO;
258 case MIXER_WAVEF_P: return AMIXER_WAVE_F;
259 case MIXER_WAVES_P: return AMIXER_WAVE_S;
260 case MIXER_WAVEC_P: return AMIXER_WAVE_C;
261 case MIXER_WAVER_P: return AMIXER_WAVE_R;
262 default: return NUM_CT_AMIXERS;
263 }
264}
265
266static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
267{
268 switch (index) {
269 case AMIXER_MASTER_F: return AMIXER_MASTER_F_C;
270 case AMIXER_PCM_F: return AMIXER_PCM_F_C;
271 case AMIXER_SPDIFI: return AMIXER_SPDIFI_C;
272 case AMIXER_LINEIN: return AMIXER_LINEIN_C;
273 case AMIXER_MIC: return AMIXER_MIC_C;
274 default: return NUM_CT_AMIXERS;
275 }
276}
277
278static unsigned char
279get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
280{
281 return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
282 ? 1 : 0;
283}
284
285static void
286set_switch_state(struct ct_mixer *mixer,
287 enum CTALSA_MIXER_CTL type, unsigned char state)
288{
289 if (state)
290 mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
291 else
292 mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
293}
294
295/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
296 * from 2^-6 to (1+1023/1024) */
297static unsigned int uint16_to_float14(unsigned int x)
298{
299 unsigned int i = 0;
300
301 if (x < 17)
302 return 0;
303
304 x *= 2031;
305 x /= 65535;
306 x += 16;
307
308 /* i <= 6 */
309 for (i = 0; !(x & 0x400); i++)
310 x <<= 1;
311
312 x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
313
314 return x;
315}
316
317static unsigned int float14_to_uint16(unsigned int x)
318{
319 unsigned int e = 0;
320
321 if (!x)
322 return x;
323
324 e = (x >> 10) & 0x7;
325 x &= 0x3ff;
326 x += 1024;
327 x >>= (7 - e);
328 x -= 16;
329 x *= 65535;
330 x /= 2031;
331
332 return x;
333}
334
335static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_info *uinfo)
337{
338 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
339 uinfo->count = 2;
340 uinfo->value.integer.min = 0;
341 uinfo->value.integer.max = 43690;
342 uinfo->value.integer.step = 128;
343
344 return 0;
345}
346
347static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
348 struct snd_ctl_elem_value *ucontrol)
349{
350 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
351 enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
352 struct amixer *amixer = NULL;
353 int i = 0;
354
355 for (i = 0; i < 2; i++) {
356 amixer = ((struct ct_mixer *)atc->mixer)->
357 amixers[type*CHN_NUM+i];
358 /* Convert 14-bit float-point scale to 16-bit integer volume */
359 ucontrol->value.integer.value[i] =
360 (float14_to_uint16(amixer->ops->get_scale(amixer)) & 0xffff);
361 }
362
363 return 0;
364}
365
366static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_value *ucontrol)
368{
369 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
370 struct ct_mixer *mixer = atc->mixer;
371 enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
372 struct amixer *amixer = NULL;
373 int i = 0, j = 0, change = 0, val = 0;
374
375 for (i = 0; i < 2; i++) {
376 /* Convert 16-bit integer volume to 14-bit float-point scale */
377 val = (ucontrol->value.integer.value[i] & 0xffff);
378 amixer = mixer->amixers[type*CHN_NUM+i];
379 if ((float14_to_uint16(amixer->ops->get_scale(amixer)) & 0xff80)
380 != (val & 0xff80)) {
381 val = uint16_to_float14(val);
382 amixer->ops->set_scale(amixer, val);
383 amixer->ops->commit_write(amixer);
384 change = 1;
385 /* Synchronize Master/PCM playback AMIXERs. */
386 if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
387 for (j = 1; j < 4; j++) {
388 amixer = mixer->
389 amixers[(type+j)*CHN_NUM+i];
390 amixer->ops->set_scale(amixer, val);
391 amixer->ops->commit_write(amixer);
392 }
393 }
394 }
395 }
396
397 return change;
398}
399
400static struct snd_kcontrol_new vol_ctl = {
401 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
402 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
403 .info = ct_alsa_mix_volume_info,
404 .get = ct_alsa_mix_volume_get,
405 .put = ct_alsa_mix_volume_put
406};
407
408static void
409do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
410{
411
412 if (MIXER_LINEIN_C_S == type) {
413 atc->select_line_in(atc);
414 set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
415 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
416 &kctls[1]->id);
417 } else if (MIXER_MIC_C_S == type) {
418 atc->select_mic_in(atc);
419 set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
420 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
421 &kctls[0]->id);
422 }
423}
424
425static void
426do_digit_io_switch(struct ct_atc *atc, int state)
427{
428 struct ct_mixer *mixer = atc->mixer;
429
430 if (state) {
431 atc->select_digit_io(atc);
432 atc->spdif_out_unmute(atc,
433 get_switch_state(mixer, MIXER_SPDIFO_P_S));
434 atc->spdif_in_unmute(atc, 1);
435 atc->line_in_unmute(atc, 0);
436 return;
437 }
438
439 if (get_switch_state(mixer, MIXER_LINEIN_C_S))
440 atc->select_line_in(atc);
441 else if (get_switch_state(mixer, MIXER_MIC_C_S))
442 atc->select_mic_in(atc);
443
444 atc->spdif_out_unmute(atc, 0);
445 atc->spdif_in_unmute(atc, 0);
446 atc->line_in_unmute(atc, 1);
447 return;
448}
449
450static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_info *uinfo)
452{
453 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
454 uinfo->count = 1;
455 uinfo->value.integer.min = 0;
456 uinfo->value.integer.max = 1;
457 uinfo->value.integer.step = 1;
458
459 return 0;
460}
461
462static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_value *ucontrol)
464{
465 struct ct_mixer *mixer =
466 ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
467 enum CTALSA_MIXER_CTL type = kcontrol->private_value;
468
469 ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
470 return 0;
471}
472
473static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
474 struct snd_ctl_elem_value *ucontrol)
475{
476 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
477 struct ct_mixer *mixer = atc->mixer;
478 enum CTALSA_MIXER_CTL type = kcontrol->private_value;
479 int state = 0;
480
481 state = ucontrol->value.integer.value[0];
482 if (get_switch_state(mixer, type) == state)
483 return 0;
484
485 set_switch_state(mixer, type, state);
486 /* Do changes in mixer. */
487 if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
488 if (state) {
489 ct_mixer_recording_select(mixer,
490 get_amixer_index(type));
491 } else {
492 ct_mixer_recording_unselect(mixer,
493 get_amixer_index(type));
494 }
495 }
496 /* Do changes out of mixer. */
497 if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
498 do_line_mic_switch(atc, type);
499 else if (MIXER_WAVEF_P_S == type)
500 atc->line_front_unmute(atc, state);
501 else if (MIXER_WAVES_P_S == type)
502 atc->line_surround_unmute(atc, state);
503 else if (MIXER_WAVEC_P_S == type)
504 atc->line_clfe_unmute(atc, state);
505 else if (MIXER_WAVER_P_S == type)
506 atc->line_rear_unmute(atc, state);
507 else if (MIXER_LINEIN_P_S == type)
508 atc->line_in_unmute(atc, state);
509 else if (MIXER_SPDIFO_P_S == type)
510 atc->spdif_out_unmute(atc, state);
511 else if (MIXER_SPDIFI_P_S == type)
512 atc->spdif_in_unmute(atc, state);
513 else if (MIXER_DIGITAL_IO_S == type)
514 do_digit_io_switch(atc, state);
515
516 return 1;
517}
518
519static struct snd_kcontrol_new swh_ctl = {
520 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
522 .info = ct_alsa_mix_switch_info,
523 .get = ct_alsa_mix_switch_get,
524 .put = ct_alsa_mix_switch_put
525};
526
527static int ct_spdif_info(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_info *uinfo)
529{
530 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
531 uinfo->count = 1;
532 return 0;
533}
534
535static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_value *ucontrol)
537{
538 ucontrol->value.iec958.status[0] = 0xff;
539 ucontrol->value.iec958.status[1] = 0xff;
540 ucontrol->value.iec958.status[2] = 0xff;
541 ucontrol->value.iec958.status[3] = 0xff;
542 return 0;
543}
544
545static int ct_spdif_default_get(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_value *ucontrol)
547{
548 unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF;
549
550 ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
551 ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
552 ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
553 ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
554
555 return 0;
556}
557
558static int ct_spdif_get(struct snd_kcontrol *kcontrol,
559 struct snd_ctl_elem_value *ucontrol)
560{
561 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
562 unsigned int status = 0;
563
564 atc->spdif_out_get_status(atc, &status);
565 ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
566 ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
567 ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
568 ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
569
570 return 0;
571}
572
573static int ct_spdif_put(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol)
575{
576 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
577 int change = 1;
578 unsigned int status = 0, old_status = 0;
579
580 status = (ucontrol->value.iec958.status[0] << 0) |
581 (ucontrol->value.iec958.status[1] << 8) |
582 (ucontrol->value.iec958.status[2] << 16) |
583 (ucontrol->value.iec958.status[3] << 24);
584
585 atc->spdif_out_get_status(atc, &old_status);
586 change = (old_status != status);
587 if (change)
588 atc->spdif_out_set_status(atc, status);
589
590 return change;
591}
592
593static struct snd_kcontrol_new iec958_mask_ctl = {
594 .access = SNDRV_CTL_ELEM_ACCESS_READ,
595 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
596 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
597 .count = 1,
598 .info = ct_spdif_info,
599 .get = ct_spdif_get_mask,
600 .private_value = MIXER_IEC958_MASK
601};
602
603static struct snd_kcontrol_new iec958_default_ctl = {
604 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
605 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
606 .count = 1,
607 .info = ct_spdif_info,
608 .get = ct_spdif_default_get,
609 .put = ct_spdif_put,
610 .private_value = MIXER_IEC958_DEFAULT
611};
612
613static struct snd_kcontrol_new iec958_ctl = {
614 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
615 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
616 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
617 .count = 1,
618 .info = ct_spdif_info,
619 .get = ct_spdif_get,
620 .put = ct_spdif_put,
621 .private_value = MIXER_IEC958_STREAM
622};
623
624#define NUM_IEC958_CTL 3
625
626static int
627ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
628{
629 struct snd_kcontrol *kctl = NULL;
630 int err = 0;
631
632 kctl = snd_ctl_new1(new, mixer->atc);
633 if (NULL == kctl)
634 return -ENOMEM;
635
636 if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
637 kctl->id.device = IEC958;
638
639 err = snd_ctl_add(mixer->atc->card, kctl);
640 if (err)
641 return err;
642
643 switch (new->private_value) {
644 case MIXER_LINEIN_C_S:
645 kctls[0] = kctl; break;
646 case MIXER_MIC_C_S:
647 kctls[1] = kctl; break;
648 default:
649 break;
650 }
651
652 return 0;
653}
654
655static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
656{
657 enum CTALSA_MIXER_CTL type = 0;
658 struct ct_atc *atc = mixer->atc;
659 int err = 0;
660
661 /* Create snd kcontrol instances on demand */
662 for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
663 if (ct_kcontrol_init_table[type].ctl) {
664 vol_ctl.name = ct_kcontrol_init_table[type].name;
665 vol_ctl.private_value = (unsigned long)type;
666 err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
667 if (err)
668 return err;
669 }
670 }
671
672 ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
673 atc->have_digit_io_switch(atc);
674 for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
675 if (ct_kcontrol_init_table[type].ctl) {
676 swh_ctl.name = ct_kcontrol_init_table[type].name;
677 swh_ctl.private_value = (unsigned long)type;
678 err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
679 if (err)
680 return err;
681 }
682 }
683
684 err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
685 if (err)
686 return err;
687
688 err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
689 if (err)
690 return err;
691
692 err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
693 if (err)
694 return err;
695
696 atc->line_front_unmute(atc, 1);
697 set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
698 atc->line_surround_unmute(atc, 0);
699 set_switch_state(mixer, MIXER_WAVES_P_S, 0);
700 atc->line_clfe_unmute(atc, 0);
701 set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
702 atc->line_rear_unmute(atc, 0);
703 set_switch_state(mixer, MIXER_WAVER_P_S, 0);
704 atc->spdif_out_unmute(atc, 0);
705 set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
706 atc->line_in_unmute(atc, 0);
707 set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
708 atc->spdif_in_unmute(atc, 0);
709 set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
710
711 set_switch_state(mixer, MIXER_PCM_C_S, 1);
712 set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
713 set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
714
715 return 0;
716}
717
718static void
719ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
720{
721 struct amixer *amix_d = NULL;
722 struct sum *sum_c = NULL;
723 int i = 0;
724
725 for (i = 0; i < 2; i++) {
726 amix_d = mixer->amixers[type*CHN_NUM+i];
727 sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
728 amix_d->ops->set_sum(amix_d, sum_c);
729 amix_d->ops->commit_write(amix_d);
730 }
731}
732
733static void
734ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
735{
736 struct amixer *amix_d = NULL;
737 int i = 0;
738
739 for (i = 0; i < 2; i++) {
740 amix_d = mixer->amixers[type*CHN_NUM+i];
741 amix_d->ops->set_sum(amix_d, NULL);
742 amix_d->ops->commit_write(amix_d);
743 }
744}
745
746static int ct_mixer_get_resources(struct ct_mixer *mixer)
747{
748 struct sum_mgr *sum_mgr = NULL;
749 struct sum *sum = NULL;
750 struct sum_desc sum_desc = {0};
751 struct amixer_mgr *amixer_mgr = NULL;
752 struct amixer *amixer = NULL;
753 struct amixer_desc am_desc = {0};
754 int err = 0;
755 int i = 0;
756
757 /* Allocate sum resources for mixer obj */
758 sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
759 sum_desc.msr = mixer->atc->msr;
760 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
761 err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
762 if (err) {
Takashi Iwaib3e0afe2009-05-14 15:19:30 +0200763 printk(KERN_ERR "ctxfi:Failed to get sum resources for "
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200764 "front output!\n");
765 break;
766 }
767 mixer->sums[i] = sum;
768 }
769 if (err)
770 goto error1;
771
772 /* Allocate amixer resources for mixer obj */
773 amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
774 am_desc.msr = mixer->atc->msr;
775 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
776 err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
777 if (err) {
Takashi Iwaib3e0afe2009-05-14 15:19:30 +0200778 printk(KERN_ERR "ctxfi:Failed to get amixer resources "
779 "for mixer obj!\n");
Wai Yew CHAY8cc72362009-05-14 08:05:58 +0200780 break;
781 }
782 mixer->amixers[i] = amixer;
783 }
784 if (err)
785 goto error2;
786
787 return 0;
788
789error2:
790 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
791 if (NULL != mixer->amixers[i]) {
792 amixer = mixer->amixers[i];
793 amixer_mgr->put_amixer(amixer_mgr, amixer);
794 mixer->amixers[i] = NULL;
795 }
796 }
797error1:
798 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
799 if (NULL != mixer->sums[i]) {
800 sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
801 mixer->sums[i] = NULL;
802 }
803 }
804
805 return err;
806}
807
808static int ct_mixer_get_mem(struct ct_mixer **rmixer)
809{
810 struct ct_mixer *mixer = NULL;
811 int err = 0;
812
813 *rmixer = NULL;
814 /* Allocate mem for mixer obj */
815 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
816 if (NULL == mixer)
817 return -ENOMEM;
818
819 mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
820 GFP_KERNEL);
821 if (NULL == mixer->amixers) {
822 err = -ENOMEM;
823 goto error1;
824 }
825 mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
826 if (NULL == mixer->sums) {
827 err = -ENOMEM;
828 goto error2;
829 }
830
831 *rmixer = mixer;
832 return 0;
833
834error2:
835 kfree(mixer->amixers);
836error1:
837 kfree(mixer);
838 return err;
839}
840
841static int ct_mixer_topology_build(struct ct_mixer *mixer)
842{
843 struct sum *sum = NULL;
844 struct amixer *amix_d = NULL, *amix_s = NULL;
845 enum CT_AMIXER_CTL i = 0, j = 0;
846
847 /* Build topology from destination to source */
848
849 /* Set up Master mixer */
850 for (i = AMIXER_MASTER_F, j = SUM_IN_F;
851 i <= AMIXER_MASTER_S; i++, j++) {
852 amix_d = mixer->amixers[i*CHN_NUM];
853 sum = mixer->sums[j*CHN_NUM];
854 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
855 amix_d = mixer->amixers[i*CHN_NUM+1];
856 sum = mixer->sums[j*CHN_NUM+1];
857 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
858 }
859
860 /* Set up Wave-out mixer */
861 for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
862 i <= AMIXER_WAVE_S; i++, j++) {
863 amix_d = mixer->amixers[i*CHN_NUM];
864 amix_s = mixer->amixers[j*CHN_NUM];
865 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
866 amix_d = mixer->amixers[i*CHN_NUM+1];
867 amix_s = mixer->amixers[j*CHN_NUM+1];
868 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
869 }
870
871 /* Set up S/PDIF-out mixer */
872 amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
873 amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
874 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
875 amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
876 amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
877 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
878
879 /* Set up PCM-in mixer */
880 for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) {
881 amix_d = mixer->amixers[i*CHN_NUM];
882 sum = mixer->sums[j*CHN_NUM];
883 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
884 amix_d = mixer->amixers[i*CHN_NUM+1];
885 sum = mixer->sums[j*CHN_NUM+1];
886 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
887 }
888
889 /* Set up Line-in mixer */
890 amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
891 sum = mixer->sums[SUM_IN_F*CHN_NUM];
892 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
893 amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
894 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
895 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
896
897 /* Set up Mic-in mixer */
898 amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
899 sum = mixer->sums[SUM_IN_F*CHN_NUM];
900 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
901 amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
902 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
903 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
904
905 /* Set up S/PDIF-in mixer */
906 amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
907 sum = mixer->sums[SUM_IN_F*CHN_NUM];
908 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
909 amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
910 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
911 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
912
913 /* Set up Master recording mixer */
914 amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
915 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
916 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
917 amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
918 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
919 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
920
921 /* Set up PCM-in recording mixer */
922 amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
923 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
924 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
925 amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
926 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
927 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
928
929 /* Set up Line-in recording mixer */
930 amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
931 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
932 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
933 amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
934 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
935 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
936
937 /* Set up Mic-in recording mixer */
938 amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
939 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
940 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
941 amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
942 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
943 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
944
945 /* Set up S/PDIF-in recording mixer */
946 amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
947 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
948 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
949 amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
950 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
951 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
952
953 return 0;
954}
955
956static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
957{
958 amixer->ops->set_input(amixer, rsc);
959 amixer->ops->commit_write(amixer);
960
961 return 0;
962}
963
964static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
965{
966 switch (type) {
967 case MIX_WAVE_FRONT: return AMIXER_WAVE_F;
968 case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
969 case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C;
970 case MIX_WAVE_REAR: return AMIXER_WAVE_R;
971 case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C;
972 case MIX_SPDIF_OUT: return AMIXER_SPDIFO;
973 case MIX_LINE_IN: return AMIXER_LINEIN;
974 case MIX_MIC_IN: return AMIXER_MIC;
975 case MIX_SPDIF_IN: return AMIXER_SPDIFI;
976 case MIX_PCMI_FRONT: return AMIXER_PCM_F;
977 case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
978 case MIX_PCMI_CENTLFE: return AMIXER_PCM_C;
979 case MIX_PCMI_REAR: return AMIXER_PCM_R;
980 default: return 0;
981 }
982}
983
984static int mixer_get_output_ports(struct ct_mixer *mixer,
985 enum MIXER_PORT_T type,
986 struct rsc **rleft, struct rsc **rright)
987{
988 enum CT_AMIXER_CTL amix = port_to_amixer(type);
989
990 if (NULL != rleft)
991 *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
992
993 if (NULL != rright)
994 *rright =
995 &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
996
997 return 0;
998}
999
1000static int mixer_set_input_left(struct ct_mixer *mixer,
1001 enum MIXER_PORT_T type, struct rsc *rsc)
1002{
1003 enum CT_AMIXER_CTL amix = port_to_amixer(type);
1004
1005 mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1006 amix = get_recording_amixer(amix);
1007 if (amix < NUM_CT_AMIXERS)
1008 mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1009
1010 return 0;
1011}
1012
1013static int
1014mixer_set_input_right(struct ct_mixer *mixer,
1015 enum MIXER_PORT_T type, struct rsc *rsc)
1016{
1017 enum CT_AMIXER_CTL amix = port_to_amixer(type);
1018
1019 mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1020 amix = get_recording_amixer(amix);
1021 if (amix < NUM_CT_AMIXERS)
1022 mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1023
1024 return 0;
1025}
1026
1027int ct_mixer_destroy(struct ct_mixer *mixer)
1028{
1029 struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
1030 struct amixer_mgr *amixer_mgr =
1031 (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
1032 struct amixer *amixer = NULL;
1033 int i = 0;
1034
1035 /* Release amixer resources */
1036 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
1037 if (NULL != mixer->amixers[i]) {
1038 amixer = mixer->amixers[i];
1039 amixer_mgr->put_amixer(amixer_mgr, amixer);
1040 }
1041 }
1042
1043 /* Release sum resources */
1044 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
1045 if (NULL != mixer->sums[i])
1046 sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
1047 }
1048
1049 /* Release mem assigned to mixer object */
1050 kfree(mixer->sums);
1051 kfree(mixer->amixers);
1052 kfree(mixer);
1053
1054 return 0;
1055}
1056
1057int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
1058{
1059 struct ct_mixer *mixer = NULL;
1060 int err = 0;
1061
1062 *rmixer = NULL;
1063
1064 /* Allocate mem for mixer obj */
1065 err = ct_mixer_get_mem(&mixer);
1066 if (err)
1067 return err;
1068
1069 mixer->switch_state = 0;
1070 mixer->atc = atc;
1071 /* Set operations */
1072 mixer->get_output_ports = mixer_get_output_ports;
1073 mixer->set_input_left = mixer_set_input_left;
1074 mixer->set_input_right = mixer_set_input_right;
1075
1076 /* Allocate chip resources for mixer obj */
1077 err = ct_mixer_get_resources(mixer);
1078 if (err)
1079 goto error;
1080
1081 /* Build internal mixer topology */
1082 ct_mixer_topology_build(mixer);
1083
1084 *rmixer = mixer;
1085
1086 return 0;
1087
1088error:
1089 ct_mixer_destroy(mixer);
1090 return err;
1091}
1092
1093int ct_alsa_mix_create(struct ct_atc *atc,
1094 enum CTALSADEVS device,
1095 const char *device_name)
1096{
1097 int err = 0;
1098
1099 /* Create snd kcontrol instances on demand */
Takashi Iwai032abb52009-06-05 16:37:19 +02001100 /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
Wai Yew CHAY8cc72362009-05-14 08:05:58 +02001101 err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
1102 if (err)
1103 return err;
1104
1105 strcpy(atc->card->mixername, device_name);
1106
1107 return 0;
1108}