Skip to content

Commit 9b4a227

Browse files
harinworkstiwai
authored andcommitted
ALSA: ctxfi: Add support for dedicated RCA switching
Add feature to support switching between the dedicated RCA output and the 7.1ch Front output. This is required for hardware that utilizes separate DAC circuits for RCA and 7.1ch channels. Changes: - Add dedicated_rca capability flag - Add "Analog Playback Route" mixer control - Implement logic to swap DAO inputs between RCA and Front ports Signed-off-by: Harin Lee <me@harin.net> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20251124180501.2760421-6-me@harin.net
1 parent a2dbaeb commit 9b4a227

8 files changed

Lines changed: 111 additions & 5 deletions

File tree

sound/pci/ctxfi/ctatc.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,24 @@ static struct capabilities atc_capabilities(struct ct_atc *atc)
987987
return hw->capabilities(hw);
988988
}
989989

990+
static void atc_dedicated_rca_select(struct ct_atc *atc)
991+
{
992+
struct dao *dao;
993+
struct ct_mixer *mixer = atc->mixer;
994+
struct rsc *rscs[2] = {NULL};
995+
996+
dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1],
997+
struct dao, daio);
998+
dao->ops->clear_left_input(dao);
999+
dao->ops->clear_right_input(dao);
1000+
1001+
mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]);
1002+
dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA],
1003+
struct dao, daio);
1004+
dao->ops->set_left_input(dao, rscs[0]);
1005+
dao->ops->set_right_input(dao, rscs[1]);
1006+
}
1007+
9901008
static int atc_output_switch_get(struct ct_atc *atc)
9911009
{
9921010
struct hw *hw = atc->hw;
@@ -1088,6 +1106,11 @@ static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
10881106
return atc_daio_unmute(atc, state, MIC);
10891107
}
10901108

1109+
static int atc_rca_unmute(struct ct_atc *atc, unsigned char state)
1110+
{
1111+
return atc_daio_unmute(atc, state, RCA);
1112+
}
1113+
10911114
static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
10921115
{
10931116
return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1303,6 +1326,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
13031326
dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
13041327
atc->chip_name, atc->model_name,
13051328
vendor_id, device_id);
1329+
atc->rca_state = 0;
13061330
return 0;
13071331
}
13081332

@@ -1400,11 +1424,11 @@ static int atc_get_resources(struct ct_atc *atc)
14001424
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
14011425
da_desc.msr = atc->msr;
14021426
for (i = 0; i < NUM_DAIOTYP; i++) {
1403-
if ((i == MIC) && !cap.dedicated_mic)
1427+
if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca))
14041428
continue;
14051429
da_desc.type = (atc->model != CTSB073X) ? i :
14061430
((i == SPDIFIO) ? SPDIFI1 : i);
1407-
da_desc.output = i < LINEIM;
1431+
da_desc.output = (i < LINEIM) || (i == RCA);
14081432
err = daio_mgr->get_daio(daio_mgr, &da_desc,
14091433
(struct daio **)&atc->daios[i]);
14101434
if (err) {
@@ -1511,6 +1535,9 @@ static void atc_connect_resources(struct ct_atc *atc)
15111535
dao->ops->set_right_input(dao, rscs[1]);
15121536
}
15131537

1538+
if (cap.dedicated_rca)
1539+
atc_dedicated_rca_select(atc);
1540+
15141541
dai = container_of(atc->daios[LINEIM], struct dai, daio);
15151542
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
15161543
(struct src **)&atc->srcs[2],
@@ -1643,12 +1670,14 @@ static const struct ct_atc atc_preset = {
16431670
.line_rear_unmute = atc_line_rear_unmute,
16441671
.line_in_unmute = atc_line_in_unmute,
16451672
.mic_unmute = atc_mic_unmute,
1673+
.rca_unmute = atc_rca_unmute,
16461674
.spdif_out_unmute = atc_spdif_out_unmute,
16471675
.spdif_in_unmute = atc_spdif_in_unmute,
16481676
.spdif_out_get_status = atc_spdif_out_get_status,
16491677
.spdif_out_set_status = atc_spdif_out_set_status,
16501678
.spdif_out_passthru = atc_spdif_out_passthru,
16511679
.capabilities = atc_capabilities,
1680+
.dedicated_rca_select = atc_dedicated_rca_select,
16521681
.output_switch_get = atc_output_switch_get,
16531682
.output_switch_put = atc_output_switch_put,
16541683
.mic_source_switch_get = atc_mic_source_switch_get,

sound/pci/ctxfi/ctatc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ struct ct_atc {
8282
const char *chip_name;
8383
const char *model_name;
8484

85+
unsigned char rca_state; /* 0 = dedicated RCA, 1 = 7.1ch Front */
86+
8587
struct ct_vm *vm; /* device virtual memory manager for this card */
8688
int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
8789
void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
@@ -113,12 +115,14 @@ struct ct_atc {
113115
int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
114116
int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
115117
int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
118+
int (*rca_unmute)(struct ct_atc *atc, unsigned char state);
116119
int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
117120
int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
118121
int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
119122
int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
120123
int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
121124
struct capabilities (*capabilities)(struct ct_atc *atc);
125+
void (*dedicated_rca_select)(struct ct_atc *atc);
122126
int (*output_switch_get)(struct ct_atc *atc);
123127
int (*output_switch_put)(struct ct_atc *atc, int position);
124128
int (*mic_source_switch_get)(struct ct_atc *atc);

sound/pci/ctxfi/ctdaio.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
4545
[LINEO4] = {.left = 0x70, .right = 0x71},
4646
[LINEIM] = {.left = 0x45, .right = 0xc5},
4747
[MIC] = {.left = 0x55, .right = 0xd5},
48+
[RCA] = {.left = 0x30, .right = 0x31},
4849
[SPDIFOO] = {.left = 0x00, .right = 0x01},
4950
[SPDIFIO] = {.left = 0x05, .right = 0x85},
5051
};
@@ -123,6 +124,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
123124
case LINEO4: return 6;
124125
case LINEIM: return 4;
125126
case MIC: return 5;
127+
case RCA: return 3;
126128
default: return -EINVAL;
127129
}
128130
default:

sound/pci/ctxfi/ctdaio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum DAIOTYP {
3131
LINEIM,
3232
SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
3333
MIC, /* Dedicated mic on Titanium HD */
34+
RCA,
3435
SPDIFI1, /* S/PDIF In on internal Drive Bay */
3536
NUM_DAIOTYP
3637
};

sound/pci/ctxfi/cthardware.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct card_conf {
6262
struct capabilities {
6363
unsigned int digit_io_switch:1;
6464
unsigned int dedicated_mic:1;
65+
unsigned int dedicated_rca:1;
6566
unsigned int output_switch:1;
6667
unsigned int mic_source_switch:1;
6768
};

sound/pci/ctxfi/cthw20k1.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
17751775
/* SB073x and Vista compatible cards have no digit IO switch */
17761776
cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
17771777
cap.dedicated_mic = 0;
1778+
cap.dedicated_rca = 0;
17781779
cap.output_switch = 0;
17791780
cap.mic_source_switch = 0;
17801781

sound/pci/ctxfi/cthw20k2.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
19301930

19311931
cap.digit_io_switch = 0;
19321932
cap.dedicated_mic = hw->model == CTSB1270;
1933+
cap.dedicated_rca = 0;
19331934
cap.output_switch = hw->model == CTSB1270;
19341935
cap.mic_source_switch = hw->model == CTSB1270;
19351936

sound/pci/ctxfi/ctmixer.c

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,14 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
547547
atc->mic_unmute(atc, state);
548548
else if (MIXER_SPDIFI_C_S == type)
549549
atc->spdif_in_unmute(atc, state);
550-
else if (MIXER_WAVEF_P_S == type)
551-
atc->line_front_unmute(atc, state);
550+
else if (MIXER_WAVEF_P_S == type) {
551+
if (cap.dedicated_rca) {
552+
atc->rca_unmute(atc, atc->rca_state ? 0 : state);
553+
atc->line_front_unmute(atc, atc->rca_state ? state : 0);
554+
} else {
555+
atc->line_front_unmute(atc, state);
556+
}
557+
}
552558
else if (MIXER_WAVES_P_S == type)
553559
atc->line_surround_unmute(atc, state);
554560
else if (MIXER_WAVEC_P_S == type)
@@ -612,6 +618,57 @@ static struct snd_kcontrol_new swh_ctl = {
612618
.put = ct_alsa_mix_switch_put
613619
};
614620

621+
static int dedicated_rca_info(struct snd_kcontrol *kcontrol,
622+
struct snd_ctl_elem_info *info)
623+
{
624+
static const char *const names[2] = {
625+
"RCA", "Front"
626+
};
627+
628+
return snd_ctl_enum_info(info, 1, 2, names);
629+
}
630+
631+
static int dedicated_rca_get(struct snd_kcontrol *kcontrol,
632+
struct snd_ctl_elem_value *ucontrol)
633+
{
634+
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
635+
636+
ucontrol->value.enumerated.item[0] = atc->rca_state;
637+
return 0;
638+
}
639+
640+
static int dedicated_rca_put(struct snd_kcontrol *kcontrol,
641+
struct snd_ctl_elem_value *ucontrol)
642+
{
643+
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
644+
unsigned int rca_state = ucontrol->value.enumerated.item[0];
645+
unsigned char state;
646+
647+
if (rca_state > 1)
648+
return -EINVAL;
649+
650+
if (rca_state == atc->rca_state)
651+
return 0;
652+
653+
state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S);
654+
do_switch(atc, MIXER_WAVEF_P_S, 0);
655+
656+
atc->rca_state = rca_state;
657+
atc->dedicated_rca_select(atc);
658+
659+
do_switch(atc, MIXER_WAVEF_P_S, state);
660+
661+
return 1;
662+
}
663+
664+
static struct snd_kcontrol_new rca_ctl = {
665+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
666+
.name = "Analog Playback Route",
667+
.info = dedicated_rca_info,
668+
.get = dedicated_rca_get,
669+
.put = dedicated_rca_put,
670+
};
671+
615672
static int ct_spdif_info(struct snd_kcontrol *kcontrol,
616673
struct snd_ctl_elem_info *uinfo)
617674
{
@@ -784,7 +841,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
784841
if (err)
785842
return err;
786843
}
787-
atc->line_front_unmute(atc, 1);
844+
845+
if (cap.dedicated_rca) {
846+
err = ct_mixer_kcontrol_new(mixer, &rca_ctl);
847+
if (err)
848+
return err;
849+
850+
atc->line_front_unmute(atc, 0);
851+
atc->rca_unmute(atc, 1);
852+
} else {
853+
atc->line_front_unmute(atc, 1);
854+
}
788855
set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
789856
atc->line_surround_unmute(atc, 0);
790857
set_switch_state(mixer, MIXER_WAVES_P_S, 0);

0 commit comments

Comments
 (0)