aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/emu10k1/emumixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/emu10k1/emumixer.c')
-rw-r--r--sound/pci/emu10k1/emumixer.c508
1 files changed, 423 insertions, 85 deletions
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 7b2c1dcc533..c5ae2a24d8a 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
* Takashi Iwai <tiwai@suse.de>
* Creative Labs, Inc.
* Routines for control of EMU10K1 chips / mixer routines
@@ -30,7 +30,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <linux/init.h>
#include <sound/core.h>
@@ -58,6 +57,9 @@ static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
unsigned long flags;
+ /* Limit: emu->spdif_bits */
+ if (idx >= 3)
+ return -EINVAL;
spin_lock_irqsave(&emu->reg_lock, flags);
ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
@@ -137,6 +139,61 @@ static char *emu1010_src_texts[] = {
"DSP 31",
};
+/* 1616(m) cardbus */
+
+static char *emu1616_src_texts[] = {
+ "Silence",
+ "Dock Mic A",
+ "Dock Mic B",
+ "Dock ADC1 Left",
+ "Dock ADC1 Right",
+ "Dock ADC2 Left",
+ "Dock ADC2 Right",
+ "Dock SPDIF Left",
+ "Dock SPDIF Right",
+ "ADAT 0",
+ "ADAT 1",
+ "ADAT 2",
+ "ADAT 3",
+ "ADAT 4",
+ "ADAT 5",
+ "ADAT 6",
+ "ADAT 7",
+ "DSP 0",
+ "DSP 1",
+ "DSP 2",
+ "DSP 3",
+ "DSP 4",
+ "DSP 5",
+ "DSP 6",
+ "DSP 7",
+ "DSP 8",
+ "DSP 9",
+ "DSP 10",
+ "DSP 11",
+ "DSP 12",
+ "DSP 13",
+ "DSP 14",
+ "DSP 15",
+ "DSP 16",
+ "DSP 17",
+ "DSP 18",
+ "DSP 19",
+ "DSP 20",
+ "DSP 21",
+ "DSP 22",
+ "DSP 23",
+ "DSP 24",
+ "DSP 25",
+ "DSP 26",
+ "DSP 27",
+ "DSP 28",
+ "DSP 29",
+ "DSP 30",
+ "DSP 31",
+};
+
+
/*
* List of data sources available for each destination
*/
@@ -196,6 +253,59 @@ static unsigned int emu1010_src_regs[] = {
EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
};
+/* 1616(m) cardbus */
+static unsigned int emu1616_src_regs[] = {
+ EMU_SRC_SILENCE,
+ EMU_SRC_DOCK_MIC_A1,
+ EMU_SRC_DOCK_MIC_B1,
+ EMU_SRC_DOCK_ADC1_LEFT1,
+ EMU_SRC_DOCK_ADC1_RIGHT1,
+ EMU_SRC_DOCK_ADC2_LEFT1,
+ EMU_SRC_DOCK_ADC2_RIGHT1,
+ EMU_SRC_MDOCK_SPDIF_LEFT1,
+ EMU_SRC_MDOCK_SPDIF_RIGHT1,
+ EMU_SRC_MDOCK_ADAT,
+ EMU_SRC_MDOCK_ADAT+1,
+ EMU_SRC_MDOCK_ADAT+2,
+ EMU_SRC_MDOCK_ADAT+3,
+ EMU_SRC_MDOCK_ADAT+4,
+ EMU_SRC_MDOCK_ADAT+5,
+ EMU_SRC_MDOCK_ADAT+6,
+ EMU_SRC_MDOCK_ADAT+7,
+ EMU_SRC_ALICE_EMU32A,
+ EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+2,
+ EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4,
+ EMU_SRC_ALICE_EMU32A+5,
+ EMU_SRC_ALICE_EMU32A+6,
+ EMU_SRC_ALICE_EMU32A+7,
+ EMU_SRC_ALICE_EMU32A+8,
+ EMU_SRC_ALICE_EMU32A+9,
+ EMU_SRC_ALICE_EMU32A+0xa,
+ EMU_SRC_ALICE_EMU32A+0xb,
+ EMU_SRC_ALICE_EMU32A+0xc,
+ EMU_SRC_ALICE_EMU32A+0xd,
+ EMU_SRC_ALICE_EMU32A+0xe,
+ EMU_SRC_ALICE_EMU32A+0xf,
+ EMU_SRC_ALICE_EMU32B,
+ EMU_SRC_ALICE_EMU32B+1,
+ EMU_SRC_ALICE_EMU32B+2,
+ EMU_SRC_ALICE_EMU32B+3,
+ EMU_SRC_ALICE_EMU32B+4,
+ EMU_SRC_ALICE_EMU32B+5,
+ EMU_SRC_ALICE_EMU32B+6,
+ EMU_SRC_ALICE_EMU32B+7,
+ EMU_SRC_ALICE_EMU32B+8,
+ EMU_SRC_ALICE_EMU32B+9,
+ EMU_SRC_ALICE_EMU32B+0xa,
+ EMU_SRC_ALICE_EMU32B+0xb,
+ EMU_SRC_ALICE_EMU32B+0xc,
+ EMU_SRC_ALICE_EMU32B+0xd,
+ EMU_SRC_ALICE_EMU32B+0xe,
+ EMU_SRC_ALICE_EMU32B+0xf,
+};
+
/*
* Data destinations - physical EMU outputs.
* Each destination has an enum mixer control to choose a data source
@@ -227,6 +337,28 @@ static unsigned int emu1010_output_dst[] = {
EMU_DST_HANA_ADAT+7, /* 23 */
};
+/* 1616(m) cardbus */
+static unsigned int emu1616_output_dst[] = {
+ EMU_DST_DOCK_DAC1_LEFT1,
+ EMU_DST_DOCK_DAC1_RIGHT1,
+ EMU_DST_DOCK_DAC2_LEFT1,
+ EMU_DST_DOCK_DAC2_RIGHT1,
+ EMU_DST_DOCK_DAC3_LEFT1,
+ EMU_DST_DOCK_DAC3_RIGHT1,
+ EMU_DST_MDOCK_SPDIF_LEFT1,
+ EMU_DST_MDOCK_SPDIF_RIGHT1,
+ EMU_DST_MDOCK_ADAT,
+ EMU_DST_MDOCK_ADAT+1,
+ EMU_DST_MDOCK_ADAT+2,
+ EMU_DST_MDOCK_ADAT+3,
+ EMU_DST_MDOCK_ADAT+4,
+ EMU_DST_MDOCK_ADAT+5,
+ EMU_DST_MDOCK_ADAT+6,
+ EMU_DST_MDOCK_ADAT+7,
+ EMU_DST_MANA_DAC_LEFT,
+ EMU_DST_MANA_DAC_RIGHT,
+};
+
/*
* Data destinations - HANA outputs going to Alice2 (audigy) for
* capture (EMU32 + I2S links)
@@ -257,14 +389,26 @@ static unsigned int emu1010_input_dst[] = {
EMU_DST_ALICE_I2S2_RIGHT,
};
-static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ char **items;
+
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 53;
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+ uinfo->value.enumerated.items = 49;
+ items = emu1616_src_texts;
+ } else {
+ uinfo->value.enumerated.items = 53;
+ items = emu1010_src_texts;
+ }
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ items[uinfo->value.enumerated.item]);
return 0;
}
@@ -272,9 +416,14 @@ static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- int channel;
+ unsigned int channel;
channel = (kcontrol->private_value) & 0xff;
+ /* Limit: emu1010_output_dst, emu->emu1010.output_source */
+ if (channel >= 24 ||
+ (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+ channel >= 18))
+ return -EINVAL;
ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
return 0;
}
@@ -283,27 +432,42 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- int change = 0;
unsigned int val;
- int channel;
+ unsigned int channel;
+ val = ucontrol->value.enumerated.item[0];
+ if (val >= 53 ||
+ (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+ val >= 49))
+ return -EINVAL;
channel = (kcontrol->private_value) & 0xff;
- if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
- val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
- change = 1;
+ /* Limit: emu1010_output_dst, emu->emu1010.output_source */
+ if (channel >= 24 ||
+ (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+ channel >= 18))
+ return -EINVAL;
+ if (emu->emu1010.output_source[channel] == val)
+ return 0;
+ emu->emu1010.output_source[channel] = val;
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1616_output_dst[channel], emu1616_src_regs[val]);
+ else
snd_emu1010_fpga_link_dst_src_write(emu,
emu1010_output_dst[channel], emu1010_src_regs[val]);
- }
- return change;
+ return 1;
}
static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- int channel;
+ unsigned int channel;
channel = (kcontrol->private_value) & 0xff;
+ /* Limit: emu1010_input_dst, emu->emu1010.input_source */
+ if (channel >= 22)
+ return -EINVAL;
ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
return 0;
}
@@ -312,18 +476,28 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- int change = 0;
unsigned int val;
- int channel;
+ unsigned int channel;
+ val = ucontrol->value.enumerated.item[0];
+ if (val >= 53 ||
+ (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+ val >= 49))
+ return -EINVAL;
channel = (kcontrol->private_value) & 0xff;
- if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
- val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
- change = 1;
+ /* Limit: emu1010_input_dst, emu->emu1010.input_source */
+ if (channel >= 22)
+ return -EINVAL;
+ if (emu->emu1010.input_source[channel] == val)
+ return 0;
+ emu->emu1010.input_source[channel] = val;
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1010_input_dst[channel], emu1616_src_regs[val]);
+ else
snd_emu1010_fpga_link_dst_src_write(emu,
emu1010_input_dst[channel], emu1010_src_regs[val]);
- }
- return change;
+ return 1;
}
#define EMU1010_SOURCE_OUTPUT(xname,chid) \
@@ -336,7 +510,7 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
.private_value = chid \
}
-static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
+static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
@@ -363,6 +537,30 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
};
+
+/* 1616(m) cardbus */
+static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
+ EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
+ EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
+ EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
+ EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
+ EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
+ EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
+ EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
+ EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
+ EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
+};
+
+
#define EMU1010_SOURCE_INPUT(xname,chid) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -373,7 +571,7 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
.private_value = chid \
}
-static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
+static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
@@ -400,15 +598,7 @@ static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
-
-static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info
static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -449,21 +639,14 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
.private_value = chid \
}
-static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
+static struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
};
-static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info
static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -504,7 +687,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
.private_value = chid \
}
-static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
+static struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
@@ -516,17 +699,19 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {
- "44100", "48000"
+ static char *texts[4] = {
+ "44100", "48000", "SPDIF", "ADAT"
};
-
+
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
return 0;
+
+
}
static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
@@ -546,6 +731,9 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
int change = 0;
val = ucontrol->value.enumerated.item[0] ;
+ /* Limit: uinfo->value.enumerated.items = 4; */
+ if (val >= 4)
+ return -EINVAL;
change = (emu->emu1010.internal_clock != val);
if (change) {
emu->emu1010.internal_clock = val;
@@ -584,6 +772,44 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
/* Unmute all */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
break;
+
+ case 2: /* Take clock from S/PDIF IN */
+ /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+ /* Default fallback clock 48kHz */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
+ /* Word Clock source, sync to S/PDIF input */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+ EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ break;
+
+ case 3:
+ /* Take clock from ADAT IN */
+ /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+ /* Default fallback clock 48kHz */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
+ /* Word Clock source, sync to ADAT input */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+
+
+ break;
}
}
return change;
@@ -644,7 +870,11 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
* update the capture volume from the cached value
* for the particular source.
*/
- source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
+ source_id = ucontrol->value.enumerated.item[0];
+ /* Limit: uinfo->value.enumerated.items = 2; */
+ /* emu->i2c_capture_volume */
+ if (source_id >= 2)
+ return -EINVAL;
change = (emu->i2c_capture_source != source_id);
if (change) {
snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
@@ -695,9 +925,13 @@ static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- int source_id;
+ unsigned int source_id;
source_id = kcontrol->private_value;
+ /* Limit: emu->i2c_capture_volume */
+ /* capture_source: uinfo->value.enumerated.items = 2 */
+ if (source_id >= 2)
+ return -EINVAL;
ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
@@ -710,10 +944,14 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
unsigned int ogain;
unsigned int ngain;
- int source_id;
+ unsigned int source_id;
int change = 0;
source_id = kcontrol->private_value;
+ /* Limit: emu->i2c_capture_volume */
+ /* capture_source: uinfo->value.enumerated.items = 2 */
+ if (source_id >= 2)
+ return -EINVAL;
ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
ngain = ucontrol->value.integer.value[0];
if (ngain > 0xff)
@@ -721,7 +959,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
if (ogain != ngain) {
if (emu->i2c_capture_source == source_id)
snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
- emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
+ emu->i2c_capture_volume[source_id][0] = ngain;
change = 1;
}
ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
@@ -731,7 +969,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
if (ogain != ngain) {
if (emu->i2c_capture_source == source_id)
snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
- emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
+ emu->i2c_capture_volume[source_id][1] = ngain;
change = 1;
}
@@ -751,7 +989,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
}
-static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
+static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
I2C_VOLUME("Mic Capture Volume", 0),
I2C_VOLUME("Line Capture Volume", 0)
};
@@ -852,6 +1090,9 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
unsigned int val;
unsigned long flags;
+ /* Limit: emu->spdif_bits */
+ if (idx >= 3)
+ return -EINVAL;
val = (ucontrol->value.iec958.status[0] << 0) |
(ucontrol->value.iec958.status[1] << 8) |
(ucontrol->value.iec958.status[2] << 16) |
@@ -871,7 +1112,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
- .count = 4,
+ .count = 3,
.info = snd_emu10k1_spdif_info,
.get = snd_emu10k1_spdif_get_mask
};
@@ -880,7 +1121,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
- .count = 4,
+ .count = 3,
.info = snd_emu10k1_spdif_info,
.get = snd_emu10k1_spdif_get,
.put = snd_emu10k1_spdif_put
@@ -1326,14 +1567,7 @@ static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
.put = snd_emu10k1_efx_attn_put
};
-static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info
static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1344,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
else
ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
+ if (emu->card_capabilities->invert_shared_spdif)
+ ucontrol->value.integer.value[0] =
+ !ucontrol->value.integer.value[0];
+
return 0;
}
@@ -1352,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
{
unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int reg, val;
+ unsigned int reg, val, sw;
int change = 0;
+ sw = ucontrol->value.integer.value[0];
+ if (emu->card_capabilities->invert_shared_spdif)
+ sw = !sw;
spin_lock_irqsave(&emu->reg_lock, flags);
if ( emu->card_capabilities->i2c_adc) {
/* Do nothing for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
reg = inl(emu->port + A_IOCFG);
- val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
+ val = sw ? A_IOCFG_GPOUT0 : 0;
change = (reg & A_IOCFG_GPOUT0) != val;
if (change) {
reg &= ~A_IOCFG_GPOUT0;
@@ -1369,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
}
}
reg = inl(emu->port + HCFG);
- val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
+ val = sw ? HCFG_GPOUT0 : 0;
change |= (reg & HCFG_GPOUT0) != val;
if (change) {
reg &= ~HCFG_GPOUT0;
@@ -1380,7 +1621,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
+static struct snd_kcontrol_new snd_emu10k1_shared_spdif =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SB Live Analog/Digital Output Jack",
@@ -1389,7 +1630,7 @@ static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
.put = snd_emu10k1_shared_spdif_put
};
-static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
+static struct snd_kcontrol_new snd_audigy_shared_spdif =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Audigy Analog/Digital Output Jack",
@@ -1398,6 +1639,45 @@ static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
.put = snd_emu10k1_shared_spdif_put
};
+/* workaround for too low volume on Audigy due to 16bit/24bit conversion */
+
+#define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info
+
+static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+
+ /* FIXME: better to use a cached version */
+ val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
+ ucontrol->value.integer.value[0] = !!val;
+ return 0;
+}
+
+static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+
+ if (ucontrol->value.integer.value[0])
+ val = 0x0f0f;
+ else
+ val = 0;
+ return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
+}
+
+static struct snd_kcontrol_new snd_audigy_capture_boost =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Capture Boost",
+ .info = snd_audigy_capture_boost_info,
+ .get = snd_audigy_capture_boost_get,
+ .put = snd_audigy_capture_boost_put
+};
+
+
/*
*/
static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
@@ -1436,8 +1716,8 @@ static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
return -ENOENT;
}
-int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
- int pcm_device, int multi_device)
+int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
+ int pcm_device, int multi_device)
{
int err, pcm;
struct snd_kcontrol *kctl;
@@ -1449,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"Master Mono Playback Volume",
"PCM Out Path & Mute",
"Mono Output Select",
- "Front Playback Switch",
- "Front Playback Volume",
"Surround Playback Switch",
"Surround Playback Volume",
"Center Playback Switch",
@@ -1538,8 +1816,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"Master Playback Switch", "Master Capture Switch",
"Master Playback Volume", "Master Capture Volume",
"Wave Master Playback Volume", "Master Playback Volume",
- "PC Speaker Playback Switch", "PC Speaker Capture Switch",
- "PC Speaker Playback Volume", "PC Speaker Capture Volume",
+ "Beep Playback Switch", "Beep Capture Switch",
+ "Beep Playback Volume", "Beep Capture Volume",
"Phone Playback Switch", "Phone Capture Switch",
"Phone Playback Volume", "Phone Capture Volume",
"Mic Playback Switch", "Mic Capture Switch",
@@ -1575,8 +1853,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
if (emu->card_capabilities->ac97_chip == 1)
return err;
- snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
- snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n");
+ dev_info(emu->card->dev,
+ "AC97 is optional on this board\n");
+ dev_info(emu->card->dev,
+ "Proceeding without ac97 mixers...\n");
snd_device_free(emu->card, pbus);
goto no_ac97; /* FIXME: get rid of ugly gotos.. */
}
@@ -1599,6 +1879,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
emu->rear_ac97 = 1;
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
+ remove_ctl(card,"Front Playback Volume");
+ remove_ctl(card,"Front Playback Switch");
}
/* remove unused AC97 controls */
snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -1633,6 +1915,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
for (; *c; c += 2)
rename_ctl(card, c[0], c[1]);
+ if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
+ remove_ctl(card, "Center Playback Volume");
+ remove_ctl(card, "LFE Playback Volume");
+ remove_ctl(card, "Wave Center Playback Volume");
+ remove_ctl(card, "Wave LFE Playback Volume");
+ }
if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */
rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
@@ -1736,7 +2024,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
return err;
}
- if ( emu->card_capabilities->emu1010) {
+ if (emu->card_capabilities->emu_model) {
; /* Disable the snd_audigy_spdif_shared_spdif */
} else if (emu->audigy) {
if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1761,30 +2049,73 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
return err;
}
- if ( emu->card_capabilities->emu1010) {
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+ /* 1616(m) cardbus */
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
+ emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
+ emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+ if (err < 0)
+ return err;
+ }
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+ if (err < 0)
+ return err;
+
+ } else if (emu->card_capabilities->emu_model) {
+ /* all other e-mu cards for now */
int i;
for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
+ emu));
if (err < 0)
return err;
}
for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
+ emu));
if (err < 0)
return err;
}
for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
if (err < 0)
return err;
}
for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
if (err < 0)
return err;
}
- err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_emu1010_internal_clock, emu));
if (err < 0)
return err;
}
@@ -1803,5 +2134,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
}
}
+ if (emu->card_capabilities->ac97_chip && emu->audigy) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
+ emu));
+ if (err < 0)
+ return err;
+ }
+
return 0;
}