2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
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.
11 * This file contains the implementation of alsa mixer device functions.
21 #include <linux/slab.h>
22 #include <sound/core.h>
23 #include <sound/control.h>
24 #include <sound/asoundef.h>
25 #include <sound/pcm.h>
26 #include <sound/tlv.h>
39 /* volume control mixers */
62 /* this should always be the last one */
66 enum CTALSA_MIXER_CTL
{
67 /* volume control mixers */
84 /* switch control mixers */
101 /* this should always be the last one */
105 #define VOL_MIXER_START MIXER_MASTER_P
106 #define VOL_MIXER_END MIXER_SPDIFI_C
107 #define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)
108 #define SWH_MIXER_START MIXER_PCM_C_S
109 #define SWH_MIXER_END MIXER_DIGITAL_IO_S
110 #define SWH_CAPTURE_START MIXER_PCM_C_S
111 #define SWH_CAPTURE_END MIXER_SPDIFI_C_S
115 struct ct_kcontrol_init
{
120 static struct ct_kcontrol_init
121 ct_kcontrol_init_table
[NUM_CTALSA_MIXERS
] = {
124 .name
= "Master Playback Volume",
128 .name
= "Master Capture Volume",
132 .name
= "PCM Playback Volume",
136 .name
= "PCM Capture Volume",
140 .name
= "Line-in Playback Volume",
144 .name
= "Line-in Capture Volume",
148 .name
= "Mic Playback Volume",
152 .name
= "Mic Capture Volume",
156 .name
= "S/PDIF-in Playback Volume",
160 .name
= "S/PDIF-in Capture Volume",
164 .name
= "S/PDIF-out Playback Volume",
168 .name
= "Front Playback Volume",
172 .name
= "Side Playback Volume",
176 .name
= "Center/LFE Playback Volume",
180 .name
= "Surround Playback Volume",
185 .name
= "PCM Capture Switch",
187 [MIXER_LINEIN_C_S
] = {
189 .name
= "Line-in Capture Switch",
193 .name
= "Mic Capture Switch",
195 [MIXER_SPDIFI_C_S
] = {
197 .name
= "S/PDIF-in Capture Switch",
199 [MIXER_LINEIN_P_S
] = {
201 .name
= "Line-in Playback Switch",
203 [MIXER_SPDIFO_P_S
] = {
205 .name
= "S/PDIF-out Playback Switch",
207 [MIXER_SPDIFI_P_S
] = {
209 .name
= "S/PDIF-in Playback Switch",
211 [MIXER_WAVEF_P_S
] = {
213 .name
= "Front Playback Switch",
215 [MIXER_WAVES_P_S
] = {
217 .name
= "Side Playback Switch",
219 [MIXER_WAVEC_P_S
] = {
221 .name
= "Center/LFE Playback Switch",
223 [MIXER_WAVER_P_S
] = {
225 .name
= "Surround Playback Switch",
227 [MIXER_DIGITAL_IO_S
] = {
229 .name
= "Digit-IO Playback Switch",
234 ct_mixer_recording_select(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
);
237 ct_mixer_recording_unselect(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
);
239 static struct snd_kcontrol
*kctls
[2] = {NULL
};
241 static enum CT_AMIXER_CTL
get_amixer_index(enum CTALSA_MIXER_CTL alsa_index
)
243 switch (alsa_index
) {
244 case MIXER_MASTER_P
: return AMIXER_MASTER_F
;
245 case MIXER_MASTER_C
: return AMIXER_MASTER_F_C
;
246 case MIXER_PCM_P
: return AMIXER_PCM_F
;
248 case MIXER_PCM_C_S
: return AMIXER_PCM_F_C
;
249 case MIXER_LINEIN_P
: return AMIXER_LINEIN
;
251 case MIXER_LINEIN_C_S
: return AMIXER_LINEIN_C
;
252 case MIXER_MIC_P
: return AMIXER_MIC
;
254 case MIXER_MIC_C_S
: return AMIXER_MIC_C
;
255 case MIXER_SPDIFI_P
: return AMIXER_SPDIFI
;
257 case MIXER_SPDIFI_C_S
: return AMIXER_SPDIFI_C
;
258 case MIXER_SPDIFO_P
: return AMIXER_SPDIFO
;
259 case MIXER_WAVEF_P
: return AMIXER_WAVE_F
;
260 case MIXER_WAVES_P
: return AMIXER_WAVE_S
;
261 case MIXER_WAVEC_P
: return AMIXER_WAVE_C
;
262 case MIXER_WAVER_P
: return AMIXER_WAVE_R
;
263 default: return NUM_CT_AMIXERS
;
267 static enum CT_AMIXER_CTL
get_recording_amixer(enum CT_AMIXER_CTL index
)
270 case AMIXER_MASTER_F
: return AMIXER_MASTER_F_C
;
271 case AMIXER_PCM_F
: return AMIXER_PCM_F_C
;
272 case AMIXER_SPDIFI
: return AMIXER_SPDIFI_C
;
273 case AMIXER_LINEIN
: return AMIXER_LINEIN_C
;
274 case AMIXER_MIC
: return AMIXER_MIC_C
;
275 default: return NUM_CT_AMIXERS
;
280 get_switch_state(struct ct_mixer
*mixer
, enum CTALSA_MIXER_CTL type
)
282 return (mixer
->switch_state
& (0x1 << (type
- SWH_MIXER_START
)))
287 set_switch_state(struct ct_mixer
*mixer
,
288 enum CTALSA_MIXER_CTL type
, unsigned char state
)
291 mixer
->switch_state
|= (0x1 << (type
- SWH_MIXER_START
));
293 mixer
->switch_state
&= ~(0x1 << (type
- SWH_MIXER_START
));
297 /* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
298 * from 2^-6 to (1+1023/1024) */
299 static unsigned int uint16_to_float14(unsigned int x
)
311 for (i
= 0; !(x
& 0x400); i
++)
314 x
= (((7 - i
) & 0x7) << 10) | (x
& 0x3ff);
319 static unsigned int float14_to_uint16(unsigned int x
)
336 #endif /* not used */
338 #define VOL_SCALE 0x1c
339 #define VOL_MAX 0x100
341 static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale
, -6400, 25, 1);
343 static int ct_alsa_mix_volume_info(struct snd_kcontrol
*kcontrol
,
344 struct snd_ctl_elem_info
*uinfo
)
346 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
348 uinfo
->value
.integer
.min
= 0;
349 uinfo
->value
.integer
.max
= VOL_MAX
;
354 static int ct_alsa_mix_volume_get(struct snd_kcontrol
*kcontrol
,
355 struct snd_ctl_elem_value
*ucontrol
)
357 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
358 enum CT_AMIXER_CTL type
= get_amixer_index(kcontrol
->private_value
);
359 struct amixer
*amixer
;
362 for (i
= 0; i
< 2; i
++) {
363 amixer
= ((struct ct_mixer
*)atc
->mixer
)->
364 amixers
[type
*CHN_NUM
+i
];
365 val
= amixer
->ops
->get_scale(amixer
) / VOL_SCALE
;
368 else if (val
> VOL_MAX
)
370 ucontrol
->value
.integer
.value
[i
] = val
;
376 static int ct_alsa_mix_volume_put(struct snd_kcontrol
*kcontrol
,
377 struct snd_ctl_elem_value
*ucontrol
)
379 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
380 struct ct_mixer
*mixer
= atc
->mixer
;
381 enum CT_AMIXER_CTL type
= get_amixer_index(kcontrol
->private_value
);
382 struct amixer
*amixer
;
383 int i
, j
, val
, oval
, change
= 0;
385 for (i
= 0; i
< 2; i
++) {
386 val
= ucontrol
->value
.integer
.value
[i
];
389 else if (val
> VOL_MAX
)
392 amixer
= mixer
->amixers
[type
*CHN_NUM
+i
];
393 oval
= amixer
->ops
->get_scale(amixer
);
395 amixer
->ops
->set_scale(amixer
, val
);
396 amixer
->ops
->commit_write(amixer
);
398 /* Synchronize Master/PCM playback AMIXERs. */
399 if (AMIXER_MASTER_F
== type
|| AMIXER_PCM_F
== type
) {
400 for (j
= 1; j
< 4; j
++) {
402 amixers
[(type
+j
)*CHN_NUM
+i
];
403 amixer
->ops
->set_scale(amixer
, val
);
404 amixer
->ops
->commit_write(amixer
);
413 static struct snd_kcontrol_new vol_ctl
= {
414 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
|
415 SNDRV_CTL_ELEM_ACCESS_TLV_READ
,
416 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
417 .info
= ct_alsa_mix_volume_info
,
418 .get
= ct_alsa_mix_volume_get
,
419 .put
= ct_alsa_mix_volume_put
,
420 .tlv
= { .p
= ct_vol_db_scale
},
424 do_line_mic_switch(struct ct_atc
*atc
, enum CTALSA_MIXER_CTL type
)
427 if (MIXER_LINEIN_C_S
== type
) {
428 atc
->select_line_in(atc
);
429 set_switch_state(atc
->mixer
, MIXER_MIC_C_S
, 0);
430 snd_ctl_notify(atc
->card
, SNDRV_CTL_EVENT_MASK_VALUE
,
432 } else if (MIXER_MIC_C_S
== type
) {
433 atc
->select_mic_in(atc
);
434 set_switch_state(atc
->mixer
, MIXER_LINEIN_C_S
, 0);
435 snd_ctl_notify(atc
->card
, SNDRV_CTL_EVENT_MASK_VALUE
,
441 do_digit_io_switch(struct ct_atc
*atc
, int state
)
443 struct ct_mixer
*mixer
= atc
->mixer
;
446 atc
->select_digit_io(atc
);
447 atc
->spdif_out_unmute(atc
,
448 get_switch_state(mixer
, MIXER_SPDIFO_P_S
));
449 atc
->spdif_in_unmute(atc
, 1);
450 atc
->line_in_unmute(atc
, 0);
454 if (get_switch_state(mixer
, MIXER_LINEIN_C_S
))
455 atc
->select_line_in(atc
);
456 else if (get_switch_state(mixer
, MIXER_MIC_C_S
))
457 atc
->select_mic_in(atc
);
459 atc
->spdif_out_unmute(atc
, 0);
460 atc
->spdif_in_unmute(atc
, 0);
461 atc
->line_in_unmute(atc
, 1);
465 static void do_switch(struct ct_atc
*atc
, enum CTALSA_MIXER_CTL type
, int state
)
467 struct ct_mixer
*mixer
= atc
->mixer
;
469 /* Do changes in mixer. */
470 if ((SWH_CAPTURE_START
<= type
) && (SWH_CAPTURE_END
>= type
)) {
472 ct_mixer_recording_select(mixer
,
473 get_amixer_index(type
));
475 ct_mixer_recording_unselect(mixer
,
476 get_amixer_index(type
));
479 /* Do changes out of mixer. */
480 if (state
&& (MIXER_LINEIN_C_S
== type
|| MIXER_MIC_C_S
== type
))
481 do_line_mic_switch(atc
, type
);
482 else if (MIXER_WAVEF_P_S
== type
)
483 atc
->line_front_unmute(atc
, state
);
484 else if (MIXER_WAVES_P_S
== type
)
485 atc
->line_surround_unmute(atc
, state
);
486 else if (MIXER_WAVEC_P_S
== type
)
487 atc
->line_clfe_unmute(atc
, state
);
488 else if (MIXER_WAVER_P_S
== type
)
489 atc
->line_rear_unmute(atc
, state
);
490 else if (MIXER_LINEIN_P_S
== type
)
491 atc
->line_in_unmute(atc
, state
);
492 else if (MIXER_SPDIFO_P_S
== type
)
493 atc
->spdif_out_unmute(atc
, state
);
494 else if (MIXER_SPDIFI_P_S
== type
)
495 atc
->spdif_in_unmute(atc
, state
);
496 else if (MIXER_DIGITAL_IO_S
== type
)
497 do_digit_io_switch(atc
, state
);
502 static int ct_alsa_mix_switch_info(struct snd_kcontrol
*kcontrol
,
503 struct snd_ctl_elem_info
*uinfo
)
505 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
507 uinfo
->value
.integer
.min
= 0;
508 uinfo
->value
.integer
.max
= 1;
509 uinfo
->value
.integer
.step
= 1;
514 static int ct_alsa_mix_switch_get(struct snd_kcontrol
*kcontrol
,
515 struct snd_ctl_elem_value
*ucontrol
)
517 struct ct_mixer
*mixer
=
518 ((struct ct_atc
*)snd_kcontrol_chip(kcontrol
))->mixer
;
519 enum CTALSA_MIXER_CTL type
= kcontrol
->private_value
;
521 ucontrol
->value
.integer
.value
[0] = get_switch_state(mixer
, type
);
525 static int ct_alsa_mix_switch_put(struct snd_kcontrol
*kcontrol
,
526 struct snd_ctl_elem_value
*ucontrol
)
528 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
529 struct ct_mixer
*mixer
= atc
->mixer
;
530 enum CTALSA_MIXER_CTL type
= kcontrol
->private_value
;
533 state
= ucontrol
->value
.integer
.value
[0];
534 if (get_switch_state(mixer
, type
) == state
)
537 set_switch_state(mixer
, type
, state
);
538 do_switch(atc
, type
, state
);
543 static struct snd_kcontrol_new swh_ctl
= {
544 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
545 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
546 .info
= ct_alsa_mix_switch_info
,
547 .get
= ct_alsa_mix_switch_get
,
548 .put
= ct_alsa_mix_switch_put
551 static int ct_spdif_info(struct snd_kcontrol
*kcontrol
,
552 struct snd_ctl_elem_info
*uinfo
)
554 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_IEC958
;
559 static int ct_spdif_get_mask(struct snd_kcontrol
*kcontrol
,
560 struct snd_ctl_elem_value
*ucontrol
)
562 ucontrol
->value
.iec958
.status
[0] = 0xff;
563 ucontrol
->value
.iec958
.status
[1] = 0xff;
564 ucontrol
->value
.iec958
.status
[2] = 0xff;
565 ucontrol
->value
.iec958
.status
[3] = 0xff;
569 static int ct_spdif_default_get(struct snd_kcontrol
*kcontrol
,
570 struct snd_ctl_elem_value
*ucontrol
)
572 unsigned int status
= SNDRV_PCM_DEFAULT_CON_SPDIF
;
574 ucontrol
->value
.iec958
.status
[0] = (status
>> 0) & 0xff;
575 ucontrol
->value
.iec958
.status
[1] = (status
>> 8) & 0xff;
576 ucontrol
->value
.iec958
.status
[2] = (status
>> 16) & 0xff;
577 ucontrol
->value
.iec958
.status
[3] = (status
>> 24) & 0xff;
582 static int ct_spdif_get(struct snd_kcontrol
*kcontrol
,
583 struct snd_ctl_elem_value
*ucontrol
)
585 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
588 atc
->spdif_out_get_status(atc
, &status
);
589 ucontrol
->value
.iec958
.status
[0] = (status
>> 0) & 0xff;
590 ucontrol
->value
.iec958
.status
[1] = (status
>> 8) & 0xff;
591 ucontrol
->value
.iec958
.status
[2] = (status
>> 16) & 0xff;
592 ucontrol
->value
.iec958
.status
[3] = (status
>> 24) & 0xff;
597 static int ct_spdif_put(struct snd_kcontrol
*kcontrol
,
598 struct snd_ctl_elem_value
*ucontrol
)
600 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
602 unsigned int status
, old_status
;
604 status
= (ucontrol
->value
.iec958
.status
[0] << 0) |
605 (ucontrol
->value
.iec958
.status
[1] << 8) |
606 (ucontrol
->value
.iec958
.status
[2] << 16) |
607 (ucontrol
->value
.iec958
.status
[3] << 24);
609 atc
->spdif_out_get_status(atc
, &old_status
);
610 change
= (old_status
!= status
);
612 atc
->spdif_out_set_status(atc
, status
);
617 static struct snd_kcontrol_new iec958_mask_ctl
= {
618 .access
= SNDRV_CTL_ELEM_ACCESS_READ
,
619 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
620 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, MASK
),
622 .info
= ct_spdif_info
,
623 .get
= ct_spdif_get_mask
,
624 .private_value
= MIXER_IEC958_MASK
627 static struct snd_kcontrol_new iec958_default_ctl
= {
628 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
629 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, DEFAULT
),
631 .info
= ct_spdif_info
,
632 .get
= ct_spdif_default_get
,
634 .private_value
= MIXER_IEC958_DEFAULT
637 static struct snd_kcontrol_new iec958_ctl
= {
638 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
639 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
640 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, PCM_STREAM
),
642 .info
= ct_spdif_info
,
645 .private_value
= MIXER_IEC958_STREAM
648 #define NUM_IEC958_CTL 3
651 ct_mixer_kcontrol_new(struct ct_mixer
*mixer
, struct snd_kcontrol_new
*new)
653 struct snd_kcontrol
*kctl
;
656 kctl
= snd_ctl_new1(new, mixer
->atc
);
660 if (SNDRV_CTL_ELEM_IFACE_PCM
== kctl
->id
.iface
)
661 kctl
->id
.device
= IEC958
;
663 err
= snd_ctl_add(mixer
->atc
->card
, kctl
);
667 switch (new->private_value
) {
668 case MIXER_LINEIN_C_S
:
669 kctls
[0] = kctl
; break;
671 kctls
[1] = kctl
; break;
679 static int ct_mixer_kcontrols_create(struct ct_mixer
*mixer
)
681 enum CTALSA_MIXER_CTL type
;
682 struct ct_atc
*atc
= mixer
->atc
;
685 /* Create snd kcontrol instances on demand */
686 for (type
= VOL_MIXER_START
; type
<= VOL_MIXER_END
; type
++) {
687 if (ct_kcontrol_init_table
[type
].ctl
) {
688 vol_ctl
.name
= ct_kcontrol_init_table
[type
].name
;
689 vol_ctl
.private_value
= (unsigned long)type
;
690 err
= ct_mixer_kcontrol_new(mixer
, &vol_ctl
);
696 ct_kcontrol_init_table
[MIXER_DIGITAL_IO_S
].ctl
=
697 atc
->have_digit_io_switch(atc
);
698 for (type
= SWH_MIXER_START
; type
<= SWH_MIXER_END
; type
++) {
699 if (ct_kcontrol_init_table
[type
].ctl
) {
700 swh_ctl
.name
= ct_kcontrol_init_table
[type
].name
;
701 swh_ctl
.private_value
= (unsigned long)type
;
702 err
= ct_mixer_kcontrol_new(mixer
, &swh_ctl
);
708 err
= ct_mixer_kcontrol_new(mixer
, &iec958_mask_ctl
);
712 err
= ct_mixer_kcontrol_new(mixer
, &iec958_default_ctl
);
716 err
= ct_mixer_kcontrol_new(mixer
, &iec958_ctl
);
720 atc
->line_front_unmute(atc
, 1);
721 set_switch_state(mixer
, MIXER_WAVEF_P_S
, 1);
722 atc
->line_surround_unmute(atc
, 0);
723 set_switch_state(mixer
, MIXER_WAVES_P_S
, 0);
724 atc
->line_clfe_unmute(atc
, 0);
725 set_switch_state(mixer
, MIXER_WAVEC_P_S
, 0);
726 atc
->line_rear_unmute(atc
, 0);
727 set_switch_state(mixer
, MIXER_WAVER_P_S
, 0);
728 atc
->spdif_out_unmute(atc
, 0);
729 set_switch_state(mixer
, MIXER_SPDIFO_P_S
, 0);
730 atc
->line_in_unmute(atc
, 0);
731 set_switch_state(mixer
, MIXER_LINEIN_P_S
, 0);
732 atc
->spdif_in_unmute(atc
, 0);
733 set_switch_state(mixer
, MIXER_SPDIFI_P_S
, 0);
735 set_switch_state(mixer
, MIXER_PCM_C_S
, 1);
736 set_switch_state(mixer
, MIXER_LINEIN_C_S
, 1);
737 set_switch_state(mixer
, MIXER_SPDIFI_C_S
, 1);
743 ct_mixer_recording_select(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
)
745 struct amixer
*amix_d
;
749 for (i
= 0; i
< 2; i
++) {
750 amix_d
= mixer
->amixers
[type
*CHN_NUM
+i
];
751 sum_c
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+i
];
752 amix_d
->ops
->set_sum(amix_d
, sum_c
);
753 amix_d
->ops
->commit_write(amix_d
);
758 ct_mixer_recording_unselect(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
)
760 struct amixer
*amix_d
;
763 for (i
= 0; i
< 2; i
++) {
764 amix_d
= mixer
->amixers
[type
*CHN_NUM
+i
];
765 amix_d
->ops
->set_sum(amix_d
, NULL
);
766 amix_d
->ops
->commit_write(amix_d
);
770 static int ct_mixer_get_resources(struct ct_mixer
*mixer
)
772 struct sum_mgr
*sum_mgr
;
774 struct sum_desc sum_desc
= {0};
775 struct amixer_mgr
*amixer_mgr
;
776 struct amixer
*amixer
;
777 struct amixer_desc am_desc
= {0};
781 /* Allocate sum resources for mixer obj */
782 sum_mgr
= (struct sum_mgr
*)mixer
->atc
->rsc_mgrs
[SUM
];
783 sum_desc
.msr
= mixer
->atc
->msr
;
784 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
785 err
= sum_mgr
->get_sum(sum_mgr
, &sum_desc
, &sum
);
787 printk(KERN_ERR
"ctxfi:Failed to get sum resources for "
791 mixer
->sums
[i
] = sum
;
796 /* Allocate amixer resources for mixer obj */
797 amixer_mgr
= (struct amixer_mgr
*)mixer
->atc
->rsc_mgrs
[AMIXER
];
798 am_desc
.msr
= mixer
->atc
->msr
;
799 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
800 err
= amixer_mgr
->get_amixer(amixer_mgr
, &am_desc
, &amixer
);
802 printk(KERN_ERR
"ctxfi:Failed to get amixer resources "
806 mixer
->amixers
[i
] = amixer
;
814 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
815 if (NULL
!= mixer
->amixers
[i
]) {
816 amixer
= mixer
->amixers
[i
];
817 amixer_mgr
->put_amixer(amixer_mgr
, amixer
);
818 mixer
->amixers
[i
] = NULL
;
822 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
823 if (NULL
!= mixer
->sums
[i
]) {
824 sum_mgr
->put_sum(sum_mgr
, (struct sum
*)mixer
->sums
[i
]);
825 mixer
->sums
[i
] = NULL
;
832 static int ct_mixer_get_mem(struct ct_mixer
**rmixer
)
834 struct ct_mixer
*mixer
;
838 /* Allocate mem for mixer obj */
839 mixer
= kzalloc(sizeof(*mixer
), GFP_KERNEL
);
843 mixer
->amixers
= kzalloc(sizeof(void *)*(NUM_CT_AMIXERS
*CHN_NUM
),
845 if (!mixer
->amixers
) {
849 mixer
->sums
= kzalloc(sizeof(void *)*(NUM_CT_SUMS
*CHN_NUM
), GFP_KERNEL
);
859 kfree(mixer
->amixers
);
865 static int ct_mixer_topology_build(struct ct_mixer
*mixer
)
868 struct amixer
*amix_d
, *amix_s
;
869 enum CT_AMIXER_CTL i
, j
;
871 /* Build topology from destination to source */
873 /* Set up Master mixer */
874 for (i
= AMIXER_MASTER_F
, j
= SUM_IN_F
;
875 i
<= AMIXER_MASTER_S
; i
++, j
++) {
876 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
877 sum
= mixer
->sums
[j
*CHN_NUM
];
878 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
879 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
880 sum
= mixer
->sums
[j
*CHN_NUM
+1];
881 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
884 /* Set up Wave-out mixer */
885 for (i
= AMIXER_WAVE_F
, j
= AMIXER_MASTER_F
;
886 i
<= AMIXER_WAVE_S
; i
++, j
++) {
887 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
888 amix_s
= mixer
->amixers
[j
*CHN_NUM
];
889 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
890 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
891 amix_s
= mixer
->amixers
[j
*CHN_NUM
+1];
892 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
895 /* Set up S/PDIF-out mixer */
896 amix_d
= mixer
->amixers
[AMIXER_SPDIFO
*CHN_NUM
];
897 amix_s
= mixer
->amixers
[AMIXER_MASTER_F
*CHN_NUM
];
898 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
899 amix_d
= mixer
->amixers
[AMIXER_SPDIFO
*CHN_NUM
+1];
900 amix_s
= mixer
->amixers
[AMIXER_MASTER_F
*CHN_NUM
+1];
901 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
903 /* Set up PCM-in mixer */
904 for (i
= AMIXER_PCM_F
, j
= SUM_IN_F
; i
<= AMIXER_PCM_S
; i
++, j
++) {
905 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
906 sum
= mixer
->sums
[j
*CHN_NUM
];
907 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
908 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
909 sum
= mixer
->sums
[j
*CHN_NUM
+1];
910 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
913 /* Set up Line-in mixer */
914 amix_d
= mixer
->amixers
[AMIXER_LINEIN
*CHN_NUM
];
915 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
916 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
917 amix_d
= mixer
->amixers
[AMIXER_LINEIN
*CHN_NUM
+1];
918 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
919 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
921 /* Set up Mic-in mixer */
922 amix_d
= mixer
->amixers
[AMIXER_MIC
*CHN_NUM
];
923 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
924 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
925 amix_d
= mixer
->amixers
[AMIXER_MIC
*CHN_NUM
+1];
926 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
927 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
929 /* Set up S/PDIF-in mixer */
930 amix_d
= mixer
->amixers
[AMIXER_SPDIFI
*CHN_NUM
];
931 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
932 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
933 amix_d
= mixer
->amixers
[AMIXER_SPDIFI
*CHN_NUM
+1];
934 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
935 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
937 /* Set up Master recording mixer */
938 amix_d
= mixer
->amixers
[AMIXER_MASTER_F_C
*CHN_NUM
];
939 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
940 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
941 amix_d
= mixer
->amixers
[AMIXER_MASTER_F_C
*CHN_NUM
+1];
942 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
943 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
945 /* Set up PCM-in recording mixer */
946 amix_d
= mixer
->amixers
[AMIXER_PCM_F_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_PCM_F_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
);
953 /* Set up Line-in recording mixer */
954 amix_d
= mixer
->amixers
[AMIXER_LINEIN_C
*CHN_NUM
];
955 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
956 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
957 amix_d
= mixer
->amixers
[AMIXER_LINEIN_C
*CHN_NUM
+1];
958 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
959 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
961 /* Set up Mic-in recording mixer */
962 amix_d
= mixer
->amixers
[AMIXER_MIC_C
*CHN_NUM
];
963 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
964 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
965 amix_d
= mixer
->amixers
[AMIXER_MIC_C
*CHN_NUM
+1];
966 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
967 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
969 /* Set up S/PDIF-in recording mixer */
970 amix_d
= mixer
->amixers
[AMIXER_SPDIFI_C
*CHN_NUM
];
971 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
972 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
973 amix_d
= mixer
->amixers
[AMIXER_SPDIFI_C
*CHN_NUM
+1];
974 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
975 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
980 static int mixer_set_input_port(struct amixer
*amixer
, struct rsc
*rsc
)
982 amixer
->ops
->set_input(amixer
, rsc
);
983 amixer
->ops
->commit_write(amixer
);
988 static enum CT_AMIXER_CTL
port_to_amixer(enum MIXER_PORT_T type
)
991 case MIX_WAVE_FRONT
: return AMIXER_WAVE_F
;
992 case MIX_WAVE_SURROUND
: return AMIXER_WAVE_S
;
993 case MIX_WAVE_CENTLFE
: return AMIXER_WAVE_C
;
994 case MIX_WAVE_REAR
: return AMIXER_WAVE_R
;
995 case MIX_PCMO_FRONT
: return AMIXER_MASTER_F_C
;
996 case MIX_SPDIF_OUT
: return AMIXER_SPDIFO
;
997 case MIX_LINE_IN
: return AMIXER_LINEIN
;
998 case MIX_MIC_IN
: return AMIXER_MIC
;
999 case MIX_SPDIF_IN
: return AMIXER_SPDIFI
;
1000 case MIX_PCMI_FRONT
: return AMIXER_PCM_F
;
1001 case MIX_PCMI_SURROUND
: return AMIXER_PCM_S
;
1002 case MIX_PCMI_CENTLFE
: return AMIXER_PCM_C
;
1003 case MIX_PCMI_REAR
: return AMIXER_PCM_R
;
1008 static int mixer_get_output_ports(struct ct_mixer
*mixer
,
1009 enum MIXER_PORT_T type
,
1010 struct rsc
**rleft
, struct rsc
**rright
)
1012 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1015 *rleft
= &((struct amixer
*)mixer
->amixers
[amix
*CHN_NUM
])->rsc
;
1019 &((struct amixer
*)mixer
->amixers
[amix
*CHN_NUM
+1])->rsc
;
1024 static int mixer_set_input_left(struct ct_mixer
*mixer
,
1025 enum MIXER_PORT_T type
, struct rsc
*rsc
)
1027 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1029 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
], rsc
);
1030 amix
= get_recording_amixer(amix
);
1031 if (amix
< NUM_CT_AMIXERS
)
1032 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
], rsc
);
1038 mixer_set_input_right(struct ct_mixer
*mixer
,
1039 enum MIXER_PORT_T type
, struct rsc
*rsc
)
1041 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1043 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
+1], rsc
);
1044 amix
= get_recording_amixer(amix
);
1045 if (amix
< NUM_CT_AMIXERS
)
1046 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
+1], rsc
);
1052 static int mixer_resume(struct ct_mixer
*mixer
)
1055 struct amixer
*amixer
;
1057 /* resume topology and volume gain. */
1058 for (i
= 0; i
< NUM_CT_AMIXERS
*CHN_NUM
; i
++) {
1059 amixer
= mixer
->amixers
[i
];
1060 amixer
->ops
->commit_write(amixer
);
1063 /* resume switch state. */
1064 for (i
= SWH_MIXER_START
; i
<= SWH_MIXER_END
; i
++) {
1065 state
= get_switch_state(mixer
, i
);
1066 do_switch(mixer
->atc
, i
, state
);
1073 int ct_mixer_destroy(struct ct_mixer
*mixer
)
1075 struct sum_mgr
*sum_mgr
= (struct sum_mgr
*)mixer
->atc
->rsc_mgrs
[SUM
];
1076 struct amixer_mgr
*amixer_mgr
=
1077 (struct amixer_mgr
*)mixer
->atc
->rsc_mgrs
[AMIXER
];
1078 struct amixer
*amixer
;
1081 /* Release amixer resources */
1082 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
1083 if (NULL
!= mixer
->amixers
[i
]) {
1084 amixer
= mixer
->amixers
[i
];
1085 amixer_mgr
->put_amixer(amixer_mgr
, amixer
);
1089 /* Release sum resources */
1090 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
1091 if (NULL
!= mixer
->sums
[i
])
1092 sum_mgr
->put_sum(sum_mgr
, (struct sum
*)mixer
->sums
[i
]);
1095 /* Release mem assigned to mixer object */
1097 kfree(mixer
->amixers
);
1103 int ct_mixer_create(struct ct_atc
*atc
, struct ct_mixer
**rmixer
)
1105 struct ct_mixer
*mixer
;
1110 /* Allocate mem for mixer obj */
1111 err
= ct_mixer_get_mem(&mixer
);
1115 mixer
->switch_state
= 0;
1117 /* Set operations */
1118 mixer
->get_output_ports
= mixer_get_output_ports
;
1119 mixer
->set_input_left
= mixer_set_input_left
;
1120 mixer
->set_input_right
= mixer_set_input_right
;
1122 mixer
->resume
= mixer_resume
;
1125 /* Allocate chip resources for mixer obj */
1126 err
= ct_mixer_get_resources(mixer
);
1130 /* Build internal mixer topology */
1131 ct_mixer_topology_build(mixer
);
1138 ct_mixer_destroy(mixer
);
1142 int ct_alsa_mix_create(struct ct_atc
*atc
,
1143 enum CTALSADEVS device
,
1144 const char *device_name
)
1148 /* Create snd kcontrol instances on demand */
1149 /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
1150 err
= ct_mixer_kcontrols_create((struct ct_mixer
*)atc
->mixer
);
1154 strcpy(atc
->card
->mixername
, device_name
);