162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
462306a36Sopenharmony_ci *                   Takashi Iwai <tiwai@suse.de>
562306a36Sopenharmony_ci *                   Lee Revell <rlrevell@joe-job.com>
662306a36Sopenharmony_ci *                   James Courtier-Dutton <James@superbug.co.uk>
762306a36Sopenharmony_ci *                   Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
862306a36Sopenharmony_ci *                   Creative Labs, Inc.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  Routines for control of EMU10K1 chips / mixer routines
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/time.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <sound/core.h>
1662306a36Sopenharmony_ci#include <sound/emu10k1.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <sound/tlv.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "p17v.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define AC97_ID_STAC9758	0x83847658
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
2862306a36Sopenharmony_ci		    const char * const *ctls, unsigned nctls)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct snd_kcontrol_new kctl = *tpl;
3162306a36Sopenharmony_ci	int err;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	for (unsigned i = 0; i < nctls; i++) {
3462306a36Sopenharmony_ci		kctl.name = ctls[i];
3562306a36Sopenharmony_ci		kctl.private_value = i;
3662306a36Sopenharmony_ci		err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
3762306a36Sopenharmony_ci		if (err < 0)
3862306a36Sopenharmony_ci			return err;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci	return 0;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
4762306a36Sopenharmony_ci	uinfo->count = 1;
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
5262306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5562306a36Sopenharmony_ci	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Limit: emu->spdif_bits */
5862306a36Sopenharmony_ci	if (idx >= 3)
5962306a36Sopenharmony_ci		return -EINVAL;
6062306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
6162306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
6262306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
6362306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
6862306a36Sopenharmony_ci				      struct snd_ctl_elem_value *ucontrol)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = 0xff;
7162306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = 0xff;
7262306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = 0xff;
7362306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = 0xff;
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx
7862306a36Sopenharmony_ci#define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define ADAT_PS(pfx, sfx) \
8162306a36Sopenharmony_ci	pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \
8262306a36Sopenharmony_ci	pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define PAIR_REGS(base, one, two) \
8562306a36Sopenharmony_ci	base ## one ## 1, \
8662306a36Sopenharmony_ci	base ## two ## 1
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define ADAT_REGS(base) \
9162306a36Sopenharmony_ci	base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * List of data sources available for each destination
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define DSP_TEXTS \
9862306a36Sopenharmony_ci	"DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \
9962306a36Sopenharmony_ci	"DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \
10062306a36Sopenharmony_ci	"DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \
10162306a36Sopenharmony_ci	"DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31"
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "")
10462306a36Sopenharmony_ci#define LR_TEXTS(base) LR_PS(base, "")
10562306a36Sopenharmony_ci#define ADAT_TEXTS(pfx) ADAT_PS(pfx, "")
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define EMU32_SRC_REGS \
10862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A, \
10962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+1, \
11062306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+2, \
11162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+3, \
11262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, \
11362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+5, \
11462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+6, \
11562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+7, \
11662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+8, \
11762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+9, \
11862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xa, \
11962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xb, \
12062306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xc, \
12162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xd, \
12262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xe, \
12362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0xf, \
12462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B, \
12562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+1, \
12662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+2, \
12762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+3, \
12862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+4, \
12962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+5, \
13062306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+6, \
13162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+7, \
13262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+8, \
13362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+9, \
13462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xa, \
13562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xb, \
13662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xc, \
13762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xd, \
13862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xe, \
13962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32B+0xf
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* 1010 rev1 */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define EMU1010_COMMON_TEXTS \
14462306a36Sopenharmony_ci	"Silence", \
14562306a36Sopenharmony_ci	PAIR_TEXTS("Dock Mic", "A", "B"), \
14662306a36Sopenharmony_ci	LR_TEXTS("Dock ADC1"), \
14762306a36Sopenharmony_ci	LR_TEXTS("Dock ADC2"), \
14862306a36Sopenharmony_ci	LR_TEXTS("Dock ADC3"), \
14962306a36Sopenharmony_ci	LR_TEXTS("0202 ADC"), \
15062306a36Sopenharmony_ci	LR_TEXTS("1010 SPDIF"), \
15162306a36Sopenharmony_ci	ADAT_TEXTS("1010 ")
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic const char * const emu1010_src_texts[] = {
15462306a36Sopenharmony_ci	EMU1010_COMMON_TEXTS,
15562306a36Sopenharmony_ci	DSP_TEXTS,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const unsigned short emu1010_src_regs[] = {
15962306a36Sopenharmony_ci	EMU_SRC_SILENCE,
16062306a36Sopenharmony_ci	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
16162306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC1),
16262306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC2),
16362306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC3),
16462306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HAMOA_ADC),
16562306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HANA_SPDIF),
16662306a36Sopenharmony_ci	ADAT_REGS(EMU_SRC_HANA_ADAT),
16762306a36Sopenharmony_ci	EMU32_SRC_REGS,
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts));
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/* 1010 rev2 */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define EMU1010b_COMMON_TEXTS \
17462306a36Sopenharmony_ci	"Silence", \
17562306a36Sopenharmony_ci	PAIR_TEXTS("Dock Mic", "A", "B"), \
17662306a36Sopenharmony_ci	LR_TEXTS("Dock ADC1"), \
17762306a36Sopenharmony_ci	LR_TEXTS("Dock ADC2"), \
17862306a36Sopenharmony_ci	LR_TEXTS("0202 ADC"), \
17962306a36Sopenharmony_ci	LR_TEXTS("Dock SPDIF"), \
18062306a36Sopenharmony_ci	LR_TEXTS("1010 SPDIF"), \
18162306a36Sopenharmony_ci	ADAT_TEXTS("Dock "), \
18262306a36Sopenharmony_ci	ADAT_TEXTS("1010 ")
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic const char * const emu1010b_src_texts[] = {
18562306a36Sopenharmony_ci	EMU1010b_COMMON_TEXTS,
18662306a36Sopenharmony_ci	DSP_TEXTS,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic const unsigned short emu1010b_src_regs[] = {
19062306a36Sopenharmony_ci	EMU_SRC_SILENCE,
19162306a36Sopenharmony_ci	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
19262306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC1),
19362306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC2),
19462306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HAMOA_ADC),
19562306a36Sopenharmony_ci	LR_REGS(EMU_SRC_MDOCK_SPDIF),
19662306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HANA_SPDIF),
19762306a36Sopenharmony_ci	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
19862306a36Sopenharmony_ci	ADAT_REGS(EMU_SRC_HANA_ADAT),
19962306a36Sopenharmony_ci	EMU32_SRC_REGS,
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts));
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* 1616(m) cardbus */
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci#define EMU1616_COMMON_TEXTS \
20662306a36Sopenharmony_ci	"Silence", \
20762306a36Sopenharmony_ci	PAIR_TEXTS("Mic", "A", "B"), \
20862306a36Sopenharmony_ci	LR_TEXTS("ADC1"), \
20962306a36Sopenharmony_ci	LR_TEXTS("ADC2"), \
21062306a36Sopenharmony_ci	LR_TEXTS("SPDIF"), \
21162306a36Sopenharmony_ci	ADAT_TEXTS("")
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic const char * const emu1616_src_texts[] = {
21462306a36Sopenharmony_ci	EMU1616_COMMON_TEXTS,
21562306a36Sopenharmony_ci	DSP_TEXTS,
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic const unsigned short emu1616_src_regs[] = {
21962306a36Sopenharmony_ci	EMU_SRC_SILENCE,
22062306a36Sopenharmony_ci	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
22162306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC1),
22262306a36Sopenharmony_ci	LR_REGS(EMU_SRC_DOCK_ADC2),
22362306a36Sopenharmony_ci	LR_REGS(EMU_SRC_MDOCK_SPDIF),
22462306a36Sopenharmony_ci	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
22562306a36Sopenharmony_ci	EMU32_SRC_REGS,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* 0404 rev1 & rev2 */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci#define EMU0404_COMMON_TEXTS \
23262306a36Sopenharmony_ci	"Silence", \
23362306a36Sopenharmony_ci	LR_TEXTS("ADC"), \
23462306a36Sopenharmony_ci	LR_TEXTS("SPDIF")
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic const char * const emu0404_src_texts[] = {
23762306a36Sopenharmony_ci	EMU0404_COMMON_TEXTS,
23862306a36Sopenharmony_ci	DSP_TEXTS,
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic const unsigned short emu0404_src_regs[] = {
24262306a36Sopenharmony_ci	EMU_SRC_SILENCE,
24362306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HAMOA_ADC),
24462306a36Sopenharmony_ci	LR_REGS(EMU_SRC_HANA_SPDIF),
24562306a36Sopenharmony_ci	EMU32_SRC_REGS,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts));
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci * Data destinations - physical EMU outputs.
25162306a36Sopenharmony_ci * Each destination has an enum mixer control to choose a data source
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#define LR_CTLS(base) LR_PS(base, " Playback Enum")
25562306a36Sopenharmony_ci#define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/* 1010 rev1 */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic const char * const emu1010_output_texts[] = {
26062306a36Sopenharmony_ci	LR_CTLS("Dock DAC1"),
26162306a36Sopenharmony_ci	LR_CTLS("Dock DAC2"),
26262306a36Sopenharmony_ci	LR_CTLS("Dock DAC3"),
26362306a36Sopenharmony_ci	LR_CTLS("Dock DAC4"),
26462306a36Sopenharmony_ci	LR_CTLS("Dock Phones"),
26562306a36Sopenharmony_ci	LR_CTLS("Dock SPDIF"),
26662306a36Sopenharmony_ci	LR_CTLS("0202 DAC"),
26762306a36Sopenharmony_ci	LR_CTLS("1010 SPDIF"),
26862306a36Sopenharmony_ci	ADAT_CTLS("1010 "),
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic const unsigned short emu1010_output_dst[] = {
27362306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC1),
27462306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC2),
27562306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC3),
27662306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC4),
27762306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_PHONES),
27862306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_SPDIF),
27962306a36Sopenharmony_ci	LR_REGS(EMU_DST_HAMOA_DAC),
28062306a36Sopenharmony_ci	LR_REGS(EMU_DST_HANA_SPDIF),
28162306a36Sopenharmony_ci	ADAT_REGS(EMU_DST_HANA_ADAT),
28262306a36Sopenharmony_ci};
28362306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic const unsigned short emu1010_output_dflt[] = {
28662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
28762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
28862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
28962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
29062306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
29162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
29262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
29362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
29462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
29562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/* 1010 rev2 */
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const char * const snd_emu1010b_output_texts[] = {
30262306a36Sopenharmony_ci	LR_CTLS("Dock DAC1"),
30362306a36Sopenharmony_ci	LR_CTLS("Dock DAC2"),
30462306a36Sopenharmony_ci	LR_CTLS("Dock DAC3"),
30562306a36Sopenharmony_ci	LR_CTLS("Dock SPDIF"),
30662306a36Sopenharmony_ci	ADAT_CTLS("Dock "),
30762306a36Sopenharmony_ci	LR_CTLS("0202 DAC"),
30862306a36Sopenharmony_ci	LR_CTLS("1010 SPDIF"),
30962306a36Sopenharmony_ci	ADAT_CTLS("1010 "),
31062306a36Sopenharmony_ci};
31162306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic const unsigned short emu1010b_output_dst[] = {
31462306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC1),
31562306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC2),
31662306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC3),
31762306a36Sopenharmony_ci	LR_REGS(EMU_DST_MDOCK_SPDIF),
31862306a36Sopenharmony_ci	ADAT_REGS(EMU_DST_MDOCK_ADAT),
31962306a36Sopenharmony_ci	LR_REGS(EMU_DST_HAMOA_DAC),
32062306a36Sopenharmony_ci	LR_REGS(EMU_DST_HANA_SPDIF),
32162306a36Sopenharmony_ci	ADAT_REGS(EMU_DST_HANA_ADAT),
32262306a36Sopenharmony_ci};
32362306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic const unsigned short emu1010b_output_dflt[] = {
32662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
32762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
32862306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
32962306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
33062306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
33162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
33262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
33362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
33462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
33562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
33662306a36Sopenharmony_ci};
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci/* 1616(m) cardbus */
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic const char * const snd_emu1616_output_texts[] = {
34162306a36Sopenharmony_ci	LR_CTLS("Dock DAC1"),
34262306a36Sopenharmony_ci	LR_CTLS("Dock DAC2"),
34362306a36Sopenharmony_ci	LR_CTLS("Dock DAC3"),
34462306a36Sopenharmony_ci	LR_CTLS("Dock SPDIF"),
34562306a36Sopenharmony_ci	ADAT_CTLS("Dock "),
34662306a36Sopenharmony_ci	LR_CTLS("Mana DAC"),
34762306a36Sopenharmony_ci};
34862306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic const unsigned short emu1616_output_dst[] = {
35162306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC1),
35262306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC2),
35362306a36Sopenharmony_ci	LR_REGS(EMU_DST_DOCK_DAC3),
35462306a36Sopenharmony_ci	LR_REGS(EMU_DST_MDOCK_SPDIF),
35562306a36Sopenharmony_ci	ADAT_REGS(EMU_DST_MDOCK_ADAT),
35662306a36Sopenharmony_ci	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic const unsigned short emu1616_output_dflt[] = {
36162306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
36262306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
36362306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
36462306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
36562306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
36662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
36762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/* 0404 rev1 & rev2 */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic const char * const snd_emu0404_output_texts[] = {
37462306a36Sopenharmony_ci	LR_CTLS("DAC"),
37562306a36Sopenharmony_ci	LR_CTLS("SPDIF"),
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic const unsigned short emu0404_output_dst[] = {
38062306a36Sopenharmony_ci	LR_REGS(EMU_DST_HAMOA_DAC),
38162306a36Sopenharmony_ci	LR_REGS(EMU_DST_HANA_SPDIF),
38262306a36Sopenharmony_ci};
38362306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts));
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic const unsigned short emu0404_output_dflt[] = {
38662306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
38762306a36Sopenharmony_ci	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst));
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci * Data destinations - FPGA outputs going to Alice2 (Audigy) for
39362306a36Sopenharmony_ci *   capture (EMU32 + I2S links)
39462306a36Sopenharmony_ci * Each destination has an enum mixer control to choose a data source
39562306a36Sopenharmony_ci */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic const char * const emu1010_input_texts[] = {
39862306a36Sopenharmony_ci	"DSP 0 Capture Enum",
39962306a36Sopenharmony_ci	"DSP 1 Capture Enum",
40062306a36Sopenharmony_ci	"DSP 2 Capture Enum",
40162306a36Sopenharmony_ci	"DSP 3 Capture Enum",
40262306a36Sopenharmony_ci	"DSP 4 Capture Enum",
40362306a36Sopenharmony_ci	"DSP 5 Capture Enum",
40462306a36Sopenharmony_ci	"DSP 6 Capture Enum",
40562306a36Sopenharmony_ci	"DSP 7 Capture Enum",
40662306a36Sopenharmony_ci	"DSP 8 Capture Enum",
40762306a36Sopenharmony_ci	"DSP 9 Capture Enum",
40862306a36Sopenharmony_ci	"DSP A Capture Enum",
40962306a36Sopenharmony_ci	"DSP B Capture Enum",
41062306a36Sopenharmony_ci	"DSP C Capture Enum",
41162306a36Sopenharmony_ci	"DSP D Capture Enum",
41262306a36Sopenharmony_ci	"DSP E Capture Enum",
41362306a36Sopenharmony_ci	"DSP F Capture Enum",
41462306a36Sopenharmony_ci	/* These exist only on rev1 EMU1010 cards. */
41562306a36Sopenharmony_ci	"DSP 10 Capture Enum",
41662306a36Sopenharmony_ci	"DSP 11 Capture Enum",
41762306a36Sopenharmony_ci	"DSP 12 Capture Enum",
41862306a36Sopenharmony_ci	"DSP 13 Capture Enum",
41962306a36Sopenharmony_ci	"DSP 14 Capture Enum",
42062306a36Sopenharmony_ci	"DSP 15 Capture Enum",
42162306a36Sopenharmony_ci};
42262306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic const unsigned short emu1010_input_dst[] = {
42562306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_0,
42662306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_1,
42762306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_2,
42862306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_3,
42962306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_4,
43062306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_5,
43162306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_6,
43262306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_7,
43362306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_8,
43462306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_9,
43562306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_A,
43662306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_B,
43762306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_C,
43862306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_D,
43962306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_E,
44062306a36Sopenharmony_ci	EMU_DST_ALICE2_EMU32_F,
44162306a36Sopenharmony_ci	/* These exist only on rev1 EMU1010 cards. */
44262306a36Sopenharmony_ci	EMU_DST_ALICE_I2S0_LEFT,
44362306a36Sopenharmony_ci	EMU_DST_ALICE_I2S0_RIGHT,
44462306a36Sopenharmony_ci	EMU_DST_ALICE_I2S1_LEFT,
44562306a36Sopenharmony_ci	EMU_DST_ALICE_I2S1_RIGHT,
44662306a36Sopenharmony_ci	EMU_DST_ALICE_I2S2_LEFT,
44762306a36Sopenharmony_ci	EMU_DST_ALICE_I2S2_RIGHT,
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic const unsigned short emu1010_input_dflt[] = {
45262306a36Sopenharmony_ci	EMU_SRC_DOCK_MIC_A1,
45362306a36Sopenharmony_ci	EMU_SRC_DOCK_MIC_B1,
45462306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_LEFT1,
45562306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_RIGHT1,
45662306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_LEFT1,
45762306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_RIGHT1,
45862306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_LEFT1,
45962306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_RIGHT1,
46062306a36Sopenharmony_ci	/* Pavel Hofman - setting defaults for all capture channels.
46162306a36Sopenharmony_ci	 * Defaults only, users will set their own values anyways, let's
46262306a36Sopenharmony_ci	 * just copy/paste. */
46362306a36Sopenharmony_ci	EMU_SRC_DOCK_MIC_A1,
46462306a36Sopenharmony_ci	EMU_SRC_DOCK_MIC_B1,
46562306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_LEFT1,
46662306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_RIGHT1,
46762306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_LEFT1,
46862306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_RIGHT1,
46962306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_LEFT1,
47062306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_RIGHT1,
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_LEFT1,
47362306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC1_RIGHT1,
47462306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_LEFT1,
47562306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC2_RIGHT1,
47662306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC3_LEFT1,
47762306a36Sopenharmony_ci	EMU_SRC_DOCK_ADC3_RIGHT1,
47862306a36Sopenharmony_ci};
47962306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic const unsigned short emu0404_input_dflt[] = {
48262306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_LEFT1,
48362306a36Sopenharmony_ci	EMU_SRC_HAMOA_ADC_RIGHT1,
48462306a36Sopenharmony_ci	EMU_SRC_SILENCE,
48562306a36Sopenharmony_ci	EMU_SRC_SILENCE,
48662306a36Sopenharmony_ci	EMU_SRC_SILENCE,
48762306a36Sopenharmony_ci	EMU_SRC_SILENCE,
48862306a36Sopenharmony_ci	EMU_SRC_SILENCE,
48962306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49062306a36Sopenharmony_ci	EMU_SRC_HANA_SPDIF_LEFT1,
49162306a36Sopenharmony_ci	EMU_SRC_HANA_SPDIF_RIGHT1,
49262306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49362306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49462306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49562306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49662306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49762306a36Sopenharmony_ci	EMU_SRC_SILENCE,
49862306a36Sopenharmony_ci};
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistruct snd_emu1010_routing_info {
50162306a36Sopenharmony_ci	const char * const *src_texts;
50262306a36Sopenharmony_ci	const char * const *out_texts;
50362306a36Sopenharmony_ci	const unsigned short *src_regs;
50462306a36Sopenharmony_ci	const unsigned short *out_regs;
50562306a36Sopenharmony_ci	const unsigned short *in_regs;
50662306a36Sopenharmony_ci	const unsigned short *out_dflts;
50762306a36Sopenharmony_ci	const unsigned short *in_dflts;
50862306a36Sopenharmony_ci	unsigned n_srcs;
50962306a36Sopenharmony_ci	unsigned n_outs;
51062306a36Sopenharmony_ci	unsigned n_ins;
51162306a36Sopenharmony_ci};
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic const struct snd_emu1010_routing_info emu1010_routing_info[] = {
51462306a36Sopenharmony_ci	{
51562306a36Sopenharmony_ci		/* rev1 1010 */
51662306a36Sopenharmony_ci		.src_regs = emu1010_src_regs,
51762306a36Sopenharmony_ci		.src_texts = emu1010_src_texts,
51862306a36Sopenharmony_ci		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		.out_dflts = emu1010_output_dflt,
52162306a36Sopenharmony_ci		.out_regs = emu1010_output_dst,
52262306a36Sopenharmony_ci		.out_texts = emu1010_output_texts,
52362306a36Sopenharmony_ci		.n_outs = ARRAY_SIZE(emu1010_output_dst),
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		.in_dflts = emu1010_input_dflt,
52662306a36Sopenharmony_ci		.in_regs = emu1010_input_dst,
52762306a36Sopenharmony_ci		.n_ins = ARRAY_SIZE(emu1010_input_dst),
52862306a36Sopenharmony_ci	},
52962306a36Sopenharmony_ci	{
53062306a36Sopenharmony_ci		/* rev2 1010 */
53162306a36Sopenharmony_ci		.src_regs = emu1010b_src_regs,
53262306a36Sopenharmony_ci		.src_texts = emu1010b_src_texts,
53362306a36Sopenharmony_ci		.n_srcs = ARRAY_SIZE(emu1010b_src_texts),
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		.out_dflts = emu1010b_output_dflt,
53662306a36Sopenharmony_ci		.out_regs = emu1010b_output_dst,
53762306a36Sopenharmony_ci		.out_texts = snd_emu1010b_output_texts,
53862306a36Sopenharmony_ci		.n_outs = ARRAY_SIZE(emu1010b_output_dst),
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		.in_dflts = emu1010_input_dflt,
54162306a36Sopenharmony_ci		.in_regs = emu1010_input_dst,
54262306a36Sopenharmony_ci		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
54362306a36Sopenharmony_ci	},
54462306a36Sopenharmony_ci	{
54562306a36Sopenharmony_ci		/* 1616(m) cardbus */
54662306a36Sopenharmony_ci		.src_regs = emu1616_src_regs,
54762306a36Sopenharmony_ci		.src_texts = emu1616_src_texts,
54862306a36Sopenharmony_ci		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		.out_dflts = emu1616_output_dflt,
55162306a36Sopenharmony_ci		.out_regs = emu1616_output_dst,
55262306a36Sopenharmony_ci		.out_texts = snd_emu1616_output_texts,
55362306a36Sopenharmony_ci		.n_outs = ARRAY_SIZE(emu1616_output_dst),
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		.in_dflts = emu1010_input_dflt,
55662306a36Sopenharmony_ci		.in_regs = emu1010_input_dst,
55762306a36Sopenharmony_ci		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
55862306a36Sopenharmony_ci	},
55962306a36Sopenharmony_ci	{
56062306a36Sopenharmony_ci		/* 0404 */
56162306a36Sopenharmony_ci		.src_regs = emu0404_src_regs,
56262306a36Sopenharmony_ci		.src_texts = emu0404_src_texts,
56362306a36Sopenharmony_ci		.n_srcs = ARRAY_SIZE(emu0404_src_texts),
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		.out_dflts = emu0404_output_dflt,
56662306a36Sopenharmony_ci		.out_regs = emu0404_output_dst,
56762306a36Sopenharmony_ci		.out_texts = snd_emu0404_output_texts,
56862306a36Sopenharmony_ci		.n_outs = ARRAY_SIZE(emu0404_output_dflt),
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		.in_dflts = emu0404_input_dflt,
57162306a36Sopenharmony_ci		.in_regs = emu1010_input_dst,
57262306a36Sopenharmony_ci		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
57362306a36Sopenharmony_ci	},
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic unsigned emu1010_idx(struct snd_emu10k1 *emu)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	return emu->card_capabilities->emu_model - 1;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
58262306a36Sopenharmony_ci					    int channel, int src)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
58562306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	snd_emu1010_fpga_link_dst_src_write(emu,
58862306a36Sopenharmony_ci		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
59262306a36Sopenharmony_ci					   int channel, int src)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
59562306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	snd_emu1010_fpga_link_dst_src_write(emu,
59862306a36Sopenharmony_ci		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
60462306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	for (unsigned i = 0; i < emu_ri->n_outs; i++)
60762306a36Sopenharmony_ci		snd_emu1010_output_source_apply(
60862306a36Sopenharmony_ci			emu, i, emu->emu1010.output_source[i]);
60962306a36Sopenharmony_ci	for (unsigned i = 0; i < emu_ri->n_ins; i++)
61062306a36Sopenharmony_ci		snd_emu1010_input_source_apply(
61162306a36Sopenharmony_ci			emu, i, emu->emu1010.input_source[i]);
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
61562306a36Sopenharmony_ci			     unsigned val)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
61862306a36Sopenharmony_ci		if (val == emu_ri->src_regs[i])
61962306a36Sopenharmony_ci			return i;
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
62462306a36Sopenharmony_ci						struct snd_ctl_elem_info *uinfo)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
62762306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
62862306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
63462306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
63762306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
63862306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
63962306a36Sopenharmony_ci	unsigned channel = kcontrol->private_value;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (channel >= emu_ri->n_outs)
64262306a36Sopenharmony_ci		return -EINVAL;
64362306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
64462306a36Sopenharmony_ci	return 0;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
64862306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
65162306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
65262306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
65362306a36Sopenharmony_ci	unsigned val = ucontrol->value.enumerated.item[0];
65462306a36Sopenharmony_ci	unsigned channel = kcontrol->private_value;
65562306a36Sopenharmony_ci	int change;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (val >= emu_ri->n_srcs)
65862306a36Sopenharmony_ci		return -EINVAL;
65962306a36Sopenharmony_ci	if (channel >= emu_ri->n_outs)
66062306a36Sopenharmony_ci		return -EINVAL;
66162306a36Sopenharmony_ci	change = (emu->emu1010.output_source[channel] != val);
66262306a36Sopenharmony_ci	if (change) {
66362306a36Sopenharmony_ci		emu->emu1010.output_source[channel] = val;
66462306a36Sopenharmony_ci		snd_emu1010_output_source_apply(emu, channel, val);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci	return change;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic const struct snd_kcontrol_new emu1010_output_source_ctl = {
67062306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
67162306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
67262306a36Sopenharmony_ci	.info = snd_emu1010_input_output_source_info,
67362306a36Sopenharmony_ci	.get = snd_emu1010_output_source_get,
67462306a36Sopenharmony_ci	.put = snd_emu1010_output_source_put
67562306a36Sopenharmony_ci};
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
67862306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
68162306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
68262306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
68362306a36Sopenharmony_ci	unsigned channel = kcontrol->private_value;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (channel >= emu_ri->n_ins)
68662306a36Sopenharmony_ci		return -EINVAL;
68762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
68862306a36Sopenharmony_ci	return 0;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
69262306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
69562306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
69662306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
69762306a36Sopenharmony_ci	unsigned val = ucontrol->value.enumerated.item[0];
69862306a36Sopenharmony_ci	unsigned channel = kcontrol->private_value;
69962306a36Sopenharmony_ci	int change;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (val >= emu_ri->n_srcs)
70262306a36Sopenharmony_ci		return -EINVAL;
70362306a36Sopenharmony_ci	if (channel >= emu_ri->n_ins)
70462306a36Sopenharmony_ci		return -EINVAL;
70562306a36Sopenharmony_ci	change = (emu->emu1010.input_source[channel] != val);
70662306a36Sopenharmony_ci	if (change) {
70762306a36Sopenharmony_ci		emu->emu1010.input_source[channel] = val;
70862306a36Sopenharmony_ci		snd_emu1010_input_source_apply(emu, channel, val);
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci	return change;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic const struct snd_kcontrol_new emu1010_input_source_ctl = {
71462306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
71562306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
71662306a36Sopenharmony_ci	.info = snd_emu1010_input_output_source_info,
71762306a36Sopenharmony_ci	.get = snd_emu1010_input_source_get,
71862306a36Sopenharmony_ci	.put = snd_emu1010_input_source_put
71962306a36Sopenharmony_ci};
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	const struct snd_emu1010_routing_info *emu_ri =
72462306a36Sopenharmony_ci		&emu1010_routing_info[emu1010_idx(emu)];
72562306a36Sopenharmony_ci	int err;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	err = add_ctls(emu, &emu1010_output_source_ctl,
72862306a36Sopenharmony_ci		       emu_ri->out_texts, emu_ri->n_outs);
72962306a36Sopenharmony_ci	if (err < 0)
73062306a36Sopenharmony_ci		return err;
73162306a36Sopenharmony_ci	err = add_ctls(emu, &emu1010_input_source_ctl,
73262306a36Sopenharmony_ci		       emu1010_input_texts, emu_ri->n_ins);
73362306a36Sopenharmony_ci	return err;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic const char * const snd_emu1010_adc_pads[] = {
73862306a36Sopenharmony_ci	"ADC1 14dB PAD 0202 Capture Switch",
73962306a36Sopenharmony_ci	"ADC1 14dB PAD Audio Dock Capture Switch",
74062306a36Sopenharmony_ci	"ADC2 14dB PAD Audio Dock Capture Switch",
74162306a36Sopenharmony_ci	"ADC3 14dB PAD Audio Dock Capture Switch",
74262306a36Sopenharmony_ci};
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic const unsigned short snd_emu1010_adc_pad_regs[] = {
74562306a36Sopenharmony_ci	EMU_HANA_0202_ADC_PAD1,
74662306a36Sopenharmony_ci	EMU_HANA_DOCK_ADC_PAD1,
74762306a36Sopenharmony_ci	EMU_HANA_DOCK_ADC_PAD2,
74862306a36Sopenharmony_ci	EMU_HANA_DOCK_ADC_PAD3,
74962306a36Sopenharmony_ci};
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci#define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
75662306a36Sopenharmony_ci	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
75962306a36Sopenharmony_ci	return 0;
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
76562306a36Sopenharmony_ci	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
76662306a36Sopenharmony_ci	unsigned int val, cache;
76762306a36Sopenharmony_ci	int change;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0];
77062306a36Sopenharmony_ci	cache = emu->emu1010.adc_pads;
77162306a36Sopenharmony_ci	if (val == 1)
77262306a36Sopenharmony_ci		cache = cache | mask;
77362306a36Sopenharmony_ci	else
77462306a36Sopenharmony_ci		cache = cache & ~mask;
77562306a36Sopenharmony_ci	change = (cache != emu->emu1010.adc_pads);
77662306a36Sopenharmony_ci	if (change) {
77762306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
77862306a36Sopenharmony_ci	        emu->emu1010.adc_pads = cache;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	return change;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
78562306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
78662306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
78762306a36Sopenharmony_ci	.info = snd_emu1010_adc_pads_info,
78862306a36Sopenharmony_ci	.get = snd_emu1010_adc_pads_get,
78962306a36Sopenharmony_ci	.put = snd_emu1010_adc_pads_put
79062306a36Sopenharmony_ci};
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic const char * const snd_emu1010_dac_pads[] = {
79462306a36Sopenharmony_ci	"DAC1 0202 14dB PAD Playback Switch",
79562306a36Sopenharmony_ci	"DAC1 Audio Dock 14dB PAD Playback Switch",
79662306a36Sopenharmony_ci	"DAC2 Audio Dock 14dB PAD Playback Switch",
79762306a36Sopenharmony_ci	"DAC3 Audio Dock 14dB PAD Playback Switch",
79862306a36Sopenharmony_ci	"DAC4 Audio Dock 14dB PAD Playback Switch",
79962306a36Sopenharmony_ci};
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic const unsigned short snd_emu1010_dac_regs[] = {
80262306a36Sopenharmony_ci	EMU_HANA_0202_DAC_PAD1,
80362306a36Sopenharmony_ci	EMU_HANA_DOCK_DAC_PAD1,
80462306a36Sopenharmony_ci	EMU_HANA_DOCK_DAC_PAD2,
80562306a36Sopenharmony_ci	EMU_HANA_DOCK_DAC_PAD3,
80662306a36Sopenharmony_ci	EMU_HANA_DOCK_DAC_PAD4,
80762306a36Sopenharmony_ci};
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci#define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
81462306a36Sopenharmony_ci	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
81762306a36Sopenharmony_ci	return 0;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
82362306a36Sopenharmony_ci	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
82462306a36Sopenharmony_ci	unsigned int val, cache;
82562306a36Sopenharmony_ci	int change;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0];
82862306a36Sopenharmony_ci	cache = emu->emu1010.dac_pads;
82962306a36Sopenharmony_ci	if (val == 1)
83062306a36Sopenharmony_ci		cache = cache | mask;
83162306a36Sopenharmony_ci	else
83262306a36Sopenharmony_ci		cache = cache & ~mask;
83362306a36Sopenharmony_ci	change = (cache != emu->emu1010.dac_pads);
83462306a36Sopenharmony_ci	if (change) {
83562306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
83662306a36Sopenharmony_ci	        emu->emu1010.dac_pads = cache;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	return change;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
84362306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
84462306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
84562306a36Sopenharmony_ci	.info = snd_emu1010_dac_pads_info,
84662306a36Sopenharmony_ci	.get = snd_emu1010_dac_pads_get,
84762306a36Sopenharmony_ci	.put = snd_emu1010_dac_pads_put
84862306a36Sopenharmony_ci};
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistruct snd_emu1010_pads_info {
85262306a36Sopenharmony_ci	const char * const *adc_ctls, * const *dac_ctls;
85362306a36Sopenharmony_ci	unsigned n_adc_ctls, n_dac_ctls;
85462306a36Sopenharmony_ci};
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic const struct snd_emu1010_pads_info emu1010_pads_info[] = {
85762306a36Sopenharmony_ci	{
85862306a36Sopenharmony_ci		/* rev1 1010 */
85962306a36Sopenharmony_ci		.adc_ctls = snd_emu1010_adc_pads,
86062306a36Sopenharmony_ci		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
86162306a36Sopenharmony_ci		.dac_ctls = snd_emu1010_dac_pads,
86262306a36Sopenharmony_ci		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
86362306a36Sopenharmony_ci	},
86462306a36Sopenharmony_ci	{
86562306a36Sopenharmony_ci		/* rev2 1010 */
86662306a36Sopenharmony_ci		.adc_ctls = snd_emu1010_adc_pads,
86762306a36Sopenharmony_ci		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
86862306a36Sopenharmony_ci		.dac_ctls = snd_emu1010_dac_pads,
86962306a36Sopenharmony_ci		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
87062306a36Sopenharmony_ci	},
87162306a36Sopenharmony_ci	{
87262306a36Sopenharmony_ci		/* 1616(m) cardbus */
87362306a36Sopenharmony_ci		.adc_ctls = snd_emu1010_adc_pads + 1,
87462306a36Sopenharmony_ci		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
87562306a36Sopenharmony_ci		.dac_ctls = snd_emu1010_dac_pads + 1,
87662306a36Sopenharmony_ci		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
87762306a36Sopenharmony_ci	},
87862306a36Sopenharmony_ci	{
87962306a36Sopenharmony_ci		/* 0404 */
88062306a36Sopenharmony_ci		.adc_ctls = NULL,
88162306a36Sopenharmony_ci		.n_adc_ctls = 0,
88262306a36Sopenharmony_ci		.dac_ctls = NULL,
88362306a36Sopenharmony_ci		.n_dac_ctls = 0,
88462306a36Sopenharmony_ci	},
88562306a36Sopenharmony_ci};
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cistatic const char * const emu1010_clock_texts[] = {
88862306a36Sopenharmony_ci	"44100", "48000", "SPDIF", "ADAT", "Dock", "BNC"
88962306a36Sopenharmony_ci};
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic const u8 emu1010_clock_vals[] = {
89262306a36Sopenharmony_ci	EMU_HANA_WCLOCK_INT_44_1K,
89362306a36Sopenharmony_ci	EMU_HANA_WCLOCK_INT_48K,
89462306a36Sopenharmony_ci	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
89562306a36Sopenharmony_ci	EMU_HANA_WCLOCK_HANA_ADAT_IN,
89662306a36Sopenharmony_ci	EMU_HANA_WCLOCK_2ND_HANA,
89762306a36Sopenharmony_ci	EMU_HANA_WCLOCK_SYNC_BNC,
89862306a36Sopenharmony_ci};
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic const char * const emu0404_clock_texts[] = {
90162306a36Sopenharmony_ci	"44100", "48000", "SPDIF", "BNC"
90262306a36Sopenharmony_ci};
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic const u8 emu0404_clock_vals[] = {
90562306a36Sopenharmony_ci	EMU_HANA_WCLOCK_INT_44_1K,
90662306a36Sopenharmony_ci	EMU_HANA_WCLOCK_INT_48K,
90762306a36Sopenharmony_ci	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
90862306a36Sopenharmony_ci	EMU_HANA_WCLOCK_SYNC_BNC,
90962306a36Sopenharmony_ci};
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistruct snd_emu1010_clock_info {
91262306a36Sopenharmony_ci	const char * const *texts;
91362306a36Sopenharmony_ci	const u8 *vals;
91462306a36Sopenharmony_ci	unsigned num;
91562306a36Sopenharmony_ci};
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic const struct snd_emu1010_clock_info emu1010_clock_info[] = {
91862306a36Sopenharmony_ci	{
91962306a36Sopenharmony_ci		// rev1 1010
92062306a36Sopenharmony_ci		.texts = emu1010_clock_texts,
92162306a36Sopenharmony_ci		.vals = emu1010_clock_vals,
92262306a36Sopenharmony_ci		.num = ARRAY_SIZE(emu1010_clock_vals),
92362306a36Sopenharmony_ci	},
92462306a36Sopenharmony_ci	{
92562306a36Sopenharmony_ci		// rev2 1010
92662306a36Sopenharmony_ci		.texts = emu1010_clock_texts,
92762306a36Sopenharmony_ci		.vals = emu1010_clock_vals,
92862306a36Sopenharmony_ci		.num = ARRAY_SIZE(emu1010_clock_vals) - 1,
92962306a36Sopenharmony_ci	},
93062306a36Sopenharmony_ci	{
93162306a36Sopenharmony_ci		// 1616(m) CardBus
93262306a36Sopenharmony_ci		.texts = emu1010_clock_texts,
93362306a36Sopenharmony_ci		// TODO: determine what is actually available.
93462306a36Sopenharmony_ci		// Pedantically, *every* source comes from the 2nd FPGA, as the
93562306a36Sopenharmony_ci		// card itself has no own (digital) audio ports. The user manual
93662306a36Sopenharmony_ci		// claims that ADAT and S/PDIF clock sources are separate, which
93762306a36Sopenharmony_ci		// can mean two things: either E-MU mapped the dock's sources to
93862306a36Sopenharmony_ci		// the primary ones, or they determine the meaning of the "Dock"
93962306a36Sopenharmony_ci		// source depending on how the ports are actually configured
94062306a36Sopenharmony_ci		// (which the 2nd FPGA must be doing anyway).
94162306a36Sopenharmony_ci		.vals = emu1010_clock_vals,
94262306a36Sopenharmony_ci		.num = ARRAY_SIZE(emu1010_clock_vals),
94362306a36Sopenharmony_ci	},
94462306a36Sopenharmony_ci	{
94562306a36Sopenharmony_ci		// 0404
94662306a36Sopenharmony_ci		.texts = emu0404_clock_texts,
94762306a36Sopenharmony_ci		.vals = emu0404_clock_vals,
94862306a36Sopenharmony_ci		.num = ARRAY_SIZE(emu0404_clock_vals),
94962306a36Sopenharmony_ci	},
95062306a36Sopenharmony_ci};
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol,
95362306a36Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
95662306a36Sopenharmony_ci	const struct snd_emu1010_clock_info *emu_ci =
95762306a36Sopenharmony_ci		&emu1010_clock_info[emu1010_idx(emu)];
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts);
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol,
96362306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source;
96862306a36Sopenharmony_ci	return 0;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
97262306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
97562306a36Sopenharmony_ci	const struct snd_emu1010_clock_info *emu_ci =
97662306a36Sopenharmony_ci		&emu1010_clock_info[emu1010_idx(emu)];
97762306a36Sopenharmony_ci	unsigned int val;
97862306a36Sopenharmony_ci	int change = 0;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0] ;
98162306a36Sopenharmony_ci	if (val >= emu_ci->num)
98262306a36Sopenharmony_ci		return -EINVAL;
98362306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
98462306a36Sopenharmony_ci	change = (emu->emu1010.clock_source != val);
98562306a36Sopenharmony_ci	if (change) {
98662306a36Sopenharmony_ci		emu->emu1010.clock_source = val;
98762306a36Sopenharmony_ci		emu->emu1010.wclock = emu_ci->vals[val];
98862306a36Sopenharmony_ci		snd_emu1010_update_clock(emu);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE);
99162306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock);
99262306a36Sopenharmony_ci		spin_unlock_irq(&emu->reg_lock);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		msleep(10);  // Allow DLL to settle
99562306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
99662306a36Sopenharmony_ci	} else {
99762306a36Sopenharmony_ci		spin_unlock_irq(&emu->reg_lock);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci	return change;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_clock_source =
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
100562306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
100662306a36Sopenharmony_ci	.name = "Clock Source",
100762306a36Sopenharmony_ci	.count = 1,
100862306a36Sopenharmony_ci	.info = snd_emu1010_clock_source_info,
100962306a36Sopenharmony_ci	.get = snd_emu1010_clock_source_get,
101062306a36Sopenharmony_ci	.put = snd_emu1010_clock_source_put
101162306a36Sopenharmony_ci};
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol,
101462306a36Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	static const char * const texts[2] = {
101762306a36Sopenharmony_ci		"44100", "48000"
101862306a36Sopenharmony_ci	};
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol,
102462306a36Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback;
102962306a36Sopenharmony_ci	return 0;
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
103362306a36Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
103662306a36Sopenharmony_ci	unsigned int val = ucontrol->value.enumerated.item[0];
103762306a36Sopenharmony_ci	int change;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (val >= 2)
104062306a36Sopenharmony_ci		return -EINVAL;
104162306a36Sopenharmony_ci	change = (emu->emu1010.clock_fallback != val);
104262306a36Sopenharmony_ci	if (change) {
104362306a36Sopenharmony_ci		emu->emu1010.clock_fallback = val;
104462306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci	return change;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_clock_fallback =
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
105262306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
105362306a36Sopenharmony_ci	.name = "Clock Fallback",
105462306a36Sopenharmony_ci	.count = 1,
105562306a36Sopenharmony_ci	.info = snd_emu1010_clock_fallback_info,
105662306a36Sopenharmony_ci	.get = snd_emu1010_clock_fallback_get,
105762306a36Sopenharmony_ci	.put = snd_emu1010_clock_fallback_put
105862306a36Sopenharmony_ci};
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
106162306a36Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	static const char * const texts[2] = {
106462306a36Sopenharmony_ci		"SPDIF", "ADAT"
106562306a36Sopenharmony_ci	};
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
107162306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
108062306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
108362306a36Sopenharmony_ci	unsigned int val;
108462306a36Sopenharmony_ci	u32 tmp;
108562306a36Sopenharmony_ci	int change = 0;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
108862306a36Sopenharmony_ci	/* Limit: uinfo->value.enumerated.items = 2; */
108962306a36Sopenharmony_ci	if (val >= 2)
109062306a36Sopenharmony_ci		return -EINVAL;
109162306a36Sopenharmony_ci	change = (emu->emu1010.optical_out != val);
109262306a36Sopenharmony_ci	if (change) {
109362306a36Sopenharmony_ci		emu->emu1010.optical_out = val;
109462306a36Sopenharmony_ci		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
109562306a36Sopenharmony_ci			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
109662306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci	return change;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_optical_out = {
110262306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
110362306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
110462306a36Sopenharmony_ci	.name =         "Optical Output Mode",
110562306a36Sopenharmony_ci	.count =	1,
110662306a36Sopenharmony_ci	.info =         snd_emu1010_optical_out_info,
110762306a36Sopenharmony_ci	.get =          snd_emu1010_optical_out_get,
110862306a36Sopenharmony_ci	.put =          snd_emu1010_optical_out_put
110962306a36Sopenharmony_ci};
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
111262306a36Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	static const char * const texts[2] = {
111562306a36Sopenharmony_ci		"SPDIF", "ADAT"
111662306a36Sopenharmony_ci	};
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistatic int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
112262306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
112762306a36Sopenharmony_ci	return 0;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
113162306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
113462306a36Sopenharmony_ci	unsigned int val;
113562306a36Sopenharmony_ci	u32 tmp;
113662306a36Sopenharmony_ci	int change = 0;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
113962306a36Sopenharmony_ci	/* Limit: uinfo->value.enumerated.items = 2; */
114062306a36Sopenharmony_ci	if (val >= 2)
114162306a36Sopenharmony_ci		return -EINVAL;
114262306a36Sopenharmony_ci	change = (emu->emu1010.optical_in != val);
114362306a36Sopenharmony_ci	if (change) {
114462306a36Sopenharmony_ci		emu->emu1010.optical_in = val;
114562306a36Sopenharmony_ci		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
114662306a36Sopenharmony_ci			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
114762306a36Sopenharmony_ci		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci	return change;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_optical_in = {
115362306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
115462306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
115562306a36Sopenharmony_ci	.name =         "Optical Input Mode",
115662306a36Sopenharmony_ci	.count =	1,
115762306a36Sopenharmony_ci	.info =         snd_emu1010_optical_in_info,
115862306a36Sopenharmony_ci	.get =          snd_emu1010_optical_in_get,
115962306a36Sopenharmony_ci	.put =          snd_emu1010_optical_in_put
116062306a36Sopenharmony_ci};
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
116362306a36Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
116462306a36Sopenharmony_ci{
116562306a36Sopenharmony_ci#if 0
116662306a36Sopenharmony_ci	static const char * const texts[4] = {
116762306a36Sopenharmony_ci		"Unknown1", "Unknown2", "Mic", "Line"
116862306a36Sopenharmony_ci	};
116962306a36Sopenharmony_ci#endif
117062306a36Sopenharmony_ci	static const char * const texts[2] = {
117162306a36Sopenharmony_ci		"Mic", "Line"
117262306a36Sopenharmony_ci	};
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 2, texts);
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_cistatic int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
117862306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
118362306a36Sopenharmony_ci	return 0;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
118762306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
119062306a36Sopenharmony_ci	unsigned int source_id;
119162306a36Sopenharmony_ci	unsigned int ngain, ogain;
119262306a36Sopenharmony_ci	u16 gpio;
119362306a36Sopenharmony_ci	int change = 0;
119462306a36Sopenharmony_ci	u32 source;
119562306a36Sopenharmony_ci	/* If the capture source has changed,
119662306a36Sopenharmony_ci	 * update the capture volume from the cached value
119762306a36Sopenharmony_ci	 * for the particular source.
119862306a36Sopenharmony_ci	 */
119962306a36Sopenharmony_ci	source_id = ucontrol->value.enumerated.item[0];
120062306a36Sopenharmony_ci	/* Limit: uinfo->value.enumerated.items = 2; */
120162306a36Sopenharmony_ci	/*        emu->i2c_capture_volume */
120262306a36Sopenharmony_ci	if (source_id >= 2)
120362306a36Sopenharmony_ci		return -EINVAL;
120462306a36Sopenharmony_ci	change = (emu->i2c_capture_source != source_id);
120562306a36Sopenharmony_ci	if (change) {
120662306a36Sopenharmony_ci		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
120762306a36Sopenharmony_ci		spin_lock_irq(&emu->emu_lock);
120862306a36Sopenharmony_ci		gpio = inw(emu->port + A_IOCFG);
120962306a36Sopenharmony_ci		if (source_id==0)
121062306a36Sopenharmony_ci			outw(gpio | 0x4, emu->port + A_IOCFG);
121162306a36Sopenharmony_ci		else
121262306a36Sopenharmony_ci			outw(gpio & ~0x4, emu->port + A_IOCFG);
121362306a36Sopenharmony_ci		spin_unlock_irq(&emu->emu_lock);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
121662306a36Sopenharmony_ci		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
121762306a36Sopenharmony_ci		if (ngain != ogain)
121862306a36Sopenharmony_ci			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
121962306a36Sopenharmony_ci		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
122062306a36Sopenharmony_ci		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
122162306a36Sopenharmony_ci		if (ngain != ogain)
122262306a36Sopenharmony_ci			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		source = 1 << (source_id + 2);
122562306a36Sopenharmony_ci		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
122662306a36Sopenharmony_ci		emu->i2c_capture_source = source_id;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci        return change;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
123462306a36Sopenharmony_ci		.name =		"Capture Source",
123562306a36Sopenharmony_ci		.info =		snd_audigy_i2c_capture_source_info,
123662306a36Sopenharmony_ci		.get =		snd_audigy_i2c_capture_source_get,
123762306a36Sopenharmony_ci		.put =		snd_audigy_i2c_capture_source_put
123862306a36Sopenharmony_ci};
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
124162306a36Sopenharmony_ci				  struct snd_ctl_elem_info *uinfo)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
124462306a36Sopenharmony_ci	uinfo->count = 2;
124562306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
124662306a36Sopenharmony_ci	uinfo->value.integer.max = 255;
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
125162306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
125462306a36Sopenharmony_ci	unsigned int source_id;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	source_id = kcontrol->private_value;
125762306a36Sopenharmony_ci	/* Limit: emu->i2c_capture_volume */
125862306a36Sopenharmony_ci        /*        capture_source: uinfo->value.enumerated.items = 2 */
125962306a36Sopenharmony_ci	if (source_id >= 2)
126062306a36Sopenharmony_ci		return -EINVAL;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
126362306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
126462306a36Sopenharmony_ci	return 0;
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_cistatic int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
126862306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
127162306a36Sopenharmony_ci	unsigned int ogain;
127262306a36Sopenharmony_ci	unsigned int ngain0, ngain1;
127362306a36Sopenharmony_ci	unsigned int source_id;
127462306a36Sopenharmony_ci	int change = 0;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	source_id = kcontrol->private_value;
127762306a36Sopenharmony_ci	/* Limit: emu->i2c_capture_volume */
127862306a36Sopenharmony_ci        /*        capture_source: uinfo->value.enumerated.items = 2 */
127962306a36Sopenharmony_ci	if (source_id >= 2)
128062306a36Sopenharmony_ci		return -EINVAL;
128162306a36Sopenharmony_ci	ngain0 = ucontrol->value.integer.value[0];
128262306a36Sopenharmony_ci	ngain1 = ucontrol->value.integer.value[1];
128362306a36Sopenharmony_ci	if (ngain0 > 0xff)
128462306a36Sopenharmony_ci		return -EINVAL;
128562306a36Sopenharmony_ci	if (ngain1 > 0xff)
128662306a36Sopenharmony_ci		return -EINVAL;
128762306a36Sopenharmony_ci	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
128862306a36Sopenharmony_ci	if (ogain != ngain0) {
128962306a36Sopenharmony_ci		if (emu->i2c_capture_source == source_id)
129062306a36Sopenharmony_ci			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
129162306a36Sopenharmony_ci		emu->i2c_capture_volume[source_id][0] = ngain0;
129262306a36Sopenharmony_ci		change = 1;
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
129562306a36Sopenharmony_ci	if (ogain != ngain1) {
129662306a36Sopenharmony_ci		if (emu->i2c_capture_source == source_id)
129762306a36Sopenharmony_ci			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
129862306a36Sopenharmony_ci		emu->i2c_capture_volume[source_id][1] = ngain1;
129962306a36Sopenharmony_ci		change = 1;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return change;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic const struct snd_kcontrol_new i2c_volume_ctl = {
130662306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
130762306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
130862306a36Sopenharmony_ci	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
130962306a36Sopenharmony_ci	.info = snd_audigy_i2c_volume_info,
131062306a36Sopenharmony_ci	.get = snd_audigy_i2c_volume_get,
131162306a36Sopenharmony_ci	.put = snd_audigy_i2c_volume_put,
131262306a36Sopenharmony_ci	.tlv = { .p = snd_audigy_db_scale2 }
131362306a36Sopenharmony_ci};
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic const char * const snd_audigy_i2c_volume_ctls[] = {
131662306a36Sopenharmony_ci	"Mic Capture Volume",
131762306a36Sopenharmony_ci	"Line Capture Volume",
131862306a36Sopenharmony_ci};
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci#if 0
132162306a36Sopenharmony_cistatic int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	static const char * const texts[] = {"44100", "48000", "96000"};
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
132962306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
133262306a36Sopenharmony_ci	unsigned int tmp;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
133562306a36Sopenharmony_ci	switch (tmp & A_SPDIF_RATE_MASK) {
133662306a36Sopenharmony_ci	case A_SPDIF_44100:
133762306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
133862306a36Sopenharmony_ci		break;
133962306a36Sopenharmony_ci	case A_SPDIF_48000:
134062306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
134162306a36Sopenharmony_ci		break;
134262306a36Sopenharmony_ci	case A_SPDIF_96000:
134362306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
134462306a36Sopenharmony_ci		break;
134562306a36Sopenharmony_ci	default:
134662306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
134762306a36Sopenharmony_ci	}
134862306a36Sopenharmony_ci	return 0;
134962306a36Sopenharmony_ci}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_cistatic int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
135262306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
135562306a36Sopenharmony_ci	int change;
135662306a36Sopenharmony_ci	unsigned int reg, val, tmp;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	switch(ucontrol->value.enumerated.item[0]) {
135962306a36Sopenharmony_ci	case 0:
136062306a36Sopenharmony_ci		val = A_SPDIF_44100;
136162306a36Sopenharmony_ci		break;
136262306a36Sopenharmony_ci	case 1:
136362306a36Sopenharmony_ci		val = A_SPDIF_48000;
136462306a36Sopenharmony_ci		break;
136562306a36Sopenharmony_ci	case 2:
136662306a36Sopenharmony_ci		val = A_SPDIF_96000;
136762306a36Sopenharmony_ci		break;
136862306a36Sopenharmony_ci	default:
136962306a36Sopenharmony_ci		val = A_SPDIF_48000;
137062306a36Sopenharmony_ci		break;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
137562306a36Sopenharmony_ci	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
137662306a36Sopenharmony_ci	tmp = reg & ~A_SPDIF_RATE_MASK;
137762306a36Sopenharmony_ci	tmp |= val;
137862306a36Sopenharmony_ci	change = (tmp != reg);
137962306a36Sopenharmony_ci	if (change)
138062306a36Sopenharmony_ci		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
138162306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
138262306a36Sopenharmony_ci	return change;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
138862306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
138962306a36Sopenharmony_ci	.name =         "Audigy SPDIF Output Sample Rate",
139062306a36Sopenharmony_ci	.count =	1,
139162306a36Sopenharmony_ci	.info =         snd_audigy_spdif_output_rate_info,
139262306a36Sopenharmony_ci	.get =          snd_audigy_spdif_output_rate_get,
139362306a36Sopenharmony_ci	.put =          snd_audigy_spdif_output_rate_put
139462306a36Sopenharmony_ci};
139562306a36Sopenharmony_ci#endif
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
139862306a36Sopenharmony_ci                                 struct snd_ctl_elem_value *ucontrol)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
140162306a36Sopenharmony_ci	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
140262306a36Sopenharmony_ci	int change;
140362306a36Sopenharmony_ci	unsigned int val;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/* Limit: emu->spdif_bits */
140662306a36Sopenharmony_ci	if (idx >= 3)
140762306a36Sopenharmony_ci		return -EINVAL;
140862306a36Sopenharmony_ci	val = (ucontrol->value.iec958.status[0] << 0) |
140962306a36Sopenharmony_ci	      (ucontrol->value.iec958.status[1] << 8) |
141062306a36Sopenharmony_ci	      (ucontrol->value.iec958.status[2] << 16) |
141162306a36Sopenharmony_ci	      (ucontrol->value.iec958.status[3] << 24);
141262306a36Sopenharmony_ci	change = val != emu->spdif_bits[idx];
141362306a36Sopenharmony_ci	if (change) {
141462306a36Sopenharmony_ci		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
141562306a36Sopenharmony_ci		emu->spdif_bits[idx] = val;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci	return change;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
142362306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
142462306a36Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
142562306a36Sopenharmony_ci	.count =	3,
142662306a36Sopenharmony_ci	.info =         snd_emu10k1_spdif_info,
142762306a36Sopenharmony_ci	.get =          snd_emu10k1_spdif_get_mask
142862306a36Sopenharmony_ci};
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_spdif_control =
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
143362306a36Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
143462306a36Sopenharmony_ci	.count =	3,
143562306a36Sopenharmony_ci	.info =         snd_emu10k1_spdif_info,
143662306a36Sopenharmony_ci	.get =          snd_emu10k1_spdif_get,
143762306a36Sopenharmony_ci	.put =          snd_emu10k1_spdif_put
143862306a36Sopenharmony_ci};
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_cistatic void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
144262306a36Sopenharmony_ci{
144362306a36Sopenharmony_ci	if (emu->audigy) {
144462306a36Sopenharmony_ci		snd_emu10k1_ptr_write_multiple(emu, voice,
144562306a36Sopenharmony_ci			A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route),
144662306a36Sopenharmony_ci			A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route),
144762306a36Sopenharmony_ci			REGLIST_END);
144862306a36Sopenharmony_ci	} else {
144962306a36Sopenharmony_ci		snd_emu10k1_ptr_write(emu, FXRT, voice,
145062306a36Sopenharmony_ci				      snd_emu10k1_compose_send_routing(route));
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_cistatic void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
145762306a36Sopenharmony_ci	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
145862306a36Sopenharmony_ci	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
145962306a36Sopenharmony_ci	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
146062306a36Sopenharmony_ci	if (emu->audigy) {
146162306a36Sopenharmony_ci		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
146262306a36Sopenharmony_ci				      snd_emu10k1_compose_audigy_sendamounts(volume));
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci/* PCM stream controls */
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
147162306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
147262306a36Sopenharmony_ci	uinfo->count = emu->audigy ? 3*8 : 3*4;
147362306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
147462306a36Sopenharmony_ci	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
147562306a36Sopenharmony_ci	return 0;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
147962306a36Sopenharmony_ci                                        struct snd_ctl_elem_value *ucontrol)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
148262306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
148362306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
148462306a36Sopenharmony_ci	int voice, idx;
148562306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
148662306a36Sopenharmony_ci	int mask = emu->audigy ? 0x3f : 0x0f;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	for (voice = 0; voice < 3; voice++)
148962306a36Sopenharmony_ci		for (idx = 0; idx < num_efx; idx++)
149062306a36Sopenharmony_ci			ucontrol->value.integer.value[(voice * num_efx) + idx] =
149162306a36Sopenharmony_ci				mix->send_routing[voice][idx] & mask;
149262306a36Sopenharmony_ci	return 0;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
149662306a36Sopenharmony_ci                                        struct snd_ctl_elem_value *ucontrol)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
149962306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
150062306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
150162306a36Sopenharmony_ci	int change = 0, voice, idx, val;
150262306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
150362306a36Sopenharmony_ci	int mask = emu->audigy ? 0x3f : 0x0f;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
150662306a36Sopenharmony_ci	for (voice = 0; voice < 3; voice++)
150762306a36Sopenharmony_ci		for (idx = 0; idx < num_efx; idx++) {
150862306a36Sopenharmony_ci			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
150962306a36Sopenharmony_ci			if (mix->send_routing[voice][idx] != val) {
151062306a36Sopenharmony_ci				mix->send_routing[voice][idx] = val;
151162306a36Sopenharmony_ci				change = 1;
151262306a36Sopenharmony_ci			}
151362306a36Sopenharmony_ci		}
151462306a36Sopenharmony_ci	if (change && mix->epcm && mix->epcm->voices[0]) {
151562306a36Sopenharmony_ci		if (!mix->epcm->voices[0]->last) {
151662306a36Sopenharmony_ci			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
151762306a36Sopenharmony_ci					    &mix->send_routing[1][0]);
151862306a36Sopenharmony_ci			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1,
151962306a36Sopenharmony_ci					    &mix->send_routing[2][0]);
152062306a36Sopenharmony_ci		} else {
152162306a36Sopenharmony_ci			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
152262306a36Sopenharmony_ci					    &mix->send_routing[0][0]);
152362306a36Sopenharmony_ci		}
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
152662306a36Sopenharmony_ci	return change;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
153262306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
153362306a36Sopenharmony_ci	.name =         "EMU10K1 PCM Send Routing",
153462306a36Sopenharmony_ci	.count =	32,
153562306a36Sopenharmony_ci	.info =         snd_emu10k1_send_routing_info,
153662306a36Sopenharmony_ci	.get =          snd_emu10k1_send_routing_get,
153762306a36Sopenharmony_ci	.put =          snd_emu10k1_send_routing_put
153862306a36Sopenharmony_ci};
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_cistatic int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
154362306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
154462306a36Sopenharmony_ci	uinfo->count = emu->audigy ? 3*8 : 3*4;
154562306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
154662306a36Sopenharmony_ci	uinfo->value.integer.max = 255;
154762306a36Sopenharmony_ci	return 0;
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
155162306a36Sopenharmony_ci                                       struct snd_ctl_elem_value *ucontrol)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
155462306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
155562306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
155662306a36Sopenharmony_ci	int idx;
155762306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	for (idx = 0; idx < 3*num_efx; idx++)
156062306a36Sopenharmony_ci		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
156162306a36Sopenharmony_ci	return 0;
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_cistatic int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
156562306a36Sopenharmony_ci                                       struct snd_ctl_elem_value *ucontrol)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
156862306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
156962306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
157062306a36Sopenharmony_ci	int change = 0, idx, val;
157162306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
157462306a36Sopenharmony_ci	for (idx = 0; idx < 3*num_efx; idx++) {
157562306a36Sopenharmony_ci		val = ucontrol->value.integer.value[idx] & 255;
157662306a36Sopenharmony_ci		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
157762306a36Sopenharmony_ci			mix->send_volume[idx/num_efx][idx%num_efx] = val;
157862306a36Sopenharmony_ci			change = 1;
157962306a36Sopenharmony_ci		}
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci	if (change && mix->epcm && mix->epcm->voices[0]) {
158262306a36Sopenharmony_ci		if (!mix->epcm->voices[0]->last) {
158362306a36Sopenharmony_ci			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
158462306a36Sopenharmony_ci						   &mix->send_volume[1][0]);
158562306a36Sopenharmony_ci			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1,
158662306a36Sopenharmony_ci						   &mix->send_volume[2][0]);
158762306a36Sopenharmony_ci		} else {
158862306a36Sopenharmony_ci			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
158962306a36Sopenharmony_ci						   &mix->send_volume[0][0]);
159062306a36Sopenharmony_ci		}
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
159362306a36Sopenharmony_ci	return change;
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
159962306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
160062306a36Sopenharmony_ci	.name =         "EMU10K1 PCM Send Volume",
160162306a36Sopenharmony_ci	.count =	32,
160262306a36Sopenharmony_ci	.info =         snd_emu10k1_send_volume_info,
160362306a36Sopenharmony_ci	.get =          snd_emu10k1_send_volume_get,
160462306a36Sopenharmony_ci	.put =          snd_emu10k1_send_volume_put
160562306a36Sopenharmony_ci};
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
161062306a36Sopenharmony_ci	uinfo->count = 3;
161162306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
161262306a36Sopenharmony_ci	uinfo->value.integer.max = 0x1fffd;
161362306a36Sopenharmony_ci	return 0;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
161762306a36Sopenharmony_ci                                struct snd_ctl_elem_value *ucontrol)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
162062306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
162162306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
162262306a36Sopenharmony_ci	int idx;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	for (idx = 0; idx < 3; idx++)
162562306a36Sopenharmony_ci		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
162662306a36Sopenharmony_ci	return 0;
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
163062306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
163362306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
163462306a36Sopenharmony_ci		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
163562306a36Sopenharmony_ci	int change = 0, idx, val;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
163862306a36Sopenharmony_ci	for (idx = 0; idx < 3; idx++) {
163962306a36Sopenharmony_ci		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
164062306a36Sopenharmony_ci		val = uval * 0x8000U / 0xffffU;
164162306a36Sopenharmony_ci		if (mix->attn[idx] != val) {
164262306a36Sopenharmony_ci			mix->attn[idx] = val;
164362306a36Sopenharmony_ci			change = 1;
164462306a36Sopenharmony_ci		}
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci	if (change && mix->epcm && mix->epcm->voices[0]) {
164762306a36Sopenharmony_ci		if (!mix->epcm->voices[0]->last) {
164862306a36Sopenharmony_ci			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
164962306a36Sopenharmony_ci			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]);
165062306a36Sopenharmony_ci		} else {
165162306a36Sopenharmony_ci			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
165262306a36Sopenharmony_ci		}
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
165562306a36Sopenharmony_ci	return change;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_attn_control =
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
166162306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
166262306a36Sopenharmony_ci	.name =         "EMU10K1 PCM Volume",
166362306a36Sopenharmony_ci	.count =	32,
166462306a36Sopenharmony_ci	.info =         snd_emu10k1_attn_info,
166562306a36Sopenharmony_ci	.get =          snd_emu10k1_attn_get,
166662306a36Sopenharmony_ci	.put =          snd_emu10k1_attn_put
166762306a36Sopenharmony_ci};
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci/* Mutichannel PCM stream controls */
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
167462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
167562306a36Sopenharmony_ci	uinfo->count = emu->audigy ? 8 : 4;
167662306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
167762306a36Sopenharmony_ci	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
167862306a36Sopenharmony_ci	return 0;
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
168262306a36Sopenharmony_ci                                        struct snd_ctl_elem_value *ucontrol)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
168562306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
168662306a36Sopenharmony_ci		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
168762306a36Sopenharmony_ci	int idx;
168862306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
168962306a36Sopenharmony_ci	int mask = emu->audigy ? 0x3f : 0x0f;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	for (idx = 0; idx < num_efx; idx++)
169262306a36Sopenharmony_ci		ucontrol->value.integer.value[idx] =
169362306a36Sopenharmony_ci			mix->send_routing[0][idx] & mask;
169462306a36Sopenharmony_ci	return 0;
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
169862306a36Sopenharmony_ci                                        struct snd_ctl_elem_value *ucontrol)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
170162306a36Sopenharmony_ci	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
170262306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
170362306a36Sopenharmony_ci	int change = 0, idx, val;
170462306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
170562306a36Sopenharmony_ci	int mask = emu->audigy ? 0x3f : 0x0f;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
170862306a36Sopenharmony_ci	for (idx = 0; idx < num_efx; idx++) {
170962306a36Sopenharmony_ci		val = ucontrol->value.integer.value[idx] & mask;
171062306a36Sopenharmony_ci		if (mix->send_routing[0][idx] != val) {
171162306a36Sopenharmony_ci			mix->send_routing[0][idx] = val;
171262306a36Sopenharmony_ci			change = 1;
171362306a36Sopenharmony_ci		}
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (change && mix->epcm) {
171762306a36Sopenharmony_ci		if (mix->epcm->voices[ch]) {
171862306a36Sopenharmony_ci			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
171962306a36Sopenharmony_ci					&mix->send_routing[0][0]);
172062306a36Sopenharmony_ci		}
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
172362306a36Sopenharmony_ci	return change;
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
172962306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
173062306a36Sopenharmony_ci	.name =         "Multichannel PCM Send Routing",
173162306a36Sopenharmony_ci	.count =	16,
173262306a36Sopenharmony_ci	.info =         snd_emu10k1_efx_send_routing_info,
173362306a36Sopenharmony_ci	.get =          snd_emu10k1_efx_send_routing_get,
173462306a36Sopenharmony_ci	.put =          snd_emu10k1_efx_send_routing_put
173562306a36Sopenharmony_ci};
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
174062306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
174162306a36Sopenharmony_ci	uinfo->count = emu->audigy ? 8 : 4;
174262306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
174362306a36Sopenharmony_ci	uinfo->value.integer.max = 255;
174462306a36Sopenharmony_ci	return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
174862306a36Sopenharmony_ci                                       struct snd_ctl_elem_value *ucontrol)
174962306a36Sopenharmony_ci{
175062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
175162306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
175262306a36Sopenharmony_ci		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
175362306a36Sopenharmony_ci	int idx;
175462306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	for (idx = 0; idx < num_efx; idx++)
175762306a36Sopenharmony_ci		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
175862306a36Sopenharmony_ci	return 0;
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
176262306a36Sopenharmony_ci                                       struct snd_ctl_elem_value *ucontrol)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
176562306a36Sopenharmony_ci	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
176662306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
176762306a36Sopenharmony_ci	int change = 0, idx, val;
176862306a36Sopenharmony_ci	int num_efx = emu->audigy ? 8 : 4;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
177162306a36Sopenharmony_ci	for (idx = 0; idx < num_efx; idx++) {
177262306a36Sopenharmony_ci		val = ucontrol->value.integer.value[idx] & 255;
177362306a36Sopenharmony_ci		if (mix->send_volume[0][idx] != val) {
177462306a36Sopenharmony_ci			mix->send_volume[0][idx] = val;
177562306a36Sopenharmony_ci			change = 1;
177662306a36Sopenharmony_ci		}
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci	if (change && mix->epcm) {
177962306a36Sopenharmony_ci		if (mix->epcm->voices[ch]) {
178062306a36Sopenharmony_ci			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
178162306a36Sopenharmony_ci						   &mix->send_volume[0][0]);
178262306a36Sopenharmony_ci		}
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
178562306a36Sopenharmony_ci	return change;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
179262306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
179362306a36Sopenharmony_ci	.name =         "Multichannel PCM Send Volume",
179462306a36Sopenharmony_ci	.count =	16,
179562306a36Sopenharmony_ci	.info =         snd_emu10k1_efx_send_volume_info,
179662306a36Sopenharmony_ci	.get =          snd_emu10k1_efx_send_volume_get,
179762306a36Sopenharmony_ci	.put =          snd_emu10k1_efx_send_volume_put
179862306a36Sopenharmony_ci};
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
180162306a36Sopenharmony_ci{
180262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
180362306a36Sopenharmony_ci	uinfo->count = 1;
180462306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
180562306a36Sopenharmony_ci	uinfo->value.integer.max = 0x1fffd;
180662306a36Sopenharmony_ci	return 0;
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_cistatic int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
181062306a36Sopenharmony_ci                                struct snd_ctl_elem_value *ucontrol)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
181362306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix =
181462306a36Sopenharmony_ci		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
181762306a36Sopenharmony_ci	return 0;
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
182162306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
182462306a36Sopenharmony_ci	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
182562306a36Sopenharmony_ci	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
182662306a36Sopenharmony_ci	int change = 0, val;
182762306a36Sopenharmony_ci	unsigned uval;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	spin_lock_irq(&emu->reg_lock);
183062306a36Sopenharmony_ci	uval = ucontrol->value.integer.value[0] & 0x1ffff;
183162306a36Sopenharmony_ci	val = uval * 0x8000U / 0xffffU;
183262306a36Sopenharmony_ci	if (mix->attn[0] != val) {
183362306a36Sopenharmony_ci		mix->attn[0] = val;
183462306a36Sopenharmony_ci		change = 1;
183562306a36Sopenharmony_ci	}
183662306a36Sopenharmony_ci	if (change && mix->epcm) {
183762306a36Sopenharmony_ci		if (mix->epcm->voices[ch]) {
183862306a36Sopenharmony_ci			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
183962306a36Sopenharmony_ci		}
184062306a36Sopenharmony_ci	}
184162306a36Sopenharmony_ci	spin_unlock_irq(&emu->reg_lock);
184262306a36Sopenharmony_ci	return change;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
184862306a36Sopenharmony_ci	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
184962306a36Sopenharmony_ci	.name =         "Multichannel PCM Volume",
185062306a36Sopenharmony_ci	.count =	16,
185162306a36Sopenharmony_ci	.info =         snd_emu10k1_efx_attn_info,
185262306a36Sopenharmony_ci	.get =          snd_emu10k1_efx_attn_get,
185362306a36Sopenharmony_ci	.put =          snd_emu10k1_efx_attn_put
185462306a36Sopenharmony_ci};
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci#define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_cistatic int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
185962306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	if (emu->audigy)
186462306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
186562306a36Sopenharmony_ci	else
186662306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
186762306a36Sopenharmony_ci	if (emu->card_capabilities->invert_shared_spdif)
186862306a36Sopenharmony_ci		ucontrol->value.integer.value[0] =
186962306a36Sopenharmony_ci			!ucontrol->value.integer.value[0];
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	return 0;
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
187562306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
187662306a36Sopenharmony_ci{
187762306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
187862306a36Sopenharmony_ci	unsigned int reg, val, sw;
187962306a36Sopenharmony_ci	int change = 0;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	sw = ucontrol->value.integer.value[0];
188262306a36Sopenharmony_ci	if (emu->card_capabilities->invert_shared_spdif)
188362306a36Sopenharmony_ci		sw = !sw;
188462306a36Sopenharmony_ci	spin_lock_irq(&emu->emu_lock);
188562306a36Sopenharmony_ci	if ( emu->card_capabilities->i2c_adc) {
188662306a36Sopenharmony_ci		/* Do nothing for Audigy 2 ZS Notebook */
188762306a36Sopenharmony_ci	} else if (emu->audigy) {
188862306a36Sopenharmony_ci		reg = inw(emu->port + A_IOCFG);
188962306a36Sopenharmony_ci		val = sw ? A_IOCFG_GPOUT0 : 0;
189062306a36Sopenharmony_ci		change = (reg & A_IOCFG_GPOUT0) != val;
189162306a36Sopenharmony_ci		if (change) {
189262306a36Sopenharmony_ci			reg &= ~A_IOCFG_GPOUT0;
189362306a36Sopenharmony_ci			reg |= val;
189462306a36Sopenharmony_ci			outw(reg | val, emu->port + A_IOCFG);
189562306a36Sopenharmony_ci		}
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci	reg = inl(emu->port + HCFG);
189862306a36Sopenharmony_ci	val = sw ? HCFG_GPOUT0 : 0;
189962306a36Sopenharmony_ci	change |= (reg & HCFG_GPOUT0) != val;
190062306a36Sopenharmony_ci	if (change) {
190162306a36Sopenharmony_ci		reg &= ~HCFG_GPOUT0;
190262306a36Sopenharmony_ci		reg |= val;
190362306a36Sopenharmony_ci		outl(reg | val, emu->port + HCFG);
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci	spin_unlock_irq(&emu->emu_lock);
190662306a36Sopenharmony_ci	return change;
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
191262306a36Sopenharmony_ci	.name =		"SB Live Analog/Digital Output Jack",
191362306a36Sopenharmony_ci	.info =		snd_emu10k1_shared_spdif_info,
191462306a36Sopenharmony_ci	.get =		snd_emu10k1_shared_spdif_get,
191562306a36Sopenharmony_ci	.put =		snd_emu10k1_shared_spdif_put
191662306a36Sopenharmony_ci};
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_shared_spdif =
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
192162306a36Sopenharmony_ci	.name =		"Audigy Analog/Digital Output Jack",
192262306a36Sopenharmony_ci	.info =		snd_emu10k1_shared_spdif_info,
192362306a36Sopenharmony_ci	.get =		snd_emu10k1_shared_spdif_get,
192462306a36Sopenharmony_ci	.put =		snd_emu10k1_shared_spdif_put
192562306a36Sopenharmony_ci};
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci/* workaround for too low volume on Audigy due to 16bit/24bit conversion */
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci#define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
193262306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
193562306a36Sopenharmony_ci	unsigned int val;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	/* FIXME: better to use a cached version */
193862306a36Sopenharmony_ci	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
193962306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = !!val;
194062306a36Sopenharmony_ci	return 0;
194162306a36Sopenharmony_ci}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_cistatic int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
194462306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
194562306a36Sopenharmony_ci{
194662306a36Sopenharmony_ci	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
194762306a36Sopenharmony_ci	unsigned int val;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0])
195062306a36Sopenharmony_ci		val = 0x0f0f;
195162306a36Sopenharmony_ci	else
195262306a36Sopenharmony_ci		val = 0;
195362306a36Sopenharmony_ci	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_capture_boost =
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
195962306a36Sopenharmony_ci	.name =		"Mic Extra Boost",
196062306a36Sopenharmony_ci	.info =		snd_audigy_capture_boost_info,
196162306a36Sopenharmony_ci	.get =		snd_audigy_capture_boost_get,
196262306a36Sopenharmony_ci	.put =		snd_audigy_capture_boost_put
196362306a36Sopenharmony_ci};
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci/*
196762306a36Sopenharmony_ci */
196862306a36Sopenharmony_cistatic void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
196962306a36Sopenharmony_ci{
197062306a36Sopenharmony_ci	struct snd_emu10k1 *emu = ac97->private_data;
197162306a36Sopenharmony_ci	emu->ac97 = NULL;
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci/*
197562306a36Sopenharmony_ci */
197662306a36Sopenharmony_cistatic int remove_ctl(struct snd_card *card, const char *name)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	struct snd_ctl_elem_id id;
197962306a36Sopenharmony_ci	memset(&id, 0, sizeof(id));
198062306a36Sopenharmony_ci	strcpy(id.name, name);
198162306a36Sopenharmony_ci	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
198262306a36Sopenharmony_ci	return snd_ctl_remove_id(card, &id);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic int rename_ctl(struct snd_card *card, const char *src, const char *dst)
198662306a36Sopenharmony_ci{
198762306a36Sopenharmony_ci	struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src);
198862306a36Sopenharmony_ci	if (kctl) {
198962306a36Sopenharmony_ci		snd_ctl_rename(card, kctl, dst);
199062306a36Sopenharmony_ci		return 0;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci	return -ENOENT;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ciint snd_emu10k1_mixer(struct snd_emu10k1 *emu,
199662306a36Sopenharmony_ci		      int pcm_device, int multi_device)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	int err;
199962306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
200062306a36Sopenharmony_ci	struct snd_card *card = emu->card;
200162306a36Sopenharmony_ci	const char * const *c;
200262306a36Sopenharmony_ci	static const char * const emu10k1_remove_ctls[] = {
200362306a36Sopenharmony_ci		/* no AC97 mono, surround, center/lfe */
200462306a36Sopenharmony_ci		"Master Mono Playback Switch",
200562306a36Sopenharmony_ci		"Master Mono Playback Volume",
200662306a36Sopenharmony_ci		"PCM Out Path & Mute",
200762306a36Sopenharmony_ci		"Mono Output Select",
200862306a36Sopenharmony_ci		"Surround Playback Switch",
200962306a36Sopenharmony_ci		"Surround Playback Volume",
201062306a36Sopenharmony_ci		"Center Playback Switch",
201162306a36Sopenharmony_ci		"Center Playback Volume",
201262306a36Sopenharmony_ci		"LFE Playback Switch",
201362306a36Sopenharmony_ci		"LFE Playback Volume",
201462306a36Sopenharmony_ci		NULL
201562306a36Sopenharmony_ci	};
201662306a36Sopenharmony_ci	static const char * const emu10k1_rename_ctls[] = {
201762306a36Sopenharmony_ci		"Surround Digital Playback Volume", "Surround Playback Volume",
201862306a36Sopenharmony_ci		"Center Digital Playback Volume", "Center Playback Volume",
201962306a36Sopenharmony_ci		"LFE Digital Playback Volume", "LFE Playback Volume",
202062306a36Sopenharmony_ci		NULL
202162306a36Sopenharmony_ci	};
202262306a36Sopenharmony_ci	static const char * const audigy_remove_ctls[] = {
202362306a36Sopenharmony_ci		/* Master/PCM controls on ac97 of Audigy has no effect */
202462306a36Sopenharmony_ci		/* On the Audigy2 the AC97 playback is piped into
202562306a36Sopenharmony_ci		 * the Philips ADC for 24bit capture */
202662306a36Sopenharmony_ci		"PCM Playback Switch",
202762306a36Sopenharmony_ci		"PCM Playback Volume",
202862306a36Sopenharmony_ci		"Master Playback Switch",
202962306a36Sopenharmony_ci		"Master Playback Volume",
203062306a36Sopenharmony_ci		"PCM Out Path & Mute",
203162306a36Sopenharmony_ci		"Mono Output Select",
203262306a36Sopenharmony_ci		/* remove unused AC97 capture controls */
203362306a36Sopenharmony_ci		"Capture Source",
203462306a36Sopenharmony_ci		"Capture Switch",
203562306a36Sopenharmony_ci		"Capture Volume",
203662306a36Sopenharmony_ci		"Mic Select",
203762306a36Sopenharmony_ci		"Headphone Playback Switch",
203862306a36Sopenharmony_ci		"Headphone Playback Volume",
203962306a36Sopenharmony_ci		"3D Control - Center",
204062306a36Sopenharmony_ci		"3D Control - Depth",
204162306a36Sopenharmony_ci		"3D Control - Switch",
204262306a36Sopenharmony_ci		"Video Playback Switch",
204362306a36Sopenharmony_ci		"Video Playback Volume",
204462306a36Sopenharmony_ci		"Mic Playback Switch",
204562306a36Sopenharmony_ci		"Mic Playback Volume",
204662306a36Sopenharmony_ci		"External Amplifier",
204762306a36Sopenharmony_ci		NULL
204862306a36Sopenharmony_ci	};
204962306a36Sopenharmony_ci	static const char * const audigy_rename_ctls[] = {
205062306a36Sopenharmony_ci		/* use conventional names */
205162306a36Sopenharmony_ci		"Wave Playback Volume", "PCM Playback Volume",
205262306a36Sopenharmony_ci		/* "Wave Capture Volume", "PCM Capture Volume", */
205362306a36Sopenharmony_ci		"Wave Master Playback Volume", "Master Playback Volume",
205462306a36Sopenharmony_ci		"AMic Playback Volume", "Mic Playback Volume",
205562306a36Sopenharmony_ci		"Master Mono Playback Switch", "Phone Output Playback Switch",
205662306a36Sopenharmony_ci		"Master Mono Playback Volume", "Phone Output Playback Volume",
205762306a36Sopenharmony_ci		NULL
205862306a36Sopenharmony_ci	};
205962306a36Sopenharmony_ci	static const char * const audigy_rename_ctls_i2c_adc[] = {
206062306a36Sopenharmony_ci		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
206162306a36Sopenharmony_ci		"Line Capture Volume", "Analog Mix Capture Volume",
206262306a36Sopenharmony_ci		"Wave Playback Volume", "OLD PCM Playback Volume",
206362306a36Sopenharmony_ci		"Wave Master Playback Volume", "Master Playback Volume",
206462306a36Sopenharmony_ci		"AMic Playback Volume", "Old Mic Playback Volume",
206562306a36Sopenharmony_ci		"CD Capture Volume", "IEC958 Optical Capture Volume",
206662306a36Sopenharmony_ci		NULL
206762306a36Sopenharmony_ci	};
206862306a36Sopenharmony_ci	static const char * const audigy_remove_ctls_i2c_adc[] = {
206962306a36Sopenharmony_ci		/* On the Audigy2 ZS Notebook
207062306a36Sopenharmony_ci		 * Capture via WM8775  */
207162306a36Sopenharmony_ci		"Mic Capture Volume",
207262306a36Sopenharmony_ci		"Analog Mix Capture Volume",
207362306a36Sopenharmony_ci		"Aux Capture Volume",
207462306a36Sopenharmony_ci		"IEC958 Optical Capture Volume",
207562306a36Sopenharmony_ci		NULL
207662306a36Sopenharmony_ci	};
207762306a36Sopenharmony_ci	static const char * const audigy_remove_ctls_1361t_adc[] = {
207862306a36Sopenharmony_ci		/* On the Audigy2 the AC97 playback is piped into
207962306a36Sopenharmony_ci		 * the Philips ADC for 24bit capture */
208062306a36Sopenharmony_ci		"PCM Playback Switch",
208162306a36Sopenharmony_ci		"PCM Playback Volume",
208262306a36Sopenharmony_ci		"Capture Source",
208362306a36Sopenharmony_ci		"Capture Switch",
208462306a36Sopenharmony_ci		"Capture Volume",
208562306a36Sopenharmony_ci		"Mic Capture Volume",
208662306a36Sopenharmony_ci		"Headphone Playback Switch",
208762306a36Sopenharmony_ci		"Headphone Playback Volume",
208862306a36Sopenharmony_ci		"3D Control - Center",
208962306a36Sopenharmony_ci		"3D Control - Depth",
209062306a36Sopenharmony_ci		"3D Control - Switch",
209162306a36Sopenharmony_ci		"Line2 Playback Volume",
209262306a36Sopenharmony_ci		"Line2 Capture Volume",
209362306a36Sopenharmony_ci		NULL
209462306a36Sopenharmony_ci	};
209562306a36Sopenharmony_ci	static const char * const audigy_rename_ctls_1361t_adc[] = {
209662306a36Sopenharmony_ci		"Master Playback Switch", "Master Capture Switch",
209762306a36Sopenharmony_ci		"Master Playback Volume", "Master Capture Volume",
209862306a36Sopenharmony_ci		"Wave Master Playback Volume", "Master Playback Volume",
209962306a36Sopenharmony_ci		"Beep Playback Switch", "Beep Capture Switch",
210062306a36Sopenharmony_ci		"Beep Playback Volume", "Beep Capture Volume",
210162306a36Sopenharmony_ci		"Phone Playback Switch", "Phone Capture Switch",
210262306a36Sopenharmony_ci		"Phone Playback Volume", "Phone Capture Volume",
210362306a36Sopenharmony_ci		"Mic Playback Switch", "Mic Capture Switch",
210462306a36Sopenharmony_ci		"Mic Playback Volume", "Mic Capture Volume",
210562306a36Sopenharmony_ci		"Line Playback Switch", "Line Capture Switch",
210662306a36Sopenharmony_ci		"Line Playback Volume", "Line Capture Volume",
210762306a36Sopenharmony_ci		"CD Playback Switch", "CD Capture Switch",
210862306a36Sopenharmony_ci		"CD Playback Volume", "CD Capture Volume",
210962306a36Sopenharmony_ci		"Aux Playback Switch", "Aux Capture Switch",
211062306a36Sopenharmony_ci		"Aux Playback Volume", "Aux Capture Volume",
211162306a36Sopenharmony_ci		"Video Playback Switch", "Video Capture Switch",
211262306a36Sopenharmony_ci		"Video Playback Volume", "Video Capture Volume",
211362306a36Sopenharmony_ci		"Master Mono Playback Switch", "Phone Output Playback Switch",
211462306a36Sopenharmony_ci		"Master Mono Playback Volume", "Phone Output Playback Volume",
211562306a36Sopenharmony_ci		NULL
211662306a36Sopenharmony_ci	};
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	if (emu->card_capabilities->ac97_chip) {
211962306a36Sopenharmony_ci		struct snd_ac97_bus *pbus;
212062306a36Sopenharmony_ci		struct snd_ac97_template ac97;
212162306a36Sopenharmony_ci		static const struct snd_ac97_bus_ops ops = {
212262306a36Sopenharmony_ci			.write = snd_emu10k1_ac97_write,
212362306a36Sopenharmony_ci			.read = snd_emu10k1_ac97_read,
212462306a36Sopenharmony_ci		};
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
212762306a36Sopenharmony_ci		if (err < 0)
212862306a36Sopenharmony_ci			return err;
212962306a36Sopenharmony_ci		pbus->no_vra = 1; /* we don't need VRA */
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		memset(&ac97, 0, sizeof(ac97));
213262306a36Sopenharmony_ci		ac97.private_data = emu;
213362306a36Sopenharmony_ci		ac97.private_free = snd_emu10k1_mixer_free_ac97;
213462306a36Sopenharmony_ci		ac97.scaps = AC97_SCAP_NO_SPDIF;
213562306a36Sopenharmony_ci		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
213662306a36Sopenharmony_ci		if (err < 0) {
213762306a36Sopenharmony_ci			if (emu->card_capabilities->ac97_chip == 1)
213862306a36Sopenharmony_ci				return err;
213962306a36Sopenharmony_ci			dev_info(emu->card->dev,
214062306a36Sopenharmony_ci				 "AC97 is optional on this board\n");
214162306a36Sopenharmony_ci			dev_info(emu->card->dev,
214262306a36Sopenharmony_ci				 "Proceeding without ac97 mixers...\n");
214362306a36Sopenharmony_ci			snd_device_free(emu->card, pbus);
214462306a36Sopenharmony_ci			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
214562306a36Sopenharmony_ci		}
214662306a36Sopenharmony_ci		if (emu->audigy) {
214762306a36Sopenharmony_ci			/* set master volume to 0 dB */
214862306a36Sopenharmony_ci			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
214962306a36Sopenharmony_ci			/* set capture source to mic */
215062306a36Sopenharmony_ci			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
215162306a36Sopenharmony_ci			/* set mono output (TAD) to mic */
215262306a36Sopenharmony_ci			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
215362306a36Sopenharmony_ci				0x0200, 0x0200);
215462306a36Sopenharmony_ci			if (emu->card_capabilities->adc_1361t)
215562306a36Sopenharmony_ci				c = audigy_remove_ctls_1361t_adc;
215662306a36Sopenharmony_ci			else
215762306a36Sopenharmony_ci				c = audigy_remove_ctls;
215862306a36Sopenharmony_ci		} else {
215962306a36Sopenharmony_ci			/*
216062306a36Sopenharmony_ci			 * Credits for cards based on STAC9758:
216162306a36Sopenharmony_ci			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
216262306a36Sopenharmony_ci			 *   Voluspa <voluspa@comhem.se>
216362306a36Sopenharmony_ci			 */
216462306a36Sopenharmony_ci			if (emu->ac97->id == AC97_ID_STAC9758) {
216562306a36Sopenharmony_ci				emu->rear_ac97 = 1;
216662306a36Sopenharmony_ci				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
216762306a36Sopenharmony_ci				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
216862306a36Sopenharmony_ci				remove_ctl(card,"Front Playback Volume");
216962306a36Sopenharmony_ci				remove_ctl(card,"Front Playback Switch");
217062306a36Sopenharmony_ci			}
217162306a36Sopenharmony_ci			/* remove unused AC97 controls */
217262306a36Sopenharmony_ci			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
217362306a36Sopenharmony_ci			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
217462306a36Sopenharmony_ci			c = emu10k1_remove_ctls;
217562306a36Sopenharmony_ci		}
217662306a36Sopenharmony_ci		for (; *c; c++)
217762306a36Sopenharmony_ci			remove_ctl(card, *c);
217862306a36Sopenharmony_ci	} else if (emu->card_capabilities->i2c_adc) {
217962306a36Sopenharmony_ci		c = audigy_remove_ctls_i2c_adc;
218062306a36Sopenharmony_ci		for (; *c; c++)
218162306a36Sopenharmony_ci			remove_ctl(card, *c);
218262306a36Sopenharmony_ci	} else {
218362306a36Sopenharmony_ci	no_ac97:
218462306a36Sopenharmony_ci		if (emu->card_capabilities->ecard)
218562306a36Sopenharmony_ci			strcpy(emu->card->mixername, "EMU APS");
218662306a36Sopenharmony_ci		else if (emu->audigy)
218762306a36Sopenharmony_ci			strcpy(emu->card->mixername, "SB Audigy");
218862306a36Sopenharmony_ci		else
218962306a36Sopenharmony_ci			strcpy(emu->card->mixername, "Emu10k1");
219062306a36Sopenharmony_ci	}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if (emu->audigy)
219362306a36Sopenharmony_ci		if (emu->card_capabilities->adc_1361t)
219462306a36Sopenharmony_ci			c = audigy_rename_ctls_1361t_adc;
219562306a36Sopenharmony_ci		else if (emu->card_capabilities->i2c_adc)
219662306a36Sopenharmony_ci			c = audigy_rename_ctls_i2c_adc;
219762306a36Sopenharmony_ci		else
219862306a36Sopenharmony_ci			c = audigy_rename_ctls;
219962306a36Sopenharmony_ci	else
220062306a36Sopenharmony_ci		c = emu10k1_rename_ctls;
220162306a36Sopenharmony_ci	for (; *c; c += 2)
220262306a36Sopenharmony_ci		rename_ctl(card, c[0], c[1]);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
220562306a36Sopenharmony_ci		remove_ctl(card, "Center Playback Volume");
220662306a36Sopenharmony_ci		remove_ctl(card, "LFE Playback Volume");
220762306a36Sopenharmony_ci		remove_ctl(card, "Wave Center Playback Volume");
220862306a36Sopenharmony_ci		remove_ctl(card, "Wave LFE Playback Volume");
220962306a36Sopenharmony_ci	}
221062306a36Sopenharmony_ci	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
221162306a36Sopenharmony_ci		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
221262306a36Sopenharmony_ci		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
221362306a36Sopenharmony_ci		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
221462306a36Sopenharmony_ci		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
221762306a36Sopenharmony_ci	if (!kctl)
221862306a36Sopenharmony_ci		return -ENOMEM;
221962306a36Sopenharmony_ci	kctl->id.device = pcm_device;
222062306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
222162306a36Sopenharmony_ci	if (err)
222262306a36Sopenharmony_ci		return err;
222362306a36Sopenharmony_ci	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
222462306a36Sopenharmony_ci	if (!kctl)
222562306a36Sopenharmony_ci		return -ENOMEM;
222662306a36Sopenharmony_ci	kctl->id.device = pcm_device;
222762306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
222862306a36Sopenharmony_ci	if (err)
222962306a36Sopenharmony_ci		return err;
223062306a36Sopenharmony_ci	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
223162306a36Sopenharmony_ci	if (!kctl)
223262306a36Sopenharmony_ci		return -ENOMEM;
223362306a36Sopenharmony_ci	kctl->id.device = pcm_device;
223462306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
223562306a36Sopenharmony_ci	if (err)
223662306a36Sopenharmony_ci		return err;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
223962306a36Sopenharmony_ci	if (!kctl)
224062306a36Sopenharmony_ci		return -ENOMEM;
224162306a36Sopenharmony_ci	kctl->id.device = multi_device;
224262306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
224362306a36Sopenharmony_ci	if (err)
224462306a36Sopenharmony_ci		return err;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
224762306a36Sopenharmony_ci	if (!kctl)
224862306a36Sopenharmony_ci		return -ENOMEM;
224962306a36Sopenharmony_ci	kctl->id.device = multi_device;
225062306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
225162306a36Sopenharmony_ci	if (err)
225262306a36Sopenharmony_ci		return err;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
225562306a36Sopenharmony_ci	if (!kctl)
225662306a36Sopenharmony_ci		return -ENOMEM;
225762306a36Sopenharmony_ci	kctl->id.device = multi_device;
225862306a36Sopenharmony_ci	err = snd_ctl_add(card, kctl);
225962306a36Sopenharmony_ci	if (err)
226062306a36Sopenharmony_ci		return err;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
226362306a36Sopenharmony_ci		/* sb live! and audigy */
226462306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
226562306a36Sopenharmony_ci		if (!kctl)
226662306a36Sopenharmony_ci			return -ENOMEM;
226762306a36Sopenharmony_ci		if (!emu->audigy)
226862306a36Sopenharmony_ci			kctl->id.device = emu->pcm_efx->device;
226962306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
227062306a36Sopenharmony_ci		if (err)
227162306a36Sopenharmony_ci			return err;
227262306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
227362306a36Sopenharmony_ci		if (!kctl)
227462306a36Sopenharmony_ci			return -ENOMEM;
227562306a36Sopenharmony_ci		if (!emu->audigy)
227662306a36Sopenharmony_ci			kctl->id.device = emu->pcm_efx->device;
227762306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
227862306a36Sopenharmony_ci		if (err)
227962306a36Sopenharmony_ci			return err;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	if (emu->card_capabilities->emu_model) {
228362306a36Sopenharmony_ci		;  /* Disable the snd_audigy_spdif_shared_spdif */
228462306a36Sopenharmony_ci	} else if (emu->audigy) {
228562306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
228662306a36Sopenharmony_ci		if (!kctl)
228762306a36Sopenharmony_ci			return -ENOMEM;
228862306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
228962306a36Sopenharmony_ci		if (err)
229062306a36Sopenharmony_ci			return err;
229162306a36Sopenharmony_ci#if 0
229262306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
229362306a36Sopenharmony_ci		if (!kctl)
229462306a36Sopenharmony_ci			return -ENOMEM;
229562306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
229662306a36Sopenharmony_ci		if (err)
229762306a36Sopenharmony_ci			return err;
229862306a36Sopenharmony_ci#endif
229962306a36Sopenharmony_ci	} else if (! emu->card_capabilities->ecard) {
230062306a36Sopenharmony_ci		/* sb live! */
230162306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
230262306a36Sopenharmony_ci		if (!kctl)
230362306a36Sopenharmony_ci			return -ENOMEM;
230462306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
230562306a36Sopenharmony_ci		if (err)
230662306a36Sopenharmony_ci			return err;
230762306a36Sopenharmony_ci	}
230862306a36Sopenharmony_ci	if (emu->card_capabilities->ca0151_chip) { /* P16V */
230962306a36Sopenharmony_ci		err = snd_p16v_mixer(emu);
231062306a36Sopenharmony_ci		if (err)
231162306a36Sopenharmony_ci			return err;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	if (emu->card_capabilities->emu_model) {
231562306a36Sopenharmony_ci		unsigned i, emu_idx = emu1010_idx(emu);
231662306a36Sopenharmony_ci		const struct snd_emu1010_routing_info *emu_ri =
231762306a36Sopenharmony_ci			&emu1010_routing_info[emu_idx];
231862306a36Sopenharmony_ci		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		for (i = 0; i < emu_ri->n_ins; i++)
232162306a36Sopenharmony_ci			emu->emu1010.input_source[i] =
232262306a36Sopenharmony_ci				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
232362306a36Sopenharmony_ci		for (i = 0; i < emu_ri->n_outs; i++)
232462306a36Sopenharmony_ci			emu->emu1010.output_source[i] =
232562306a36Sopenharmony_ci				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
232662306a36Sopenharmony_ci		snd_emu1010_apply_sources(emu);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci		kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
232962306a36Sopenharmony_ci		err = snd_ctl_add(card, kctl);
233062306a36Sopenharmony_ci		if (err < 0)
233162306a36Sopenharmony_ci			return err;
233262306a36Sopenharmony_ci		err = snd_ctl_add(card,
233362306a36Sopenharmony_ci			snd_ctl_new1(&snd_emu1010_clock_fallback, emu));
233462306a36Sopenharmony_ci		if (err < 0)
233562306a36Sopenharmony_ci			return err;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci		err = add_ctls(emu, &emu1010_adc_pads_ctl,
233862306a36Sopenharmony_ci			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
233962306a36Sopenharmony_ci		if (err < 0)
234062306a36Sopenharmony_ci			return err;
234162306a36Sopenharmony_ci		err = add_ctls(emu, &emu1010_dac_pads_ctl,
234262306a36Sopenharmony_ci			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
234362306a36Sopenharmony_ci		if (err < 0)
234462306a36Sopenharmony_ci			return err;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci		if (!emu->card_capabilities->no_adat) {
234762306a36Sopenharmony_ci			err = snd_ctl_add(card,
234862306a36Sopenharmony_ci				snd_ctl_new1(&snd_emu1010_optical_out, emu));
234962306a36Sopenharmony_ci			if (err < 0)
235062306a36Sopenharmony_ci				return err;
235162306a36Sopenharmony_ci			err = snd_ctl_add(card,
235262306a36Sopenharmony_ci				snd_ctl_new1(&snd_emu1010_optical_in, emu));
235362306a36Sopenharmony_ci			if (err < 0)
235462306a36Sopenharmony_ci				return err;
235562306a36Sopenharmony_ci		}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci		err = add_emu1010_source_mixers(emu);
235862306a36Sopenharmony_ci		if (err < 0)
235962306a36Sopenharmony_ci			return err;
236062306a36Sopenharmony_ci	}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	if ( emu->card_capabilities->i2c_adc) {
236362306a36Sopenharmony_ci		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
236462306a36Sopenharmony_ci		if (err < 0)
236562306a36Sopenharmony_ci			return err;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		err = add_ctls(emu, &i2c_volume_ctl,
236862306a36Sopenharmony_ci			       snd_audigy_i2c_volume_ctls,
236962306a36Sopenharmony_ci			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
237062306a36Sopenharmony_ci		if (err < 0)
237162306a36Sopenharmony_ci			return err;
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	if (emu->card_capabilities->ac97_chip && emu->audigy) {
237562306a36Sopenharmony_ci		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
237662306a36Sopenharmony_ci						     emu));
237762306a36Sopenharmony_ci		if (err < 0)
237862306a36Sopenharmony_ci			return err;
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	return 0;
238262306a36Sopenharmony_ci}
2383