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_get(struct snd_kcontrol
*kcontrol
,
570 struct snd_ctl_elem_value
*ucontrol
)
572 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
575 atc
->spdif_out_get_status(atc
, &status
);
578 status
= SNDRV_PCM_DEFAULT_CON_SPDIF
;
580 ucontrol
->value
.iec958
.status
[0] = (status
>> 0) & 0xff;
581 ucontrol
->value
.iec958
.status
[1] = (status
>> 8) & 0xff;
582 ucontrol
->value
.iec958
.status
[2] = (status
>> 16) & 0xff;
583 ucontrol
->value
.iec958
.status
[3] = (status
>> 24) & 0xff;
588 static int ct_spdif_put(struct snd_kcontrol
*kcontrol
,
589 struct snd_ctl_elem_value
*ucontrol
)
591 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
593 unsigned int status
, old_status
;
595 status
= (ucontrol
->value
.iec958
.status
[0] << 0) |
596 (ucontrol
->value
.iec958
.status
[1] << 8) |
597 (ucontrol
->value
.iec958
.status
[2] << 16) |
598 (ucontrol
->value
.iec958
.status
[3] << 24);
600 atc
->spdif_out_get_status(atc
, &old_status
);
601 change
= (old_status
!= status
);
603 atc
->spdif_out_set_status(atc
, status
);
608 static struct snd_kcontrol_new iec958_mask_ctl
= {
609 .access
= SNDRV_CTL_ELEM_ACCESS_READ
,
610 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
611 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, MASK
),
613 .info
= ct_spdif_info
,
614 .get
= ct_spdif_get_mask
,
615 .private_value
= MIXER_IEC958_MASK
618 static struct snd_kcontrol_new iec958_default_ctl
= {
619 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
620 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, DEFAULT
),
622 .info
= ct_spdif_info
,
625 .private_value
= MIXER_IEC958_DEFAULT
628 static struct snd_kcontrol_new iec958_ctl
= {
629 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
630 .iface
= SNDRV_CTL_ELEM_IFACE_PCM
,
631 .name
= SNDRV_CTL_NAME_IEC958("", PLAYBACK
, PCM_STREAM
),
633 .info
= ct_spdif_info
,
636 .private_value
= MIXER_IEC958_STREAM
639 #define NUM_IEC958_CTL 3
642 ct_mixer_kcontrol_new(struct ct_mixer
*mixer
, struct snd_kcontrol_new
*new)
644 struct snd_kcontrol
*kctl
;
647 kctl
= snd_ctl_new1(new, mixer
->atc
);
651 if (SNDRV_CTL_ELEM_IFACE_PCM
== kctl
->id
.iface
)
652 kctl
->id
.device
= IEC958
;
654 err
= snd_ctl_add(mixer
->atc
->card
, kctl
);
658 switch (new->private_value
) {
659 case MIXER_LINEIN_C_S
:
660 kctls
[0] = kctl
; break;
662 kctls
[1] = kctl
; break;
670 static int ct_mixer_kcontrols_create(struct ct_mixer
*mixer
)
672 enum CTALSA_MIXER_CTL type
;
673 struct ct_atc
*atc
= mixer
->atc
;
676 /* Create snd kcontrol instances on demand */
677 for (type
= VOL_MIXER_START
; type
<= VOL_MIXER_END
; type
++) {
678 if (ct_kcontrol_init_table
[type
].ctl
) {
679 vol_ctl
.name
= ct_kcontrol_init_table
[type
].name
;
680 vol_ctl
.private_value
= (unsigned long)type
;
681 err
= ct_mixer_kcontrol_new(mixer
, &vol_ctl
);
687 ct_kcontrol_init_table
[MIXER_DIGITAL_IO_S
].ctl
=
688 atc
->have_digit_io_switch(atc
);
689 for (type
= SWH_MIXER_START
; type
<= SWH_MIXER_END
; type
++) {
690 if (ct_kcontrol_init_table
[type
].ctl
) {
691 swh_ctl
.name
= ct_kcontrol_init_table
[type
].name
;
692 swh_ctl
.private_value
= (unsigned long)type
;
693 err
= ct_mixer_kcontrol_new(mixer
, &swh_ctl
);
699 err
= ct_mixer_kcontrol_new(mixer
, &iec958_mask_ctl
);
703 err
= ct_mixer_kcontrol_new(mixer
, &iec958_default_ctl
);
707 err
= ct_mixer_kcontrol_new(mixer
, &iec958_ctl
);
711 atc
->line_front_unmute(atc
, 1);
712 set_switch_state(mixer
, MIXER_WAVEF_P_S
, 1);
713 atc
->line_surround_unmute(atc
, 0);
714 set_switch_state(mixer
, MIXER_WAVES_P_S
, 0);
715 atc
->line_clfe_unmute(atc
, 0);
716 set_switch_state(mixer
, MIXER_WAVEC_P_S
, 0);
717 atc
->line_rear_unmute(atc
, 0);
718 set_switch_state(mixer
, MIXER_WAVER_P_S
, 0);
719 atc
->spdif_out_unmute(atc
, 0);
720 set_switch_state(mixer
, MIXER_SPDIFO_P_S
, 0);
721 atc
->line_in_unmute(atc
, 0);
722 set_switch_state(mixer
, MIXER_LINEIN_P_S
, 0);
723 atc
->spdif_in_unmute(atc
, 0);
724 set_switch_state(mixer
, MIXER_SPDIFI_P_S
, 0);
726 set_switch_state(mixer
, MIXER_PCM_C_S
, 1);
727 set_switch_state(mixer
, MIXER_LINEIN_C_S
, 1);
728 set_switch_state(mixer
, MIXER_SPDIFI_C_S
, 1);
734 ct_mixer_recording_select(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
)
736 struct amixer
*amix_d
;
740 for (i
= 0; i
< 2; i
++) {
741 amix_d
= mixer
->amixers
[type
*CHN_NUM
+i
];
742 sum_c
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+i
];
743 amix_d
->ops
->set_sum(amix_d
, sum_c
);
744 amix_d
->ops
->commit_write(amix_d
);
749 ct_mixer_recording_unselect(struct ct_mixer
*mixer
, enum CT_AMIXER_CTL type
)
751 struct amixer
*amix_d
;
754 for (i
= 0; i
< 2; i
++) {
755 amix_d
= mixer
->amixers
[type
*CHN_NUM
+i
];
756 amix_d
->ops
->set_sum(amix_d
, NULL
);
757 amix_d
->ops
->commit_write(amix_d
);
761 static int ct_mixer_get_resources(struct ct_mixer
*mixer
)
763 struct sum_mgr
*sum_mgr
;
765 struct sum_desc sum_desc
= {0};
766 struct amixer_mgr
*amixer_mgr
;
767 struct amixer
*amixer
;
768 struct amixer_desc am_desc
= {0};
772 /* Allocate sum resources for mixer obj */
773 sum_mgr
= (struct sum_mgr
*)mixer
->atc
->rsc_mgrs
[SUM
];
774 sum_desc
.msr
= mixer
->atc
->msr
;
775 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
776 err
= sum_mgr
->get_sum(sum_mgr
, &sum_desc
, &sum
);
778 printk(KERN_ERR
"ctxfi:Failed to get sum resources for "
782 mixer
->sums
[i
] = sum
;
787 /* Allocate amixer resources for mixer obj */
788 amixer_mgr
= (struct amixer_mgr
*)mixer
->atc
->rsc_mgrs
[AMIXER
];
789 am_desc
.msr
= mixer
->atc
->msr
;
790 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
791 err
= amixer_mgr
->get_amixer(amixer_mgr
, &am_desc
, &amixer
);
793 printk(KERN_ERR
"ctxfi:Failed to get amixer resources "
797 mixer
->amixers
[i
] = amixer
;
805 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
806 if (NULL
!= mixer
->amixers
[i
]) {
807 amixer
= mixer
->amixers
[i
];
808 amixer_mgr
->put_amixer(amixer_mgr
, amixer
);
809 mixer
->amixers
[i
] = NULL
;
813 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
814 if (NULL
!= mixer
->sums
[i
]) {
815 sum_mgr
->put_sum(sum_mgr
, (struct sum
*)mixer
->sums
[i
]);
816 mixer
->sums
[i
] = NULL
;
823 static int ct_mixer_get_mem(struct ct_mixer
**rmixer
)
825 struct ct_mixer
*mixer
;
829 /* Allocate mem for mixer obj */
830 mixer
= kzalloc(sizeof(*mixer
), GFP_KERNEL
);
834 mixer
->amixers
= kzalloc(sizeof(void *)*(NUM_CT_AMIXERS
*CHN_NUM
),
836 if (!mixer
->amixers
) {
840 mixer
->sums
= kzalloc(sizeof(void *)*(NUM_CT_SUMS
*CHN_NUM
), GFP_KERNEL
);
850 kfree(mixer
->amixers
);
856 static int ct_mixer_topology_build(struct ct_mixer
*mixer
)
859 struct amixer
*amix_d
, *amix_s
;
860 enum CT_AMIXER_CTL i
, j
;
862 /* Build topology from destination to source */
864 /* Set up Master mixer */
865 for (i
= AMIXER_MASTER_F
, j
= SUM_IN_F
;
866 i
<= AMIXER_MASTER_S
; i
++, j
++) {
867 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
868 sum
= mixer
->sums
[j
*CHN_NUM
];
869 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
870 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
871 sum
= mixer
->sums
[j
*CHN_NUM
+1];
872 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
875 /* Set up Wave-out mixer */
876 for (i
= AMIXER_WAVE_F
, j
= AMIXER_MASTER_F
;
877 i
<= AMIXER_WAVE_S
; i
++, j
++) {
878 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
879 amix_s
= mixer
->amixers
[j
*CHN_NUM
];
880 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
881 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
882 amix_s
= mixer
->amixers
[j
*CHN_NUM
+1];
883 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
886 /* Set up S/PDIF-out mixer */
887 amix_d
= mixer
->amixers
[AMIXER_SPDIFO
*CHN_NUM
];
888 amix_s
= mixer
->amixers
[AMIXER_MASTER_F
*CHN_NUM
];
889 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
890 amix_d
= mixer
->amixers
[AMIXER_SPDIFO
*CHN_NUM
+1];
891 amix_s
= mixer
->amixers
[AMIXER_MASTER_F
*CHN_NUM
+1];
892 amix_d
->ops
->setup(amix_d
, &amix_s
->rsc
, INIT_VOL
, NULL
);
894 /* Set up PCM-in mixer */
895 for (i
= AMIXER_PCM_F
, j
= SUM_IN_F
; i
<= AMIXER_PCM_S
; i
++, j
++) {
896 amix_d
= mixer
->amixers
[i
*CHN_NUM
];
897 sum
= mixer
->sums
[j
*CHN_NUM
];
898 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
899 amix_d
= mixer
->amixers
[i
*CHN_NUM
+1];
900 sum
= mixer
->sums
[j
*CHN_NUM
+1];
901 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
904 /* Set up Line-in mixer */
905 amix_d
= mixer
->amixers
[AMIXER_LINEIN
*CHN_NUM
];
906 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
907 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
908 amix_d
= mixer
->amixers
[AMIXER_LINEIN
*CHN_NUM
+1];
909 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
910 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
912 /* Set up Mic-in mixer */
913 amix_d
= mixer
->amixers
[AMIXER_MIC
*CHN_NUM
];
914 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
915 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
916 amix_d
= mixer
->amixers
[AMIXER_MIC
*CHN_NUM
+1];
917 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
918 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
920 /* Set up S/PDIF-in mixer */
921 amix_d
= mixer
->amixers
[AMIXER_SPDIFI
*CHN_NUM
];
922 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
];
923 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
924 amix_d
= mixer
->amixers
[AMIXER_SPDIFI
*CHN_NUM
+1];
925 sum
= mixer
->sums
[SUM_IN_F
*CHN_NUM
+1];
926 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
928 /* Set up Master recording mixer */
929 amix_d
= mixer
->amixers
[AMIXER_MASTER_F_C
*CHN_NUM
];
930 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
931 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
932 amix_d
= mixer
->amixers
[AMIXER_MASTER_F_C
*CHN_NUM
+1];
933 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
934 amix_d
->ops
->setup(amix_d
, &sum
->rsc
, INIT_VOL
, NULL
);
936 /* Set up PCM-in recording mixer */
937 amix_d
= mixer
->amixers
[AMIXER_PCM_F_C
*CHN_NUM
];
938 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
939 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
940 amix_d
= mixer
->amixers
[AMIXER_PCM_F_C
*CHN_NUM
+1];
941 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
942 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
944 /* Set up Line-in recording mixer */
945 amix_d
= mixer
->amixers
[AMIXER_LINEIN_C
*CHN_NUM
];
946 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
947 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
948 amix_d
= mixer
->amixers
[AMIXER_LINEIN_C
*CHN_NUM
+1];
949 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
950 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
952 /* Set up Mic-in recording mixer */
953 amix_d
= mixer
->amixers
[AMIXER_MIC_C
*CHN_NUM
];
954 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
955 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
956 amix_d
= mixer
->amixers
[AMIXER_MIC_C
*CHN_NUM
+1];
957 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
958 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
960 /* Set up S/PDIF-in recording mixer */
961 amix_d
= mixer
->amixers
[AMIXER_SPDIFI_C
*CHN_NUM
];
962 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
];
963 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
964 amix_d
= mixer
->amixers
[AMIXER_SPDIFI_C
*CHN_NUM
+1];
965 sum
= mixer
->sums
[SUM_IN_F_C
*CHN_NUM
+1];
966 amix_d
->ops
->setup(amix_d
, NULL
, INIT_VOL
, sum
);
971 static int mixer_set_input_port(struct amixer
*amixer
, struct rsc
*rsc
)
973 amixer
->ops
->set_input(amixer
, rsc
);
974 amixer
->ops
->commit_write(amixer
);
979 static enum CT_AMIXER_CTL
port_to_amixer(enum MIXER_PORT_T type
)
982 case MIX_WAVE_FRONT
: return AMIXER_WAVE_F
;
983 case MIX_WAVE_SURROUND
: return AMIXER_WAVE_S
;
984 case MIX_WAVE_CENTLFE
: return AMIXER_WAVE_C
;
985 case MIX_WAVE_REAR
: return AMIXER_WAVE_R
;
986 case MIX_PCMO_FRONT
: return AMIXER_MASTER_F_C
;
987 case MIX_SPDIF_OUT
: return AMIXER_SPDIFO
;
988 case MIX_LINE_IN
: return AMIXER_LINEIN
;
989 case MIX_MIC_IN
: return AMIXER_MIC
;
990 case MIX_SPDIF_IN
: return AMIXER_SPDIFI
;
991 case MIX_PCMI_FRONT
: return AMIXER_PCM_F
;
992 case MIX_PCMI_SURROUND
: return AMIXER_PCM_S
;
993 case MIX_PCMI_CENTLFE
: return AMIXER_PCM_C
;
994 case MIX_PCMI_REAR
: return AMIXER_PCM_R
;
999 static int mixer_get_output_ports(struct ct_mixer
*mixer
,
1000 enum MIXER_PORT_T type
,
1001 struct rsc
**rleft
, struct rsc
**rright
)
1003 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1006 *rleft
= &((struct amixer
*)mixer
->amixers
[amix
*CHN_NUM
])->rsc
;
1010 &((struct amixer
*)mixer
->amixers
[amix
*CHN_NUM
+1])->rsc
;
1015 static int mixer_set_input_left(struct ct_mixer
*mixer
,
1016 enum MIXER_PORT_T type
, struct rsc
*rsc
)
1018 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1020 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
], rsc
);
1021 amix
= get_recording_amixer(amix
);
1022 if (amix
< NUM_CT_AMIXERS
)
1023 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
], rsc
);
1029 mixer_set_input_right(struct ct_mixer
*mixer
,
1030 enum MIXER_PORT_T type
, struct rsc
*rsc
)
1032 enum CT_AMIXER_CTL amix
= port_to_amixer(type
);
1034 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
+1], rsc
);
1035 amix
= get_recording_amixer(amix
);
1036 if (amix
< NUM_CT_AMIXERS
)
1037 mixer_set_input_port(mixer
->amixers
[amix
*CHN_NUM
+1], rsc
);
1043 static int mixer_resume(struct ct_mixer
*mixer
)
1046 struct amixer
*amixer
;
1048 /* resume topology and volume gain. */
1049 for (i
= 0; i
< NUM_CT_AMIXERS
*CHN_NUM
; i
++) {
1050 amixer
= mixer
->amixers
[i
];
1051 amixer
->ops
->commit_write(amixer
);
1054 /* resume switch state. */
1055 for (i
= SWH_MIXER_START
; i
<= SWH_MIXER_END
; i
++) {
1056 state
= get_switch_state(mixer
, i
);
1057 do_switch(mixer
->atc
, i
, state
);
1064 int ct_mixer_destroy(struct ct_mixer
*mixer
)
1066 struct sum_mgr
*sum_mgr
= (struct sum_mgr
*)mixer
->atc
->rsc_mgrs
[SUM
];
1067 struct amixer_mgr
*amixer_mgr
=
1068 (struct amixer_mgr
*)mixer
->atc
->rsc_mgrs
[AMIXER
];
1069 struct amixer
*amixer
;
1072 /* Release amixer resources */
1073 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
1074 if (NULL
!= mixer
->amixers
[i
]) {
1075 amixer
= mixer
->amixers
[i
];
1076 amixer_mgr
->put_amixer(amixer_mgr
, amixer
);
1080 /* Release sum resources */
1081 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
1082 if (NULL
!= mixer
->sums
[i
])
1083 sum_mgr
->put_sum(sum_mgr
, (struct sum
*)mixer
->sums
[i
]);
1086 /* Release mem assigned to mixer object */
1088 kfree(mixer
->amixers
);
1094 int ct_mixer_create(struct ct_atc
*atc
, struct ct_mixer
**rmixer
)
1096 struct ct_mixer
*mixer
;
1101 /* Allocate mem for mixer obj */
1102 err
= ct_mixer_get_mem(&mixer
);
1106 mixer
->switch_state
= 0;
1108 /* Set operations */
1109 mixer
->get_output_ports
= mixer_get_output_ports
;
1110 mixer
->set_input_left
= mixer_set_input_left
;
1111 mixer
->set_input_right
= mixer_set_input_right
;
1113 mixer
->resume
= mixer_resume
;
1116 /* Allocate chip resources for mixer obj */
1117 err
= ct_mixer_get_resources(mixer
);
1121 /* Build internal mixer topology */
1122 ct_mixer_topology_build(mixer
);
1129 ct_mixer_destroy(mixer
);
1133 int ct_alsa_mix_create(struct ct_atc
*atc
,
1134 enum CTALSADEVS device
,
1135 const char *device_name
)
1139 /* Create snd kcontrol instances on demand */
1140 /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
1141 err
= ct_mixer_kcontrols_create((struct ct_mixer
*)atc
->mixer
);
1145 strcpy(atc
->card
->mixername
, device_name
);