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 int ct_alsa_mix_switch_info(struct snd_kcontrol
*kcontrol
,
466 struct snd_ctl_elem_info
*uinfo
)
468 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
470 uinfo
->value
.integer
.min
= 0;
471 uinfo
->value
.integer
.max
= 1;
472 uinfo
->value
.integer
.step
= 1;
477 static int ct_alsa_mix_switch_get(struct snd_kcontrol
*kcontrol
,
478 struct snd_ctl_elem_value
*ucontrol
)
480 struct ct_mixer
*mixer
=
481 ((struct ct_atc
*)snd_kcontrol_chip(kcontrol
))->mixer
;
482 enum CTALSA_MIXER_CTL type
= kcontrol
->private_value
;
484 ucontrol
->value
.integer
.value
[0] = get_switch_state(mixer
, type
);
488 static int ct_alsa_mix_switch_put(struct snd_kcontrol
*kcontrol
,
489 struct snd_ctl_elem_value
*ucontrol
)
491 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
492 struct ct_mixer
*mixer
= atc
->mixer
;
493 enum CTALSA_MIXER_CTL type
= kcontrol
->private_value
;
496 state
= ucontrol
->value
.integer
.value
[0];
497 if (get_switch_state(mixer
, type
) == state
)
500 set_switch_state(mixer
, type
, state
);
501 /* Do changes in mixer. */
502 if ((SWH_CAPTURE_START
<= type
) && (SWH_CAPTURE_END
>= type
)) {
504 ct_mixer_recording_select(mixer
,
505 get_amixer_index(type
));
507 ct_mixer_recording_unselect(mixer
,
508 get_amixer_index(type
));
511 /* Do changes out of mixer. */
512 if (state
&& (MIXER_LINEIN_C_S
== type
|| MIXER_MIC_C_S
== type
))
513 do_line_mic_switch(atc
, type
);
514 else if (MIXER_WAVEF_P_S
== type
)
515 atc
->line_front_unmute(atc
, state
);
516 else if (MIXER_WAVES_P_S
== type
)
517 atc
->line_surround_unmute(atc
, state
);
518 else if (MIXER_WAVEC_P_S
== type
)
519 atc
->line_clfe_unmute(atc
, state
);
520 else if (MIXER_WAVER_P_S
== type
)
521 atc
->line_rear_unmute(atc
, state
);
522 else if (MIXER_LINEIN_P_S
== type
)
523 atc
->line_in_unmute(atc
, state
);
524 else if (MIXER_SPDIFO_P_S
== type
)
525 atc
->spdif_out_unmute(atc
, state
);
526 else if (MIXER_SPDIFI_P_S
== type
)
527 atc
->spdif_in_unmute(atc
, state
);
528 else if (MIXER_DIGITAL_IO_S
== type
)
529 do_digit_io_switch(atc
, state
);
534 static struct snd_kcontrol_new swh_ctl
= {
535 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
536 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
537 .info
= ct_alsa_mix_switch_info
,
538 .get
= ct_alsa_mix_switch_get
,
539 .put
= ct_alsa_mix_switch_put
542 static int ct_spdif_info(struct snd_kcontrol
*kcontrol
,
543 struct snd_ctl_elem_info
*uinfo
)
545 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_IEC958
;
550 static int ct_spdif_get_mask(struct snd_kcontrol
*kcontrol
,
551 struct snd_ctl_elem_value
*ucontrol
)
553 ucontrol
->value
.iec958
.status
[0] = 0xff;
554 ucontrol
->value
.iec958
.status
[1] = 0xff;
555 ucontrol
->value
.iec958
.status
[2] = 0xff;
556 ucontrol
->value
.iec958
.status
[3] = 0xff;
560 static int ct_spdif_default_get(struct snd_kcontrol
*kcontrol
,
561 struct snd_ctl_elem_value
*ucontrol
)
563 unsigned int status
= SNDRV_PCM_DEFAULT_CON_SPDIF
;
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;
573 static int ct_spdif_get(struct snd_kcontrol
*kcontrol
,
574 struct snd_ctl_elem_value
*ucontrol
)
576 struct ct_atc
*atc
= snd_kcontrol_chip(kcontrol
);
579 atc
->spdif_out_get_status(atc
, &status
);
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
,
623 .get
= ct_spdif_default_get
,
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 (NULL
== mixer
->amixers
) {
840 mixer
->sums
= kzalloc(sizeof(void *)*(NUM_CT_SUMS
*CHN_NUM
), GFP_KERNEL
);
841 if (NULL
== mixer
->sums
) {
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
);
1042 int ct_mixer_destroy(struct ct_mixer
*mixer
)
1044 struct sum_mgr
*sum_mgr
= (struct sum_mgr
*)mixer
->atc
->rsc_mgrs
[SUM
];
1045 struct amixer_mgr
*amixer_mgr
=
1046 (struct amixer_mgr
*)mixer
->atc
->rsc_mgrs
[AMIXER
];
1047 struct amixer
*amixer
;
1050 /* Release amixer resources */
1051 for (i
= 0; i
< (NUM_CT_AMIXERS
* CHN_NUM
); i
++) {
1052 if (NULL
!= mixer
->amixers
[i
]) {
1053 amixer
= mixer
->amixers
[i
];
1054 amixer_mgr
->put_amixer(amixer_mgr
, amixer
);
1058 /* Release sum resources */
1059 for (i
= 0; i
< (NUM_CT_SUMS
* CHN_NUM
); i
++) {
1060 if (NULL
!= mixer
->sums
[i
])
1061 sum_mgr
->put_sum(sum_mgr
, (struct sum
*)mixer
->sums
[i
]);
1064 /* Release mem assigned to mixer object */
1066 kfree(mixer
->amixers
);
1072 int ct_mixer_create(struct ct_atc
*atc
, struct ct_mixer
**rmixer
)
1074 struct ct_mixer
*mixer
;
1079 /* Allocate mem for mixer obj */
1080 err
= ct_mixer_get_mem(&mixer
);
1084 mixer
->switch_state
= 0;
1086 /* Set operations */
1087 mixer
->get_output_ports
= mixer_get_output_ports
;
1088 mixer
->set_input_left
= mixer_set_input_left
;
1089 mixer
->set_input_right
= mixer_set_input_right
;
1091 /* Allocate chip resources for mixer obj */
1092 err
= ct_mixer_get_resources(mixer
);
1096 /* Build internal mixer topology */
1097 ct_mixer_topology_build(mixer
);
1104 ct_mixer_destroy(mixer
);
1108 int ct_alsa_mix_create(struct ct_atc
*atc
,
1109 enum CTALSADEVS device
,
1110 const char *device_name
)
1114 /* Create snd kcontrol instances on demand */
1115 /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
1116 err
= ct_mixer_kcontrols_create((struct ct_mixer
*)atc
->mixer
);
1120 strcpy(atc
->card
->mixername
, device_name
);