summaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-09 17:24:04 +0100
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-09 17:24:04 +0100
commit6026179519896e7d35b2564e7544487d1c8948e7 (patch)
treec78c7032abce24d846423572204f1cd4e97d8efc /sound/pci
parentMerge branch 'for-linus' of git://www.atmel.no/~hskinnemoen/linux/kernel/avr32 (diff)
parent[PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED (diff)
downloadlinux-6026179519896e7d35b2564e7544487d1c8948e7.tar.xz
linux-6026179519896e7d35b2564e7544487d1c8948e7.zip
Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (212 commits) [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED [ALSA] version 1.0.14rc2 [ALSA] ASoC documentation updates [ALSA] ca0106 - Add missing sysfs device assignment [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880 [ALSA] aoa: remove suspend/resume printks [ALSA] Fix possible deadlocks in sequencer at removal of ports [ALSA] emu10k1 - Fix STAC9758 front channel [ALSA] soc - Clean up with kmemdup() [ALSA] snd-ak4114: Fix two array overflows [ALSA] ac97_bus power management [ALSA] usbaudio - Add support for Edirol UA-101 [ALSA] hda-codec - Add ALC861VD/ALC660VD support [ALSA] soc - ASoC 0.13 Sharp poodle machine [ALSA] soc - ASoC 0.13 Sharp tosa machine [ALSA] soc - ASoC 0.13 spitz machine [ALSA] soc - ASoC Sharp corgi machine [ALSA] soc - ASoC 0.13 pxa2xx DMA [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver ...
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/Kconfig30
-rw-r--r--sound/pci/ac97/ac97_codec.c64
-rw-r--r--sound/pci/ac97/ac97_patch.c549
-rw-r--r--sound/pci/ac97/ac97_patch.h1
-rw-r--r--sound/pci/ac97/ak4531_codec.c6
-rw-r--r--sound/pci/als300.c6
-rw-r--r--sound/pci/atiixp.c31
-rw-r--r--sound/pci/atiixp_modem.c2
-rw-r--r--sound/pci/ca0106/ca0106_main.c21
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c50
-rw-r--r--sound/pci/cs4281.c2
-rw-r--r--sound/pci/echoaudio/darla20.c1
-rw-r--r--sound/pci/echoaudio/darla24.c1
-rw-r--r--sound/pci/echoaudio/echo3g.c1
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.c18
-rw-r--r--sound/pci/echoaudio/gina20.c1
-rw-r--r--sound/pci/echoaudio/gina24.c1
-rw-r--r--sound/pci/echoaudio/indigo.c1
-rw-r--r--sound/pci/echoaudio/indigodj.c1
-rw-r--r--sound/pci/echoaudio/indigoio.c1
-rw-r--r--sound/pci/echoaudio/layla20.c1
-rw-r--r--sound/pci/echoaudio/layla24.c1
-rw-r--r--sound/pci/echoaudio/mia.c1
-rw-r--r--sound/pci/echoaudio/mona.c1
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c616
-rw-r--r--sound/pci/emu10k1/emu10k1x.c6
-rw-r--r--sound/pci/emu10k1/emufx.c204
-rw-r--r--sound/pci/emu10k1/emumixer.c745
-rw-r--r--sound/pci/emu10k1/emupcm.c147
-rw-r--r--sound/pci/emu10k1/emuproc.c34
-rw-r--r--sound/pci/emu10k1/io.c104
-rw-r--r--sound/pci/emu10k1/p16v.c14
-rw-r--r--sound/pci/emu10k1/p17v.h47
-rw-r--r--sound/pci/emu10k1/voice.c2
-rw-r--r--sound/pci/ens1370.c154
-rw-r--r--sound/pci/es1938.c2
-rw-r--r--sound/pci/fm801.c2
-rw-r--r--sound/pci/hda/Makefile11
-rw-r--r--sound/pci/hda/hda_codec.c68
-rw-r--r--sound/pci/hda/hda_intel.c33
-rw-r--r--sound/pci/hda/hda_local.h12
-rw-r--r--sound/pci/hda/hda_patch.h6
-rw-r--r--sound/pci/hda/patch_analog.c165
-rw-r--r--sound/pci/hda/patch_cmedia.c24
-rw-r--r--sound/pci/hda/patch_conexant.c1311
-rw-r--r--sound/pci/hda/patch_realtek.c2367
-rw-r--r--sound/pci/hda/patch_sigmatel.c692
-rw-r--r--sound/pci/hda/patch_via.c1396
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/amp.c4
-rw-r--r--sound/pci/ice1712/amp.h2
-rw-r--r--sound/pci/ice1712/aureon.c186
-rw-r--r--sound/pci/ice1712/aureon.h6
-rw-r--r--sound/pci/ice1712/delta.c34
-rw-r--r--sound/pci/ice1712/delta.h2
-rw-r--r--sound/pci/ice1712/ews.c24
-rw-r--r--sound/pci/ice1712/ews.h2
-rw-r--r--sound/pci/ice1712/hoontech.c7
-rw-r--r--sound/pci/ice1712/hoontech.h2
-rw-r--r--sound/pci/ice1712/ice1712.c74
-rw-r--r--sound/pci/ice1712/ice1712.h18
-rw-r--r--sound/pci/ice1712/ice1724.c78
-rw-r--r--sound/pci/ice1712/juli.c36
-rw-r--r--sound/pci/ice1712/juli.h2
-rw-r--r--sound/pci/ice1712/phase.c76
-rw-r--r--sound/pci/ice1712/phase.h2
-rw-r--r--sound/pci/ice1712/pontis.c42
-rw-r--r--sound/pci/ice1712/pontis.h2
-rw-r--r--sound/pci/ice1712/prodigy192.c40
-rw-r--r--sound/pci/ice1712/prodigy192.h2
-rw-r--r--sound/pci/ice1712/revo.c372
-rw-r--r--sound/pci/ice1712/revo.h13
-rw-r--r--sound/pci/ice1712/vt1720_mobo.c59
-rw-r--r--sound/pci/ice1712/vt1720_mobo.h2
-rw-r--r--sound/pci/ice1712/wtm.c542
-rw-r--r--sound/pci/ice1712/wtm.h20
-rw-r--r--sound/pci/intel8x0.c208
-rw-r--r--sound/pci/intel8x0m.c120
-rw-r--r--sound/pci/korg1212/korg1212.c45
-rw-r--r--sound/pci/maestro3.c373
-rw-r--r--sound/pci/mixart/mixart_mixer.c4
-rw-r--r--sound/pci/nm256/nm256.c56
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c6
-rw-r--r--sound/pci/rme9652/hdsp.c38
-rw-r--r--sound/pci/rme9652/hdspm.c1242
-rw-r--r--sound/pci/trident/trident_main.c4
-rw-r--r--sound/pci/via82xx.c134
-rw-r--r--sound/pci/via82xx_modem.c2
-rw-r--r--sound/pci/vx222/vx222.c4
-rw-r--r--sound/pci/vx222/vx222_ops.c2
-rw-r--r--sound/pci/ymfpci/ymfpci_image.h6
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c171
93 files changed, 10903 insertions, 2119 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 8a6b1803c763..1bcfb3aac18d 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -236,7 +236,7 @@ config SND_CS5535AUDIO
config SND_DARLA20
tristate "(Echoaudio) Darla20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla.
@@ -247,7 +247,7 @@ config SND_DARLA20
config SND_GINA20
tristate "(Echoaudio) Gina20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina.
@@ -258,7 +258,7 @@ config SND_GINA20
config SND_LAYLA20
tristate "(Echoaudio) Layla20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -270,7 +270,7 @@ config SND_LAYLA20
config SND_DARLA24
tristate "(Echoaudio) Darla24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla24.
@@ -281,7 +281,7 @@ config SND_DARLA24
config SND_GINA24
tristate "(Echoaudio) Gina24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina24.
@@ -292,7 +292,7 @@ config SND_GINA24
config SND_LAYLA24
tristate "(Echoaudio) Layla24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -304,7 +304,7 @@ config SND_LAYLA24
config SND_MONA
tristate "(Echoaudio) Mona"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -316,7 +316,7 @@ config SND_MONA
config SND_MIA
tristate "(Echoaudio) Mia"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -328,7 +328,7 @@ config SND_MIA
config SND_ECHO3G
tristate "(Echoaudio) 3G cards"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -340,7 +340,7 @@ config SND_ECHO3G
config SND_INDIGO
tristate "(Echoaudio) Indigo"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo.
@@ -351,7 +351,7 @@ config SND_INDIGO
config SND_INDIGOIO
tristate "(Echoaudio) Indigo IO"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
@@ -362,7 +362,7 @@ config SND_INDIGOIO
config SND_INDIGODJ
tristate "(Echoaudio) Indigo DJ"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
@@ -373,6 +373,7 @@ config SND_INDIGODJ
config SND_EMU10K1
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
depends on SND
+ select FW_LOADER
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
@@ -575,6 +576,7 @@ config SND_INTEL8X0M
config SND_KORG1212
tristate "Korg 1212 IO"
depends on SND
+ select FW_LOADER
select SND_PCM
help
Say Y here to include support for Korg 1212IO soundcards.
@@ -585,6 +587,7 @@ config SND_KORG1212
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
depends on SND
+ select FW_LOADER
select SND_AC97_CODEC
help
Say Y here to include support for soundcards based on ESS Maestro 3
@@ -629,7 +632,7 @@ config SND_PCXHR
config SND_RIPTIDE
tristate "Conexant Riptide"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@@ -734,6 +737,7 @@ config SND_VX222
config SND_YMFPCI
tristate "Yamaha YMF724/740/744/754"
depends on SND
+ select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index d2994cb4c8c9..74ed81081478 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
-{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL },
+{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL },
{ 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL },
{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
@@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
static void update_power_regs(struct snd_ac97 *ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+#define ac97_is_power_save_mode(ac97) \
+ ((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save)
+#else
+#define ac97_is_power_save_mode(ac97) 0
+#endif
+
/*
* I/O routines
@@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
{
if (ac97) {
#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (ac97->power_workq)
- destroy_workqueue(ac97->power_workq);
+ cancel_delayed_work(&ac97->power_work);
+ flush_scheduled_work();
#endif
snd_ac97_proc_done(ac97);
if (ac97->bus)
@@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
/*
* set dB information
*/
-static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
-static unsigned int *find_db_scale(unsigned int maxval)
+static const unsigned int *find_db_scale(unsigned int maxval)
{
switch (maxval) {
case 0x0f: return db_scale_4bit;
@@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval)
return NULL;
}
-static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
-{
+static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv)
+{
kctl->tlv.p = tlv;
if (tlv)
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
@@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
mutex_init(&ac97->reg_mutex);
mutex_init(&ac97->page_mutex);
#ifdef CONFIG_SND_AC97_POWER_SAVE
- ac97->power_workq = create_workqueue("ac97");
INIT_DELAYED_WORK(&ac97->power_work, do_update_power);
#endif
@@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
udelay(100);
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
snd_ac97_write(ac97, AC97_POWERDOWN, power);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (power_save) {
+ if (ac97_is_power_save_mode(ac97)) {
udelay(100);
/* AC-link powerdown, internal Clk disable */
/* FIXME: this may cause click noises on some boards */
power |= AC97_PD_PR4 | AC97_PD_PR5;
snd_ac97_write(ac97, AC97_POWERDOWN, power);
}
-#endif
}
@@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
}
}
- if (power_save && !powerup && ac97->power_workq)
+ if (ac97_is_power_save_mode(ac97) && !powerup)
/* adjust power-down bits after two seconds delay
* (for avoiding loud click noises for many (OSS) apps
* that open/close frequently)
*/
- queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
- else
+ schedule_delayed_work(&ac97->power_work, HZ*2);
+ else {
+ cancel_delayed_work(&ac97->power_work);
update_power_regs(ac97);
+ }
return 0;
}
@@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97)
unsigned int power_up, bits;
int i;
+ power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
+ power_up |= (1 << PWIDX_MIC);
+ if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
+ power_up |= (1 << PWIDX_SURR);
+ if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
+ power_up |= (1 << PWIDX_CLFE);
#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (power_save)
+ if (ac97_is_power_save_mode(ac97))
power_up = ac97->power_up;
- else {
-#endif
- power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
- power_up |= (1 << PWIDX_MIC);
- if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
- power_up |= (1 << PWIDX_SURR);
- if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
- power_up |= (1 << PWIDX_CLFE);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
- }
#endif
if (power_up) {
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
@@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
return;
if (ac97->build_ops->suspend)
ac97->build_ops->suspend(ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+ cancel_delayed_work(&ac97->power_work);
+ flush_scheduled_work();
+#endif
snd_ac97_powerdown(ac97);
}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index e813968e0cf8..641d0c8d659e 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
/* replace with a new TLV */
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
- unsigned int *tlv)
+ const unsigned int *tlv)
{
struct snd_ctl_elem_id sid;
struct snd_kcontrol *kctl;
@@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97)
return ac97->channel_mode >= 2;
}
+/* system has shared jacks with surround out enabled */
+static inline int is_shared_surrout(struct snd_ac97 *ac97)
+{
+ return !ac97->indep_surround && is_surround_on(ac97);
+}
+
+/* system has shared jacks with center/lfe out enabled */
+static inline int is_shared_clfeout(struct snd_ac97 *ac97)
+{
+ return !ac97->indep_surround && is_clfe_on(ac97);
+}
+
+/* system has shared jacks with line in enabled */
static inline int is_shared_linein(struct snd_ac97 *ac97)
{
- return ! ac97->indep_surround && is_surround_on(ac97);
+ return !ac97->indep_surround && !is_surround_on(ac97);
}
+/* system has shared jacks with mic in enabled */
static inline int is_shared_micin(struct snd_ac97 *ac97)
{
- return ! ac97->indep_surround && is_clfe_on(ac97);
+ return !ac97->indep_surround && !is_clfe_on(ac97);
}
@@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
{
int err;
+ /* the register bit is writable, but the function is not implemented: */
+ snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL);
+
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
return err;
@@ -1552,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
};
-static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
static int patch_ad1885_specific(struct snd_ac97 * ac97)
{
@@ -1609,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97)
return 0;
}
-/* MISC bits */
+/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
#define AC97_AD198X_MBC 0x0003 /* mic boost */
#define AC97_AD198X_MBC_20 0x0000 /* +20dB */
#define AC97_AD198X_MBC_10 0x0001 /* +10dB */
#define AC97_AD198X_MBC_30 0x0002 /* +30dB */
#define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */
-#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */
-#define AC97_AD198X_VREF_0 0x000c /* 0V */
+#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */
+#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */
+#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD)
+#define AC97_AD198X_VREF_SHIFT 2
#define AC97_AD198X_SRU 0x0010 /* sample rate unlock */
#define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */
#define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */
#define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */
-#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */
+ /* 0 = 6-to-4, 1 = 6-to-2 downmix */
#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */
#define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */
#define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */
@@ -1630,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97)
#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */
#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */
+/* MISC 1 bits (AD1986 register 0x76) */
+#define AC97_AD1986_MBC 0x0003 /* mic boost */
+#define AC97_AD1986_MBC_20 0x0000 /* +20dB */
+#define AC97_AD1986_MBC_10 0x0001 /* +10dB */
+#define AC97_AD1986_MBC_30 0x0002 /* +30dB */
+#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */
+#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */
+#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
+#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */
+#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */
+#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */
+#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */
+#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */
+#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */
+#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */
+#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */
+ /* 0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */
+#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */
+#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */
+#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */
+#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */
+#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */
+
+/* MISC 2 bits (AD1986 register 0x70) */
+#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */
+
+#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */
+#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */
+#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */
+#define AC97_AD1986_CVREF_MASK \
+ (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
+#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */
+#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */
+#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */
+#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */
+#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */
+#define AC97_AD1986_MVREF_MASK \
+ (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
+
+/* MISC 3 bits (AD1986 register 0x7a) */
+#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */
+
+#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */
+#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */
+#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */
+#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */
+#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */
+#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */
+#define AC97_AD1986_LVREF_MASK \
+ (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
+#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */
+#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */
+#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */
+ /* input select Surround DACs */
+#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */
+ /* select C/LFE DACs */
+#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */
+
+/* Serial Config bits (AD1986 register 0x74) (incomplete) */
+#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */
+#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */
+#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */
+#define AC97_AD1986_OMS_MASK \
+ (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
+#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */
+#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */
+#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */
+#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */
+ /* are MIC sources */
+
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -1952,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97)
return 0;
}
+static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ static const int reg2ctrl[4] = {2, 0, 1, 3};
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+ val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK)
+ >> AC97_AD198X_VREF_SHIFT;
+ ucontrol->value.enumerated.item[0] = reg2ctrl[val];
+ return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ static const int ctrl2reg[4] = {1, 2, 0, 3};
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ if (ucontrol->value.enumerated.item[0] > 3
+ || ucontrol->value.enumerated.item[0] < 0)
+ return -EINVAL;
+ val = ctrl2reg[ucontrol->value.enumerated.item[0]]
+ << AC97_AD198X_VREF_SHIFT;
+ return snd_ac97_update_bits(ac97, AC97_AD_MISC,
+ AC97_AD198X_VREF_MASK, val);
+}
+
static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
- AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
+ AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Front/Surround",
+ .info = snd_ac97_ad1888_lohpsel_info,
+ .get = snd_ac97_ad1888_lohpsel_get,
+ .put = snd_ac97_ad1888_lohpsel_put
+ },
+ AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
+ AC97_SINGLE("Spread Front to Surround and Center/LFE",
+ AC97_AD_MISC, 7, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Downmix",
+ .info = snd_ac97_ad1888_downmix_info,
+ .get = snd_ac97_ad1888_downmix_get,
+ .put = snd_ac97_ad1888_downmix_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "V_REFOUT",
+ .info = snd_ac97_ad1985_vrefout_info,
+ .get = snd_ac97_ad1985_vrefout_get,
+ .put = snd_ac97_ad1985_vrefout_put
+ },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+
+ AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
};
static void ad1985_update_jacks(struct snd_ac97 *ac97)
@@ -1967,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
{
int err;
- if ((err = patch_ad1980_specific(ac97)) < 0)
+ /* rename 0x04 as "Master" and 0x02 as "Master Surround" */
+ snd_ac97_rename_vol_ctl(ac97, "Master Playback",
+ "Master Surround Playback");
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
+
+ if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
return err;
- return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));
+
+ return patch_build_controls(ac97, snd_ac97_ad1985_controls,
+ ARRAY_SIZE(snd_ac97_ad1985_controls));
}
static struct snd_ac97_build_ops patch_ad1985_build_ops = {
@@ -1989,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97)
ac97->build_ops = &patch_ad1985_build_ops;
misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* switch front/surround line-out/hp-out */
- /* center/LFE, mic in 3.75V mode */
/* AD-compatible mode */
/* Stereo mutes enabled */
- /* in accordance with ADI driver: misc | 0x5c28 */
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
- AC97_AD198X_VREFH |
AC97_AD198X_LOSEL |
AC97_AD198X_HPSEL |
- AC97_AD198X_CLDIS |
- AC97_AD198X_LODIS |
AC97_AD198X_MSPLT |
AC97_AD198X_AC97NC);
ac97->flags |= AC97_STEREO_MUTES;
+
+ /* update current jack configuration */
+ ad1985_update_jacks(ac97);
+
/* on AD1985 rev. 3, AC'97 revision bits are zero */
ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23;
return 0;
}
+static int snd_ac97_ad1986_bool_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;
+}
+
+static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ val = ac97->regs[AC97_AD_MISC3];
+ ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
+ return 0;
+}
+
+static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ int ret0;
+ int ret1;
+ int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
+
+ ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
+ ucontrol->value.integer.value[0] != 0
+ ? AC97_AD1986_LOSEL : 0);
+ if (ret0 < 0)
+ return ret0;
+
+ /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+ ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+ (ucontrol->value.integer.value[0] != 0
+ || sprd)
+ ? AC97_AD1986_SOSEL : 0);
+ if (ret1 < 0)
+ return ret1;
+
+ return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ val = ac97->regs[AC97_AD_MISC];
+ ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
+ return 0;
+}
+
+static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ int ret0;
+ int ret1;
+ int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
+
+ ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
+ ucontrol->value.integer.value[0] != 0
+ ? AC97_AD1986_SPRD : 0);
+ if (ret0 < 0)
+ return ret0;
+
+ /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+ ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+ (ucontrol->value.integer.value[0] != 0
+ || sprd)
+ ? AC97_AD1986_SOSEL : 0);
+ if (ret1 < 0)
+ return ret1;
+
+ return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
+ return 0;
+}
+
+static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char swap = ucontrol->value.integer.value[0] != 0;
+
+ if (swap != ac97->spec.ad18xx.swap_mic_linein) {
+ ac97->spec.ad18xx.swap_mic_linein = swap;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* Use MIC_1/2 V_REFOUT as the "get" value */
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+ unsigned short reg = ac97->regs[AC97_AD_MISC2];
+ if ((reg & AC97_AD1986_MVREF0) != 0)
+ val = 2;
+ else if ((reg & AC97_AD1986_MVREF1) != 0)
+ val = 3;
+ else if ((reg & AC97_AD1986_MVREF2) != 0)
+ val = 1;
+ else
+ val = 0;
+ ucontrol->value.enumerated.item[0] = val;
+ return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short cval;
+ unsigned short lval;
+ unsigned short mval;
+ int cret;
+ int lret;
+ int mret;
+
+ switch (ucontrol->value.enumerated.item[0])
+ {
+ case 0: /* High-Z */
+ cval = 0;
+ lval = 0;
+ mval = 0;
+ break;
+ case 1: /* 3.7 V */
+ cval = AC97_AD1986_CVREF2;
+ lval = AC97_AD1986_LVREF2;
+ mval = AC97_AD1986_MVREF2;
+ break;
+ case 2: /* 2.25 V */
+ cval = AC97_AD1986_CVREF0;
+ lval = AC97_AD1986_LVREF0;
+ mval = AC97_AD1986_MVREF0;
+ break;
+ case 3: /* 0 V */
+ cval = AC97_AD1986_CVREF1;
+ lval = AC97_AD1986_LVREF1;
+ mval = AC97_AD1986_MVREF1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+ AC97_AD1986_CVREF_MASK, cval);
+ if (cret < 0)
+ return cret;
+ lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
+ AC97_AD1986_LVREF_MASK, lval);
+ if (lret < 0)
+ return lret;
+ mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+ AC97_AD1986_MVREF_MASK, mval);
+ if (mret < 0)
+ return mret;
+
+ return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
+}
+
+static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
+ AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Front/Surround",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_lososel_get,
+ .put = snd_ac97_ad1986_lososel_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Mic/Line In",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_miclisel_get,
+ .put = snd_ac97_ad1986_miclisel_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Spread Front to Surround and Center/LFE",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_spread_get,
+ .put = snd_ac97_ad1986_spread_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Downmix",
+ .info = snd_ac97_ad1888_downmix_info,
+ .get = snd_ac97_ad1888_downmix_get,
+ .put = snd_ac97_ad1888_downmix_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "V_REFOUT",
+ .info = snd_ac97_ad1985_vrefout_info,
+ .get = snd_ac97_ad1986_vrefout_get,
+ .put = snd_ac97_ad1986_vrefout_put
+ },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+
+ AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
+};
+
+static void ad1986_update_jacks(struct snd_ac97 *ac97)
+{
+ unsigned short misc_val = 0;
+ unsigned short ser_val;
+
+ /* disable SURROUND and CENTER/LFE if not surround mode */
+ if (! is_surround_on(ac97))
+ misc_val |= AC97_AD1986_SODIS;
+ if (! is_clfe_on(ac97))
+ misc_val |= AC97_AD1986_CLDIS;
+
+ /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
+ if (is_shared_linein(ac97))
+ misc_val |= AC97_AD1986_LISEL_SURR;
+ else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+ misc_val |= AC97_AD1986_LISEL_MIC;
+ snd_ac97_update_bits(ac97, AC97_AD_MISC,
+ AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
+ AC97_AD1986_LISEL_MASK,
+ misc_val);
+
+ /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
+ if (is_shared_micin(ac97))
+ ser_val = AC97_AD1986_OMS_C;
+ else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+ ser_val = AC97_AD1986_OMS_L;
+ else
+ ser_val = AC97_AD1986_OMS_M;
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
+ AC97_AD1986_OMS_MASK,
+ ser_val);
+}
+
+static int patch_ad1986_specific(struct snd_ac97 *ac97)
+{
+ int err;
+
+ if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
+ return err;
+
+ return patch_build_controls(ac97, snd_ac97_ad1986_controls,
+ ARRAY_SIZE(snd_ac97_ad1985_controls));
+}
+
+static struct snd_ac97_build_ops patch_ad1986_build_ops = {
+ .build_post_spdif = patch_ad198x_post_spdif,
+ .build_specific = patch_ad1986_specific,
+#ifdef CONFIG_PM
+ .resume = ad18xx_resume,
+#endif
+ .update_jacks = ad1986_update_jacks,
+};
+
+int patch_ad1986(struct snd_ac97 * ac97)
+{
+ patch_ad1881(ac97);
+ ac97->build_ops = &patch_ad1986_build_ops;
+ ac97->flags |= AC97_STEREO_MUTES;
+
+ /* update current jack configuration */
+ ad1986_update_jacks(ac97);
+
+ return 0;
+}
+
+
/*
* realtek ALC65x/850 codecs
*/
@@ -2014,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0);
- /* update shared Mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* disable/enable vref */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@@ -2064,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = {
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
};
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
static int patch_alc650_specific(struct snd_ac97 * ac97)
{
@@ -2149,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0, 0);
- /* update shared mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@@ -2264,7 +2727,8 @@ int patch_alc655(struct snd_ac97 * ac97)
if (ac97->subsystem_vendor == 0x1462 &&
(ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
ac97->subsystem_device == 0x0161 || /* LG K1 Express */
- ac97->subsystem_device == 0x0351)) /* MSI L725 laptop */
+ ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
+ ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
else
val |= (1 << 1); /* Pin 47 is spdif input pin */
@@ -2297,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
/* SURR 1kOhm (bit4), Amp (bit5) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
shared ? (1<<5) : (1<<4));
/* LINE-IN = 0, SURROUND = 2 */
snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
shared ? (2<<12) : (0<<12));
- /* update shared mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* Vref disable (bit12), 1kOhm (bit13) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
shared ? (1<<12) : (1<<13));
@@ -2379,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97)
*/
static void cm9738_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
- is_shared_linein(ac97) ? (1 << 10) : 0);
+ is_shared_surrout(ac97) ? (1 << 10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = {
@@ -2463,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = {
static void cm9739_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
- is_shared_linein(ac97) ? (1 << 10) : 0);
- /* shared Mic */
+ is_shared_surrout(ac97) ? (1 << 10) : 0);
+ /* shared Mic In / Center/LFE Out **/
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
- is_shared_micin(ac97) ? 0x1000 : 0x2000);
+ is_shared_clfeout(ac97) ? 0x1000 : 0x2000);
}
static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = {
@@ -2580,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97)
val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)];
val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)];
- val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)];
- val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)];
+ val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)];
+ val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)];
snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val);
}
@@ -2821,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97)
snd_ac97_write_cache(ac97, 0x5c, 0x20);
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+ ac97->build_ops = &patch_vt1616_ops;
return 0;
}
@@ -2828,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97)
*/
static void it2646_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 9,
- is_shared_linein(ac97) ? (1<<9) : 0);
- /* shared Mic */
+ is_shared_surrout(ac97) ? (1<<9) : 0);
+ /* shared Mic / Center/LFE Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 10,
- is_shared_micin(ac97) ? (1<<10) : 0);
+ is_shared_clfeout(ac97) ? (1<<10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = {
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 741979217207..94340daaaf1f 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97);
int patch_ad1981a(struct snd_ac97 * ac97);
int patch_ad1981b(struct snd_ac97 * ac97);
int patch_ad1985(struct snd_ac97 * ac97);
+int patch_ad1986(struct snd_ac97 * ac97);
int patch_alc650(struct snd_ac97 * ac97);
int patch_alc655(struct snd_ac97 * ac97);
int patch_alc850(struct snd_ac97 * ac97);
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
index c153cb79c518..dc26820a03a5 100644
--- a/sound/pci/ac97/ak4531_codec.c
+++ b/sound/pci/ac97/ak4531_codec.c
@@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
static struct snd_kcontrol_new snd_ak4531_controls[] = {
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 9f406fbe0d95..8afcb98ca7bb 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
}
static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
- snd_pcm_hw_params_t * hw_params)
+ struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
@@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip)
snd_als300_dbgcallleave();
}
-static int __devinit snd_als300_create(snd_card_t *card,
+static int __devinit snd_als300_create(struct snd_card *card,
struct pci_dev *pci, int chip_type,
struct snd_als300 **rchip)
{
@@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card,
void *irq_handler;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_als300_dev_free,
};
*rchip = NULL;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 476c3433073e..7d8053b5e8d5 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static int ac97_clock = 48000;
static char *ac97_quirk;
static int spdif_aclink = 1;
+static int ac97_codec = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
@@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444);
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
+module_param(ac97_codec, int, 0444);
+MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing.");
module_param(spdif_aclink, bool, 0444);
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
@@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
+static struct snd_pci_quirk atiixp_quirks[] __devinitdata = {
+ SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0),
+ { } /* terminator */
+};
/*
* lowlevel functions
@@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
ATI_REG_ISR_CODEC2_NOT_READY)
#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
+static int ac97_probing_bugs(struct pci_dev *pci)
+{
+ const struct snd_pci_quirk *q;
+
+ q = snd_pci_quirk_lookup(pci, atiixp_quirks);
+ if (q) {
+ snd_printdd(KERN_INFO "Atiixp quirk for %s. "
+ "Forcing codec %d\n", q->name, q->value);
+ return q->value;
+ }
+ /* this hardware doesn't need workarounds. Probe for codec */
+ return -1;
+}
+
static int snd_atiixp_codec_detect(struct atiixp *chip)
{
int timeout;
chip->codec_not_ready_bits = 0;
+ if (ac97_codec == -1)
+ ac97_codec = ac97_probing_bugs(chip->pci);
+ if (ac97_codec >= 0) {
+ chip->codec_not_ready_bits |=
+ CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10));
+ return 0;
+ }
+
atiixp_write(chip, IER, CODEC_CHECK_BITS);
/* wait for the interrupts */
timeout = 50;
@@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if (! chip->spdif_over_aclink)
ac97.scaps |= AC97_SCAP_NO_SPDIF;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index cc2e6b9d407e..904023fe4f26 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
chip->ac97[i] = NULL; /* to be sure */
snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index f61f052f6d14..ea6712b63c9f 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1382,7 +1382,6 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
chip->spdif_enable = 0; /* Set digital SPDIF output off */
- chip->capture_source = 3; /* Set CAPTURE_SOURCE */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
@@ -1402,8 +1401,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
}
- snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
- chip->capture_source = 3; /* Set CAPTURE_SOURCE */
+ if (chip->details->i2c_adc == 1) {
+ /* Select MIC, Line in, TAD in, AUX in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+ /* Default to CAPTURE_SOURCE to i2s in */
+ chip->capture_source = 3;
+ } else if (chip->details->ac97 == 1) {
+ /* Default to AC97 in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
+ /* Default to CAPTURE_SOURCE to AC97 in */
+ chip->capture_source = 4;
+ } else {
+ /* Select MIC, Line in, TAD in, AUX in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+ /* Default to Set CAPTURE_SOURCE to i2s in */
+ chip->capture_source = 3;
+ }
if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
@@ -1605,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
snd_ca0106_proc_init(chip);
#endif
+ snd_card_set_dev(card, &pci->dev);
+
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 9855f528ea78..b913a1fb8c21 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -74,8 +74,8 @@
#include "ca0106.h"
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
.private_value = ((chid) << 8) | (reg) \
}
-#define I2C_VOLUME(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
- .info = snd_ca0106_i2c_volume_info, \
- .get = snd_ca0106_i2c_volume_get, \
- .put = snd_ca0106_i2c_volume_put, \
- .tlv = { .p = snd_ca0106_db_scale2 }, \
- .private_value = chid \
-}
-
-
static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("Analog Front Playback Volume",
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
@@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("CAPTURE feedback Playback Volume",
1, CAPTURE_CONTROL),
- I2C_VOLUME("Phone Capture Volume", 0),
- I2C_VOLUME("Mic Capture Volume", 1),
- I2C_VOLUME("Line in Capture Volume", 2),
- I2C_VOLUME("Aux Capture Volume", 3),
-
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Capture Source",
+ .name = "Digital Source Capture Enum",
.info = snd_ca0106_capture_source_info,
.get = snd_ca0106_capture_source_get,
.put = snd_ca0106_capture_source_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
+ .name = "Analog Source Capture Enum",
.info = snd_ca0106_i2c_capture_source_info,
.get = snd_ca0106_i2c_capture_source_get,
.put = snd_ca0106_i2c_capture_source_put
@@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
};
+#define I2C_VOLUME(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_ca0106_i2c_volume_info, \
+ .get = snd_ca0106_i2c_volume_get, \
+ .put = snd_ca0106_i2c_volume_put, \
+ .tlv = { .p = snd_ca0106_db_scale2 }, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
+ I2C_VOLUME("Phone Capture Volume", 0),
+ I2C_VOLUME("Mic Capture Volume", 1),
+ I2C_VOLUME("Line in Capture Volume", 2),
+ I2C_VOLUME("Aux Capture Volume", 3),
+};
+
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
@@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return err;
}
if (emu->details->i2c_adc == 1) {
+ for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
if (emu->details->gpio_type == 1)
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
else /* gpio_type == 2 */
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 8e5519de7115..44cf54607647 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
static struct snd_kcontrol_new snd_cs4281_fm_vol =
{
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
index b7108e29a668..8e7fe033270f 100644
--- a/sound/pci/echoaudio/darla20.c
+++ b/sound/pci/echoaudio/darla20.c
@@ -47,6 +47,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
index e59a982ee361..a13c623eb999 100644
--- a/sound/pci/echoaudio/darla24.c
+++ b/sound/pci/echoaudio/darla24.c
@@ -51,6 +51,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
index 12099fe1547d..8fb15823aca5 100644
--- a/sound/pci/echoaudio/echo3g.c
+++ b/sound/pci/echoaudio/echo3g.c
@@ -58,6 +58,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index d26a1d1f3ed1..48eb7c599111 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on);
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
char force);
-#include <linux/irq.h>
+#include <linux/interrupt.h>
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 047e0b5bf15d..6a428b81dba6 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
+static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
static int get_firmware(const struct firmware **fw_entry,
const struct firmware *frm, struct echoaudio *chip)
@@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
.name = "Line Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
+ .tlv = {.p = db_scale_output_gain},
};
#else
static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif
@@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
return changed;
}
+static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
+
static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
.name = "Line Capture Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_input_gain_info,
.get = snd_echo_input_gain_get,
.put = snd_echo_input_gain_put,
+ .tlv = {.p = db_scale_input_gain},
};
#endif /* ECHOCARD_HAS_INPUT_GAIN */
@@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
.name = "Monitor Mixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_mixer_info,
.get = snd_echo_mixer_get,
.put = snd_echo_mixer_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_MONITOR */
@@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
.name = "VMixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vmixer_info,
.get = snd_echo_vmixer_get,
.put = snd_echo_vmixer_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_VMIXER */
@@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
.name = "VU-meters",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vumeters_info,
.get = snd_echo_vumeters_get,
+ .tlv = {.p = db_scale_output_gain},
};
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
index 29d6d12f80ca..af4d32026e4a 100644
--- a/sound/pci/echoaudio/gina20.c
+++ b/sound/pci/echoaudio/gina20.c
@@ -51,6 +51,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
index e464d720d0bd..9ff454a947ed 100644
--- a/sound/pci/echoaudio/gina24.c
+++ b/sound/pci/echoaudio/gina24.c
@@ -57,6 +57,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
index bfd2467099ac..37eb726fd03d 100644
--- a/sound/pci/echoaudio/indigo.c
+++ b/sound/pci/echoaudio/indigo.c
@@ -49,6 +49,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
index 8ed7ff1fd875..dc8b91824181 100644
--- a/sound/pci/echoaudio/indigodj.c
+++ b/sound/pci/echoaudio/indigodj.c
@@ -49,6 +49,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
index a8788e959171..eadf3263453a 100644
--- a/sound/pci/echoaudio/indigoio.c
+++ b/sound/pci/echoaudio/indigoio.c
@@ -50,6 +50,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
index e503d74b3ba9..6cede497579e 100644
--- a/sound/pci/echoaudio/layla20.c
+++ b/sound/pci/echoaudio/layla20.c
@@ -56,6 +56,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
index d4581fdc841c..44f735426aa0 100644
--- a/sound/pci/echoaudio/layla24.c
+++ b/sound/pci/echoaudio/layla24.c
@@ -58,6 +58,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
index be40c64263d2..dc172d03ac3f 100644
--- a/sound/pci/echoaudio/mia.c
+++ b/sound/pci/echoaudio/mia.c
@@ -56,6 +56,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
index 5dc512add372..c856ed50dd9a 100644
--- a/sound/pci/echoaudio/mona.c
+++ b/sound/pci/echoaudio/mona.c
@@ -55,6 +55,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 972ec40d8166..80aa585eade4 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -3,8 +3,10 @@
* Creative Labs, Inc.
* Routines for control of EMU10K1 chips
*
- * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
* Added support for Audigy 2 Value.
+ * Added EMU 1010 support.
+ * General bug fixes and enhancements.
*
*
* BUGS:
@@ -41,8 +43,10 @@
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include <linux/firmware.h>
#include "p16v.h"
#include "tina2.h"
+#include "p17v.h"
/*************************************************************************
@@ -117,11 +121,28 @@ static unsigned int spi_dac_init[] = {
0x0622,
0x1400,
};
+
+static unsigned int i2c_adc_init[][2] = {
+ { 0x17, 0x00 }, /* Reset */
+ { 0x07, 0x00 }, /* Timeout */
+ { 0x0b, 0x22 }, /* Interface control */
+ { 0x0c, 0x22 }, /* Master mode control */
+ { 0x0d, 0x08 }, /* Powerdown control */
+ { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */
+ { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */
+ { 0x10, 0x7b }, /* ALC Control 1 */
+ { 0x11, 0x00 }, /* ALC Control 2 */
+ { 0x12, 0x32 }, /* ALC Control 3 */
+ { 0x13, 0x00 }, /* Noise gate control */
+ { 0x14, 0xa6 }, /* Limiter control */
+ { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */
+};
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
{
unsigned int silent_page;
int ch;
+ u32 tmp;
/* disable audio and lock cache */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
@@ -160,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Hacks for Alice3 to work independent of haP16V driver */
- u32 tmp;
-
//Setup SRCMulti_I2S SamplingRate
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
@@ -181,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
}
if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
- u32 tmp;
-
snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
//Setup SRCMulti_I2S SamplingRate
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
@@ -211,7 +228,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
int size, n;
size = ARRAY_SIZE(spi_dac_init);
- for (n=0; n < size; n++)
+ for (n = 0; n < size; n++)
snd_emu10k1_spi_write(emu, spi_dac_init[n]);
snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);
@@ -228,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
}
+ if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
+ int size, n;
+
+ snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);
+ tmp = inl(emu->port + A_IOCFG);
+ outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */
+ tmp = inl(emu->port + A_IOCFG);
+ size = ARRAY_SIZE(i2c_adc_init);
+ for (n = 0; n < size; n++)
+ snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+ for (n=0; n < 4; n++) {
+ emu->i2c_capture_volume[n][0]= 0xcf;
+ emu->i2c_capture_volume[n][1]= 0xcf;
+ }
+
+ }
+
snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
@@ -239,6 +273,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
}
+ if (emu->card_capabilities->emu1010) {
+ outl(HCFG_AUTOMUTE_ASYNC |
+ HCFG_EMU32_SLAVE |
+ HCFG_AUDIOENABLE, emu->port + HCFG);
/*
* Hokay, setup HCFG
* Mute Disable Audio = 0
@@ -246,7 +284,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
* Lock Sound Memory = 0
* Auto Mute = 1
*/
- if (emu->audigy) {
+ } else if (emu->audigy) {
if (emu->revision == 4) /* audigy2 */
outl(HCFG_AUDIOENABLE |
HCFG_AC3ENABLE_CDSPDIF |
@@ -265,8 +303,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
if (enable_ir) { /* enable IR for SB Live */
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
unsigned int reg = inl(emu->port + A_IOCFG);
outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
@@ -284,8 +324,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
}
}
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) { /* enable analog output */
unsigned int reg = inl(emu->port + A_IOCFG);
outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
@@ -302,8 +344,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
/* Enable analog/digital outs on audigy */
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
@@ -596,133 +640,423 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
return 0;
}
-static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename)
{
- if (reg<0 || reg>0x3f)
- return 1;
- reg+=0x40; /* 0x40 upwards are registers. */
- if (value<0 || value>0x3f) /* 0 to 0x3f are values */
- return 1;
- outl(reg, emu->port + A_IOCFG);
- outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
- outl(value, emu->port + A_IOCFG);
- outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
-
- return 0;
-}
-
-static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
-{
- if (reg<0 || reg>0x3f)
- return 1;
- reg+=0x40; /* 0x40 upwards are registers. */
- outl(reg, emu->port + A_IOCFG);
- outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
- *value = inl(emu->port + A_IOCFG);
-
- return 0;
-}
+ int err;
+ int n, i;
+ int reg;
+ int value;
+ const struct firmware *fw_entry;
+
+ if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
+ snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err);
+ return err;
+ }
+ snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+ if (fw_entry->size != 0x133a4) {
+ snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
+ return -EINVAL;
+ }
-static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value)
-{
- snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) );
+ /* The FPGA is a Xilinx Spartan IIE XC2S50E */
+ /* GPIO7 -> FPGA PGMN
+ * GPIO6 -> FPGA CCLK
+ * GPIO5 -> FPGA DIN
+ * FPGA CONFIG OFF -> FPGA PGMN
+ */
+ outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */
+ udelay(1);
+ outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
+ udelay(100); /* Allow FPGA memory to clean */
+ for(n = 0; n < fw_entry->size; n++) {
+ value=fw_entry->data[n];
+ for(i = 0; i < 8; i++) {
+ reg = 0x80;
+ if (value & 0x1)
+ reg = reg | 0x20;
+ value = value >> 1;
+ outl(reg, emu->port + A_IOCFG);
+ outl(reg | 0x40, emu->port + A_IOCFG);
+ }
+ }
+ /* After programming, set GPIO bit 4 high again. */
+ outl(0x10, emu->port + A_IOCFG);
+
+ release_firmware(fw_entry);
return 0;
}
-static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
{
unsigned int i;
- int tmp;
-
- snd_printk(KERN_ERR "emu1212m: Special config.\n");
+ int tmp,tmp2;
+ int reg;
+ int err;
+ const char *hana_filename = "emu/hana.fw";
+ const char *dock_filename = "emu/audio_dock.fw";
+
+ snd_printk(KERN_INFO "emu1010: Special config.\n");
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
outl(0x0005a00c, emu->port + HCFG);
- outl(0x0005a004, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
+ outl(0x0005a004, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Mute all codecs.
+ */
outl(0x0005a000, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Mute all codecs.
+ */
outl(0x0005a000, emu->port + HCFG);
- snd_emu1212m_fpga_read(emu, 0x22, &tmp );
- snd_emu1212m_fpga_read(emu, 0x23, &tmp );
- snd_emu1212m_fpga_read(emu, 0x24, &tmp );
- snd_emu1212m_fpga_write(emu, 0x04, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x0b, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0b, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x10, &tmp );
- snd_emu1212m_fpga_write(emu, 0x10, 0x00 );
- snd_emu1212m_fpga_read(emu, 0x11, &tmp );
- snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
- snd_emu1212m_fpga_read(emu, 0x13, &tmp );
- snd_emu1212m_fpga_write(emu, 0x13, 0x0f );
- snd_emu1212m_fpga_read(emu, 0x11, &tmp );
- snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
- snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_write(emu, 0x09, 0x0f );
- snd_emu1212m_fpga_write(emu, 0x06, 0x00 );
- snd_emu1212m_fpga_write(emu, 0x05, 0x00 );
- snd_emu1212m_fpga_write(emu, 0x0e, 0x12 );
- snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200);
- snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201);
- snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500);
- snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501);
- snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400);
- snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401);
- snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402);
- snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403);
- snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404);
- snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405);
- snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406);
- snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407);
- snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100);
- snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104);
- snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200);
- snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201);
- for (i=0;i < 0x20;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000);
+ /* Disable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+
+ /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printdd("reg1=0x%x\n",reg);
+ if (reg == 0x55) {
+ /* FPGA netlist already present so clear it */
+ /* Return to programming mode */
+
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 );
}
- for (i=0;i < 4;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printdd("reg2=0x%x\n",reg);
+ if (reg == 0x55) {
+ /* FPGA failed to return to programming mode */
+ return -ENODEV;
}
- for (i=0;i < 7;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000);
+ snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
+ if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) {
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename);
+ return err;
}
- for (i=0;i < 7;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000);
+
+ /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ if (reg != 0x55) {
+ /* FPGA failed to be programmed */
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
+ return -ENODEV;
}
- snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108);
- snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c);
- snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110);
- snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114);
- snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118);
- snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c);
- snd_emu1212m_fpga_write(emu, 0x07, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+ snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
+ snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 );
+ snd_printk("Hana ver:%d.%d\n",tmp ,tmp2);
+ /* Enable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON );
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp );
+ /* ADAT input. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp );
+ /* Set no attenuation on Audio Dock pads. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 );
+ emu->emu1010.adc_pads = 0x00;
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+ /* Unmute Audio dock DACs, Headphone source DAC-4. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp );
+ /* DAC PADs. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f );
+ emu->emu1010.dac_pads = 0x0f;
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+ /* SPDIF Format. Set Consumer mode, 24bit, copy enable */
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 );
+ /* MIDI routing */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 );
+ /* Unknown. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c );
+ /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */
+ /* IRQ Enable: All off */
+ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 );
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg);
+ /* Default WCLK set to 48kHz. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 );
+ /* Word Clock source, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+ //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ /* Audio Dock LEDs. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
- outl(0x0000a000, emu->port + HCFG);
+#if 0
+ /* For 96kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2);
+#endif
+#if 0
+ /* For 192kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4);
+#endif
+#if 1
+ /* For 48kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+#endif
+#if 0
+ /* Original */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
+#endif
+ for (i = 0;i < 0x20; i++ ) {
+ /* AudioDock Elink <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 4; i++) {
+ /* Hana SPDIF Out <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 7; i++) {
+ /* Hamoa DAC <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 7; i++) {
+ /* Hana ADAT Out <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
+ }
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+
+ /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
+ outl(0x0000a000, emu->port + HCFG);
+ /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Un-Mute all codecs.
+ */
outl(0x0000a001, emu->port + HCFG);
+
/* Initial boot complete. Now patches */
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
-
- snd_emu1212m_fpga_read(emu, 0x20, &tmp );
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
-
- snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312);
- snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313);
- snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302);
- snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */
+
+ /* Delay to allow Audio Dock to settle */
+ msleep(100);
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+ /* FIXME: The loading of this should be able to happen any time,
+ * as the user can plug/unplug it at any time
+ */
+ if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) {
+ /* Audio Dock attached */
+ /* Return to Audio Dock programming mode */
+ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
+ if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) {
+ return err;
+ }
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+ /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+ if (reg != 0x55) {
+ /* FPGA failed to be programmed */
+ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
+ return 0;
+ return -ENODEV;
+ }
+ snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
+ snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+ }
+#if 0
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */
+#endif
+ /* Default outputs */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[0] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[1] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
+ emu->emu1010.output_source[2] = 23;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
+ emu->emu1010.output_source[3] = 24;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
+ emu->emu1010.output_source[4] = 25;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
+ emu->emu1010.output_source[5] = 26;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
+ emu->emu1010.output_source[6] = 27;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
+ emu->emu1010.output_source[7] = 28;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[8] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[9] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[10] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[11] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[12] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[13] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[14] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[15] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[16] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[17] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
+ emu->emu1010.output_source[18] = 23;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
+ emu->emu1010.output_source[19] = 24;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
+ emu->emu1010.output_source[20] = 25;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
+ emu->emu1010.output_source[21] = 26;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
+ emu->emu1010.output_source[22] = 27;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
+ emu->emu1010.output_source[23] = 28;
+
+ /* TEMP: Select SPDIF in/out */
+ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
+
+ /* TEMP: Select 48kHz SPDIF out */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */
+ /* Word Clock source, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+ //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ emu->emu1010.internal_clock = 1; /* 48000 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */
+ //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */
+ //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */
+ //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */
return 0;
}
@@ -747,6 +1081,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
}
snd_emu10k1_free_efx(emu);
}
+ if (emu->card_capabilities->emu1010) {
+ /* Disable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+ }
if (emu->memhdr)
snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
@@ -838,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
.ac97_chip = 1} ,
/* Audigy 2 ZS Notebook Cardbus card.*/
- /* Tested by James@superbug.co.uk 22th December 2005 */
+ /* Tested by James@superbug.co.uk 6th November 2006 */
/* Audio output 7.1/Headphones working.
* Digital output working. (AC3 not checked, only PCM)
- * Audio inputs not tested.
+ * Audio Mic/Line inputs working.
+ * Digital input not tested.
*/
/* DSP: Tina2
* DAC: Wolfson WM8768/WM8568
@@ -849,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = {
* AC97: None
* CA0151: None
*/
+ /* Tested by James@superbug.co.uk 4th April 2006 */
+ /* A_IOCFG bits
+ * Output
+ * 0: Not Used
+ * 1: 0 = Mute all the 7.1 channel out. 1 = unmute.
+ * 2: Analog input 0 = line in, 1 = mic in
+ * 3: Not Used
+ * 4: Digital output 0 = off, 1 = on.
+ * 5: Not Used
+ * 6: Not Used
+ * 7: Not Used
+ * Input
+ * All bits 1 (0x3fxx) means nothing plugged in.
+ * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing.
+ * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing.
+ * C-D: 2 = Front/Rear/etc, 3 = nothing.
+ * E-F: Always 0
+ *
+ */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
.driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
.id = "Audigy2",
@@ -856,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ca0108_chip = 1,
.ca_cardbus_chip = 1,
.spi_dac = 1,
+ .i2c_adc = 1,
.spk71 = 1} ,
{.vendor = 0x1102, .device = 0x0008,
.driver = "Audigy2", .name = "Audigy 2 Value [Unknown]",
@@ -865,11 +1224,12 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ac97_chip = 1} ,
/* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
- .driver = "Audigy2", .name = "E-mu 1212m [4001]",
- .id = "EMU1212m",
+ .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+ .id = "EMU1010",
.emu10k2_chip = 1,
.ca0102_chip = 1,
- .emu1212m = 1} ,
+ .spk71 = 1,
+ .emu1010 = 1} ,
/* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
.driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]",
@@ -1297,8 +1657,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
} else if (emu->card_capabilities->ca_cardbus_chip) {
if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
goto error;
- } else if (emu->card_capabilities->emu1212m) {
- if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) {
+ } else if (emu->card_capabilities->emu1010) {
+ if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
snd_emu10k1_free(emu);
return err;
}
@@ -1446,8 +1806,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
snd_emu10k1_ecard_init(emu);
else if (emu->card_capabilities->ca_cardbus_chip)
snd_emu10k1_cardbus_init(emu);
- else if (emu->card_capabilities->emu1212m)
- snd_emu10k1_emu1212m_init(emu);
+ else if (emu->card_capabilities->emu1010)
+ snd_emu10k1_emu1010_init(emu);
else
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
snd_emu10k1_init(emu, emu->enable_ir, 1);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 2199b42a6019..bb0fec7f7e1b 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream)
u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
int i;
- for(i=0; i < runtime->periods; i++) {
+ for(i = 0; i < runtime->periods; i++) {
*table_base++=runtime->dma_addr+(i*period_size_bytes);
*table_base++=period_size_bytes<<16;
}
@@ -1042,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
continue;
- if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff)
- && (channel_id >=0) && (channel_id <= 2) )
+ if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff)
+ && (channel_id >= 0) && (channel_id <= 2) )
snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
}
}
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 13cd6ce89811..c02012cccd8e 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -3,6 +3,9 @@
* Creative Labs, Inc.
* Routines for effect processor FX8010
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -293,7 +296,7 @@ static const u32 db_table[101] = {
};
/* EMU10k1/EMU10k2 DSP control db gain */
-static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
static const u32 onoff_table[2] = {
0x00000000, 0x00000001
@@ -652,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
return NULL;
}
+#define MAX_TLV_SIZE 256
+
+static unsigned int *copy_tlv(const unsigned int __user *_tlv)
+{
+ unsigned int data[2];
+ unsigned int *tlv;
+
+ if (!_tlv)
+ return NULL;
+ if (copy_from_user(data, _tlv, sizeof(data)))
+ return NULL;
+ if (data[1] >= MAX_TLV_SIZE)
+ return NULL;
+ tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
+ if (!tlv)
+ return NULL;
+ memcpy(tlv, data, sizeof(data));
+ if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
+ kfree(tlv);
+ return NULL;
+ }
+ return tlv;
+}
+
+static int copy_gctl(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_fx8010_control_gpr *gctl,
+ struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+ int idx)
+{
+ struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+ if (emu->support_tlv)
+ return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
+ octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+ if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
+ return -EFAULT;
+ gctl->tlv = NULL;
+ return 0;
+}
+
+static int copy_gctl_to_user(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+ struct snd_emu10k1_fx8010_control_gpr *gctl,
+ int idx)
+{
+ struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+ if (emu->support_tlv)
+ return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
+
+ octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+ return copy_to_user(&octl[idx], gctl, sizeof(*octl));
+}
+
static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_code *icode)
{
unsigned int i;
struct snd_ctl_elem_id __user *_id;
struct snd_ctl_elem_id id;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_control_gpr *gctl;
int err;
@@ -673,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
if (! gctl)
return -ENOMEM;
err = 0;
- for (i = 0, _gctl = icode->gpr_add_controls;
- i < icode->gpr_add_control_count; i++, _gctl++) {
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ for (i = 0; i < icode->gpr_add_control_count; i++) {
+ if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -694,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
goto __error;
}
}
- for (i = 0, _gctl = icode->gpr_list_controls;
- i < icode->gpr_list_control_count; i++, _gctl++) {
+ for (i = 0; i < icode->gpr_list_control_count; i++) {
/* FIXME: we need to check the WRITE access */
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -715,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
kctl->private_value = 0;
list_del(&ctl->list);
kfree(ctl);
+ if (kctl->tlv.p)
+ kfree(kctl->tlv.p);
}
static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_code *icode)
{
unsigned int i, j;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_control_gpr *gctl;
struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
struct snd_kcontrol_new knew;
@@ -737,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
goto __error;
}
- for (i = 0, _gctl = icode->gpr_add_controls;
- i < icode->gpr_add_control_count; i++, _gctl++) {
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ for (i = 0; i < icode->gpr_add_control_count; i++) {
+ if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -760,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
knew.device = gctl->id.device;
knew.subdevice = gctl->id.subdevice;
knew.info = snd_emu10k1_gpr_ctl_info;
- if (gctl->tlv.p) {
- knew.tlv.p = gctl->tlv.p;
+ knew.tlv.p = copy_tlv(gctl->tlv);
+ if (knew.tlv.p)
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
- }
knew.get = snd_emu10k1_gpr_ctl_get;
knew.put = snd_emu10k1_gpr_ctl_put;
memset(nctl, 0, sizeof(*nctl));
@@ -782,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
if (ctl == NULL) {
err = -ENOMEM;
+ kfree(knew.tlv.p);
goto __error;
}
knew.private_value = (unsigned long)ctl;
*ctl = *nctl;
if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
kfree(ctl);
+ kfree(knew.tlv.p);
goto __error;
}
kctl->private_free = snd_emu10k1_ctl_private_free;
@@ -838,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
unsigned int i = 0, j;
unsigned int total = 0;
struct snd_emu10k1_fx8010_control_gpr *gctl;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_ctl *ctl;
struct snd_ctl_elem_id *id;
struct list_head *list;
@@ -847,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
if (! gctl)
return -ENOMEM;
- _gctl = icode->gpr_list_controls;
list_for_each(list, &emu->fx8010.gpr_ctl) {
ctl = emu10k1_gpr_ctl(list);
total++;
- if (_gctl && i < icode->gpr_list_control_count) {
+ if (icode->gpr_list_controls &&
+ i < icode->gpr_list_control_count) {
memset(gctl, 0, sizeof(*gctl));
id = &ctl->kcontrol->id;
gctl->id.iface = id->iface;
@@ -868,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
gctl->min = ctl->min;
gctl->max = ctl->max;
gctl->translation = ctl->translation;
- if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
+ if (copy_gctl_to_user(emu, icode->gpr_list_controls,
+ gctl, i)) {
kfree(gctl);
return -EFAULT;
}
- _gctl++;
i++;
}
}
@@ -1023,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
ctl->min = 0;
ctl->max = 100;
- ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->tlv = snd_emu10k1_db_scale1;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
}
@@ -1038,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
ctl->min = 0;
ctl->max = 100;
- ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->tlv = snd_emu10k1_db_scale1;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
}
@@ -1069,6 +1123,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
}
+static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+ struct snd_emu10k1_fx8010_code *icode,
+ u32 *ptr, int tmp, int bit_shifter16,
+ int reg_in, int reg_out)
+{
+ A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
+ A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
+ A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
+ A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
+ A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
+ return 1;
+}
/*
* initial DSP configuration for Audigy
@@ -1077,6 +1146,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
{
int err, i, z, gpr, nctl;
+ int bit_shifter16;
const int playback = 10;
const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
const int stereo_mix = capture + 2;
@@ -1114,17 +1184,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
ptr = 0;
nctl = 0;
gpr = stereo_mix + 10;
+ gpr_map[gpr++] = 0x00007fff;
+ gpr_map[gpr++] = 0x00008000;
+ gpr_map[gpr++] = 0x0000ffff;
+ bit_shifter16 = gpr;
/* stop FX processor */
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
-#if 0
- /* FIX: jcd test */
- for (z = 0; z < 80; z=z+2) {
- A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
- A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
- }
-#endif /* jcd test */
#if 1
/* PCM front Playback Volume (independent from stereo mix) */
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
@@ -1182,13 +1249,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
gpr += 2;
-
+
/*
* inputs
*/
#define A_ADD_VOLUME_IN(var,vol,input) \
A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
+ /* emu1212 DSP 0 and DSP 1 Capture */
+ if (emu->card_capabilities->emu1010) {
+ A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
+ A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
+ gpr += 2;
+ }
/* AC'97 Playback Volume - used only for mic (renamed later) */
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
@@ -1429,6 +1503,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/* digital outputs */
/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
+ if (emu->card_capabilities->emu1010) {
+ /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
+ snd_printk("EMU outputs on\n");
+ for (z = 0; z < 8; z++) {
+ A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
+ }
+ }
/* IEC958 Optical Raw Playback Switch */
gpr_map[gpr++] = 0;
@@ -1466,9 +1547,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
#endif
- /* EFX capture - capture the 16 EXTINs */
- for (z = 0; z < 16; z++) {
- A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+ if (emu->card_capabilities->emu1010) {
+ snd_printk("EMU inputs on\n");
+ /* Capture 8 channels of S32_LE sound */
+
+ /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
+ /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
+ /* A_P16VIN(0) is delayed by one sample,
+ * so all other A_P16VIN channels will need to also be delayed
+ */
+ /* Left ADC in. 1 of 2 */
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
+ /* Right ADC in 1 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
+ /* For 96kHz mode */
+ /* Left ADC in. 2 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
+ /* Right ADC in 2 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+
+#if 0
+ for (z = 4; z < 8; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+ }
+ for (z = 0xc; z < 0x10; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+ }
+#endif
+ } else {
+ /* EFX capture - capture the 16 EXTINs */
+ /* Capture 16 channels of S16_LE sound */
+ for (z = 0; z < 16; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+ }
}
#endif /* JCD test */
@@ -1488,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
seg = snd_enter_user();
icode->gpr_add_control_count = nctl;
icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+ emu->support_tlv = 1; /* support TLV */
err = snd_emu10k1_icode_poke(emu, icode);
+ emu->support_tlv = 0; /* clear again */
snd_leave_user(seg);
__err:
@@ -2105,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
seg = snd_enter_user();
icode->gpr_add_control_count = i;
icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+ emu->support_tlv = 1; /* support TLV */
err = snd_emu10k1_icode_poke(emu, icode);
+ emu->support_tlv = 0; /* clear again */
snd_leave_user(seg);
if (err >= 0)
err = snd_emu10k1_ipcm_poke(emu, ipcm);
@@ -2138,7 +2271,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
}
-#if 0 // FIXME: who use them?
+#if 0 /* FIXME: who use them? */
int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
{
if (output < 0 || output >= 6)
@@ -2249,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un
int res;
switch (cmd) {
+ case SNDRV_EMU10K1_IOCTL_PVERSION:
+ emu->support_tlv = 1;
+ return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
case SNDRV_EMU10K1_IOCTL_INFO:
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index c31f3d0877fa..4db6e1ca1665 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -5,6 +5,9 @@
* Routines for control of EMU10K1 chips / mixer routines
* Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -32,9 +35,15 @@
#include <linux/init.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include <linux/delay.h>
+#include <sound/tlv.h>
+
+#include "p17v.h"
#define AC97_ID_STAC9758 0x83847658
+static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
+
static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -68,6 +77,669 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
return 0;
}
+static char *emu1010_src_texts[] = {
+ "Silence",
+ "Dock Mic A",
+ "Dock Mic B",
+ "Dock ADC1 Left",
+ "Dock ADC1 Right",
+ "Dock ADC2 Left",
+ "Dock ADC2 Right",
+ "Dock ADC3 Left",
+ "Dock ADC3 Right",
+ "0202 ADC Left",
+ "0202 ADC Right",
+ "0202 SPDIF Left",
+ "0202 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",
+};
+
+static unsigned int emu1010_src_regs[] = {
+ EMU_SRC_SILENCE,/* 0 */
+ EMU_SRC_DOCK_MIC_A1, /* 1 */
+ EMU_SRC_DOCK_MIC_B1, /* 2 */
+ EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
+ EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
+ EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
+ EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
+ EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
+ EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
+ EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
+ EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
+ EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
+ EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
+ EMU_SRC_HANA_ADAT, /* 13 */
+ EMU_SRC_HANA_ADAT+1, /* 14 */
+ EMU_SRC_HANA_ADAT+2, /* 15 */
+ EMU_SRC_HANA_ADAT+3, /* 16 */
+ EMU_SRC_HANA_ADAT+4, /* 17 */
+ EMU_SRC_HANA_ADAT+5, /* 18 */
+ EMU_SRC_HANA_ADAT+6, /* 19 */
+ EMU_SRC_HANA_ADAT+7, /* 20 */
+ EMU_SRC_ALICE_EMU32A, /* 21 */
+ EMU_SRC_ALICE_EMU32A+1, /* 22 */
+ EMU_SRC_ALICE_EMU32A+2, /* 23 */
+ EMU_SRC_ALICE_EMU32A+3, /* 24 */
+ EMU_SRC_ALICE_EMU32A+4, /* 25 */
+ EMU_SRC_ALICE_EMU32A+5, /* 26 */
+ EMU_SRC_ALICE_EMU32A+6, /* 27 */
+ EMU_SRC_ALICE_EMU32A+7, /* 28 */
+ EMU_SRC_ALICE_EMU32A+8, /* 29 */
+ EMU_SRC_ALICE_EMU32A+9, /* 30 */
+ EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
+ EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
+ EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
+ EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
+ EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
+ EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
+ EMU_SRC_ALICE_EMU32B, /* 37 */
+ EMU_SRC_ALICE_EMU32B+1, /* 38 */
+ EMU_SRC_ALICE_EMU32B+2, /* 39 */
+ EMU_SRC_ALICE_EMU32B+3, /* 40 */
+ EMU_SRC_ALICE_EMU32B+4, /* 41 */
+ EMU_SRC_ALICE_EMU32B+5, /* 42 */
+ EMU_SRC_ALICE_EMU32B+6, /* 43 */
+ EMU_SRC_ALICE_EMU32B+7, /* 44 */
+ EMU_SRC_ALICE_EMU32B+8, /* 45 */
+ EMU_SRC_ALICE_EMU32B+9, /* 46 */
+ EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
+ EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
+ EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
+ EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
+ EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
+ EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
+};
+
+static unsigned int emu1010_output_dst[] = {
+ EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
+ EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
+ EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
+ EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
+ EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
+ EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
+ EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
+ EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
+ EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
+ EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
+ EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
+ EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
+ EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
+ EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
+ EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
+ EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
+ EMU_DST_HANA_ADAT, /* 16 */
+ EMU_DST_HANA_ADAT+1, /* 17 */
+ EMU_DST_HANA_ADAT+2, /* 18 */
+ EMU_DST_HANA_ADAT+3, /* 19 */
+ EMU_DST_HANA_ADAT+4, /* 20 */
+ EMU_DST_HANA_ADAT+5, /* 21 */
+ EMU_DST_HANA_ADAT+6, /* 22 */
+ EMU_DST_HANA_ADAT+7, /* 23 */
+};
+
+static unsigned int emu1010_input_dst[] = {
+ EMU_DST_ALICE2_EMU32_0,
+ EMU_DST_ALICE2_EMU32_1,
+ EMU_DST_ALICE2_EMU32_2,
+ EMU_DST_ALICE2_EMU32_3,
+ EMU_DST_ALICE2_EMU32_4,
+ EMU_DST_ALICE2_EMU32_5,
+ EMU_DST_ALICE2_EMU32_6,
+ EMU_DST_ALICE2_EMU32_7,
+ EMU_DST_ALICE2_EMU32_8,
+ EMU_DST_ALICE2_EMU32_9,
+ EMU_DST_ALICE2_EMU32_A,
+ EMU_DST_ALICE2_EMU32_B,
+ EMU_DST_ALICE2_EMU32_C,
+ EMU_DST_ALICE2_EMU32_D,
+ EMU_DST_ALICE2_EMU32_E,
+ EMU_DST_ALICE2_EMU32_F,
+ EMU_DST_ALICE_I2S0_LEFT,
+ EMU_DST_ALICE_I2S0_RIGHT,
+ EMU_DST_ALICE_I2S1_LEFT,
+ EMU_DST_ALICE_I2S1_RIGHT,
+ EMU_DST_ALICE_I2S2_LEFT,
+ EMU_DST_ALICE_I2S2_RIGHT,
+};
+
+static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 53;
+ 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]);
+ return 0;
+}
+
+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;
+
+ channel = (kcontrol->private_value) & 0xff;
+ ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
+ return 0;
+}
+
+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;
+
+ 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;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1010_output_dst[channel], emu1010_src_regs[val]);
+ }
+ return change;
+}
+
+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;
+
+ channel = (kcontrol->private_value) & 0xff;
+ ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
+ return 0;
+}
+
+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;
+
+ 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;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1010_input_dst[channel], emu1010_src_regs[val]);
+ }
+ return change;
+}
+
+#define EMU1010_SOURCE_OUTPUT(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_input_output_source_info, \
+ .get = snd_emu1010_output_source_get, \
+ .put = snd_emu1010_output_source_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
+ 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 DAC4 Left Playback Enum", 6),
+ EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
+ EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
+ EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
+ EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
+ EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
+ EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
+ EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
+};
+
+#define EMU1010_SOURCE_INPUT(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_input_output_source_info, \
+ .get = snd_emu1010_input_source_get, \
+ .put = snd_emu1010_input_source_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
+ EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
+ EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
+ EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
+ EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
+ EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
+ EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
+ EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
+ EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
+ EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
+ EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
+ EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
+ EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
+ EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
+ EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
+ EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
+ EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
+ EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
+ EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
+ EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
+ EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
+ EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
+ EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
+};
+
+
+
+
+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;
+}
+
+static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
+ return 0;
+}
+
+static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int val, cache;
+ val = ucontrol->value.integer.value[0];
+ cache = emu->emu1010.adc_pads;
+ if (val == 1)
+ cache = cache | mask;
+ else
+ cache = cache & ~mask;
+ if (cache != emu->emu1010.adc_pads) {
+ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+ emu->emu1010.adc_pads = cache;
+ }
+
+ return 0;
+}
+
+
+
+#define EMU1010_ADC_PADS(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_adc_pads_info, \
+ .get = snd_emu1010_adc_pads_get, \
+ .put = snd_emu1010_adc_pads_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
+ 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;
+}
+
+static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
+ return 0;
+}
+
+static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int val, cache;
+ val = ucontrol->value.integer.value[0];
+ cache = emu->emu1010.dac_pads;
+ if (val == 1)
+ cache = cache | mask;
+ else
+ cache = cache & ~mask;
+ if (cache != emu->emu1010.dac_pads) {
+ snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+ emu->emu1010.dac_pads = cache;
+ }
+
+ return 0;
+}
+
+
+
+#define EMU1010_DAC_PADS(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_dac_pads_info, \
+ .get = snd_emu1010_dac_pads_get, \
+ .put = snd_emu1010_dac_pads_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
+ 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),
+ EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
+ EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
+};
+
+
+static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[2] = {
+ "44100", "48000"
+ };
+
+ 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;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
+ return 0;
+}
+
+static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.enumerated.item[0] ;
+ change = (emu->emu1010.internal_clock != val);
+ if (change) {
+ emu->emu1010.internal_clock = val;
+ switch (val) {
+ case 0:
+ /* 44100 */
+ /* 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_44_1K );
+ /* Word Clock source, Internal 44.1kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+ EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ break;
+ case 1:
+ /* 48000 */
+ /* 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, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+ EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ break;
+ }
+ }
+ return change;
+}
+
+static struct snd_kcontrol_new snd_emu1010_internal_clock =
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Internal Rate",
+ .count = 1,
+ .info = snd_emu1010_internal_clock_info,
+ .get = snd_emu1010_internal_clock_get,
+ .put = snd_emu1010_internal_clock_put
+};
+
+static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+#if 0
+ static char *texts[4] = {
+ "Unknown1", "Unknown2", "Mic", "Line"
+ };
+#endif
+ static char *texts[2] = {
+ "Mic", "Line"
+ };
+
+ 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;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
+ return 0;
+}
+
+static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int source_id;
+ unsigned int ngain, ogain;
+ u32 gpio;
+ int change = 0;
+ unsigned long flags;
+ u32 source;
+ /* If the capture source has changed,
+ * update the capture volume from the cached value
+ * for the particular source.
+ */
+ source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
+ change = (emu->i2c_capture_source != source_id);
+ if (change) {
+ snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ gpio = inl(emu->port + A_IOCFG);
+ if (source_id==0)
+ outl(gpio | 0x4, emu->port + A_IOCFG);
+ else
+ outl(gpio & ~0x4, emu->port + A_IOCFG);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+
+ ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+ if (ngain != ogain)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
+ ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
+ if (ngain != ogain)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+
+ source = 1 << (source_id + 2);
+ snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
+ emu->i2c_capture_source = source_id;
+ }
+ return change;
+}
+
+static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_audigy_i2c_capture_source_info,
+ .get = snd_audigy_i2c_capture_source_get,
+ .put = snd_audigy_i2c_capture_source_put
+};
+
+static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 255;
+ return 0;
+}
+
+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;
+
+ source_id = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
+ ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
+ return 0;
+}
+
+static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int ogain;
+ unsigned int ngain;
+ int source_id;
+ int change = 0;
+
+ source_id = kcontrol->private_value;
+ ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ngain = ucontrol->value.integer.value[0];
+ if (ngain > 0xff)
+ return 0;
+ 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];
+ change = 1;
+ }
+ ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
+ ngain = ucontrol->value.integer.value[1];
+ if (ngain > 0xff)
+ return 0;
+ 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];
+ change = 1;
+ }
+
+ return change;
+}
+
+#define I2C_VOLUME(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_audigy_i2c_volume_info, \
+ .get = snd_audigy_i2c_volume_get, \
+ .put = snd_audigy_i2c_volume_put, \
+ .tlv = { .p = snd_audigy_db_scale2 }, \
+ .private_value = chid \
+}
+
+
+static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
+ I2C_VOLUME("Mic Capture Volume", 0),
+ I2C_VOLUME("Line Capture Volume", 0)
+};
+
#if 0
static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -668,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
int change = 0;
spin_lock_irqsave(&emu->reg_lock, flags);
- if (emu->audigy) {
+ 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;
change = (reg & A_IOCFG_GPOUT0) != val;
@@ -806,6 +1480,24 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"AMic Playback Volume", "Mic Playback Volume",
NULL
};
+ static char *audigy_rename_ctls_i2c_adc[] = {
+ //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
+ "Line Capture Volume", "Analog Mix Capture Volume",
+ "Wave Playback Volume", "OLD PCM Playback Volume",
+ "Wave Master Playback Volume", "Master Playback Volume",
+ "AMic Playback Volume", "Old Mic Playback Volume",
+ "CD Capture Volume", "IEC958 Optical Capture Volume",
+ NULL
+ };
+ static char *audigy_remove_ctls_i2c_adc[] = {
+ /* On the Audigy2 ZS Notebook
+ * Capture via WM8775 */
+ "Mic Capture Volume",
+ "Analog Mix Capture Volume",
+ "Aux Capture Volume",
+ "IEC958 Optical Capture Volume",
+ NULL
+ };
static char *audigy_remove_ctls_1361t_adc[] = {
/* On the Audigy2 the AC97 playback is piped into
* the Philips ADC for 24bit capture */
@@ -890,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if (emu->ac97->id == AC97_ID_STAC9758) {
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 unused AC97 controls */
snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -898,6 +1591,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
}
for (; *c; c++)
remove_ctl(card, *c);
+ } else if (emu->card_capabilities->i2c_adc) {
+ c = audigy_remove_ctls_i2c_adc;
+ for (; *c; c++)
+ remove_ctl(card, *c);
} else {
no_ac97:
if (emu->card_capabilities->ecard)
@@ -911,6 +1608,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if (emu->audigy)
if (emu->card_capabilities->adc_1361t)
c = audigy_rename_ctls_1361t_adc;
+ else if (emu->card_capabilities->i2c_adc)
+ c = audigy_rename_ctls_i2c_adc;
else
c = audigy_rename_ctls;
else
@@ -1021,7 +1720,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
return err;
}
- if ( emu->card_capabilities->emu1212m) {
+ if ( emu->card_capabilities->emu1010) {
; /* Disable the snd_audigy_spdif_shared_spdif */
} else if (emu->audigy) {
if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1045,6 +1744,48 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if ((err = snd_p16v_mixer(emu)))
return err;
}
+
+ if ( emu->card_capabilities->emu1010) {
+ 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));
+ 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); 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); 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;
+ }
+
+ if ( emu->card_capabilities->i2c_adc) {
+ int i;
+
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 717e92ec9e0a..ab4f5df5241b 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
1,
&epcm->extra);
if (err < 0) {
- // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame);
+ /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */
for (i = 0; i < voices; i++) {
snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
epcm->voices[i] = NULL;
@@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
}
}
- // setup routing
+ /* setup routing */
if (emu->audigy) {
snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
snd_emu10k1_compose_audigy_fxrt1(send_routing));
@@ -353,12 +353,15 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
} else
snd_emu10k1_ptr_write(emu, FXRT, voice,
snd_emu10k1_compose_send_routing(send_routing));
- // Stop CA
- // Assumption that PT is already 0 so no harm overwriting
+ /* Stop CA */
+ /* Assumption that PT is already 0 so no harm overwriting */
snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+ if (emu->card_capabilities->emu1010)
+ pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+ else
+ pitch_target = emu10k1_calc_pitch_target(runtime->rate);
if (extra)
snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr |
emu10k1_select_interprom(pitch_target) |
@@ -367,14 +370,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) |
emu10k1_select_interprom(pitch_target) |
(w_16 ? 0 : CCCA_8BITSELECT));
- // Clear filter delay memory
+ /* Clear filter delay memory */
snd_emu10k1_ptr_write(emu, Z1, voice, 0);
snd_emu10k1_ptr_write(emu, Z2, voice, 0);
- // invalidate maps
+ /* invalidate maps */
silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
- // modulation envelope
+ /* modulation envelope */
snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff);
snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff);
snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0);
@@ -385,12 +388,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0);
snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0);
snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000);
- // volume envelope
+ /* volume envelope */
snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f);
snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000);
- // filter envelope
+ /* filter envelope */
snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f);
- // pitch envelope
+ /* pitch envelope */
snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0);
spin_unlock_irqrestore(&emu->reg_lock, flags);
@@ -468,7 +471,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream)
snd_emu10k1_voice_free(epcm->emu, epcm->extra);
epcm->extra = NULL;
}
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
if (epcm->voices[i]) {
snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
epcm->voices[i] = NULL;
@@ -637,7 +640,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
stereo = (!extra && runtime->channels == 2);
sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;
ccis = emu10k1_ccis(stereo, sample == 0);
- // set cs to 2 * number of cache registers beside the invalidated
+ /* set cs to 2 * number of cache registers beside the invalidated */
cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;
if (cs > 16) cs = 16;
for (i = 0; i < cs; i++) {
@@ -646,14 +649,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);
}
}
- // reset cache
+ /* reset cache */
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);
snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
if (stereo) {
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
}
- // fill cache
+ /* fill cache */
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
if (stereo) {
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
@@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s
voice = evoice->number;
pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+ if (emu->card_capabilities->emu1010)
+ pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+ else
+ pitch_target = emu10k1_calc_pitch_target(runtime->rate);
snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
if (master || evoice->epcm->type == PLAYBACK_EFX)
snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
@@ -732,7 +738,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
struct snd_emu10k1_pcm_mixer *mix;
int result = 0;
- // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));
+ /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */
spin_lock(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -778,10 +784,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- // hmm this should cause full and half full interrupt to be raised?
+ /* hmm this should cause full and half full interrupt to be raised? */
outl(epcm->capture_ipr, emu->port + IPR);
snd_emu10k1_intr_enable(emu, epcm->capture_inte);
- // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs);
+ /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */
switch (epcm->type) {
case CAPTURE_AC97ADC:
snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
@@ -790,6 +796,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
if (emu->audigy) {
snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
+ snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2);
} else
snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
break;
@@ -851,7 +858,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
ptr -= runtime->buffer_size;
}
#endif
- // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size);
+ /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */
return ptr;
}
@@ -868,7 +875,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
spin_lock(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- // prepare voices
+ /* prepare voices */
for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);
}
@@ -917,7 +924,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s
if (!epcm->running)
return 0;
if (epcm->first_ptr) {
- udelay(50); // hack, it takes awhile until capture is started
+ udelay(50); /* hack, it takes awhile until capture is started */
epcm->first_ptr = 0;
}
ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
@@ -972,6 +979,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture =
.fifo_size = 0,
};
+static struct snd_pcm_hardware snd_emu10k1_capture_efx =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .rate_min = 44100,
+ .rate_max = 192000,
+ .channels_min = 8,
+ .channels_max = 8,
+ .buffer_bytes_max = (64*1024),
+ .period_bytes_min = 384,
+ .period_bytes_max = (64*1024),
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0,
+};
+
/*
*
*/
@@ -1016,7 +1045,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream)
struct snd_emu10k1_pcm_mixer *mix;
int i;
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
mix = &emu->efx_pcm_mixer[i];
mix->epcm = NULL;
snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
@@ -1045,7 +1074,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_efx_playback;
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
mix = &emu->efx_pcm_mixer[i];
mix->send_routing[0][0] = i;
memset(&mix->send_volume, 0, sizeof(mix->send_volume));
@@ -1199,15 +1228,69 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
epcm->capture_idx_reg = FXIDX;
substream->runtime->private_data = epcm;
substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
- runtime->hw = snd_emu10k1_capture;
+ runtime->hw = snd_emu10k1_capture_efx;
runtime->hw.rates = SNDRV_PCM_RATE_48000;
runtime->hw.rate_min = runtime->hw.rate_max = 48000;
spin_lock_irq(&emu->reg_lock);
- runtime->hw.channels_min = runtime->hw.channels_max = 0;
- for (idx = 0; idx < nefx; idx++) {
- if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
- runtime->hw.channels_min++;
- runtime->hw.channels_max++;
+ if (emu->card_capabilities->emu1010) {
+ /* TODO
+ * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
+ * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
+ * rate_min = 44100,
+ * rate_max = 192000,
+ * channels_min = 8,
+ * channels_max = 8,
+ * Need to add mixer control to fix sample rate
+ *
+ * There are 16 mono channels of 16bits each.
+ * 24bit Audio uses 2x channels over 16bit
+ * 96kHz uses 2x channels over 48kHz
+ * 192kHz uses 4x channels over 48kHz
+ * So, for 48kHz 24bit, one has 8 channels
+ * for 96kHz 24bit, one has 4 channels
+ * for 192kHz 24bit, one has 2 channels
+ */
+#if 1
+ switch (emu->emu1010.internal_clock) {
+ case 0:
+ /* For 44.1kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_44100;
+ runtime->hw.rate_min = runtime->hw.rate_max = 44100;
+ runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ break;
+ case 1:
+ /* For 48kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_48000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 48000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ break;
+ };
+#endif
+#if 0
+ /* For 96kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_96000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 96000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 4;
+#endif
+#if 0
+ /* For 192kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_192000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 192000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 2;
+#endif
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ /* efx_voices_mask[0] is expected to be zero
+ * efx_voices_mask[1] is expected to have 16bits set
+ */
+ } else {
+ runtime->hw.channels_min = runtime->hw.channels_max = 0;
+ for (idx = 0; idx < nefx; idx++) {
+ if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
+ runtime->hw.channels_min++;
+ runtime->hw.channels_max++;
+ }
}
}
epcm->capture_cr_val = emu->efx_voices_mask[0];
@@ -1460,7 +1543,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
unsigned int count,
unsigned int tram_shift)
{
- // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count);
+ /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */
if ((tram_shift & 1) == 0) {
while (count--) {
*dst_left-- = *src++;
@@ -1537,7 +1620,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
unsigned int i;
- // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2);
+ /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */
memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index b939e03aaedf..2c1585991bc8 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -3,6 +3,9 @@
* Creative Labs, Inc.
* Routines for control of EMU10K1 chips / proc interface routines
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -255,7 +258,7 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry,
unsigned int val, tmp, n;
val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0);
tmp = (val >> 16) & 0x8;
- for (n=0;n<4;n++) {
+ for (n = 0; n < 4; n++) {
tmp = val >> (16 + (n*4));
if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]);
else snd_iprintf(buffer, "Channel %d: No input\n", n);
@@ -372,6 +375,27 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
}
#ifdef CONFIG_SND_DEBUG
+static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_emu10k1 *emu = entry->private_data;
+ unsigned long value;
+ unsigned long flags;
+ unsigned long regs;
+ int i;
+ snd_iprintf(buffer, "EMU1010 Registers:\n\n");
+
+ for(i = 0; i < 0x30; i+=1) {
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ regs=i+0x40; /* 0x40 upwards are registers. */
+ outl(regs, emu->port + A_IOCFG);
+ outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ value = inl(emu->port + A_IOCFG);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f);
+ }
+}
+
static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -398,7 +422,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry,
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
- if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
+ if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) {
spin_lock_irqsave(&emu->emu_lock, flags);
outl(val, emu->port + (reg & 0xfffffffc));
spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -474,7 +498,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
continue;
- if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
+ if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) )
snd_ptr_write(emu, iobase, reg, channel_id, val);
}
}
@@ -531,6 +555,10 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
{
struct snd_info_entry *entry;
#ifdef CONFIG_SND_DEBUG
+ if ((emu->card_capabilities->emu1010) &&
+ snd_card_proc_new(emu->card, "emu1010_regs", &entry)) {
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read);
+ }
if (! snd_card_proc_new(emu->card, "io_regs", &entry)) {
snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read);
entry->c.text.write = snd_emu_proc_io_reg_write;
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 029e7856c43b..116e1c8d9361 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include <sound/emu10k1.h>
#include <linux/delay.h>
+#include "p17v.h"
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
{
@@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
return 0;
}
+/* The ADC does not support i2c read, so only write is implemented */
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
+ u32 reg,
+ u32 value)
+{
+ u32 tmp;
+ int timeout = 0;
+ int status;
+ int retry;
+ if ((reg > 0x7f) || (value > 0x1ff)) {
+ snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+ return -EINVAL;
+ }
+
+ tmp = reg << 25 | value << 16;
+ // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+ /* Not sure what this I2C channel controls. */
+ /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
+
+ /* This controls the I2C connected to the WM8775 ADC Codec */
+ snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
+ tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
+
+ for (retry = 0; retry < 10; retry++) {
+ /* Send the data to i2c */
+ //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
+ //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+ tmp = 0;
+ tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
+ snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
+
+ /* Wait till the transaction ends */
+ while (1) {
+ udelay(10);
+ status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
+ // snd_printk("I2C:status=0x%x\n", status);
+ timeout++;
+ if ((status & I2C_A_ADC_START) == 0)
+ break;
+
+ if (timeout > 1000) {
+ snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
+ break;
+ }
+ }
+ //Read back and see if the transaction is successful
+ if ((status & I2C_A_ADC_ABORT) == 0)
+ break;
+ }
+
+ if (retry == 10) {
+ snd_printk(KERN_ERR "Writing to ADC failed!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+{
+ if (reg < 0 || reg > 0x3f)
+ return 1;
+ reg += 0x40; /* 0x40 upwards are registers. */
+ if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
+ return 1;
+ outl(reg, emu->port + A_IOCFG);
+ udelay(10);
+ outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ udelay(10);
+ outl(value, emu->port + A_IOCFG);
+ udelay(10);
+ outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+
+ return 0;
+}
+
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
+{
+ if (reg < 0 || reg > 0x3f)
+ return 1;
+ reg += 0x40; /* 0x40 upwards are registers. */
+ outl(reg, emu->port + A_IOCFG);
+ udelay(10);
+ outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ udelay(10);
+ *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+
+ return 0;
+}
+
+/* Each Destination has one and only one Source,
+ * but one Source can feed any number of Destinations simultaneously.
+ */
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
+{
+ snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
+
+ return 0;
+}
+
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
unsigned long flags;
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 4e0f95438f47..465f8d505329 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -253,7 +253,7 @@ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
//struct snd_pcm_runtime *runtime = substream->runtime;
//struct snd_emu10k1_pcm *epcm = runtime->private_data;
- emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
+ emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0;
/* FIXME: maybe zero others */
return 0;
}
@@ -264,7 +264,7 @@ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
//struct snd_pcm_runtime *runtime = substream->runtime;
//struct snd_emu10k1_pcm *epcm = runtime->private_data;
- emu->p16v_capture_voice.use=0;
+ emu->p16v_capture_voice.use = 0;
/* FIXME: maybe zero others */
return 0;
}
@@ -349,7 +349,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
break;
}
/* FIXME: Check emu->buffer.size before actually writing to it. */
- for(i=0; i < runtime->periods; i++) {
+ for(i = 0; i < runtime->periods; i++) {
table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
table_base[(i*2)+1]=period_size_bytes<<16;
}
@@ -394,7 +394,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
/* FIXME: Check emu->buffer.size before actually writing to it. */
snd_emu10k1_ptr20_write(emu, 0x13, channel, 0);
snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
- snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
+ snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes
snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);
//snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */
//snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
@@ -437,7 +437,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
struct snd_pcm_substream *s;
u32 basic = 0;
u32 inte = 0;
- int running=0;
+ int running = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -445,7 +445,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_STOP:
default:
- running=0;
+ running = 0;
break;
}
snd_pcm_group_for_each(pos, substream) {
@@ -785,7 +785,7 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol,
}
return change;
}
-static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
#define P16V_VOL(xname,xreg,xhl) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
index 7ddb5be632cf..4ef5f68a9cd0 100644
--- a/sound/pci/emu10k1/p17v.h
+++ b/sound/pci/emu10k1/p17v.h
@@ -43,6 +43,53 @@
#define P17V_I2C_ADDR 0x3d /* I2C Address */
#define P17V_I2C_0 0x3e /* I2C Data */
#define P17V_I2C_1 0x3f /* I2C Data */
+/* I2C values */
+#define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */
+#define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */
+#define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */
+#define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */
+#define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */
+#define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */
+
+#define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */
+#define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */
+#define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */
+#define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */
+#define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */
+#define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */
+
+#define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */
+#define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */
+
+#define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */
+#define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */
+#define ADC_MASTER 0x0000000c /*ADC Master Mode Control */
+#define ADC_POWER 0x0000000d /*ADC PowerDown Control */
+#define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */
+#define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */
+#define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */
+#define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */
+#define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */
+#define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */
+#define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */
+#define ADC_MUX 0x00000015 /*ADC Mux offset */
+#if 0
+/* FIXME: Not tested yet. */
+#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain
+#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB
+#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute
+#define ADC_MUTE 0x000000c0 //Value to mute ADC
+#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select
+#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock
+#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter
+#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window
+#endif
+
+#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
+#define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux
+#define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux
#define P17V_START_AUDIO 0x40 /* Start Audio bit */
/* 41 - 47: Reserved */
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 94eca82dd4fc..1db50fe61475 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -83,7 +83,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
if (first_voice == last_voice)
return -ENOMEM;
- for (i=0; i < number; i++) {
+ for (i = 0; i < number; i++) {
voice = &emu->voices[(first_voice + i) % NUM_G];
// printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
voice->use = 1;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index a84f6b21024f..425b167522d5 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -413,8 +413,6 @@ struct ensoniq {
} u;
struct pci_dev *pci;
- unsigned short subsystem_vendor_id;
- unsigned short subsystem_device_id;
struct snd_card *card;
struct snd_pcm *pcm1; /* DAC1/ADC PCM */
struct snd_pcm *pcm2; /* DAC2 PCM */
@@ -1607,11 +1605,26 @@ static void snd_ensoniq_mixer_free_ac97(struct snd_ac97 *ac97)
ensoniq->u.es1371.ac97 = NULL;
}
-static struct {
+struct es1371_quirk {
unsigned short vid; /* vendor ID */
unsigned short did; /* device ID */
unsigned char rev; /* revision */
-} es1371_spdif_present[] __devinitdata = {
+};
+
+static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
+ struct es1371_quirk *list)
+{
+ while (list->vid != (unsigned short)PCI_ANY_ID) {
+ if (ensoniq->pci->vendor == list->vid &&
+ ensoniq->pci->device == list->did &&
+ ensoniq->rev == list->rev)
+ return 1;
+ list++;
+ }
+ return 0;
+}
+
+static struct es1371_quirk es1371_spdif_present[] __devinitdata = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1620,12 +1633,19 @@ static struct {
{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }
};
-static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int has_line)
+static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */
+ SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */
+ { } /* end */
+};
+
+static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq,
+ int has_spdif, int has_line)
{
struct snd_card *card = ensoniq->card;
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
- int err, idx;
+ int err;
static struct snd_ac97_bus_ops ops = {
.write = snd_es1371_codec_write,
.read = snd_es1371_codec_read,
@@ -1641,33 +1661,28 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h
ac97.scaps = AC97_SCAP_AUDIO;
if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0)
return err;
- for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if ((ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
- ensoniq->pci->device == es1371_spdif_present[idx].did &&
- ensoniq->rev == es1371_spdif_present[idx].rev) || has_spdif > 0) {
- struct snd_kcontrol *kctl;
- int i, index = 0;
-
- if (has_spdif < 0)
- break;
-
- ensoniq->spdif_default = ensoniq->spdif_stream =
- SNDRV_PCM_DEFAULT_CON_SPDIF;
- outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
-
- if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
- index++;
-
- for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
- kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
- if (! kctl)
- return -ENOMEM;
- kctl->id.index = index;
- if ((err = snd_ctl_add(card, kctl)) < 0)
- return err;
- }
- break;
+ if (has_spdif > 0 ||
+ (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) {
+ struct snd_kcontrol *kctl;
+ int i, index = 0;
+
+ ensoniq->spdif_default = ensoniq->spdif_stream =
+ SNDRV_PCM_DEFAULT_CON_SPDIF;
+ outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
+
+ if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
+ index++;
+
+ for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
+ kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.index = index;
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
}
+ }
if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) {
/* mirror rear to front speakers */
ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
@@ -1676,12 +1691,10 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h
if (err < 0)
return err;
}
- if (((ensoniq->subsystem_vendor_id == 0x1274) &&
- (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */
- ((ensoniq->subsystem_vendor_id == 0x1458) &&
- (ensoniq->subsystem_device_id == 0xa000)) || /* GA-8IEXP */
- has_line > 0) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq));
+ if (has_line > 0 ||
+ snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line,
+ ensoniq));
if (err < 0)
return err;
}
@@ -1956,21 +1969,15 @@ static int snd_ensoniq_dev_free(struct snd_device *device)
}
#ifdef CHIP1371
-static struct {
- unsigned short svid; /* subsystem vendor ID */
- unsigned short sdid; /* subsystem device ID */
-} es1371_amplifier_hack[] = {
- { .svid = 0x107b, .sdid = 0x2150 }, /* Gateway Solo 2150 */
- { .svid = 0x13bd, .sdid = 0x100c }, /* EV1938 on Mebius PC-MJ100V */
- { .svid = 0x1102, .sdid = 0x5938 }, /* Targa Xtender300 */
- { .svid = 0x1102, .sdid = 0x8938 }, /* IPC Topnote G notebook */
- { .svid = PCI_ANY_ID, .sdid = PCI_ANY_ID }
+static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */
+ SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */
+ SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */
+ SND_PCI_QUIRK_ID(0x1102, 0x8938), /* IPC Topnote G notebook */
+ { } /* end */
};
-static struct {
- unsigned short vid; /* vendor ID */
- unsigned short did; /* device ID */
- unsigned char rev; /* revision */
-} es1371_ac97_reset_hack[] = {
+
+static struct es1371_quirk es1371_ac97_reset_hack[] = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1984,7 +1991,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
{
#ifdef CHIP1371
int idx;
- struct pci_dev *pci = ensoniq->pci;
#endif
/* this code was part of snd_ensoniq_create before intruduction
* of suspend/resume
@@ -1999,16 +2005,12 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
outl(0, ES_REG(ensoniq, 1371_LEGACY));
- for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
- pci->device == es1371_ac97_reset_hack[idx].did &&
- ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
- outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
- /* need to delay around 20ms(bleech) to give
- some CODECs enough time to wakeup */
- msleep(20);
- break;
- }
+ if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) {
+ outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
+ /* need to delay around 20ms(bleech) to give
+ some CODECs enough time to wakeup */
+ msleep(20);
+ }
/* AC'97 warm reset to start the bitclk */
outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL));
inl(ES_REG(ensoniq, CONTROL));
@@ -2112,11 +2114,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
struct ensoniq ** rensoniq)
{
struct ensoniq *ensoniq;
- unsigned short cmdw;
unsigned char cmdb;
-#ifdef CHIP1371
- int idx;
-#endif
int err;
static struct snd_device_ops ops = {
.dev_free = snd_ensoniq_dev_free,
@@ -2159,10 +2157,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
pci_set_master(pci);
pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb);
ensoniq->rev = cmdb;
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &cmdw);
- ensoniq->subsystem_vendor_id = cmdw;
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw);
- ensoniq->subsystem_device_id = cmdw;
#ifdef CHIP1370
#if 0
ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE |
@@ -2175,19 +2169,11 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
ensoniq->ctrl = 0;
ensoniq->sctrl = 0;
ensoniq->cssr = 0;
- for (idx = 0; es1371_amplifier_hack[idx].svid != (unsigned short)PCI_ANY_ID; idx++)
- if (ensoniq->subsystem_vendor_id == es1371_amplifier_hack[idx].svid &&
- ensoniq->subsystem_device_id == es1371_amplifier_hack[idx].sdid) {
- ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */
- break;
- }
- for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
- pci->device == es1371_ac97_reset_hack[idx].did &&
- ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
- ensoniq->cssr |= ES_1371_ST_AC97_RST;
- break;
- }
+ if (snd_pci_quirk_lookup(pci, es1371_amplifier_hack))
+ ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */
+
+ if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack))
+ ensoniq->cssr |= ES_1371_ST_AC97_RST;
#endif
snd_ensoniq_chip_init(ensoniq);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 66ac26c5a240..fec29a108945 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1344,7 +1344,7 @@ static unsigned int db_scale_line[] = {
8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
};
-static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
static struct snd_kcontrol_new snd_es1938_controls[] = {
ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index b7b361ce3a93..6dc578bbeec9 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1157,7 +1157,7 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol,
return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
}
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
#define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index dbacba6177db..60d7b05a204a 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,14 @@
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
+snd-hda-codec-objs := hda_codec.o \
+ hda_generic.o \
+ patch_realtek.o \
+ patch_cmedia.o \
+ patch_analog.o \
+ patch_sigmatel.o \
+ patch_si3054.o \
+ patch_atihdmi.o \
+ patch_conexant.o \
+ patch_via.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 18bbc87e376f..8f34fb447983 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -52,6 +52,7 @@ struct hda_vendor_id {
static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x10ec, "Realtek" },
{ 0x1057, "Motorola" },
+ { 0x1106, "VIA" },
{ 0x11d4, "Analog Devices" },
{ 0x13f6, "C-Media" },
{ 0x14f1, "Conexant" },
@@ -262,7 +263,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
unsol->queue[wp] = res;
unsol->queue[wp + 1] = res_ex;
- queue_work(unsol->workq, &unsol->work);
+ schedule_work(&unsol->work);
return 0;
}
@@ -309,12 +310,6 @@ static int init_unsol_queue(struct hda_bus *bus)
snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
return -ENOMEM;
}
- unsol->workq = create_singlethread_workqueue("hda_codec");
- if (! unsol->workq) {
- snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
- kfree(unsol);
- return -ENOMEM;
- }
INIT_WORK(&unsol->work, process_unsol_events);
unsol->bus = bus;
bus->unsol = unsol;
@@ -333,7 +328,7 @@ static int snd_hda_bus_free(struct hda_bus *bus)
if (! bus)
return 0;
if (bus->unsol) {
- destroy_workqueue(bus->unsol->workq);
+ flush_scheduled_work();
kfree(bus->unsol);
}
list_for_each_safe(p, n, &bus->codec_list) {
@@ -1714,6 +1709,8 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
/**
* snd_hda_check_board_config - compare the current codec with the config table
* @codec: the HDA codec
+ * @num_configs: number of config enums
+ * @models: array of model name strings
* @tbl: configuration table, terminated by null entries
*
* Compares the modelname or PCI subsystem id of the current codec with the
@@ -1722,33 +1719,44 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
*
* If no entries are matching, the function returns a negative value.
*/
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl)
-{
- const struct hda_board_config *c;
-
- if (codec->bus->modelname) {
- for (c = tbl; c->modelname || c->pci_subvendor; c++) {
- if (c->modelname &&
- ! strcmp(codec->bus->modelname, c->modelname)) {
- snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
- return c->config;
+int snd_hda_check_board_config(struct hda_codec *codec,
+ int num_configs, const char **models,
+ const struct snd_pci_quirk *tbl)
+{
+ if (codec->bus->modelname && models) {
+ int i;
+ for (i = 0; i < num_configs; i++) {
+ if (models[i] &&
+ !strcmp(codec->bus->modelname, models[i])) {
+ snd_printd(KERN_INFO "hda_codec: model '%s' is "
+ "selected\n", models[i]);
+ return i;
}
}
}
- if (codec->bus->pci) {
- u16 subsystem_vendor, subsystem_device;
- pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
- for (c = tbl; c->modelname || c->pci_subvendor; c++) {
- if (c->pci_subvendor == subsystem_vendor &&
- (! c->pci_subdevice /* all match */||
- (c->pci_subdevice == subsystem_device))) {
- snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
- subsystem_vendor, subsystem_device, c->config);
- return c->config;
- }
+ if (!codec->bus->pci || !tbl)
+ return -1;
+
+ tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
+ if (!tbl)
+ return -1;
+ if (tbl->value >= 0 && tbl->value < num_configs) {
+#ifdef CONFIG_SND_DEBUG_DETECT
+ char tmp[10];
+ const char *model = NULL;
+ if (models)
+ model = models[tbl->value];
+ if (!model) {
+ sprintf(tmp, "#%d", tbl->value);
+ model = tmp;
}
+ snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
+ "for config %x:%x (%s)\n",
+ model, tbl->subvendor, tbl->subdevice,
+ (tbl->name ? tbl->name : "Unknown device"));
+#endif
+ return tbl->value;
}
return -1;
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1a7e82104bb9..b9a8e238b0a8 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -199,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* STATESTS int mask: SD2,SD1,SD0 */
#define STATESTS_INT_MASK 0x07
-#define AZX_MAX_CODECS 4
+#define AZX_MAX_CODECS 3
/* SD_CTL bits */
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
@@ -1285,7 +1285,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
- 1024 * 64, 1024 * 128);
+ 1024 * 64, 1024 * 1024);
chip->pcm[pcm_dev] = pcm;
if (chip->pcm_devs < pcm_dev + 1)
chip->pcm_devs = pcm_dev + 1;
@@ -1391,6 +1391,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
return -1;
}
chip->irq = chip->pci->irq;
+ pci_intx(chip->pci, !chip->msi);
return 0;
}
@@ -1502,6 +1503,31 @@ static int azx_dev_free(struct snd_device *device)
}
/*
+ * white/black-listing for position_fix
+ */
+static const struct snd_pci_quirk position_fix_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
+ {}
+};
+
+static int __devinit check_position_fix(struct azx *chip, int fix)
+{
+ const struct snd_pci_quirk *q;
+
+ if (fix == POS_FIX_AUTO) {
+ q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+ if (q) {
+ snd_printdd(KERN_INFO
+ "hda_intel: position_fix set to %d "
+ "for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
+ return q->value;
+ }
+ }
+ return fix;
+}
+
+/*
* constructor
*/
static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
@@ -1535,7 +1561,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->driver_type = driver_type;
chip->msi = enable_msi;
- chip->position_fix = position_fix;
+ chip->position_fix = check_position_fix(chip, position_fix);
+
chip->single_cmd = single_cmd;
#if BITS_PER_LONG != 64
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 9ca1baf860bd..39718d6cdadd 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -173,14 +173,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
/*
* Misc
*/
-struct hda_board_config {
- const char *modelname;
- int config;
- unsigned short pci_subvendor;
- unsigned short pci_subdevice;
-};
-
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
+int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
+ const char **modelnames,
+ const struct snd_pci_quirk *pci_list);
int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew);
/*
@@ -204,7 +199,6 @@ struct hda_bus_unsolicited {
unsigned int rp, wp;
/* workqueue */
- struct workqueue_struct *workq;
struct work_struct work;
struct hda_bus *bus;
};
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 0b668793face..9f9e9ae44a9d 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -14,6 +14,10 @@ extern struct hda_codec_preset snd_hda_preset_sigmatel[];
extern struct hda_codec_preset snd_hda_preset_si3054[];
/* ATI HDMI codecs */
extern struct hda_codec_preset snd_hda_preset_atihdmi[];
+/* Conexant audio codec */
+extern struct hda_codec_preset snd_hda_preset_conexant[];
+/* VIA codecs */
+extern struct hda_codec_preset snd_hda_preset_via[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
@@ -22,5 +26,7 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_sigmatel,
snd_hda_preset_si3054,
snd_hda_preset_atihdmi,
+ snd_hda_preset_conexant,
+ snd_hda_preset_via,
NULL
};
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 076365bc10e9..38977bce70e2 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -782,54 +782,63 @@ static struct hda_channel_mode ad1986a_modes[3] = {
/* eapd initialization */
static struct hda_verb ad1986a_eapd_init_verbs[] = {
- {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00},
+ {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
{}
};
+/* Ultra initialization */
+static struct hda_verb ad1986a_ultra_init[] = {
+ /* eapd initialization */
+ { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
+ /* CLFE -> Mic in */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
+ { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+ { } /* end */
+};
+
/* models */
-enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD };
-
-static struct hda_board_config ad1986a_cfg_tbl[] = {
- { .modelname = "6stack", .config = AD1986A_6STACK },
- { .modelname = "3stack", .config = AD1986A_3STACK },
- { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
- .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x817f,
- .config = AD1986A_3STACK }, /* ASUS P5P-L2 */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
- .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb,
- .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */
- { .modelname = "laptop", .config = AD1986A_LAPTOP },
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
- .config = AD1986A_LAPTOP }, /* FSC V2060 */
- { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017,
- .config = AD1986A_LAPTOP }, /* Samsung M50 */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
- .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
- { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD },
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung X11-T2300 Culesa */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x12b3,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS V1j */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
- .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */
- { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
- .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
+enum {
+ AD1986A_6STACK,
+ AD1986A_3STACK,
+ AD1986A_LAPTOP,
+ AD1986A_LAPTOP_EAPD,
+ AD1986A_ULTRA,
+ AD1986A_MODELS
+};
+
+static const char *ad1986a_models[AD1986A_MODELS] = {
+ [AD1986A_6STACK] = "6stack",
+ [AD1986A_3STACK] = "3stack",
+ [AD1986A_LAPTOP] = "laptop",
+ [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
+ [AD1986A_ULTRA] = "ultra",
+};
+
+static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
+ SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+ SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
{}
};
@@ -861,7 +870,9 @@ static int patch_ad1986a(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
/* override some parameters */
- board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
+ ad1986a_models,
+ ad1986a_cfg_tbl);
switch (board_config) {
case AD1986A_3STACK:
spec->num_mixers = 2;
@@ -891,6 +902,15 @@ static int patch_ad1986a(struct hda_codec *codec)
spec->multiout.dig_out_nid = 0;
spec->input_mux = &ad1986a_laptop_eapd_capture_source;
break;
+ case AD1986A_ULTRA:
+ spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = ad1986a_ultra_init;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+ spec->multiout.dig_out_nid = 0;
+ break;
}
return 0;
@@ -1391,20 +1411,27 @@ static struct hda_input_mux ad1981_thinkpad_capture_source = {
};
/* models */
-enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD };
+enum {
+ AD1981_BASIC,
+ AD1981_HP,
+ AD1981_THINKPAD,
+ AD1981_MODELS
+};
+
+static const char *ad1981_models[AD1981_MODELS] = {
+ [AD1981_HP] = "hp",
+ [AD1981_THINKPAD] = "thinkpad",
+ [AD1981_BASIC] = "basic",
+};
-static struct hda_board_config ad1981_cfg_tbl[] = {
- { .modelname = "hp", .config = AD1981_HP },
+static struct snd_pci_quirk ad1981_cfg_tbl[] = {
/* All HP models */
- { .pci_subvendor = 0x103c, .config = AD1981_HP },
- { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c,
- .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */
- { .modelname = "thinkpad", .config = AD1981_THINKPAD },
+ SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
+ /* HP nx6320 (reversed SSID, H/W bug) */
+ SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
/* Lenovo Thinkpad T60/X60/Z6xx */
- { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD },
- { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597,
- .config = AD1981_THINKPAD }, /* Z60m/t */
- { .modelname = "basic", .config = AD1981_BASIC },
+ SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
+ SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
{}
};
@@ -1437,7 +1464,9 @@ static int patch_ad1981(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
/* override some parameters */
- board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
+ ad1981_models,
+ ad1981_cfg_tbl);
switch (board_config) {
case AD1981_HP:
spec->mixers[0] = ad1981_hp_mixers;
@@ -2565,15 +2594,14 @@ static int ad1988_auto_init(struct hda_codec *codec)
/*
*/
-static struct hda_board_config ad1988_cfg_tbl[] = {
- { .modelname = "6stack", .config = AD1988_6STACK },
- { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG },
- { .modelname = "3stack", .config = AD1988_3STACK },
- { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG },
- { .modelname = "laptop", .config = AD1988_LAPTOP },
- { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG },
- { .modelname = "auto", .config = AD1988_AUTO },
- {}
+static const char *ad1988_models[AD1988_MODEL_LAST] = {
+ [AD1988_6STACK] = "6stack",
+ [AD1988_6STACK_DIG] = "6stack-dig",
+ [AD1988_3STACK] = "3stack",
+ [AD1988_3STACK_DIG] = "3stack-dig",
+ [AD1988_LAPTOP] = "laptop",
+ [AD1988_LAPTOP_DIG] = "laptop-dig",
+ [AD1988_AUTO] = "auto",
};
static int patch_ad1988(struct hda_codec *codec)
@@ -2591,8 +2619,9 @@ static int patch_ad1988(struct hda_codec *codec)
if (is_rev2(codec))
snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
- board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);
- if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
+ ad1988_models, NULL);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
board_config = AD1988_AUTO;
}
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index d38ce22507ae..5b9d3a31a1ae 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -40,6 +40,7 @@ enum {
CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
CMI_AUTO, /* let driver guess it */
+ CMI_MODELS
};
struct cmi_spec {
@@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec)
/*
*/
-static struct hda_board_config cmi9880_cfg_tbl[] = {
- { .modelname = "minimal", .config = CMI_MINIMAL },
- { .modelname = "min_fp", .config = CMI_MIN_FP },
- { .modelname = "full", .config = CMI_FULL },
- { .modelname = "full_dig", .config = CMI_FULL_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
- { .modelname = "allout", .config = CMI_ALLOUT },
- { .modelname = "auto", .config = CMI_AUTO },
+static const char *cmi9880_models[CMI_MODELS] = {
+ [CMI_MINIMAL] = "minimal",
+ [CMI_MIN_FP] = "min_fp",
+ [CMI_FULL] = "full",
+ [CMI_FULL_DIG] = "full_dig",
+ [CMI_ALLOUT] = "allout",
+ [CMI_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
{} /* terminator */
};
@@ -633,7 +637,9 @@ static int patch_cmi9880(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
+ cmi9880_models,
+ cmi9880_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
spec->board_config = CMI_AUTO; /* try everything */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
new file mode 100644
index 000000000000..73f4668238c6
--- /dev/null
+++ b/sound/pci/hda/patch_conexant.c
@@ -0,0 +1,1311 @@
+/*
+ * HD audio interface patch for Conexant HDA audio codec
+ *
+ * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
+ * Takashi Iwai <tiwai@suse.de>
+ * Tobin Davis <tdavis@dsl-only.net>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define CXT_PIN_DIR_IN 0x00
+#define CXT_PIN_DIR_OUT 0x01
+#define CXT_PIN_DIR_INOUT 0x02
+#define CXT_PIN_DIR_IN_NOMICBIAS 0x03
+#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
+
+#define CONEXANT_HP_EVENT 0x37
+#define CONEXANT_MIC_EVENT 0x38
+
+
+
+struct conexant_spec {
+
+ struct snd_kcontrol_new *mixers[5];
+ int num_mixers;
+
+ const struct hda_verb *init_verbs[5]; /* initialization verbs
+ * don't forget NULL
+ * termination!
+ */
+ unsigned int num_init_verbs;
+
+ /* playback */
+ struct hda_multi_out multiout; /* playback set-up
+ * max_channels, dacs must be set
+ * dig_out_nid and hp_nid are optional
+ */
+ unsigned int cur_eapd;
+ unsigned int need_dac_fix;
+
+ /* capture */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ hda_nid_t dig_in_nid; /* digital-in NID; optional */
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ hda_nid_t *capsrc_nids;
+ unsigned int cur_mux[3];
+
+ /* channel model */
+ const struct hda_channel_mode *channel_mode;
+ int num_channel_mode;
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[2]; /* used in build_pcms() */
+
+ struct mutex amp_mutex; /* PCM volume/mute control mutex */
+ unsigned int spdif_route;
+
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_imux;
+ hda_nid_t private_dac_nids[4];
+
+};
+
+static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+ stream_tag,
+ format, substream);
+}
+
+static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ 0, 0, 0);
+ return 0;
+}
+
+
+
+static struct hda_pcm_stream conexant_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = conexant_playback_pcm_open,
+ .prepare = conexant_playback_pcm_prepare,
+ .cleanup = conexant_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream conexant_pcm_analog_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .prepare = conexant_capture_pcm_prepare,
+ .cleanup = conexant_capture_pcm_cleanup
+ },
+};
+
+
+static struct hda_pcm_stream conexant_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = conexant_dig_playback_pcm_open,
+ .close = conexant_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream conexant_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in alc_build_pcms */
+};
+
+static int conexant_build_pcms(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "CONEXANT Analog";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+ if (spec->multiout.dig_out_nid) {
+ info++;
+ codec->num_pcms++;
+ info->name = "Conexant Digital";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ conexant_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dig_out_nid;
+ if (spec->dig_in_nid) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ conexant_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ return 0;
+}
+
+static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->capsrc_nids[adc_idx],
+ &spec->cur_mux[adc_idx]);
+}
+
+static int conexant_init(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_init_verbs; i++)
+ snd_hda_sequence_write(codec, spec->init_verbs[i]);
+ return 0;
+}
+
+static void conexant_free(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int i;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+
+ kfree(codec->spec);
+}
+
+#ifdef CONFIG_PM
+static int conexant_resume(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ codec->patch_ops.init(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+ return 0;
+}
+#endif
+
+static int conexant_build_controls(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+ if (err < 0)
+ return err;
+ }
+ if (spec->multiout.dig_out_nid) {
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+ if (spec->dig_in_nid) {
+ err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static struct hda_codec_ops conexant_patch_ops = {
+ .build_controls = conexant_build_controls,
+ .build_pcms = conexant_build_pcms,
+ .init = conexant_init,
+ .free = conexant_free,
+#ifdef CONFIG_PM
+ .resume = conexant_resume,
+#endif
+};
+
+/*
+ * EAPD control
+ * the private value = nid | (invert << 8)
+ */
+
+static int conexant_eapd_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;
+}
+
+static int conexant_eapd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int invert = (kcontrol->private_value >> 8) & 1;
+ if (invert)
+ ucontrol->value.integer.value[0] = !spec->cur_eapd;
+ else
+ ucontrol->value.integer.value[0] = spec->cur_eapd;
+ return 0;
+}
+
+static int conexant_eapd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int invert = (kcontrol->private_value >> 8) & 1;
+ hda_nid_t nid = kcontrol->private_value & 0xff;
+ unsigned int eapd;
+ eapd = ucontrol->value.integer.value[0];
+ if (invert)
+ eapd = !eapd;
+ if (eapd == spec->cur_eapd && !codec->in_resume)
+ return 0;
+ spec->cur_eapd = eapd;
+ snd_hda_codec_write(codec, nid,
+ 0, AC_VERB_SET_EAPD_BTLENABLE,
+ eapd ? 0x02 : 0x00);
+ return 1;
+}
+
+/* controls for test mode */
+#ifdef CONFIG_SND_DEBUG
+
+static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
+ spec->num_channel_mode);
+}
+
+static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
+ spec->num_channel_mode,
+ spec->multiout.max_channels);
+}
+
+static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+ spec->num_channel_mode,
+ &spec->multiout.max_channels);
+ if (err >= 0 && spec->need_dac_fix)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+ return err;
+}
+
+#define CXT_PIN_MODE(xname, nid, dir) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = conexant_ch_mode_info, \
+ .get = conexant_ch_mode_get, \
+ .put = conexant_ch_mode_put, \
+ .private_value = nid | (dir<<16) }
+
+static int cxt_gpio_data_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;
+}
+
+static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long *valp = ucontrol->value.integer.value;
+ unsigned int val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DATA, 0x00);
+
+ *valp = (val & mask) != 0;
+ return 0;
+}
+
+static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long val = *ucontrol->value.integer.value;
+ unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DATA,
+ 0x00);
+ unsigned int old_data = gpio_data;
+
+ /* Set/unset the masked GPIO bit(s) as needed */
+ if (val == 0)
+ gpio_data &= ~mask;
+ else
+ gpio_data |= mask;
+ if (gpio_data == old_data && !codec->in_resume)
+ return 0;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
+ return 1;
+}
+
+#define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = cxt_gpio_data_info, \
+ .get = cxt_gpio_data_get, \
+ .put = cxt_gpio_data_put, \
+ .private_value = nid | (mask<<16) }
+
+static int cxt_spdif_ctrl_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;
+}
+
+static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long *valp = ucontrol->value.integer.value;
+ unsigned int val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT, 0x00);
+
+ *valp = (val & mask) != 0;
+ return 0;
+}
+
+static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long val = *ucontrol->value.integer.value;
+ unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT,
+ 0x00);
+ unsigned int old_data = ctrl_data;
+
+ /* Set/unset the masked control bit(s) as needed */
+ if (val == 0)
+ ctrl_data &= ~mask;
+ else
+ ctrl_data |= mask;
+ if (ctrl_data == old_data && !codec->in_resume)
+ return 0;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+ ctrl_data);
+ return 1;
+}
+
+#define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = cxt_spdif_ctrl_info, \
+ .get = cxt_spdif_ctrl_get, \
+ .put = cxt_spdif_ctrl_put, \
+ .private_value = nid | (mask<<16) }
+
+#endif /* CONFIG_SND_DEBUG */
+
+/* Conexant 5045 specific */
+
+static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
+static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
+static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
+#define CXT5045_SPDIF_OUT 0x13
+
+static struct hda_channel_mode cxt5045_modes[1] = {
+ { 2, NULL },
+};
+
+static struct hda_input_mux cxt5045_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "ExtMic", 0x1 },
+ { "LineIn", 0x2 },
+ }
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ if (!conexant_eapd_put(kcontrol, ucontrol))
+ return 0;
+
+ /* toggle HP mute appropriately */
+ snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ return 1;
+}
+
+/* bind volumes of both NID 0x10 and 0x11 */
+static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change;
+
+ change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ return change;
+}
+
+
+/* mute internal speaker if HP is plugged */
+static void cxt5045_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x11, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5045_hp_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ res >>= 26;
+ switch (res) {
+ case CONEXANT_HP_EVENT:
+ cxt5045_hp_automute(codec);
+ break;
+ }
+}
+
+static struct snd_kcontrol_new cxt5045_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = cxt5045_hp_master_vol_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5045_hp_master_sw_put,
+ .private_value = 0x11,
+ },
+
+ {}
+};
+
+static struct hda_verb cxt5045_init_verbs[] = {
+ /* Line in, Mic */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ /* HP, Amp */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {0x1A, AC_VERB_SET_CONNECT_SEL,0x01},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+ /* Record selector: Front mic */
+ {0x14, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+ /* SPDIF route: PCM */
+ { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
+ /* pin sensing on HP and Mic jacks */
+ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ /* EAPD */
+ {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+ { } /* end */
+};
+
+#ifdef CONFIG_SND_DEBUG
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+static struct hda_input_mux cxt5045_test_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "MIXER", 0x0 },
+ { "MIC1 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "HP-OUT pin", 0x3 },
+ { "CD pin", 0x4 },
+ },
+};
+
+static struct snd_kcontrol_new cxt5045_test_mixer[] = {
+
+ /* Output controls */
+ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+
+ /* Modes for retasking pin widgets */
+ CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
+ CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT),
+
+ /* Loopback mixer controls */
+ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT),
+
+ /* Controls for GPIO pins, assuming they exist and are configured as outputs */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+#if 0 /* limit this to one GPIO pin for now */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+ CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01),
+
+ HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
+static struct hda_verb cxt5045_test_init_verbs[] = {
+ /* Enable all GPIOs as outputs with an initial value of 0 */
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+ /* Enable retasking pins as output, initially without power amp */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ /* Disable digital (SPDIF) pins initially, but users can enable
+ * them via a mixer switch. In the case of SPDIF-out, this initverb
+ * payload also sets the generation to 0, output to be in "consumer"
+ * PCM format, copyright asserted, no pre-emphasis and no validity
+ * control.
+ */
+ {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+ /* Start with output sum widgets muted and their output gains at min */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* Unmute retasking pin widget output buffers since the default
+ * state appears to be output. As the pin mode is changed by the
+ * user the pin mode control will take care of enabling the pin's
+ * input/output buffers as needed.
+ */
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Mute capture amp left and right */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+ /* Set ADC connection select to match default mixer setting (mic1
+ * pin)
+ */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mute all inputs to mixer widget (even unconnected ones) */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+
+ { }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5045_init(struct hda_codec *codec)
+{
+ conexant_init(codec);
+ cxt5045_hp_automute(codec);
+ return 0;
+}
+
+
+enum {
+ CXT5045_LAPTOP, /* Laptops w/ EAPD support */
+#ifdef CONFIG_SND_DEBUG
+ CXT5045_TEST,
+#endif
+ CXT5045_MODELS
+};
+
+static const char *cxt5045_models[CXT5045_MODELS] = {
+ [CXT5045_LAPTOP] = "laptop",
+#ifdef CONFIG_SND_DEBUG
+ [CXT5045_TEST] = "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
+ {}
+};
+
+static int patch_cxt5045(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
+ spec->multiout.dac_nids = cxt5045_dac_nids;
+ spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT;
+ spec->num_adc_nids = 1;
+ spec->adc_nids = cxt5045_adc_nids;
+ spec->capsrc_nids = cxt5045_capsrc_nids;
+ spec->input_mux = &cxt5045_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = cxt5045_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = cxt5045_init_verbs;
+ spec->spdif_route = 0;
+ spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
+ spec->channel_mode = cxt5045_modes,
+
+
+ codec->patch_ops = conexant_patch_ops;
+ codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+
+ board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+ cxt5045_models,
+ cxt5045_cfg_tbl);
+ switch (board_config) {
+ case CXT5045_LAPTOP:
+ spec->input_mux = &cxt5045_capture_source;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5045_init_verbs;
+ spec->mixers[0] = cxt5045_mixers;
+ codec->patch_ops.init = cxt5045_init;
+ break;
+#ifdef CONFIG_SND_DEBUG
+ case CXT5045_TEST:
+ spec->input_mux = &cxt5045_test_capture_source;
+ spec->mixers[0] = cxt5045_test_mixer;
+ spec->init_verbs[0] = cxt5045_test_init_verbs;
+#endif
+ }
+ return 0;
+}
+
+
+/* Conexant 5047 specific */
+
+static hda_nid_t cxt5047_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
+static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
+#define CXT5047_SPDIF_OUT 0x11
+
+static struct hda_channel_mode cxt5047_modes[1] = {
+ { 2, NULL },
+};
+
+static struct hda_input_mux cxt5047_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "ExtMic", 0x1 },
+ { "IntMic", 0x2 },
+ }
+};
+
+static struct hda_input_mux cxt5047_hp_capture_source = {
+ .num_items = 1,
+ .items = {
+ { "ExtMic", 0x1 },
+ }
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ if (!conexant_eapd_put(kcontrol, ucontrol))
+ return 0;
+
+ /* toggle HP mute appropriately */
+ snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ return 1;
+}
+
+#if 0
+/* bind volumes of both NID 0x13 and 0x1d */
+static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change;
+
+ change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ return change;
+}
+#endif
+
+/* mute internal speaker if HP is plugged */
+static void cxt5047_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x13, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5047_hp_automic(struct hda_codec *codec)
+{
+ static struct hda_verb mic_jack_on[] = {
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {}
+ };
+ static struct hda_verb mic_jack_off[] = {
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {}
+ };
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x08, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ if (present)
+ snd_hda_sequence_write(codec, mic_jack_on);
+ else
+ snd_hda_sequence_write(codec, mic_jack_off);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5047_hp_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ res >>= 26;
+ switch (res) {
+ case CONEXANT_HP_EVENT:
+ cxt5047_hp_automute(codec);
+ break;
+ case CONEXANT_MIC_EVENT:
+ cxt5047_hp_automic(codec);
+ break;
+ }
+}
+
+static struct snd_kcontrol_new cxt5047_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5047_hp_master_sw_put,
+ .private_value = 0x13,
+ },
+
+ {}
+};
+
+static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5047_hp_master_sw_put,
+ .private_value = 0x13,
+ },
+ { } /* end */
+};
+
+static struct hda_verb cxt5047_init_verbs[] = {
+ /* Line in, Mic, Built-in Mic */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ /* HP, Amp */
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {0x1A, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+ /* Record selector: Front mic */
+ {0x12, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+ /* SPDIF route: PCM */
+ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
+ { } /* end */
+};
+
+/* configuration for Toshiba Laptops */
+static struct hda_verb cxt5047_toshiba_init_verbs[] = {
+ {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+ /* pin sensing on HP and Mic jacks */
+ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+ {}
+};
+
+/* configuration for HP Laptops */
+static struct hda_verb cxt5047_hp_init_verbs[] = {
+ /* pin sensing on HP and Mic jacks */
+ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+ {}
+};
+
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+#ifdef CONFIG_SND_DEBUG
+static struct hda_input_mux cxt5047_test_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "MIXER", 0x0 },
+ { "LINE1 pin", 0x1 },
+ { "MIC1 pin", 0x2 },
+ { "MIC2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ },
+};
+
+static struct snd_kcontrol_new cxt5047_test_mixer[] = {
+
+ /* Output only controls */
+ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+
+ /* Modes for retasking pin widgets */
+ CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT),
+ CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT),
+
+ /* Loopback mixer controls */
+ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT),
+
+#if 0
+ /* Controls for GPIO pins, assuming they exist and are configured as outputs */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+ CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01),
+
+ HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
+static struct hda_verb cxt5047_test_init_verbs[] = {
+ /* Enable all GPIOs as outputs with an initial value of 0 */
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+ /* Enable retasking pins as output, initially without power amp */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ /* Disable digital (SPDIF) pins initially, but users can enable
+ * them via a mixer switch. In the case of SPDIF-out, this initverb
+ * payload also sets the generation to 0, output to be in "consumer"
+ * PCM format, copyright asserted, no pre-emphasis and no validity
+ * control.
+ */
+ {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+ /* Ensure mic1, mic2, line1 pin widgets take input from the
+ * OUT1 sum bus when acting as an output.
+ */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* Start with output sum widgets muted and their output gains at min */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* Unmute retasking pin widget output buffers since the default
+ * state appears to be output. As the pin mode is changed by the
+ * user the pin mode control will take care of enabling the pin's
+ * input/output buffers as needed.
+ */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Mute capture amp left and right */
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+ /* Set ADC connection select to match default mixer setting (mic1
+ * pin)
+ */
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mute all inputs to mixer widget (even unconnected ones) */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+ { }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5047_hp_init(struct hda_codec *codec)
+{
+ conexant_init(codec);
+ cxt5047_hp_automute(codec);
+ cxt5047_hp_automic(codec);
+ return 0;
+}
+
+
+enum {
+ CXT5047_LAPTOP, /* Laptops w/o EAPD support */
+ CXT5047_LAPTOP_HP, /* Some HP laptops */
+ CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */
+#ifdef CONFIG_SND_DEBUG
+ CXT5047_TEST,
+#endif
+ CXT5047_MODELS
+};
+
+static const char *cxt5047_models[CXT5047_MODELS] = {
+ [CXT5047_LAPTOP] = "laptop",
+ [CXT5047_LAPTOP_HP] = "laptop-hp",
+ [CXT5047_LAPTOP_EAPD] = "laptop-eapd",
+#ifdef CONFIG_SND_DEBUG
+ [CXT5047_TEST] = "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
+ SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
+ {}
+};
+
+static int patch_cxt5047(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
+ spec->multiout.dac_nids = cxt5047_dac_nids;
+ spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT;
+ spec->num_adc_nids = 1;
+ spec->adc_nids = cxt5047_adc_nids;
+ spec->capsrc_nids = cxt5047_capsrc_nids;
+ spec->input_mux = &cxt5047_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = cxt5047_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = cxt5047_init_verbs;
+ spec->spdif_route = 0;
+ spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes),
+ spec->channel_mode = cxt5047_modes,
+
+ codec->patch_ops = conexant_patch_ops;
+ codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
+
+ board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
+ cxt5047_models,
+ cxt5047_cfg_tbl);
+ switch (board_config) {
+ case CXT5047_LAPTOP:
+ break;
+ case CXT5047_LAPTOP_HP:
+ spec->input_mux = &cxt5047_hp_capture_source;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5047_hp_init_verbs;
+ spec->mixers[0] = cxt5047_hp_mixers;
+ codec->patch_ops.init = cxt5047_hp_init;
+ break;
+ case CXT5047_LAPTOP_EAPD:
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
+ break;
+#ifdef CONFIG_SND_DEBUG
+ case CXT5047_TEST:
+ spec->input_mux = &cxt5047_test_capture_source;
+ spec->mixers[0] = cxt5047_test_mixer;
+ spec->init_verbs[0] = cxt5047_test_init_verbs;
+#endif
+ }
+ return 0;
+}
+
+struct hda_codec_preset snd_hda_preset_conexant[] = {
+ { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 },
+ { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 },
+ {} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4e0c3c1b908b..145682b78071 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,6 +32,10 @@
#include "hda_codec.h"
#include "hda_local.h"
+#define ALC880_FRONT_EVENT 0x01
+#define ALC880_DCVOL_EVENT 0x02
+#define ALC880_HP_EVENT 0x04
+#define ALC880_MIC_EVENT 0x08
/* ALC880 board config type */
enum {
@@ -48,7 +52,10 @@ enum {
ALC880_ASUS_DIG,
ALC880_ASUS_W1V,
ALC880_ASUS_DIG2,
+ ALC880_FUJITSU,
ALC880_UNIWILL_DIG,
+ ALC880_UNIWILL,
+ ALC880_UNIWILL_P53,
ALC880_CLEVO,
ALC880_TCL_S700,
ALC880_LG,
@@ -77,8 +84,12 @@ enum {
/* ALC262 models */
enum {
ALC262_BASIC,
+ ALC262_HIPPO,
+ ALC262_HIPPO_1,
ALC262_FUJITSU,
ALC262_HP_BPC,
+ ALC262_HP_BPC_D7000_WL,
+ ALC262_HP_BPC_D7000_WF,
ALC262_BENQ_ED8,
ALC262_AUTO,
ALC262_MODEL_LAST /* last tag */
@@ -91,16 +102,30 @@ enum {
ALC861_3ST_DIG,
ALC861_6ST_DIG,
ALC861_UNIWILL_M31,
+ ALC861_TOSHIBA,
+ ALC861_ASUS,
+ ALC861_ASUS_LAPTOP,
ALC861_AUTO,
ALC861_MODEL_LAST,
};
+/* ALC861-VD models */
+enum {
+ ALC660VD_3ST,
+ ALC861VD_3ST,
+ ALC861VD_3ST_DIG,
+ ALC861VD_6ST_DIG,
+ ALC861VD_AUTO,
+ ALC861VD_MODEL_LAST,
+};
+
/* ALC882 models */
enum {
ALC882_3ST_DIG,
ALC882_6ST_DIG,
ALC882_ARIMA,
ALC882_AUTO,
+ ALC885_MACPRO,
ALC882_MODEL_LAST,
};
@@ -110,8 +135,12 @@ enum {
ALC883_3ST_6ch_DIG,
ALC883_3ST_6ch,
ALC883_6ST_DIG,
+ ALC883_TARGA_DIG,
+ ALC883_TARGA_2ch_DIG,
ALC888_DEMO_BOARD,
ALC883_ACER,
+ ALC883_MEDION,
+ ALC883_LAPTOP_EAPD,
ALC883_AUTO,
ALC883_MODEL_LAST,
};
@@ -1015,6 +1044,60 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
{ } /* end */
};
+/* Uniwill */
+static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+ HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+ HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
/*
* build control elements
*/
@@ -1248,6 +1331,159 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
{ }
};
+/*
+ * Uniwill pin configuration:
+ * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
+ * line = 0x1a
+ */
+static struct hda_verb alc880_uniwill_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
+ /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+
+ { }
+};
+
+/*
+* Uniwill P53
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
+ */
+static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
+
+ { }
+};
+
+static struct hda_verb alc880_beep_init_verbs[] = {
+ { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_uniwill_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+
+ present = snd_hda_codec_read(codec, 0x18, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc880_uniwill_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == ALC880_HP_EVENT ||
+ (res >> 28) == ALC880_MIC_EVENT)
+ alc880_uniwill_automute(codec);
+}
+
+static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x21, 0,
+ AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f;
+
+ snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
+ 0x7f, present);
+ snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
+ 0x7f, present);
+
+ snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
+ 0x7f, present);
+ snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
+ 0x7f, present);
+
+}
+static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == ALC880_HP_EVENT)
+ alc880_uniwill_p53_hp_automute(codec);
+ if ((res >> 28) == ALC880_DCVOL_EVENT)
+ alc880_uniwill_p53_dcvol_automute(codec);
+}
+
/* FIXME! */
/*
* F1734 pin configuration:
@@ -2125,159 +2361,112 @@ static struct hda_verb alc880_test_init_verbs[] = {
/*
*/
-static struct hda_board_config alc880_cfg_tbl[] = {
- /* Back 3 jack, front 2 jack */
- { .modelname = "3stack", .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
- /* TCL S700 */
- { .modelname = "tcl", .config = ALC880_TCL_S700 },
- { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
-
- /* Back 3 jack, front 2 jack (Internal add Aux-In) */
- { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
-
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
-
- /* Clevo laptops */
- { .modelname = "clevo", .config = ALC880_CLEVO },
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
- .config = ALC880_CLEVO }, /* Clevo m520G NB */
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
- .config = ALC880_CLEVO }, /* Clevo m665n */
-
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
-
- /* Back 5 jack, front 2 jack */
- { .modelname = "5stack", .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
-
- /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560,
- .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */
- /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
- { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
- /* note subvendor = 0 below */
- /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
-
- { .modelname = "w810", .config = ALC880_W810 },
- { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
-
- { .modelname = "z71v", .config = ALC880_Z71V },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
-
- { .modelname = "6stack", .config = ALC880_6ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
- { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
-
- { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
- { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */
- { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */
-
- { .modelname = "asus", .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
- { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
- { .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
- { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
-
- { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
-
- { .modelname = "F1734", .config = ALC880_F1734 },
- { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
-
- { .modelname = "lg", .config = ALC880_LG },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
-
- { .modelname = "lg-lw", .config = ALC880_LG_LW },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
-
+static const char *alc880_models[ALC880_MODEL_LAST] = {
+ [ALC880_3ST] = "3stack",
+ [ALC880_TCL_S700] = "tcl",
+ [ALC880_3ST_DIG] = "3stack-digout",
+ [ALC880_CLEVO] = "clevo",
+ [ALC880_5ST] = "5stack",
+ [ALC880_5ST_DIG] = "5stack-digout",
+ [ALC880_W810] = "w810",
+ [ALC880_Z71V] = "z71v",
+ [ALC880_6ST] = "6stack",
+ [ALC880_6ST_DIG] = "6stack-digout",
+ [ALC880_ASUS] = "asus",
+ [ALC880_ASUS_W1V] = "asus-w1v",
+ [ALC880_ASUS_DIG] = "asus-dig",
+ [ALC880_ASUS_DIG2] = "asus-dig2",
+ [ALC880_UNIWILL_DIG] = "uniwill",
+ [ALC880_UNIWILL_P53] = "uniwill-p53",
+ [ALC880_FUJITSU] = "fujitsu",
+ [ALC880_F1734] = "F1734",
+ [ALC880_LG] = "lg",
+ [ALC880_LG_LW] = "lg-lw",
#ifdef CONFIG_SND_DEBUG
- { .modelname = "test", .config = ALC880_TEST },
+ [ALC880_TEST] = "test",
#endif
- { .modelname = "auto", .config = ALC880_AUTO },
+ [ALC880_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc880_cfg_tbl[] = {
+ /* Broken BIOS configuration */
+ SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+
+ SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
+ SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
+ SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
+
+ SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
+
+ SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
+ SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
+ /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
+ SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
+ SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
+ SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
+
+ SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+ SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+ SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+ SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
+ SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+ SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+ SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
+
+ SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+ SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
+ SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
+ SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
+
+ SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
+ SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+ SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
+
+ SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
+ SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
+
+ SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
{}
};
@@ -2438,7 +2627,8 @@ static struct alc_config_preset alc880_presets[] = {
},
[ALC880_UNIWILL_DIG] = {
.mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
- .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_pin_asus_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
.dac_nids = alc880_asus_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
@@ -2447,6 +2637,46 @@ static struct alc_config_preset alc880_presets[] = {
.need_dac_fix = 1,
.input_mux = &alc880_capture_source,
},
+ [ALC880_UNIWILL] = {
+ .mixers = { alc880_uniwill_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_unsol_event,
+ .init_hook = alc880_uniwill_automute,
+ },
+ [ALC880_UNIWILL_P53] = {
+ .mixers = { alc880_uniwill_p53_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_p53_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+ .channel_mode = alc880_threestack_modes,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_p53_unsol_event,
+ .init_hook = alc880_uniwill_p53_hp_automute,
+ },
+ [ALC880_FUJITSU] = {
+ .mixers = { alc880_fujitsu_mixer,
+ alc880_pcbeep_mixer, },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_p53_init_verbs,
+ alc880_beep_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_p53_unsol_event,
+ .init_hook = alc880_uniwill_p53_hp_automute,
+ },
[ALC880_CLEVO] = {
.mixers = { alc880_three_stack_mixer },
.init_verbs = { alc880_volume_init_verbs,
@@ -2841,8 +3071,10 @@ static int patch_alc880(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
- if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
+ alc880_models,
+ alc880_cfg_tbl);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
"trying auto-probe from BIOS...\n");
board_config = ALC880_AUTO;
@@ -3090,11 +3322,20 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
* and the output jack. If this turns out to be the case for all such
* models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
* to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * The C20x Tablet series have a mono internal speaker which is controlled
+ * via the chip's Mono sum widget and pin complex, so include the necessary
+ * controls for such models. On models without a "mono speaker" the control
+ * won't do anything.
*/
static struct snd_kcontrol_new alc260_acer_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+ HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
+ HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3409,11 +3650,11 @@ static struct hda_verb alc260_acer_init_verbs[] = {
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
/* Line In jack is connected to Line1 pin */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Ensure all other unused pins are disabled and muted. */
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -3441,6 +3682,8 @@ static struct hda_verb alc260_acer_init_verbs[] = {
/* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Unmute Mic1 and Line1 pin widget input buffers since they start as
* inputs. If the pin mode is changed by the user the pin mode control
* will take care of enabling the pin's input/output buffers as needed.
@@ -3928,33 +4171,33 @@ static void alc260_auto_init(struct hda_codec *codec)
/*
* ALC260 configurations
*/
-static struct hda_board_config alc260_cfg_tbl[] = {
- { .modelname = "basic", .config = ALC260_BASIC },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
- .config = ALC260_BASIC }, /* Sony VAIO */
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc,
- .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
- .config = ALC260_BASIC }, /* Sony VAIO */
- { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
- .config = ALC260_BASIC }, /* CTL Travel Master U553W */
- { .modelname = "hp", .config = ALC260_HP },
- { .modelname = "hp-3013", .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
- { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
- { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
- { .modelname = "acer", .config = ALC260_ACER },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
+static const char *alc260_models[ALC260_MODEL_LAST] = {
+ [ALC260_BASIC] = "basic",
+ [ALC260_HP] = "hp",
+ [ALC260_HP_3013] = "hp-3013",
+ [ALC260_FUJITSU_S702X] = "fujitsu",
+ [ALC260_ACER] = "acer",
#ifdef CONFIG_SND_DEBUG
- { .modelname = "test", .config = ALC260_TEST },
+ [ALC260_TEST] = "test",
#endif
- { .modelname = "auto", .config = ALC260_AUTO },
+ [ALC260_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc260_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
+ SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
+ SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
+ SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
{}
};
@@ -4053,8 +4296,10 @@ static int patch_alc260(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
- if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
+ alc260_models,
+ alc260_cfg_tbl);
+ if (board_config < 0) {
snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
"trying auto-probe from BIOS...\n");
board_config = ALC260_AUTO;
@@ -4207,8 +4452,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4313,6 +4560,100 @@ static struct hda_verb alc882_eapd_verbs[] = {
{ }
};
+/* Mac Pro test */
+static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_verb alc882_macpro_init_verbs[] = {
+ /* Front mixer: unmute input/output amp left and right (volume = 0) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Front Pin: output 0 (0x0c) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Speaker: output */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
+ /* Headphone output (output 0 - 0x0c) */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* ADC1: mute amp left and right */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC3: mute amp left and right */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ { }
+};
+static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+ unsigned int gpiostate, gpiomask, gpiodir;
+
+ gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+
+ if (!muted)
+ gpiostate |= (1 << pin);
+ else
+ gpiostate &= ~(1 << pin);
+
+ gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_MASK, 0);
+ gpiomask |= (1 << pin);
+
+ gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DIRECTION, 0);
+ gpiodir |= (1 << pin);
+
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, gpiomask);
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+ msleep(1);
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -4435,19 +4776,20 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = {
/*
* configuration and preset
*/
-static struct hda_board_config alc882_cfg_tbl[] = {
- { .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
- { .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* MSI */
- { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* Foxconn */
- { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* ECS to Intel*/
- { .modelname = "arima", .config = ALC882_ARIMA },
- { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054,
- .config = ALC882_ARIMA }, /* Arima W820Di1 */
- { .modelname = "auto", .config = ALC882_AUTO },
+static const char *alc882_models[ALC882_MODEL_LAST] = {
+ [ALC882_3ST_DIG] = "3stack-dig",
+ [ALC882_6ST_DIG] = "6stack-dig",
+ [ALC882_ARIMA] = "arima",
+ [ALC885_MACPRO] = "macpro",
+ [ALC882_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc882_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
+ SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
{}
};
@@ -4484,6 +4826,17 @@ static struct alc_config_preset alc882_presets[] = {
.channel_mode = alc882_sixstack_modes,
.input_mux = &alc882_capture_source,
},
+ [ALC885_MACPRO] = {
+ .mixers = { alc882_macpro_mixer },
+ .init_verbs = { alc882_macpro_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .input_mux = &alc882_capture_source,
+ },
};
@@ -4584,7 +4937,9 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+ alc882_models,
+ alc882_cfg_tbl);
if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
@@ -4609,6 +4964,11 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config != ALC882_AUTO)
setup_preset(spec, &alc882_presets[board_config]);
+ if (board_config == ALC885_MACPRO) {
+ alc882_gpio_mute(codec, 0, 0);
+ alc882_gpio_mute(codec, 1, 0);
+ }
+
spec->stream_name_analog = "ALC882 Analog";
spec->stream_analog_playback = &alc882_pcm_analog_playback;
spec->stream_analog_capture = &alc882_pcm_analog_capture;
@@ -4767,6 +5127,13 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
{ 8, alc883_sixstack_ch8_init },
};
+static struct hda_verb alc883_medion_eapd_verbs[] = {
+ /* eanable EAPD on medion laptop */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
+ { }
+};
+
/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
*/
@@ -4788,8 +5155,10 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4818,8 +5187,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4854,8 +5225,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4875,6 +5248,101 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_tagra_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc883_chmode_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4963,6 +5431,45 @@ static struct hda_verb alc883_init_verbs[] = {
{ }
};
+static struct hda_verb alc883_tagra_verbs[] = {
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
+
+ { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_tagra_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3);
+}
+
+static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc883_tagra_automute(codec);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -5057,32 +5564,42 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
/*
* configuration and preset
*/
-static struct hda_board_config alc883_cfg_tbl[] = {
- { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
- { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
- .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
- { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch },
- { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
- .config = ALC883_3ST_6ch },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601,
- .config = ALC883_3ST_6ch }, /* D102GGC */
- { .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
- .config = ALC883_6ST_DIG }, /* MSI */
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x7280,
- .config = ALC883_6ST_DIG }, /* MSI K9A Platinum (MS-7280) */
- { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
- .config = ALC883_6ST_DIG }, /* Foxconn */
- { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
- { .modelname = "acer", .config = ALC883_ACER },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/,
- .config = ALC883_ACER },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102,
- .config = ALC883_ACER },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f,
- .config = ALC883_ACER },
- { .modelname = "auto", .config = ALC883_AUTO },
+static const char *alc883_models[ALC883_MODEL_LAST] = {
+ [ALC883_3ST_2ch_DIG] = "3stack-dig",
+ [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
+ [ALC883_3ST_6ch] = "3stack-6ch",
+ [ALC883_6ST_DIG] = "6stack-dig",
+ [ALC883_TARGA_DIG] = "targa-dig",
+ [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
+ [ALC888_DEMO_BOARD] = "6stack-dig-demo",
+ [ALC883_ACER] = "acer",
+ [ALC883_MEDION] = "medion",
+ [ALC883_LAPTOP_EAPD] = "laptop-eapd",
+ [ALC883_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+ SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+ SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
{}
};
@@ -5139,6 +5656,35 @@ static struct alc_config_preset alc883_presets[] = {
.channel_mode = alc883_sixstack_modes,
.input_mux = &alc883_capture_source,
},
+ [ALC883_TARGA_DIG] = {
+ .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+ .channel_mode = alc883_3ST_6ch_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc883_capture_source,
+ .unsol_event = alc883_tagra_unsol_event,
+ .init_hook = alc883_tagra_automute,
+ },
+ [ALC883_TARGA_2ch_DIG] = {
+ .mixers = { alc883_tagra_2ch_mixer},
+ .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .input_mux = &alc883_capture_source,
+ .unsol_event = alc883_tagra_unsol_event,
+ .init_hook = alc883_tagra_automute,
+ },
[ALC888_DEMO_BOARD] = {
.mixers = { alc883_base_mixer, alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs },
@@ -5169,6 +5715,31 @@ static struct alc_config_preset alc883_presets[] = {
.channel_mode = alc883_3ST_2ch_modes,
.input_mux = &alc883_capture_source,
},
+ [ALC883_MEDION] = {
+ .mixers = { alc883_fivestack_mixer,
+ alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs,
+ alc883_medion_eapd_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+ .channel_mode = alc883_sixstack_modes,
+ .input_mux = &alc883_capture_source,
+ },
+ [ALC883_LAPTOP_EAPD] = {
+ .mixers = { alc883_base_mixer,
+ alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .input_mux = &alc883_capture_source,
+ },
};
@@ -5277,8 +5848,10 @@ static int patch_alc883(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl);
- if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
+ alc883_models,
+ alc883_cfg_tbl);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
"trying auto-probe from BIOS...\n");
board_config = ALC883_AUTO;
@@ -5355,6 +5928,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+ /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -5377,6 +5968,30 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+ HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
#define alc262_capture_mixer alc882_capture_mixer
#define alc262_capture_alt_mixer alc882_capture_alt_mixer
@@ -5459,6 +6074,103 @@ static struct hda_verb alc262_init_verbs[] = {
{ }
};
+static struct hda_verb alc262_hippo_unsol_verbs[] = {
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {}
+};
+
+static struct hda_verb alc262_hippo1_unsol_verbs[] = {
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {}
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hippo_automute(struct hda_codec *codec, int force)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int mute;
+
+ if (force || ! spec->sense_updated) {
+ unsigned int present;
+ /* need to execute and sync at first */
+ snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, 0x15, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ spec->jack_present = (present & 0x80000000) != 0;
+ spec->sense_updated = 1;
+ }
+ if (spec->jack_present) {
+ /* mute internal speaker */
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ } else {
+ /* unmute internal speaker if necessary */
+ mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) != ALC880_HP_EVENT)
+ return;
+ alc262_hippo_automute(codec, 1);
+}
+
+static void alc262_hippo1_automute(struct hda_codec *codec, int force)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int mute;
+
+ if (force || ! spec->sense_updated) {
+ unsigned int present;
+ /* need to execute and sync at first */
+ snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ spec->jack_present = (present & 0x80000000) != 0;
+ spec->sense_updated = 1;
+ }
+ if (spec->jack_present) {
+ /* mute internal speaker */
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ } else {
+ /* unmute internal speaker if necessary */
+ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo1_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) != ALC880_HP_EVENT)
+ return;
+ alc262_hippo1_automute(codec, 1);
+}
+
/*
* fujitsu model
* 0x14 = headphone/spdif-out, 0x15 = internal speaker
@@ -5809,6 +6521,100 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
{ }
};
+static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ * Note: PASD motherboards uses the Line In 2 as the input for front
+ * panel mic (mic 2)
+ */
+ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+ /*
+ * Set up output mixers (0x0c - 0x0e)
+ */
+ /* set vol=0 to output mixers */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* set up input amps for analog loopback */
+ /* Amp Indices: DAC = 0, mixer = 1 */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
+
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+ /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
+ /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+ /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+ /* Input mixer3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+ /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+
+ { }
+};
+
/* pcm configuration: identiacal with ALC880 */
#define alc262_pcm_analog_playback alc880_pcm_analog_playback
#define alc262_pcm_analog_capture alc880_pcm_analog_capture
@@ -5866,26 +6672,35 @@ static void alc262_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static struct hda_board_config alc262_cfg_tbl[] = {
- { .modelname = "basic", .config = ALC262_BASIC },
- { .modelname = "fujitsu", .config = ALC262_FUJITSU },
- { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
- .config = ALC262_FUJITSU },
- { .modelname = "hp-bpc", .config = ALC262_HP_BPC },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x280c,
- .config = ALC262_HP_BPC }, /* xw4400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x2801,
- .config = ALC262_HP_BPC }, /* q965 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
- .config = ALC262_HP_BPC }, /* xw6400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015,
- .config = ALC262_HP_BPC }, /* xw8400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
- .config = ALC262_HP_BPC }, /* xw9400 */
- { .modelname = "benq", .config = ALC262_BENQ_ED8 },
- { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560,
- .config = ALC262_BENQ_ED8 },
- { .modelname = "auto", .config = ALC262_AUTO },
+static const char *alc262_models[ALC262_MODEL_LAST] = {
+ [ALC262_BASIC] = "basic",
+ [ALC262_HIPPO] = "hippo",
+ [ALC262_HIPPO_1] = "hippo_1",
+ [ALC262_FUJITSU] = "fujitsu",
+ [ALC262_HP_BPC] = "hp-bpc",
+ [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+ [ALC262_BENQ_ED8] = "benq",
+ [ALC262_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc262_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+ SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+ SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
+ SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+ SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
{}
};
@@ -5900,6 +6715,30 @@ static struct alc_config_preset alc262_presets[] = {
.channel_mode = alc262_modes,
.input_mux = &alc262_capture_source,
},
+ [ALC262_HIPPO] = {
+ .mixers = { alc262_base_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .dig_out_nid = ALC262_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_hippo_unsol_event,
+ },
+ [ALC262_HIPPO_1] = {
+ .mixers = { alc262_hippo1_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x02,
+ .dig_out_nid = ALC262_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_hippo1_unsol_event,
+ },
[ALC262_FUJITSU] = {
.mixers = { alc262_fujitsu_mixer },
.init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
@@ -5922,6 +6761,27 @@ static struct alc_config_preset alc262_presets[] = {
.channel_mode = alc262_modes,
.input_mux = &alc262_HP_capture_source,
},
+ [ALC262_HP_BPC_D7000_WF] = {
+ .mixers = { alc262_HP_BPC_WildWest_mixer },
+ .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_HP_capture_source,
+ },
+ [ALC262_HP_BPC_D7000_WL] = {
+ .mixers = { alc262_HP_BPC_WildWest_mixer,
+ alc262_HP_BPC_WildWest_option_mixer },
+ .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_HP_capture_source,
+ },
[ALC262_BENQ_ED8] = {
.mixers = { alc262_base_mixer },
.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -5940,7 +6800,7 @@ static int patch_alc262(struct hda_codec *codec)
int board_config;
int err;
- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
@@ -5956,9 +6816,11 @@ static int patch_alc262(struct hda_codec *codec)
}
#endif
- board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
-
- if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
+ alc262_models,
+ alc262_cfg_tbl);
+
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
"trying auto-probe from BIOS...\n");
board_config = ALC262_AUTO;
@@ -6078,6 +6940,44 @@ static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
{ 4, alc861_uniwill_m31_ch4_init },
};
+/* Set mic1 and line-in as input and unmute the mixer */
+static struct hda_verb alc861_asus_ch2_init[] = {
+ /* set pin widget 1Ah (line in) for input */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+ { } /* end */
+};
+/* Set mic1 nad line-in as output and mute mixer */
+static struct hda_verb alc861_asus_ch6_init[] = {
+ /* set pin widget 1Ah (line in) for output (Back Surround)*/
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+ /* set pin widget 18h (mic1) for output (CLFE)*/
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+ { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
+ { } /* end */
+};
+
+static struct hda_channel_mode alc861_asus_modes[2] = {
+ { 2, alc861_asus_ch2_init },
+ { 6, alc861_asus_ch6_init },
+};
+
/* patch-ALC861 */
static struct snd_kcontrol_new alc861_base_mixer[] = {
@@ -6154,7 +7054,29 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
.private_value = ARRAY_SIZE(alc861_threestack_modes),
},
{ } /* end */
-};
+};
+
+static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+ /* output mixer control */
+ HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+
+ /*Capture mixer control */
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .count = 1,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
/* output mixer control */
HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
@@ -6196,7 +7118,58 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
},
{ } /* end */
};
-
+
+static struct snd_kcontrol_new alc861_asus_mixer[] = {
+ /* output mixer control */
+ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+
+ /* Input mixer control */
+ HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */
+
+ /* Capture mixer control */
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .count = 1,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ .private_value = ARRAY_SIZE(alc861_asus_modes),
+ },
+ { }
+};
+
+/* additional mixer */
+static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
+ { }
+};
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -6217,7 +7190,7 @@ static struct hda_verb alc861_base_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6281,7 +7254,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6341,7 +7314,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6385,6 +7358,74 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
{ }
};
+static struct hda_verb alc861_asus_init_verbs[] = {
+ /*
+ * Unmute ADC0 and set the default input to mic-in
+ */
+ /* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
+ /* route front PCM to HP */
+ { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ /* port-B for mic-in (rear panel) with vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-C for line-in (rear panel) */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* port-D for Front */
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-E for HP out (front panel) */
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */
+ /* route front PCM to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-F for mic-in (front panel) with vref */
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-G for CLFE (rear panel) */
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* port-H for side (rear panel) */
+ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* CD-in */
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* route front mic to ADC1*/
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ /* Unmute DAC0~3 & spdif out*/
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Unmute Mixer 14 (mic) 1c (Line in)*/
+ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ /* Unmute Stereo Mixer 15 */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, /* Output 0~12 step */
+
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ { }
+};
+
+/* additional init verbs for ASUS laptops */
+static struct hda_verb alc861_asus_laptop_init_verbs[] = {
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
+ { }
+};
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -6437,6 +7478,39 @@ static struct hda_verb alc861_auto_init_verbs[] = {
{ }
};
+static struct hda_verb alc861_toshiba_init_verbs[] = {
+ {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc861_toshiba_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x0f, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3,
+ 0x80, present ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3,
+ 0x80, present ? 0 : 0x80);
+}
+
+static void alc861_toshiba_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 6bit tag is placed at 26 bit!
+ */
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc861_toshiba_automute(codec);
+}
+
/* pcm configuration: identiacal with ALC880 */
#define alc861_pcm_analog_playback alc880_pcm_analog_playback
#define alc861_pcm_analog_capture alc880_pcm_analog_capture
@@ -6710,19 +7784,29 @@ static void alc861_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static struct hda_board_config alc861_cfg_tbl[] = {
- { .modelname = "3stack", .config = ALC861_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
- .config = ALC861_3ST },
- { .modelname = "3stack-660", .config = ALC660_3ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
- .config = ALC660_3ST },
- { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
- { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
- { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31},
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072,
- .config = ALC861_UNIWILL_M31 },
- { .modelname = "auto", .config = ALC861_AUTO },
+static const char *alc861_models[ALC861_MODEL_LAST] = {
+ [ALC861_3ST] = "3stack",
+ [ALC660_3ST] = "3stack-660",
+ [ALC861_3ST_DIG] = "3stack-dig",
+ [ALC861_6ST_DIG] = "6stack-dig",
+ [ALC861_UNIWILL_M31] = "uniwill-m31",
+ [ALC861_TOSHIBA] = "toshiba",
+ [ALC861_ASUS] = "asus",
+ [ALC861_ASUS_LAPTOP] = "asus-laptop",
+ [ALC861_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc861_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
+ SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST),
+ SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
+ SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+ SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+ SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+ SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
{}
};
@@ -6789,8 +7873,48 @@ static struct alc_config_preset alc861_presets[] = {
.adc_nids = alc861_adc_nids,
.input_mux = &alc861_capture_source,
},
-
-};
+ [ALC861_TOSHIBA] = {
+ .mixers = { alc861_toshiba_mixer },
+ .init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ .unsol_event = alc861_toshiba_unsol_event,
+ .init_hook = alc861_toshiba_automute,
+ },
+ [ALC861_ASUS] = {
+ .mixers = { alc861_asus_mixer },
+ .init_verbs = { alc861_asus_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .dig_out_nid = ALC861_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
+ .channel_mode = alc861_asus_modes,
+ .need_dac_fix = 1,
+ .hp_nid = 0x06,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ },
+ [ALC861_ASUS_LAPTOP] = {
+ .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
+ .init_verbs = { alc861_asus_init_verbs,
+ alc861_asus_laptop_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .dig_out_nid = ALC861_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .need_dac_fix = 1,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ },
+};
static int patch_alc861(struct hda_codec *codec)
@@ -6799,15 +7923,17 @@ static int patch_alc861(struct hda_codec *codec)
int board_config;
int err;
- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
+ alc861_models,
+ alc861_cfg_tbl);
- if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
"trying auto-probe from BIOS...\n");
board_config = ALC861_AUTO;
@@ -6846,19 +7972,706 @@ static int patch_alc861(struct hda_codec *codec)
}
/*
+ * ALC861-VD support
+ *
+ * Based on ALC882
+ *
+ * In addition, an independent DAC
+ */
+#define ALC861VD_DIGOUT_NID 0x06
+
+static hda_nid_t alc861vd_dac_nids[4] = {
+ /* front, surr, clfe, side surr */
+ 0x02, 0x03, 0x04, 0x05
+};
+
+/* dac_nids for ALC660vd are in a different order - according to
+ * Realtek's driver.
+ * This should probably tesult in a different mixer for 6stack models
+ * of ALC660vd codecs, but for now there is only 3stack mixer
+ * - and it is the same as in 861vd.
+ * adc_nids in ALC660vd are (is) the same as in 861vd
+ */
+static hda_nid_t alc660vd_dac_nids[3] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x04, 0x03
+};
+
+static hda_nid_t alc861vd_adc_nids[1] = {
+ /* ADC0 */
+ 0x09,
+};
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+static struct hda_input_mux alc861vd_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+#define alc861vd_mux_enum_info alc_mux_enum_info
+#define alc861vd_mux_enum_get alc_mux_enum_get
+
+static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux = spec->input_mux;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ static hda_nid_t capture_mixers[1] = { 0x22 };
+ hda_nid_t nid = capture_mixers[adc_idx];
+ unsigned int *cur_val = &spec->cur_mux[adc_idx];
+ unsigned int i, idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (*cur_val == idx && ! codec->in_resume)
+ return 0;
+ for (i = 0; i < imux->num_items; i++) {
+ unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ v | (imux->items[i].index << 8));
+ }
+ *cur_val = idx;
+ return 1;
+}
+
+/*
+ * 2ch mode
+ */
+static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+ { 2, NULL }
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch6_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch8_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc861vd_6stack_modes[2] = {
+ { 6, alc861vd_6stack_ch6_init },
+ { 8, alc861vd_6stack_ch8_init },
+};
+
+static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ *FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = alc861vd_mux_enum_info,
+ .get = alc861vd_mux_enum_get,
+ .put = alc861vd_mux_enum_put,
+ },
+ { } /* end */
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
+ HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+ { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc861vd_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0 and set the default input to mic-in
+ */
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
+ * the analog-loopback mixer widget
+ */
+ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)},
+
+ /*
+ * Set up output mixers (0x02 - 0x05)
+ */
+ /* set vol=0 to output mixers */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* set up input amps for analog loopback */
+ /* Amp Indices: DAC = 0, mixer = 1 */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ { }
+};
+
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static struct hda_verb alc861vd_3stack_init_verbs[] = {
+ /*
+ * Set pin mode and muting
+ */
+ /* set front pin widgets 0x14 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mic (rear) pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line-2 In: Headphone output (output 0 - 0x0c) */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
+
+/*
+ * 6-stack pin configuration:
+ */
+static struct hda_verb alc861vd_6stack_init_verbs[] = {
+ /*
+ * Set pin mode and muting
+ */
+ /* set front pin widgets 0x14 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Rear Pin: output 1 (0x0d) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+ /* CLFE Pin: output 2 (0x0e) */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+ /* Side Pin: output 3 (0x0f) */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+
+ /* Mic (rear) pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line-2 In: Headphone output (output 0 - 0x0c) */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
+#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
+#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
+#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
+
+/*
+ * configuration and preset
+ */
+static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
+ [ALC660VD_3ST] = "3stack-660",
+ [ALC861VD_3ST] = "3stack",
+ [ALC861VD_3ST_DIG] = "3stack-digout",
+ [ALC861VD_6ST_DIG] = "6stack-digout",
+ [ALC861VD_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+ SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
+ SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+
+ SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST),
+ {}
+};
+
+static struct alc_config_preset alc861vd_presets[] = {
+ [ALC660VD_3ST] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+ .dac_nids = alc660vd_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+ .adc_nids = alc861vd_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_3ST] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_3ST_DIG] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_6ST_DIG] = {
+ .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_6stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
+ .channel_mode = alc861vd_6stack_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+};
+
+/*
+ * BIOS auto configuration
+ */
+static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type, int dac_idx)
+{
+ /* set as output */
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+}
+
+static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i <= HDA_SIDE; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ if (nid)
+ alc861vd_auto_set_output_and_unmute(codec, nid,
+ PIN_OUT, i);
+ }
+}
+
+
+static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front and use dac 0 */
+ alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
+#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
+
+static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+ if (alc861vd_is_input_pin(nid)) {
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ i <= AUTO_PIN_FRONT_MIC ?
+ PIN_VREF80 : PIN_IN);
+ if (nid != ALC861VD_PIN_CD_NID)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE);
+ }
+ }
+}
+
+#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
+#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
+
+/* add playback controls from the parsed DAC table */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+ hda_nid_t nid_v, nid_s;
+ int i, err;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (! spec->multiout.dac_nids[i])
+ continue;
+ nid_v = alc861vd_idx_to_mixer_vol(
+ alc880_dac_to_idx(
+ spec->multiout.dac_nids[i]));
+ nid_s = alc861vd_idx_to_mixer_switch(
+ alc880_dac_to_idx(
+ spec->multiout.dac_nids[i]));
+
+ if (i == 2) {
+ /* Center/LFE */
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_v, 1,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_v, 2,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_s, 1,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_s, 2,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
+/* add playback controls for speaker and HP outputs */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
+ hda_nid_t pin, const char *pfx)
+{
+ hda_nid_t nid_v, nid_s;
+ int err;
+ char name[32];
+
+ if (! pin)
+ return 0;
+
+ if (alc880_is_fixed_pin(pin)) {
+ nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
+ /* specify the DAC as the extra output */
+ if (! spec->multiout.hp_nid)
+ spec->multiout.hp_nid = nid_v;
+ else
+ spec->multiout.extra_out_nid[0] = nid_v;
+ /* control HP volume/switch on the output mixer amp */
+ nid_v = alc861vd_idx_to_mixer_vol(
+ alc880_fixed_pin_idx(pin));
+ nid_s = alc861vd_idx_to_mixer_switch(
+ alc880_fixed_pin_idx(pin));
+
+ sprintf(name, "%s Playback Volume", pfx);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
+ HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", pfx);
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
+ HDA_INPUT))) < 0)
+ return err;
+ } else if (alc880_is_multi_pin(pin)) {
+ /* set manual connection */
+ /* we have only a switch on HP-out PIN */
+ sprintf(name, "%s Playback Switch", pfx);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0,
+ HDA_OUTPUT))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* parse the BIOS configuration and set up the alc_spec
+ * return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ * Based on ALC880 version - had to change it to override
+ * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+
+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+ alc861vd_ignore)) < 0)
+ return err;
+ if (! spec->autocfg.line_outs)
+ return 0; /* can't find valid BIOS pin config */
+
+ if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
+ (err = alc861vd_auto_create_multi_out_ctls(spec,
+ &spec->autocfg)) < 0 ||
+ (err = alc861vd_auto_create_extra_out(spec,
+ spec->autocfg.speaker_pins[0], "Speaker")) < 0 ||
+ (err = alc861vd_auto_create_extra_out(spec,
+ spec->autocfg.hp_pins[0], "Headphone")) < 0 ||
+ (err = alc880_auto_create_analog_input_ctls(spec,
+ &spec->autocfg)) < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->init_verbs[spec->num_init_verbs++]
+ = alc861vd_volume_init_verbs;
+
+ spec->num_mux_defs = 1;
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+/* additional initialization for auto-configuration model */
+static void alc861vd_auto_init(struct hda_codec *codec)
+{
+ alc861vd_auto_init_multi_out(codec);
+ alc861vd_auto_init_hp_out(codec);
+ alc861vd_auto_init_analog_input(codec);
+}
+
+static int patch_alc861vd(struct hda_codec *codec)
+{
+ struct alc_spec *spec;
+ int err, board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
+ alc861vd_models,
+ alc861vd_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
+ "ALC861VD, trying auto-probe from BIOS...\n");
+ board_config = ALC861VD_AUTO;
+ }
+
+ if (board_config == ALC861VD_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc861vd_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ } else if (! err) {
+ printk(KERN_INFO
+ "hda_codec: Cannot set up configuration "
+ "from BIOS. Using base mode...\n");
+ board_config = ALC861VD_3ST;
+ }
+ }
+
+ if (board_config != ALC861VD_AUTO)
+ setup_preset(spec, &alc861vd_presets[board_config]);
+
+ spec->stream_name_analog = "ALC861VD Analog";
+ spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
+ spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
+
+ spec->stream_name_digital = "ALC861VD Digital";
+ spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
+ spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
+
+ spec->adc_nids = alc861vd_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+
+ spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
+ spec->num_mixers++;
+
+ codec->patch_ops = alc_patch_ops;
+
+ if (board_config == ALC861VD_AUTO)
+ spec->init_hook = alc861vd_auto_init;
+
+ return 0;
+}
+
+/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
- { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+ { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
+ .patch = patch_alc861 },
+ { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
+ { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
+ { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
+ { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
- { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861",
- .patch = patch_alc861 },
- { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
- .patch = patch_alc861 },
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fe51ef3e49d2..6f4a39273b98 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -37,14 +37,37 @@
#define NUM_CONTROL_ALLOC 32
#define STAC_HP_EVENT 0x37
-#define STAC_REF 0
-#define STAC_D945GTP3 1
-#define STAC_D945GTP5 2
-#define STAC_MACMINI 3
-#define STAC_922X_MODELS 4 /* number of 922x models */
-#define STAC_D965_3ST 4
-#define STAC_D965_5ST 5
-#define STAC_927X_MODELS 6 /* number of 922x models */
+enum {
+ STAC_REF,
+ STAC_9200_MODELS
+};
+
+enum {
+ STAC_9205_REF,
+ STAC_9205_MODELS
+};
+
+enum {
+ STAC_925x_REF,
+ STAC_M2_2,
+ STAC_MA6,
+ STAC_925x_MODELS
+};
+
+enum {
+ STAC_D945_REF,
+ STAC_D945GTP3,
+ STAC_D945GTP5,
+ STAC_MACMINI,
+ STAC_922X_MODELS
+};
+
+enum {
+ STAC_D965_REF,
+ STAC_D965_3ST,
+ STAC_D965_5ST,
+ STAC_927X_MODELS
+};
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
@@ -67,6 +90,9 @@ struct sigmatel_spec {
unsigned int num_adcs;
hda_nid_t *mux_nids;
unsigned int num_muxes;
+ hda_nid_t *dmic_nids;
+ unsigned int num_dmics;
+ hda_nid_t dmux_nid;
hda_nid_t dig_in_nid;
/* pin widgets */
@@ -80,6 +106,8 @@ struct sigmatel_spec {
struct snd_kcontrol_new *mixer;
/* capture source */
+ struct hda_input_mux *dinput_mux;
+ unsigned int cur_dmux;
struct hda_input_mux *input_mux;
unsigned int cur_mux[3];
@@ -92,6 +120,7 @@ struct sigmatel_spec {
struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used;
struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_dimux;
struct hda_input_mux private_imux;
};
@@ -107,6 +136,18 @@ static hda_nid_t stac9200_dac_nids[1] = {
0x02,
};
+static hda_nid_t stac925x_adc_nids[1] = {
+ 0x03,
+};
+
+static hda_nid_t stac925x_mux_nids[1] = {
+ 0x0f,
+};
+
+static hda_nid_t stac925x_dac_nids[1] = {
+ 0x02,
+};
+
static hda_nid_t stac922x_adc_nids[2] = {
0x06, 0x07,
};
@@ -131,11 +172,20 @@ static hda_nid_t stac9205_mux_nids[2] = {
0x19, 0x1a
};
+static hda_nid_t stac9205_dmic_nids[3] = {
+ 0x17, 0x18, 0
+};
+
static hda_nid_t stac9200_pin_nids[8] = {
0x08, 0x09, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12,
};
+static hda_nid_t stac925x_pin_nids[8] = {
+ 0x07, 0x08, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x10, 0x11,
+};
+
static hda_nid_t stac922x_pin_nids[10] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x15, 0x1b,
@@ -154,6 +204,34 @@ static hda_nid_t stac9205_pin_nids[12] = {
};
+static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
+}
+
+static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_dmux;
+ return 0;
+}
+
+static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
+ spec->dmux_nid, &spec->cur_dmux);
+}
+
static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -187,6 +265,12 @@ static struct hda_verb stac9200_core_init[] = {
{}
};
+static struct hda_verb stac925x_core_init[] = {
+ /* set dac0mux for dac converter */
+ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {}
+};
+
static struct hda_verb stac922x_core_init[] = {
/* set master volume and direct control */
{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -232,6 +316,23 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new stac925x_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 1,
+ .info = stac92xx_mux_enum_info,
+ .get = stac92xx_mux_enum_get,
+ .put = stac92xx_mux_enum_put,
+ },
+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
+ { } /* end */
+};
+
/* This needs to be generated dynamically based on sequence */
static struct snd_kcontrol_new stac922x_mixer[] = {
{
@@ -263,7 +364,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = {
{ } /* end */
};
-static snd_kcontrol_new_t stac927x_mixer[] = {
+static struct snd_kcontrol_new stac927x_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -278,7 +379,15 @@ static snd_kcontrol_new_t stac927x_mixer[] = {
{ } /* end */
};
-static snd_kcontrol_new_t stac9205_mixer[] = {
+static struct snd_kcontrol_new stac9205_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Input Source",
+ .count = 1,
+ .info = stac92xx_dmux_enum_info,
+ .get = stac92xx_dmux_enum_get,
+ .put = stac92xx_dmux_enum_put,
+ },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -327,22 +436,64 @@ static unsigned int ref9200_pin_configs[8] = {
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
};
-static unsigned int *stac9200_brd_tbl[] = {
- ref9200_pin_configs,
+static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
+ [STAC_REF] = ref9200_pin_configs,
+};
+
+static const char *stac9200_models[STAC_9200_MODELS] = {
+ [STAC_REF] = "ref",
};
-static struct hda_board_config stac9200_cfg_tbl[] = {
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF },
+static struct snd_pci_quirk stac9200_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_REF),
/* Dell laptops have BIOS problem */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5,
- .config = STAC_REF }, /* Dell Inspiron 630m */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2,
- .config = STAC_REF }, /* Dell Latitude D620 */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb,
- .config = STAC_REF }, /* Dell Latitude 120L */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
+ "Dell Inspiron 630m", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
+ "Dell Latitude D620", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
+ "Dell Latitude 120L", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
+ "Dell Latitude D820", STAC_REF),
+ {} /* terminator */
+};
+
+static unsigned int ref925x_pin_configs[8] = {
+ 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+ 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925x_MA6_pin_configs[8] = {
+ 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+ 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM2_2_pin_configs[8] = {
+ 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020,
+ 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
+ [STAC_REF] = ref925x_pin_configs,
+ [STAC_M2_2] = stac925xM2_2_pin_configs,
+ [STAC_MA6] = stac925x_MA6_pin_configs,
+};
+
+static const char *stac925x_models[STAC_925x_MODELS] = {
+ [STAC_REF] = "ref",
+ [STAC_M2_2] = "m2-2",
+ [STAC_MA6] = "m6",
+};
+
+static struct snd_pci_quirk stac925x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
+ SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
{} /* terminator */
};
@@ -365,100 +516,80 @@ static unsigned int d945gtp5_pin_configs[10] = {
};
static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
- [STAC_REF] = ref922x_pin_configs,
+ [STAC_D945_REF] = ref922x_pin_configs,
[STAC_D945GTP3] = d945gtp3_pin_configs,
[STAC_D945GTP5] = d945gtp5_pin_configs,
[STAC_MACMINI] = d945gtp5_pin_configs,
};
-static struct hda_board_config stac922x_cfg_tbl[] = {
- { .modelname = "5stack", .config = STAC_D945GTP5 },
- { .modelname = "3stack", .config = STAC_D945GTP3 },
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
- /* Intel 945G based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0101,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0202,
- .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0606,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0601,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0111,
- .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1115,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1116,
- .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1117,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1118,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1119,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x8826,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5049,
- .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5055,
- .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5048,
- .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0110,
- .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0404,
- .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0303,
- .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0013,
- .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0417,
- .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */
- /* Intel 945P based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0b0b,
- .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0112,
- .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0d0d,
- .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0909,
- .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0505,
- .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0707,
- .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */
- /* other systems */
- { .pci_subvendor = 0x8384,
- .pci_subdevice = 0x7680,
- .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
+static const char *stac922x_models[STAC_922X_MODELS] = {
+ [STAC_D945_REF] = "ref",
+ [STAC_D945GTP5] = "5stack",
+ [STAC_D945GTP3] = "3stack",
+ [STAC_MACMINI] = "macmini",
+};
+
+static struct snd_pci_quirk stac922x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_D945_REF),
+ /* Intel 945G based systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
+ "Intel D945G", STAC_D945GTP3),
+ /* Intel D945G 5-stack systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
+ "Intel D945G", STAC_D945GTP5),
+ /* Intel 945P based systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
+ "Intel D945P", STAC_D945GTP5),
+ /* other systems */
+ /* Apple Mac Mini (early 2006) */
+ SND_PCI_QUIRK(0x8384, 0x7680,
+ "Mac Mini", STAC_MACMINI),
{} /* terminator */
};
@@ -484,120 +615,72 @@ static unsigned int d965_5st_pin_configs[14] = {
};
static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
- [STAC_REF] = ref927x_pin_configs,
+ [STAC_D965_REF] = ref927x_pin_configs,
[STAC_D965_3ST] = d965_3st_pin_configs,
[STAC_D965_5ST] = d965_5st_pin_configs,
};
-static struct hda_board_config stac927x_cfg_tbl[] = {
- { .modelname = "5stack", .config = STAC_D965_5ST },
- { .modelname = "3stack", .config = STAC_D965_3ST },
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
+static const char *stac927x_models[STAC_927X_MODELS] = {
+ [STAC_D965_REF] = "ref",
+ [STAC_D965_3ST] = "3stack",
+ [STAC_D965_5ST] = "5stack",
+};
+
+static struct snd_pci_quirk stac927x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_D965_REF),
/* Intel 946 based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x3d01,
- .config = STAC_D965_3ST }, /* D946 configuration */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0xa301,
- .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
/* 965 based 3 stack systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2116,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2115,
- .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2114,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2113,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2112,
- .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2111,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2110,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2009,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2008,
- .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2007,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2006,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2005,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2004,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2003,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2002,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2001,
- .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
/* 965 based 5 stack systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2301,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2302,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2303,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2304,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2305,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2501,
- .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2502,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2503,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2504,
- .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
{} /* terminator */
};
static unsigned int ref9205_pin_configs[12] = {
0x40000100, 0x40000100, 0x01016011, 0x01014010,
- 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
- 0x40000100, 0x40000100, 0x01441030, 0x01c41030
+ 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
+ 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
};
-static unsigned int *stac9205_brd_tbl[] = {
+static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
ref9205_pin_configs,
};
-static struct hda_board_config stac9205_cfg_tbl[] = {
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
+static const char *stac9205_models[STAC_9205_MODELS] = {
+ [STAC_9205_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac9205_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_9205_REF),
{} /* terminator */
};
@@ -1154,6 +1237,58 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
return 0;
}
+/* labels for dmic mux inputs */
+static const char *stac92xx_dmic_labels[5] = {
+ "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
+ "Digital Mic 3", "Digital Mic 4"
+};
+
+/* create playback/capture controls for input pins on dmic capable codecs */
+static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct hda_input_mux *dimux = &spec->private_dimux;
+ hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+ int i, j;
+
+ dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
+ dimux->items[dimux->num_items].index = 0;
+ dimux->num_items++;
+
+ for (i = 0; i < spec->num_dmics; i++) {
+ int index;
+ int num_cons;
+ unsigned int def_conf;
+
+ def_conf = snd_hda_codec_read(codec,
+ spec->dmic_nids[i],
+ 0,
+ AC_VERB_GET_CONFIG_DEFAULT,
+ 0);
+ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+ continue;
+
+ num_cons = snd_hda_get_connections(codec,
+ spec->dmux_nid,
+ con_lst,
+ HDA_MAX_NUM_INPUTS);
+ for (j = 0; j < num_cons; j++)
+ if (con_lst[j] == spec->dmic_nids[i]) {
+ index = j;
+ goto found;
+ }
+ continue;
+found:
+ dimux->items[dimux->num_items].label =
+ stac92xx_dmic_labels[dimux->num_items];
+ dimux->items[dimux->num_items].index = index;
+ dimux->num_items++;
+ }
+
+ return 0;
+}
+
/* create playback/capture controls for input pins */
static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
@@ -1238,7 +1373,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
struct sigmatel_spec *spec = codec->spec;
int err;
- if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
+ if ((err = snd_hda_parse_pin_def_config(codec,
+ &spec->autocfg,
+ spec->dmic_nids)) < 0)
return err;
if (! spec->autocfg.line_outs)
return 0; /* can't find valid pin config */
@@ -1254,6 +1391,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
(err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
return err;
+ if (spec->num_dmics > 0)
+ if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
+ &spec->autocfg)) < 0)
+ return err;
+
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
if (spec->multiout.max_channels > 2)
spec->surr_switch = 1;
@@ -1267,6 +1409,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->input_mux = &spec->private_imux;
+ spec->dinput_mux = &spec->private_dimux;
return 1;
}
@@ -1366,6 +1509,7 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->input_mux = &spec->private_imux;
+ spec->dinput_mux = &spec->private_dimux;
return 1;
}
@@ -1448,6 +1592,11 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_set_pinctl(codec, nid, pinctl);
}
}
+ if (spec->num_dmics > 0)
+ for (i = 0; i < spec->num_dmics; i++)
+ stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
+ AC_PINCTL_IN_EN);
+
if (cfg->dig_out_pin)
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
AC_PINCTL_OUT_EN);
@@ -1598,7 +1747,9 @@ static int patch_stac9200(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 8;
spec->pin_nids = stac9200_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
+ stac9200_models,
+ stac9200_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1618,6 +1769,7 @@ static int patch_stac9200(struct hda_codec *codec)
spec->adc_nids = stac9200_adc_nids;
spec->mux_nids = stac9200_mux_nids;
spec->num_muxes = 1;
+ spec->num_dmics = 0;
spec->init = stac9200_core_init;
spec->mixer = stac9200_mixer;
@@ -1633,6 +1785,56 @@ static int patch_stac9200(struct hda_codec *codec)
return 0;
}
+static int patch_stac925x(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+ spec->num_pins = 8;
+ spec->pin_nids = stac925x_pin_nids;
+ spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+ stac925x_models,
+ stac925x_cfg_tbl);
+ if (spec->board_config < 0) {
+ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n");
+ err = stac92xx_save_bios_config_regs(codec);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
+ spec->pin_configs = spec->bios_pin_configs;
+ } else if (stac925x_brd_tbl[spec->board_config] != NULL){
+ spec->pin_configs = stac925x_brd_tbl[spec->board_config];
+ stac92xx_set_config_regs(codec);
+ }
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = stac925x_dac_nids;
+ spec->adc_nids = stac925x_adc_nids;
+ spec->mux_nids = stac925x_mux_nids;
+ spec->num_muxes = 1;
+ spec->num_dmics = 0;
+
+ spec->init = stac925x_core_init;
+ spec->mixer = stac925x_mixer;
+
+ err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
+
+ codec->patch_ops = stac92xx_patch_ops;
+
+ return 0;
+}
+
static int patch_stac922x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -1645,7 +1847,9 @@ static int patch_stac922x(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 10;
spec->pin_nids = stac922x_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
+ stac922x_models,
+ stac922x_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
"using BIOS defaults\n");
@@ -1663,6 +1867,7 @@ static int patch_stac922x(struct hda_codec *codec)
spec->adc_nids = stac922x_adc_nids;
spec->mux_nids = stac922x_mux_nids;
spec->num_muxes = 2;
+ spec->num_dmics = 0;
spec->init = stac922x_core_init;
spec->mixer = stac922x_mixer;
@@ -1695,7 +1900,9 @@ static int patch_stac927x(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 14;
spec->pin_nids = stac927x_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
+ stac927x_models,
+ stac927x_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1714,6 +1921,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = d965_core_init;
spec->mixer = stac9227_mixer;
break;
@@ -1721,6 +1929,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = d965_core_init;
spec->mixer = stac9227_mixer;
break;
@@ -1728,6 +1937,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = stac927x_core_init;
spec->mixer = stac927x_mixer;
}
@@ -1757,7 +1967,9 @@ static int patch_stac9205(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 14;
spec->pin_nids = stac9205_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
+ stac9205_models,
+ stac9205_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1773,13 +1985,28 @@ static int patch_stac9205(struct hda_codec *codec)
spec->adc_nids = stac9205_adc_nids;
spec->mux_nids = stac9205_mux_nids;
- spec->num_muxes = 3;
+ spec->num_muxes = 2;
+ spec->dmic_nids = stac9205_dmic_nids;
+ spec->num_dmics = 2;
+ spec->dmux_nid = 0x1d;
spec->init = stac9205_core_init;
spec->mixer = stac9205_mixer;
spec->multiout.dac_nids = spec->dac_nids;
+ /* Configure GPIO0 as EAPD output */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
+ /* Configure GPIO0 as CMOS */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+ /* Assert GPIO0 high */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, 0x00000001);
+ /* Enable GPIO0 */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, 0x00000001);
+
err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
if (err < 0) {
stac92xx_free(codec);
@@ -1963,18 +2190,19 @@ enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
/* Unknown. id=0x83847661 and subsys=0x104D1200. */
STAC9872K_VAIO,
/* AR Series. id=0x83847664 and subsys=104D1300 */
- CXD9872AKD_VAIO
- };
-
-static struct hda_board_config stac9872_cfg_tbl[] = {
- { .modelname = "vaio", .config = CXD9872RD_VAIO },
- { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
- .config = CXD9872RD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
- .config = CXD9872RD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd,
- .config = CXD9872AKD_VAIO },
+ CXD9872AKD_VAIO,
+ STAC_9872_MODELS,
+};
+
+static const char *stac9872_models[STAC_9872_MODELS] = {
+ [CXD9872RD_VAIO] = "vaio",
+ [CXD9872AKD_VAIO] = "vaio-ar",
+};
+
+static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
+ SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
+ SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
{}
};
@@ -1983,7 +2211,9 @@ static int patch_stac9872(struct hda_codec *codec)
struct sigmatel_spec *spec;
int board_config;
- board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+ stac9872_models,
+ stac9872_cfg_tbl);
if (board_config < 0)
/* unknown config, let generic-parser do its job... */
return snd_hda_parse_generic_codec(codec);
@@ -2055,6 +2285,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
{ .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
{ .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
+ { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
+ { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
+ { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
+ { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
+ { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
+ { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
/* The following does not take into account .id=0x83847661 when subsys =
* 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
* currently not fully supported.
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
new file mode 100644
index 000000000000..4c839b031729
--- /dev/null
+++ b/sound/pci/hda/patch_via.c
@@ -0,0 +1,1396 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for VIA VT1708 codec
+ *
+ * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
+ * Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
+/* */
+/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
+/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
+/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
+/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* amp values */
+#define AMP_VAL_IDX_SHIFT 19
+#define AMP_VAL_IDX_MASK (0x0f<<19)
+
+#define NUM_CONTROL_ALLOC 32
+#define NUM_VERB_ALLOC 32
+
+/* Pin Widget NID */
+#define VT1708_HP_NID 0x13
+#define VT1708_DIGOUT_NID 0x14
+#define VT1708_DIGIN_NID 0x16
+
+#define VT1709_HP_DAC_NID 0x28
+#define VT1709_DIGOUT_NID 0x13
+#define VT1709_DIGIN_NID 0x17
+
+#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
+#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
+#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
+
+
+enum {
+ VIA_CTL_WIDGET_VOL,
+ VIA_CTL_WIDGET_MUTE,
+};
+
+enum {
+ AUTO_SEQ_FRONT,
+ AUTO_SEQ_SURROUND,
+ AUTO_SEQ_CENLFE,
+ AUTO_SEQ_SIDE
+};
+
+static struct snd_kcontrol_new vt1708_control_templates[] = {
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+ HDA_CODEC_MUTE(NULL, 0, 0, 0),
+};
+
+
+struct via_spec {
+ /* codec parameterization */
+ struct snd_kcontrol_new *mixers[3];
+ unsigned int num_mixers;
+
+ struct hda_verb *init_verbs;
+
+ char *stream_name_analog;
+ struct hda_pcm_stream *stream_analog_playback;
+ struct hda_pcm_stream *stream_analog_capture;
+
+ char *stream_name_digital;
+ struct hda_pcm_stream *stream_digital_playback;
+ struct hda_pcm_stream *stream_digital_capture;
+
+ /* playback */
+ struct hda_multi_out multiout;
+
+ /* capture */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ hda_nid_t dig_in_nid;
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ unsigned int cur_mux[3];
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[2];
+
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_imux;
+ hda_nid_t private_dac_nids[4];
+};
+
+static hda_nid_t vt1708_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x15, 0x27
+};
+
+static hda_nid_t vt1709_adc_nids[3] = {
+ /* ADC1-2 */
+ 0x14, 0x15, 0x16
+};
+
+/* add dynamic controls */
+static int via_add_control(struct via_spec *spec, int type, const char *name,
+ unsigned long val)
+{
+ struct snd_kcontrol_new *knew;
+
+ if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+ int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+ /* array + terminator */
+ knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
+ if (!knew)
+ return -ENOMEM;
+ if (spec->kctl_alloc) {
+ memcpy(knew, spec->kctl_alloc,
+ sizeof(*knew) * spec->num_kctl_alloc);
+ kfree(spec->kctl_alloc);
+ }
+ spec->kctl_alloc = knew;
+ spec->num_kctl_alloc = num;
+ }
+
+ knew = &spec->kctl_alloc[spec->num_kctl_used];
+ *knew = vt1708_control_templates[type];
+ knew->name = kstrdup(name, GFP_KERNEL);
+
+ if (!knew->name)
+ return -ENOMEM;
+ knew->private_value = val;
+ spec->num_kctl_used++;
+ return 0;
+}
+
+/* create input playback/capture controls for the given pin */
+static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
+ const char *ctlname, int idx, int mix_nid)
+{
+ char name[32];
+ int err;
+
+ sprintf(name, "%s Playback Volume", ctlname);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", ctlname);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static void via_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type,
+ int dac_idx)
+{
+ /* set as output */
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_type);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+}
+
+
+static void via_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ if (nid)
+ via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+ }
+}
+
+static void via_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+static void via_auto_init_analog_input(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ (i <= AUTO_PIN_FRONT_MIC ?
+ PIN_VREF50 : PIN_IN));
+
+ }
+}
+/*
+ * input MUX handling
+ */
+static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ return 0;
+}
+
+static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ unsigned int vendor_id = codec->vendor_id;
+
+ /* AIW0 lydia 060801 add for correct sw0 input select */
+ if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ 0x18, &spec->cur_mux[adc_idx]);
+ else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
+ IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ 0x19, &spec->cur_mux[adc_idx]);
+ else
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->adc_nids[adc_idx],
+ &spec->cur_mux[adc_idx]);
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output mixers (0x19 - 0x1b)
+ */
+ /* set vol=0 to output mixers */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Setup default input to PW4 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Set mic as default input of sw0 */
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+};
+
+static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+ stream_tag, format, substream);
+}
+
+static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ 0, 0, 0);
+ return 0;
+}
+
+static struct hda_pcm_stream vt1708_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x15, /* NID to query formats and rates */
+ .ops = {
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int via_build_controls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+ int i;
+
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->multiout.dig_out_nid) {
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+ if (spec->dig_in_nid) {
+ err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int via_build_pcms(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = spec->stream_name_analog;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ codec->num_pcms++;
+ info++;
+ info->name = spec->stream_name_digital;
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *(spec->stream_digital_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dig_out_nid;
+ }
+ if (spec->dig_in_nid) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ *(spec->stream_digital_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static void via_free(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ unsigned int i;
+
+ if (!spec)
+ return;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+
+ kfree(codec->spec);
+}
+
+static int via_init(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ snd_hda_sequence_write(codec, spec->init_verbs);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int via_resume(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ via_init(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+
+ return 0;
+}
+#endif
+
+/*
+ */
+static struct hda_codec_ops via_patch_ops = {
+ .build_controls = via_build_controls,
+ .build_pcms = via_build_pcms,
+ .init = via_init,
+ .free = via_free,
+#ifdef CONFIG_PM
+ .resume = via_resume,
+#endif
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int i;
+ hda_nid_t nid;
+
+ spec->multiout.num_dacs = cfg->line_outs;
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ for(i = 0; i < 4; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ spec->multiout.dac_nids[i] = 0x13;
+ break;
+ case AUTO_SEQ_SIDE:
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ hda_nid_t nid, nid_vol = 0;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+
+ if (i != AUTO_SEQ_FRONT)
+ nid_vol = 0x1b - i + 1;
+
+ if (i == AUTO_SEQ_CENLFE) {
+ /* Center/LFE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT){
+ /* add control to mixer index 0 */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+
+ /* add control to PW3 */
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ static char *labels[] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, err, idx = 0;
+
+ /* for internal loopback recording select */
+ imux->items[imux->num_items].label = "Stereo Mixer";
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (!cfg->input_pins[i])
+ continue;
+
+ switch (cfg->input_pins[i]) {
+ case 0x1d: /* Mic */
+ idx = 2;
+ break;
+
+ case 0x1e: /* Line In */
+ idx = 3;
+ break;
+
+ case 0x21: /* Front Mic */
+ idx = 4;
+ break;
+
+ case 0x24: /* CD */
+ idx = 1;
+ break;
+ }
+ err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+ idx, 0x17);
+ if (err < 0)
+ return err;
+ imux->items[imux->num_items].label = labels[i];
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+ }
+ return 0;
+}
+
+static int vt1708_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+ if (spec->autocfg.dig_in_pin)
+ spec->dig_in_nid = VT1708_DIGIN_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->init_verbs = vt1708_volume_init_verbs;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+/* init callback for auto-configuration model -- overriding the default init */
+static int via_auto_init(struct hda_codec *codec)
+{
+ via_init(codec);
+ via_auto_init_multi_out(codec);
+ via_auto_init_hp_out(codec);
+ via_auto_init_analog_input(codec);
+ return 0;
+}
+
+static int patch_vt1708(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt1708_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+
+ spec->stream_name_analog = "VT1708 Analog";
+ spec->stream_analog_playback = &vt1708_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1708_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1708 Digital";
+ spec->stream_digital_playback = &vt1708_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1708_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1708_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1709_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output selector (0x1a, 0x1b, 0x29)
+ */
+ /* set vol=0 to output mixers */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /*
+ * Unmute PW3 and PW4
+ */
+ {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Set input of PW4 as AOW4 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Set mic as default input of sw0 */
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ { }
+};
+
+static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 10,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 6,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x14, /* NID to query formats and rates */
+ .ops = {
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int i;
+ hda_nid_t nid;
+
+ if (cfg->line_outs == 4) /* 10 channels */
+ spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
+ else if (cfg->line_outs == 3) /* 6 channels */
+ spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ if (cfg->line_outs == 4) { /* 10 channels */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ /* AOW0 */
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ /* AOW2 */
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ /* AOW3 */
+ spec->multiout.dac_nids[i] = 0x27;
+ break;
+ case AUTO_SEQ_SIDE:
+ /* AOW1 */
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
+
+ } else if (cfg->line_outs == 3) { /* 6 channels */
+ for(i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch(i) {
+ case AUTO_SEQ_FRONT:
+ /* AOW0 */
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ /* AOW2 */
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ /* AOW1 */
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ hda_nid_t nid = 0;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+
+ if (i == AUTO_SEQ_CENLFE) {
+ /* Center/LFE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT){
+ /* add control to mixer index 0 */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+
+ /* add control to PW3 */
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_SURROUND) {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_SIDE) {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ if (spec->multiout.num_dacs == 5) /* 10 channels */
+ spec->multiout.hp_nid = VT1709_HP_DAC_NID;
+ else if (spec->multiout.num_dacs == 3) /* 6 channels */
+ spec->multiout.hp_nid = 0;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ static char *labels[] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, err, idx = 0;
+
+ /* for internal loopback recording select */
+ imux->items[imux->num_items].label = "Stereo Mixer";
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (!cfg->input_pins[i])
+ continue;
+
+ switch (cfg->input_pins[i]) {
+ case 0x1d: /* Mic */
+ idx = 2;
+ break;
+
+ case 0x1e: /* Line In */
+ idx = 3;
+ break;
+
+ case 0x21: /* Front Mic */
+ idx = 4;
+ break;
+
+ case 0x23: /* CD */
+ idx = 1;
+ break;
+ }
+ err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+ idx, 0x18);
+ if (err < 0)
+ return err;
+ imux->items[imux->num_items].label = labels[i];
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+ }
+ return 0;
+}
+
+static int vt1709_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+ if (spec->autocfg.dig_in_pin)
+ spec->dig_in_nid = VT1709_DIGIN_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+static int patch_vt1709_10ch(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ err = vt1709_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration. "
+ "Using genenic mode...\n");
+ }
+
+ spec->init_verbs = vt1709_10ch_volume_init_verbs;
+
+ spec->stream_name_analog = "VT1709 Analog";
+ spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1709 Digital";
+ spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1709_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output selector (0x1a, 0x1b, 0x29)
+ */
+ /* set vol=0 to output mixers */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /*
+ * Unmute PW3 and PW4
+ */
+ {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Set input of PW4 as MW0 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0},
+ /* Set mic as default input of sw0 */
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ { }
+};
+
+static int patch_vt1709_6ch(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ err = vt1709_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration. "
+ "Using genenic mode...\n");
+ }
+
+ spec->init_verbs = vt1709_6ch_volume_init_verbs;
+
+ spec->stream_name_analog = "VT1709 Analog";
+ spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1709 Digital";
+ spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1709_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_via[] = {
+ { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ {} /* terminator */
+};
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 7837cef8855c..6efdd62f6837 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
snd-ice17xx-ak4xxx-objs := ak4xxx.o
snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
index 59c4078ad331..6e22d326df32 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -42,7 +42,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits[] = {
+ static const unsigned short wm_inits[] = {
WM_ATTEN_L, 0x0000, /* 0 db */
WM_ATTEN_R, 0x0000, /* 0 db */
WM_DAC_CTRL, 0x0008, /* 24bit I2S */
@@ -75,7 +75,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_AV710,
.name = "Chaintech AV-710",
diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h
index a0fc89b48122..7b667bad0c6b 100644
--- a/sound/pci/ice1712/amp.h
+++ b/sound/pci/ice1712/amp.h
@@ -42,7 +42,7 @@
#define WM_DAC_CTRL 0x02
#define WM_INT_CTRL 0x03
-extern struct snd_ice1712_card_info snd_vt1724_amp_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_amp_cards[];
#endif /* __SOUND_AMP_H */
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 9e76cebd2d22..6941d85dfec9 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -294,7 +294,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r
static int aureon_ac97_init (struct snd_ice1712 *ice)
{
int i;
- static unsigned short ac97_defaults[] = {
+ static const unsigned short ac97_defaults[] = {
0x00, 0x9640,
0x02, 0x8000,
0x04, 0x8000,
@@ -474,7 +474,8 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned
tmp = snd_ice1712_gpio_read(ice);
- if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
mosi = PRODIGY_SPI_MOSI;
clk = PRODIGY_SPI_CLK;
@@ -601,7 +602,9 @@ static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
{
aureon_spi_write(ice,
- (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
+ ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
+ PRODIGY_WM_CS : AUREON_WM_CS),
(reg << 9) | (val & 0x1ff), 16);
}
@@ -661,17 +664,17 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
/*
* Logarithmic volume values for WM8770
* Computed as 20 * Log10(255 / x)
*/
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -1064,14 +1067,14 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
*/
static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"CD", //AIN1
"Aux", //AIN2
"Line", //AIN3
"Mic", //AIN4
"AC97" //AIN5
};
- static char *universe_texts[] = {
+ static const char * const universe_texts[] = {
"Aux1", //AIN1
"CD", //AIN2
"Phono", //AIN3
@@ -1137,11 +1140,11 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static char *aureon_texts[] = {
+ static const char * const aureon_texts[] = {
"CD", //RXP0
"Optical" //RXP1
};
- static char *prodigy_texts[] = {
+ static const char * const prodigy_texts[] = {
"CD",
"Coax"
};
@@ -1288,12 +1291,14 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
tmp2 = tmp = snd_ice1712_gpio_read(ice);
if (enable)
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
tmp |= AUREON_HP_SEL;
else
tmp |= PRODIGY_HP_SEL;
else
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
tmp &= ~ AUREON_HP_SEL;
else
tmp &= ~ PRODIGY_HP_SEL;
@@ -1363,7 +1368,7 @@ static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
*/
static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "128x", "64x" };
+ static const char * const texts[2] = { "128x", "64x" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
@@ -1406,7 +1411,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl
* mixers
*/
-static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -1521,7 +1526,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
@@ -1587,7 +1592,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new ac97_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 Playback Switch",
@@ -1692,7 +1697,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 Playback Switch",
@@ -1824,8 +1829,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
};
-
-static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
+static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
@@ -1870,7 +1874,6 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
}
};
-
static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
{
unsigned int i, counts;
@@ -1898,7 +1901,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
return err;
}
}
- else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
if (err < 0)
@@ -1906,7 +1910,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
}
}
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
unsigned char id;
snd_ice1712_save_gpio_status(ice);
id = aureon_cs8415_get(ice, CS8415_ID);
@@ -1936,7 +1941,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit aureon_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits_aureon[] = {
+ static const unsigned short wm_inits_aureon[] = {
/* These come first to reduce init pop noise */
0x1b, 0x044, /* ADC Mux (AC'97 source) */
0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -1972,7 +1977,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
0x1a, 0x000, /* -12dB ADC/R */
(unsigned short)-1
};
- static unsigned short wm_inits_prodigy[] = {
+ static const unsigned short wm_inits_prodigy[] = {
/* These come first to reduce init pop noise */
0x1b, 0x000, /* ADC Mux */
@@ -2014,7 +2019,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
(unsigned short)-1
};
- static unsigned short cs_inits[] = {
+ static const unsigned short cs_inits[] = {
0x0441, /* RUN */
0x0180, /* no mute, OMCK output on RMCK pin */
0x0201, /* S/PDIF source on RXP1 */
@@ -2022,7 +2027,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
(unsigned short)-1
};
unsigned int tmp;
- unsigned short *p;
+ const unsigned short *p;
int err, i;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
@@ -2062,7 +2067,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
/* initialize WM8770 codec */
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
- ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
p = wm_inits_prodigy;
else
p = wm_inits_aureon;
@@ -2070,7 +2076,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
wm_put(ice, p[0], p[1]);
/* initialize CS8415A codec */
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
for (p = cs_inits; *p != (unsigned short)-1; p++)
aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
ice->spec.aureon.cs8415_mux = 1;
@@ -2100,73 +2107,58 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char aureon51_eeprom[] __devinitdata = {
- 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char aureon51_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-static unsigned char aureon71_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char aureon71_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-
-static unsigned char prodigy71_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+#define prodigy71_eeprom aureon71_eeprom
+
+static const unsigned char prodigy71lt_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-
-static unsigned char prodigy71lt_eeprom[] __devinitdata = {
- 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
-};
-
+#define prodigy71xt_eeprom prodigy71lt_eeprom
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
.name = "Terratec Aureon 5.1-Sky",
@@ -2217,5 +2209,15 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
.eeprom_data = prodigy71lt_eeprom,
.driver = "Prodigy71LT",
},
+ {
+ .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
+ .name = "Audiotrak Prodigy 7.1 XT",
+ .model = "prodigy71xt",
+ .chip_init = aureon_init,
+ .build_controls = aureon_add_controls,
+ .eeprom_size = sizeof(prodigy71xt_eeprom),
+ .eeprom_data = prodigy71xt_eeprom,
+ .driver = "Prodigy71LT",
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h
index 3b7bea656c57..79e58e88ed47 100644
--- a/sound/pci/ice1712/aureon.h
+++ b/sound/pci/ice1712/aureon.h
@@ -28,15 +28,17 @@
"{Terratec,Aureon 7.1 Space},"\
"{Terratec,Aureon 7.1 Universe}," \
"{AudioTrak,Prodigy 7.1}," \
- "{AudioTrak,Prodigy 7.1 LT},"
+ "{AudioTrak,Prodigy 7.1 LT},"\
+ "{AudioTrak,Prodigy 7.1 XT},"
#define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */
#define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */
#define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */
#define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */
#define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */
+#define VT1724_SUBDEVICE_PRODIGY71XT 0x36315441 /* PRODIGY 7.1 XT*/
-extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
/* GPIO bits */
#define AUREON_CS8415_CS (1 << 22)
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index af659800c9b0..3eeb36c6e985 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -416,7 +416,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READ),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -429,7 +429,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini
* initialize the chips on M-Audio cards
*/
-static struct snd_akm4xxx akm_audiophile __devinitdata = {
+static const struct snd_akm4xxx akm_audiophile __devinitdata = {
.type = SND_AK4528,
.num_adcs = 2,
.num_dacs = 2,
@@ -438,7 +438,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -450,7 +450,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta410 __devinitdata = {
+static const struct snd_akm4xxx akm_delta410 __devinitdata = {
.type = SND_AK4529,
.num_adcs = 2,
.num_dacs = 8,
@@ -459,7 +459,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
.caddr = 0,
.cif = 0,
.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -471,7 +471,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta1010lt __devinitdata = {
+static const struct snd_akm4xxx akm_delta1010lt __devinitdata = {
.type = SND_AK4524,
.num_adcs = 8,
.num_dacs = 8,
@@ -481,7 +481,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
.caddr = 2,
.cif = 0, /* the default level of the CIF pin from AK4524 */
.data_mask = ICE1712_DELTA_1010LT_DOUT,
@@ -493,7 +493,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta44 __devinitdata = {
+static const struct snd_akm4xxx akm_delta44 __devinitdata = {
.type = SND_AK4524,
.num_adcs = 4,
.num_dacs = 4,
@@ -503,7 +503,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
.caddr = 2,
.cif = 0, /* the default level of the CIF pin from AK4524 */
.data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA,
@@ -515,7 +515,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_vx442 __devinitdata = {
+static const struct snd_akm4xxx akm_vx442 __devinitdata = {
.type = SND_AK4524,
.num_adcs = 4,
.num_dacs = 4,
@@ -525,7 +525,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = ICE1712_VX442_DOUT,
@@ -650,15 +650,15 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
* additional controls for M-Audio cards
*/
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
-static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
@@ -735,7 +735,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_DELTA1010,
.name = "M Audio Delta 1010",
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index 746ebde94522..e65d669af639 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -46,7 +46,7 @@
#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
/* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
/*
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index b135389fec6c..9b7ff302c072 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -332,7 +332,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate)
/*
*/
-static struct snd_akm4xxx akm_ews88mt __devinitdata = {
+static const struct snd_akm4xxx akm_ews88mt __devinitdata = {
.num_adcs = 8,
.num_dacs = 8,
.type = SND_AK4524,
@@ -342,7 +342,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -354,7 +354,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_ewx2496 __devinitdata = {
+static const struct snd_akm4xxx akm_ewx2496 __devinitdata = {
.num_adcs = 2,
.num_dacs = 2,
.type = SND_AK4524,
@@ -363,7 +363,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -375,7 +375,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_6fire __devinitdata = {
+static const struct snd_akm4xxx akm_6fire __devinitdata = {
.num_adcs = 6,
.num_dacs = 6,
.type = SND_AK4524,
@@ -384,7 +384,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_6FIRE_SERIAL_DATA,
@@ -578,7 +578,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn
return val != nval;
}
-static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Sensitivity Switch",
@@ -678,7 +678,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st
return ndata != data;
}
-static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
@@ -687,7 +687,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
.count = 8,
};
-static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Output Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
@@ -769,7 +769,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct
.private_value = xshift | (xinvert << 8),\
}
-static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0),
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0),
@@ -909,7 +909,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str
.private_value = xshift | (xinvert << 8),\
}
-static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Analog Input Select",
@@ -989,7 +989,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_EWX2496,
.name = "TerraTec EWX24/96",
diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h
index a12a0b053558..df449b4741f6 100644
--- a/sound/pci/ice1712/ews.h
+++ b/sound/pci/ice1712/ews.h
@@ -40,7 +40,7 @@
#define ICE1712_SUBDEVICE_PHASE88 0x3b155111
/* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_ews_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_ews_cards[];
/* TerraTec EWX 24/96 configuration definitions */
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 3f27d04e7d3c..df97313aaf83 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -239,7 +239,7 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip)
static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice)
{
/* Hoontech STDSP24 with modified hardware */
- static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
+ static const struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
.num_adcs = 2,
.num_dacs = 2,
.type = SND_AK4524,
@@ -248,7 +248,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice)
}
};
- static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
+ static const struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_STDSP24_SERIAL_DATA,
@@ -298,7 +298,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_STDSP24,
.name = "Hoontech SoundTrack Audio DSP24",
@@ -325,4 +325,3 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
},
{ } /* terminator */
};
-
diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h
index 1ee538b20fbf..b62d6e4f6c71 100644
--- a/sound/pci/ice1712/hoontech.h
+++ b/sound/pci/ice1712/hoontech.h
@@ -35,7 +35,7 @@
#define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */
#define ICE1712_SUBDEVICE_EVENT_EZ8 0x00010001 /* A dummy id for EZ8 */
-extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
/* Hoontech SoundTrack Audio DSP 24 GPIO definitions */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 8ba31cfb9045..830a1bbd7110 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -107,7 +107,7 @@ module_param_array(dxr_enable, int, NULL, 0444);
MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
-static struct pci_device_id snd_ice1712_ids[] = {
+static const struct pci_device_id snd_ice1712_ids[] = {
{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */
{ 0, }
};
@@ -287,7 +287,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru
return val != nval;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mixer To AC97",
.info = snd_ice1712_digmix_route_ac97_info,
@@ -719,7 +719,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s
return bytes_to_frames(substream->runtime, ptr);
}
-static struct snd_pcm_hardware snd_ice1712_playback =
+static const struct snd_pcm_hardware snd_ice1712_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -739,7 +739,7 @@ static struct snd_pcm_hardware snd_ice1712_playback =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_playback_ds =
+static const struct snd_pcm_hardware snd_ice1712_playback_ds =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -759,7 +759,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_ds =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_capture =
+static const struct snd_pcm_hardware snd_ice1712_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1133,7 +1133,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea
return bytes_to_frames(substream->runtime, ptr);
}
-static struct snd_pcm_hardware snd_ice1712_playback_pro =
+static const struct snd_pcm_hardware snd_ice1712_playback_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1153,7 +1153,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_pro =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_capture_pro =
+static const struct snd_pcm_hardware snd_ice1712_capture_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1378,9 +1378,9 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
-static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Playback Switch",
@@ -1404,7 +1404,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata
},
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Multi Capture Switch",
.info = snd_ice1712_pro_mixer_switch_info,
@@ -1413,7 +1413,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit
.private_value = 10,
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
.info = snd_ice1712_pro_mixer_switch_info,
@@ -1423,7 +1423,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd
.count = 2,
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -1435,7 +1435,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit
.tlv = { .p = db_scale_playback }
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
.info = snd_ice1712_pro_mixer_volume_info,
@@ -1627,7 +1627,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1712 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1663,7 +1663,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1714,7 +1714,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1723,7 +1723,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
.get = snd_ice1712_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1750,7 +1750,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE),
@@ -1811,7 +1811,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol,
static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1840,7 +1840,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned char xlate[16] = {
+ static const unsigned char xlate[16] = {
9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
};
unsigned char val;
@@ -1864,7 +1864,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1891,7 +1891,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_ice1712_pro_internal_clock_info,
@@ -1902,7 +1902,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1931,7 +1931,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont
struct snd_ctl_elem_value *ucontrol)
{
int val;
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1948,7 +1948,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont
static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1962,7 +1962,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock Default",
.info = snd_ice1712_pro_internal_clock_default_info,
@@ -2001,7 +2001,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_ice1712_pro_rate_locking_info,
@@ -2040,7 +2040,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_ice1712_pro_rate_reset_info,
@@ -2054,7 +2054,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"PCM Out", /* 0 */
"H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */
"H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */
@@ -2207,7 +2207,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Playback Route",
.info = snd_ice1712_pro_route_info,
@@ -2215,7 +2215,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata
.put = snd_ice1712_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_ice1712_pro_route_info,
@@ -2257,7 +2257,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Volume Rate",
.info = snd_ice1712_pro_volume_rate_info,
@@ -2290,7 +2290,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -2305,7 +2305,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
/*
* list of available boards
*/
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_ice1712_hoontech_cards,
snd_ice1712_delta_cards,
snd_ice1712_ews_cards,
@@ -2329,7 +2329,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
{
int dev = 0xa0; /* EEPROM device address */
unsigned int i, size;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (! modelname || ! *modelname) {
ice->eeprom.subvendor = 0;
@@ -2658,7 +2658,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
*
*/
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
static int __devinit snd_ice1712_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
@@ -2667,7 +2667,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
struct snd_card *card;
struct snd_ice1712 *ice;
int pcm_dev = 0, err;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (dev >= SNDRV_CARDS)
return -ENODEV;
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index ce27eac40d4e..c3d9feaaf57d 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -28,6 +28,7 @@
#include <sound/i2c.h>
#include <sound/ak4xxx-adda.h>
#include <sound/ak4114.h>
+#include <sound/pt2258.h>
#include <sound/pcm.h>
#include <sound/mpu401.h>
@@ -381,6 +382,11 @@ struct snd_ice1712 {
unsigned short master[2];
unsigned short vol[8];
} phase28;
+ /* a non-standard I2C device for revo51 */
+ struct revo51_spec {
+ struct snd_i2c_device *dev;
+ struct snd_pt2258 *pt2258;
+ } revo51;
/* Hoontech-specific setting */
struct hoontech_spec {
unsigned char boxbits[4];
@@ -462,6 +468,14 @@ static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice,
snd_ice1712_gpio_write(ice, mask & bits);
}
+static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
+ unsigned int mask)
+{
+ ice->gpio.direction &= ~mask;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ return (snd_ice1712_gpio_read(ice) & mask);
+}
+
int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
@@ -500,8 +514,8 @@ struct snd_ice1712_card_info {
unsigned int mpu401_2_info_flags;
const char *mpu401_1_name;
const char *mpu401_2_name;
- unsigned int eeprom_size;
- unsigned char *eeprom_data;
+ const unsigned int eeprom_size;
+ const unsigned char *eeprom_data;
};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 3e3a102e6c34..1127ebdf5fec 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -50,7 +50,7 @@
#include "prodigy192.h"
#include "juli.h"
#include "phase.h"
-
+#include "wtm.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -64,6 +64,7 @@ MODULE_SUPPORTED_DEVICE("{"
PRODIGY192_DEVICE_DESC
JULI_DEVICE_DESC
PHASE_DEVICE_DESC
+ WTM_DEVICE_DESC
"{VIA,VT1720},"
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
@@ -86,7 +87,7 @@ MODULE_PARM_DESC(model, "Use the given board model.");
/* Both VT1720 and VT1724 have the same PCI IDs */
-static struct pci_device_id snd_vt1724_ids[] = {
+static const struct pci_device_id snd_vt1724_ids[] = {
{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, }
};
@@ -341,7 +342,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
what = 0;
snd_pcm_group_for_each(pos, substream) {
- struct vt1724_pcm_reg *reg;
+ const struct vt1724_pcm_reg *reg;
s = snd_pcm_group_substream_entry(pos);
reg = s->runtime->private_data;
what |= reg->start;
@@ -605,7 +606,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
- struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+ const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
spin_lock_irq(&ice->reg_lock);
outl(substream->runtime->dma_addr, ice->profi_port + reg->addr);
@@ -620,7 +621,7 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
- struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+ const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
size_t ptr;
if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start))
@@ -646,21 +647,21 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
#endif
}
-static struct vt1724_pcm_reg vt1724_playback_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_pro_reg = {
.addr = VT1724_MT_PLAYBACK_ADDR,
.size = VT1724_MT_PLAYBACK_SIZE,
.count = VT1724_MT_PLAYBACK_COUNT,
.start = VT1724_PDMA0_START,
};
-static struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
.addr = VT1724_MT_CAPTURE_ADDR,
.size = VT1724_MT_CAPTURE_SIZE,
.count = VT1724_MT_CAPTURE_COUNT,
.start = VT1724_RDMA0_START,
};
-static struct snd_pcm_hardware snd_vt1724_playback_pro =
+static const struct snd_pcm_hardware snd_vt1724_playback_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -679,7 +680,7 @@ static struct snd_pcm_hardware snd_vt1724_playback_pro =
.periods_max = 1024,
};
-static struct snd_pcm_hardware snd_vt1724_spdif =
+static const struct snd_pcm_hardware snd_vt1724_spdif =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -701,7 +702,7 @@ static struct snd_pcm_hardware snd_vt1724_spdif =
.periods_max = 1024,
};
-static struct snd_pcm_hardware snd_vt1724_2ch_stereo =
+static const struct snd_pcm_hardware snd_vt1724_2ch_stereo =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -773,7 +774,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
int chs;
- runtime->private_data = &vt1724_playback_pro_reg;
+ runtime->private_data = (void *)&vt1724_playback_pro_reg;
ice->playback_pro_substream = substream;
runtime->hw = snd_vt1724_playback_pro;
snd_pcm_set_sync(substream);
@@ -802,7 +803,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_capture_pro_reg;
+ runtime->private_data = (void *)&vt1724_capture_pro_reg;
ice->capture_pro_substream = substream;
runtime->hw = snd_vt1724_2ch_stereo;
snd_pcm_set_sync(substream);
@@ -888,14 +889,14 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device)
* SPDIF PCM
*/
-static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
.addr = VT1724_MT_PDMA4_ADDR,
.size = VT1724_MT_PDMA4_SIZE,
.count = VT1724_MT_PDMA4_COUNT,
.start = VT1724_PDMA4_START,
};
-static struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
.addr = VT1724_MT_RDMA1_ADDR,
.size = VT1724_MT_RDMA1_SIZE,
.count = VT1724_MT_RDMA1_COUNT,
@@ -953,7 +954,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_playback_spdif_reg;
+ runtime->private_data = (void *)&vt1724_playback_spdif_reg;
ice->playback_con_substream = substream;
if (ice->force_pdma4) {
runtime->hw = snd_vt1724_2ch_stereo;
@@ -985,7 +986,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_capture_spdif_reg;
+ runtime->private_data = (void *)&vt1724_capture_spdif_reg;
ice->capture_con_substream = substream;
if (ice->force_rdma1) {
runtime->hw = snd_vt1724_2ch_stereo;
@@ -1090,7 +1091,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device)
* independent surround PCMs
*/
-static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
+static const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
{
.addr = VT1724_MT_PDMA1_ADDR,
.size = VT1724_MT_PDMA1_SIZE,
@@ -1136,7 +1137,7 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream)
return -EBUSY; /* FIXME: should handle blocking mode properly */
}
mutex_unlock(&ice->open_mutex);
- runtime->private_data = &vt1724_playback_dma_regs[substream->number];
+ runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number];
ice->playback_con_substream_ds[substream->number] = substream;
runtime->hw = snd_vt1724_2ch_stereo;
snd_pcm_set_sync(substream);
@@ -1317,7 +1318,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1724 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1430,7 +1431,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol,
return (val != old);
}
-static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1462,7 +1463,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1471,7 +1472,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
.get = snd_vt1724_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1516,7 +1517,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol,
return old != val;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* FIXME: the following conflict with IEC958 Playback Route */
@@ -1584,7 +1585,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol,
static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts_1724[] = {
+ static const char * const texts_1724[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1602,7 +1603,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
"192000", /* 14: 14 */
"IEC958 Input", /* 15: -- */
};
- static char *texts_1720[] = {
+ static const char * const texts_1720[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1635,7 +1636,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned char xlate[16] = {
+ static const unsigned char xlate[16] = {
9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
};
unsigned char val;
@@ -1694,7 +1695,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_vt1724_pro_internal_clock_info,
@@ -1733,7 +1734,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_vt1724_pro_rate_locking_info,
@@ -1772,7 +1773,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_vt1724_pro_rate_reset_info,
@@ -1816,7 +1817,7 @@ static int get_route_val(struct snd_ice1712 *ice, int shift)
{
unsigned long val;
unsigned char eitem;
- static unsigned char xlate[8] = {
+ static const unsigned char xlate[8] = {
0, 255, 1, 2, 255, 255, 3, 4,
};
@@ -1835,7 +1836,7 @@ static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift)
{
unsigned int old_val, nval;
int change;
- static unsigned char xroute[8] = {
+ static const unsigned char xroute[8] = {
0, /* PCM */
2, /* PSDIN0 Left */
3, /* PSDIN0 Right */
@@ -1891,7 +1892,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
digital_route_shift(idx));
}
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Playback Route",
.info = snd_vt1724_pro_route_info,
@@ -1899,7 +1900,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata =
.put = snd_vt1724_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_vt1724_pro_route_info,
@@ -1935,7 +1936,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -1947,9 +1948,9 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
*
*/
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_revo_cards,
snd_vt1724_amp_cards,
snd_vt1724_aureon_cards,
@@ -1958,6 +1959,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_prodigy192_cards,
snd_vt1724_juli_cards,
snd_vt1724_phase_cards,
+ snd_vt1724_wtm_cards,
NULL,
};
@@ -2007,7 +2009,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
{
const int dev = 0xa0; /* EEPROM device address */
unsigned int i, size;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (! modelname || ! *modelname) {
ice->eeprom.subvendor = 0;
@@ -2306,7 +2308,7 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
struct snd_card *card;
struct snd_ice1712 *ice;
int pcm_dev = 0, err;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (dev >= SNDRV_CARDS)
return -ENODEV;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 5176b41ea9d3..d88172fa95da 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -125,7 +125,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
snd_akm4xxx_reset(ak, 0);
}
-static struct snd_akm4xxx akm_juli_dac __devinitdata = {
+static const struct snd_akm4xxx akm_juli_dac __devinitdata = {
.type = SND_AK4358,
.num_dacs = 2,
.ops = {
@@ -146,7 +146,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit juli_init(struct snd_ice1712 *ice)
{
- static unsigned char ak4114_init_vals[] = {
+ static const unsigned char ak4114_init_vals[] = {
/* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
/* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S,
/* AK4114_REG_IO0 */ AK4114_TX1E,
@@ -154,7 +154,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
/* AK4114_REG_INT0_MASK */ 0,
/* AK4114_REG_INT1_MASK */ 0
};
- static unsigned char ak4114_init_txcsb[] = {
+ static const unsigned char ak4114_init_txcsb[] = {
0x41, 0x02, 0x2c, 0x00, 0x00
};
int err;
@@ -206,24 +206,24 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char juli_eeprom[] __devinitdata = {
- 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0x9f, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x7f, /* GPIO_DIR2 */
- 0x9f, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x7f, /* GPIO_MASK2 */
- 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */
- 0x80, /* GPIO_STATE1: mute */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char juli_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x20, /* clock 512, mpu401, 1xADC, 1xDACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0x9f,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x7f,
+ [ICE_EEP2_GPIO_MASK] = 0x9f,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x7f,
+ [ICE_EEP2_GPIO_STATE] = 0x16, /* internal clock, multiple 1x, 48kHz */
+ [ICE_EEP2_GPIO_STATE1] = 0x80, /* mute */
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_JULI,
.name = "ESI Juli@",
diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h
index d9f8534fd92e..1b9294f8bce3 100644
--- a/sound/pci/ice1712/juli.h
+++ b/sound/pci/ice1712/juli.h
@@ -5,6 +5,6 @@
#define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */
-extern struct snd_ice1712_card_info snd_vt1724_juli_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_juli_cards[];
#endif /* __SOUND_JULI_H */
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index e08d73f4ff85..0751718f4d7b 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -71,7 +71,7 @@
* Logarithmic volume values for WM8770
* Computed as 20 * Log10(255 / x)
*/
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -89,13 +89,13 @@ static unsigned char wm_vol[256] = {
#define WM_VOL_MAX (sizeof(wm_vol) - 1)
#define WM_VOL_MUTE 0x8000
-static struct snd_akm4xxx akm_phase22 __devinitdata = {
+static const struct snd_akm4xxx akm_phase22 __devinitdata = {
.type = SND_AK4524,
.num_dacs = 2,
.num_adcs = 2,
};
-static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
.caddr = 2,
.cif = 1,
.data_mask = 1 << 4,
@@ -152,36 +152,36 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
return 0;
}
-static unsigned char phase22_eeprom[] __devinitdata = {
- 0x00, /* SYSCONF: 1xADC, 1xDACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit*/
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xFF, /* GPIO_DIR */
- 0xFF, /* GPIO_DIR1 */
- 0xFF, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE: */
- 0x00, /* GPIO_STATE1: */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char phase22_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0xff,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-static unsigned char phase28_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char phase28_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/*
@@ -343,7 +343,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
static int __devinit phase28_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits_phase28[] = {
+ static const unsigned short wm_inits_phase28[] = {
/* These come first to reduce init pop noise */
0x1b, 0x044, /* ADC Mux (AC'97 source) */
0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -382,7 +382,7 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
unsigned int tmp;
struct snd_akm4xxx *ak;
- unsigned short *p;
+ const unsigned short *p;
int i;
ice->num_total_dacs = 8;
@@ -697,10 +697,10 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
-static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -815,7 +815,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
@@ -870,7 +870,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
return 0;
}
-struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_PHASE22,
.name = "Terratec PHASE 22",
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
index 13e841b55488..ad379a99bf92 100644
--- a/sound/pci/ice1712/phase.h
+++ b/sound/pci/ice1712/phase.h
@@ -31,7 +31,7 @@
#define VT1724_SUBDEVICE_PHASE28 0x3b154911
/* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_phase_cards[];
/* PHASE28 GPIO bits */
#define PHASE28_SPI_MISO (1 << 21)
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6c74c2d2e7f3..9552497f0765 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -434,7 +434,7 @@ static unsigned int spi_read(struct snd_ice1712 *ice, unsigned int dev, unsigned
*/
static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"Coax", /* RXP0 */
"Optical", /* RXP1 */
"CD", /* RXP2 */
@@ -565,13 +565,13 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
/*
* mixers
*/
-static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
+static const struct snd_kcontrol_new pontis_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -741,7 +741,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit pontis_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits[] = {
+ static const unsigned short wm_inits[] = {
/* These come first to reduce init pop noise */
WM_ADC_MUX, 0x00c0, /* ADC mute */
WM_DAC_MUTE, 0x0001, /* DAC softmute */
@@ -750,7 +750,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
WM_POWERDOWN, 0x0008, /* All power-up except HP */
WM_RESET, 0x0000, /* reset */
};
- static unsigned short wm_inits2[] = {
+ static const unsigned short wm_inits2[] = {
WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */
WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */
@@ -776,7 +776,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
WM_DAC_MUTE, 0x0000, /* DAC unmute */
WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */
};
- static unsigned char cs_inits[] = {
+ static const unsigned char cs_inits[] = {
0x04, 0x80, /* RUN, RXP0 */
0x05, 0x05, /* slave, 24bit */
0x01, 0x00,
@@ -826,24 +826,24 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char pontis_eeprom[] __devinitdata = {
- 0x08, /* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0x07, /* GPIO_DIR */
- 0x00, /* GPIO_DIR1 */
- 0x00, /* GPIO_DIR2 (ignored) */
- 0x0f, /* GPIO_MASK (4-7 reserved for CS8416) */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 (ignored) */
- 0x06, /* GPIO_STATE (0-low, 1-high, 2-high) */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 (ignored) */
+static const unsigned char pontis_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0x07,
+ [ICE_EEP2_GPIO_DIR1] = 0x00,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* ignored */
+ [ICE_EEP2_GPIO_MASK] = 0x0f, /* 4-7 reserved for CS8416 */
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* ignored */
+ [ICE_EEP2_GPIO_STATE] = 0x06, /* 0-low, 1-high, 2-high */
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* ignored */
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
{
.subvendor = VT1720_SUBDEVICE_PONTIS_MS300,
.name = "Pontis MS300",
diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h
index d0d1378b935c..1a418255c19e 100644
--- a/sound/pci/ice1712/pontis.h
+++ b/sound/pci/ice1712/pontis.h
@@ -28,6 +28,6 @@
#define VT1720_SUBDEVICE_PONTIS_MS300 0x00020002 /* a dummy id for MS300 */
-extern struct snd_ice1712_card_info snd_vt1720_pontis_cards[];
+extern const struct snd_ice1712_card_info snd_vt1720_pontis_cards[];
#endif /* __SOUND_PONTIS_H */
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 41b2605daa3a..31cc66eb9f8f 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -357,14 +357,14 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl
}
#endif
-static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
/*
* mixers
*/
-static struct snd_kcontrol_new stac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new stac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -475,7 +475,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit prodigy192_init(struct snd_ice1712 *ice)
{
- static unsigned short stac_inits_prodigy[] = {
+ static const unsigned short stac_inits_prodigy[] = {
STAC946X_RESET, 0,
/* STAC946X_MASTER_VOLUME, 0,
STAC946X_LF_VOLUME, 0,
@@ -486,7 +486,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
STAC946X_LFE_VOLUME, 0,*/
(unsigned short)-1
};
- unsigned short *p;
+ const unsigned short *p;
/* prodigy 192 */
ice->num_total_dacs = 6;
@@ -506,25 +506,25 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char prodigy71_eeprom[] __devinitdata = {
- 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0xbf, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char prodigy71_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0xbf,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_PRODIGY192VE,
.name = "Audiotrak Prodigy 192",
diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h
index 94c824e24e06..2fa2e62b9e04 100644
--- a/sound/pci/ice1712/prodigy192.h
+++ b/sound/pci/ice1712/prodigy192.h
@@ -6,6 +6,6 @@
#define VT1724_SUBDEVICE_PRODIGY192VE 0x34495345 /* PRODIGY 192 VE */
-extern struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[];
#endif /* __SOUND_PRODIGY192_H */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index bf98ea34feb0..025a7e8497c3 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -84,38 +84,142 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
}
/*
+ * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
+ */
+
+static void revo_i2c_start(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_save_gpio_status(ice);
+}
+
+static void revo_i2c_stop(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int mask, val;
+
+ val = 0;
+ if (clock)
+ val |= VT1724_REVO_I2C_CLOCK; /* write SCL */
+ if (data)
+ val |= VT1724_REVO_I2C_DATA; /* write SDA */
+ mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
+ ice->gpio.direction &= ~mask;
+ ice->gpio.direction |= val;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ snd_ice1712_gpio_set_mask(ice, ~mask);
+}
+
+static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int val = 0;
+
+ if (clk)
+ val |= VT1724_REVO_I2C_CLOCK;
+ if (data)
+ val |= VT1724_REVO_I2C_DATA;
+ snd_ice1712_gpio_write_bits(ice,
+ VT1724_REVO_I2C_DATA |
+ VT1724_REVO_I2C_CLOCK, val);
+ udelay(5);
+}
+
+static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ int bit;
+
+ if (ack)
+ udelay(5);
+ bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
+ return bit;
+}
+
+static struct snd_i2c_bit_ops revo51_bit_ops = {
+ .start = revo_i2c_start,
+ .stop = revo_i2c_stop,
+ .direction = revo_i2c_direction,
+ .setlines = revo_i2c_setlines,
+ .getdata = revo_i2c_getdata,
+};
+
+static int revo51_i2c_init(struct snd_ice1712 *ice,
+ struct snd_pt2258 *pt)
+{
+ int err;
+
+ /* create the I2C bus */
+ err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
+ if (err < 0)
+ return err;
+
+ ice->i2c->private_data = ice;
+ ice->i2c->hw_ops.bit = &revo51_bit_ops;
+
+ /* create the I2C device */
+ err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
+ &ice->spec.revo51.dev);
+ if (err < 0)
+ return err;
+
+ pt->card = ice->card;
+ pt->i2c_bus = ice->i2c;
+ pt->i2c_dev = ice->spec.revo51.dev;
+ ice->spec.revo51.pt2258 = pt;
+
+ snd_pt2258_reset(pt);
+
+ return 0;
+}
+
+/*
* initialize the chips on M-Audio Revolution cards
*/
#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
-static struct snd_akm4xxx_dac_channel revo71_front[] = {
+static const struct snd_akm4xxx_dac_channel revo71_front[] = {
AK_DAC("PCM Playback Volume", 2)
};
-static struct snd_akm4xxx_dac_channel revo71_surround[] = {
+static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
AK_DAC("PCM Center Playback Volume", 1),
AK_DAC("PCM LFE Playback Volume", 1),
AK_DAC("PCM Side Playback Volume", 2),
AK_DAC("PCM Rear Playback Volume", 2),
};
-static struct snd_akm4xxx_dac_channel revo51_dac[] = {
+static const struct snd_akm4xxx_dac_channel revo51_dac[] = {
AK_DAC("PCM Playback Volume", 2),
AK_DAC("PCM Center Playback Volume", 1),
AK_DAC("PCM LFE Playback Volume", 1),
AK_DAC("PCM Rear Playback Volume", 2),
};
-static struct snd_akm4xxx_adc_channel revo51_adc[] = {
+static const char *revo51_adc_input_names[] = {
+ "Mic",
+ "Line",
+ "CD",
+ NULL
+};
+
+static const struct snd_akm4xxx_adc_channel revo51_adc[] = {
{
.name = "PCM Capture Volume",
.switch_name = "PCM Capture Switch",
- .num_channels = 2
+ .num_channels = 2,
+ .input_names = revo51_adc_input_names
},
};
-static struct snd_akm4xxx akm_revo_front __devinitdata = {
+static const struct snd_akm4xxx akm_revo_front __devinitdata = {
.type = SND_AK4381,
.num_dacs = 2,
.ops = {
@@ -124,7 +228,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = {
.dac_info = revo71_front,
};
-static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
.caddr = 1,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
@@ -136,7 +240,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo_surround __devinitdata = {
+static const struct snd_akm4xxx akm_revo_surround __devinitdata = {
.type = SND_AK4355,
.idx_offset = 1,
.num_dacs = 6,
@@ -146,7 +250,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = {
.dac_info = revo71_surround,
};
-static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
.caddr = 3,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
@@ -158,7 +262,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo51 __devinitdata = {
+static const struct snd_akm4xxx akm_revo51 __devinitdata = {
.type = SND_AK4358,
.num_dacs = 6,
.ops = {
@@ -167,36 +271,213 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = {
.dac_info = revo51_dac,
};
-static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS1,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo51_adc __devinitdata = {
+static const struct snd_akm4xxx akm_revo51_adc __devinitdata = {
.type = SND_AK5365,
.num_adcs = 2,
.adc_info = revo51_adc,
};
-static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS0,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .add_flags = VT1724_REVO_CCLK, /* high at init */
+ .mask_flags = 0,
+};
+
+static struct snd_pt2258 ptc_revo51_volume;
+
+/* AK4358 for AP192 DAC, AK5385A for ADC */
+static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+ struct snd_ice1712 *ice = ak->private_data[0];
+
+ revo_set_rate_val(ak, rate);
+
+#if 1 /* FIXME: do we need this procedure? */
+ /* reset DFS pin of AK5385A for ADC, too */
+ /* DFS0 (pin 18) -- GPIO10 pin 77 */
+ snd_ice1712_save_gpio_status(ice);
+ snd_ice1712_gpio_write_bits(ice, 1 << 10,
+ rate > 48000 ? (1 << 10) : 0);
+ snd_ice1712_restore_gpio_status(ice);
+#endif
+}
+
+static const struct snd_akm4xxx_dac_channel ap192_dac[] = {
+ AK_DAC("PCM Playback Volume", 2)
+};
+
+static const struct snd_akm4xxx akm_ap192 __devinitdata = {
+ .type = SND_AK4358,
+ .num_dacs = 2,
+ .ops = {
+ .set_rate_val = ap192_set_rate_val
+ },
+ .dac_info = ap192_dac,
+};
+
+static const struct snd_ak4xxx_private akm_ap192_priv __devinitdata = {
+ .caddr = 2,
+ .cif = 0,
+ .data_mask = VT1724_REVO_CDOUT,
+ .clk_mask = VT1724_REVO_CCLK,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
+ .cs_addr = VT1724_REVO_CS3,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
+#if 0
+/* FIXME: ak4114 makes the sound much lower due to some confliction,
+ * so let's disable it right now...
+ */
+#define BUILD_AK4114_AP192
+#endif
+
+#ifdef BUILD_AK4114_AP192
+/* AK4114 support on Audiophile 192 */
+/* CDTO (pin 32) -- GPIO2 pin 52
+ * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
+ * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
+ * CSN (pin 35) -- GPIO7 pin 59
+ */
+#define AK4114_ADDR 0x00
+
+static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
+ unsigned int data, int idx)
+{
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* set data */
+ if (data & (1 << idx))
+ gpio |= VT1724_REVO_CDOUT;
+ else
+ gpio &= ~VT1724_REVO_CDOUT;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+}
+
+static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
+ int idx)
+{
+ unsigned char data = 0;
+
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* read data */
+ if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN)
+ data |= (1 << idx);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+ return data;
+}
+
+static unsigned char ap192_4wire_start(struct snd_ice1712 *ice)
+{
+ unsigned int tmp;
+
+ snd_ice1712_save_gpio_status(ice);
+ tmp = snd_ice1712_gpio_read(ice);
+ tmp |= VT1724_REVO_CCLK; /* high at init */
+ tmp |= VT1724_REVO_CS0;
+ tmp &= ~VT1724_REVO_CS3;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ return tmp;
+}
+
+static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
+{
+ tmp |= VT1724_REVO_CS3;
+ tmp |= VT1724_REVO_CS0;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+static void ap192_ak4114_write(void *private_data, unsigned char addr,
+ unsigned char data)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp, addrdata;
+
+ tmp = ap192_4wire_start(ice);
+ addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
+ addrdata = (addrdata << 8) | data;
+ write_data(ice, tmp, addrdata, 15);
+ ap192_4wire_finish(ice, tmp);
+}
+
+static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp;
+ unsigned char data;
+
+ tmp = ap192_4wire_start(ice);
+ write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
+ data = read_data(ice, tmp, 7);
+ ap192_4wire_finish(ice, tmp);
+ return data;
+}
+
+static int ap192_ak4114_init(struct snd_ice1712 *ice)
+{
+ static const unsigned char ak4114_init_vals[] = {
+ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+ AK4114_DIF_I24I2S,
+ AK4114_TX1E,
+ AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+ 0,
+ 0
+ };
+ static const unsigned char ak4114_init_txcsb[] = {
+ 0x41, 0x02, 0x2c, 0x00, 0x00
+ };
+ struct ak4114 *ak;
+ int err;
+
+ return snd_ak4114_create(ice->card,
+ ap192_ak4114_read,
+ ap192_ak4114_write,
+ ak4114_init_vals, ak4114_init_txcsb,
+ ice, &ak);
+}
+#endif /* BUILD_AK4114_AP192 */
+
static int __devinit revo_init(struct snd_ice1712 *ice)
{
struct snd_akm4xxx *ak;
@@ -213,6 +494,10 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ ice->num_total_dacs = 2;
+ ice->num_total_adcs = 2;
+ break;
default:
snd_BUG();
return -EINVAL;
@@ -235,14 +520,28 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
break;
case VT1724_SUBDEVICE_REVOLUTION51:
ice->akm_codecs = 2;
- if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
+ err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
+ &akm_revo51_priv, ice);
+ if (err < 0)
return err;
- err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
+ err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
&akm_revo51_adc_priv, ice);
if (err < 0)
return err;
- /* unmute all codecs - needed! */
- snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+ err = revo51_i2c_init(ice, &ptc_revo51_volume);
+ if (err < 0)
+ return err;
+ /* unmute all codecs */
+ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+ VT1724_REVO_MUTE);
+ break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ ice->akm_codecs = 1;
+ err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv,
+ ice);
+ if (err < 0)
+ return err;
+
break;
}
@@ -256,16 +555,34 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice)
switch (ice->eeprom.subvendor) {
case VT1724_SUBDEVICE_REVOLUTION71:
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+ break;
case VT1724_SUBDEVICE_REVOLUTION51:
err = snd_ice1712_akm4xxx_build_controls(ice);
if (err < 0)
return err;
+ err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
+ if (err < 0)
+ return err;
+ break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+#ifdef BUILD_AK4114_AP192
+ err = ap192_ak4114_init(ice);
+ if (err < 0)
+ return err;
+#endif
+ break;
}
return 0;
}
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
.name = "M Audio Revolution-7.1",
@@ -280,5 +597,12 @@ struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
.chip_init = revo_init,
.build_controls = revo_add_controls,
},
+ {
+ .subvendor = VT1724_SUBDEVICE_AUDIOPHILE192,
+ .name = "M Audio Audiophile192",
+ .model = "ap192",
+ .chip_init = revo_init,
+ .build_controls = revo_add_controls,
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h
index efbb86ec3289..2a24488fad80 100644
--- a/sound/pci/ice1712/revo.h
+++ b/sound/pci/ice1712/revo.h
@@ -26,13 +26,15 @@
#define REVO_DEVICE_DESC \
"{MidiMan M Audio,Revolution 7.1},"\
- "{MidiMan M Audio,Revolution 5.1},"
+ "{MidiMan M Audio,Revolution 5.1},"\
+ "{MidiMan M Audio,Audiophile 192},"
#define VT1724_SUBDEVICE_REVOLUTION71 0x12143036
#define VT1724_SUBDEVICE_REVOLUTION51 0x12143136
+#define VT1724_SUBDEVICE_AUDIOPHILE192 0x12143236
/* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_revo_cards[];
/*
@@ -42,9 +44,12 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
#define VT1724_REVO_CCLK 0x02
#define VT1724_REVO_CDIN 0x04 /* not used */
#define VT1724_REVO_CDOUT 0x08
-#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */
+#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for (revo51) */
#define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
-#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
+#define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */
+#define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */
+#define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */
+#define VT1724_REVO_CS3 0x80 /* AK4114 for AP192 */
#define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
#endif /* __SOUND_REVO_H */
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
index 7ca263c13091..72b060d63c29 100644
--- a/sound/pci/ice1712/vt1720_mobo.c
+++ b/sound/pci/ice1712/vt1720_mobo.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include "ice1712.h"
+#include "envy24ht.h"
#include "vt1720_mobo.h"
@@ -55,41 +56,41 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice)
/* EEPROM image */
-static unsigned char k8x800_eeprom[] __devinitdata = {
- 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */
- 0x02, /* ACLINK: ACLINK, packed */
- 0x00, /* I2S: - */
- 0x00, /* SPDIF: - */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x00, /* - */
- 0xff, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* - */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* - */
+static const unsigned char k8x800_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */
+ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */
+ [ICE_EEP2_I2S] = 0x00, /* - */
+ [ICE_EEP2_SPDIF] = 0x00, /* - */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_MASK] = 0xff,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */
};
-static unsigned char sn25p_eeprom[] __devinitdata = {
- 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */
- 0x02, /* ACLINK: ACLINK, packed */
- 0x00, /* I2S: - */
- 0x41, /* SPDIF: - */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x00, /* - */
- 0xff, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* - */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* - */
+static const unsigned char sn25p_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */
+ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */
+ [ICE_EEP2_I2S] = 0x00, /* - */
+ [ICE_EEP2_SPDIF] = 0x41, /* - */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_MASK] = 0xff,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
{
.subvendor = VT1720_SUBDEVICE_K8X800,
.name = "Albatron K8X800 Pro II",
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
index 0b1b0ee1bea7..70af3ad64a5d 100644
--- a/sound/pci/ice1712/vt1720_mobo.h
+++ b/sound/pci/ice1712/vt1720_mobo.h
@@ -36,6 +36,6 @@
#define VT1720_SUBDEVICE_9CJS 0x0f272327
#define VT1720_SUBDEVICE_SN25P 0x97123650
-extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
+extern const struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
#endif /* __SOUND_VT1720_MOBO_H */
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
new file mode 100644
index 000000000000..4a706b16a0b9
--- /dev/null
+++ b/sound/pci/ice1712/wtm.c
@@ -0,0 +1,542 @@
+/*
+ * ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ * Lowlevel functions for Ego Sys Waveterminal 192M
+ *
+ * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
+ * Some functions are taken from the Prodigy192 driver
+ * source
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "wtm.h"
+#include "stac946x.h"
+
+
+/*
+ * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
+ */
+static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
+ unsigned char val)
+{
+ snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
+{
+ return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
+}
+
+/*
+ * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
+ */
+static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
+ unsigned char val)
+{
+ snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
+{
+ return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
+}
+
+
+/*
+ * DAC mute control
+ */
+static int stac9460_dac_mute_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;
+ return 0;
+}
+
+static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int idx, id;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ id = 0;
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ }
+ if (id < 6)
+ val = stac9460_get(ice, idx);
+ else
+ val = stac9460_2_get(ice,idx - 6);
+ ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+ return 0;
+}
+
+static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int id, idx;
+ int change;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ old = stac9460_get(ice, idx);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+ (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ stac9460_put(ice, idx, new);
+ stac9460_2_put(ice, idx, new);
+ }
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ if (id < 6)
+ old = stac9460_get(ice, idx);
+ else
+ old = stac9460_2_get(ice, idx - 6);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+ (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ if (id < 6)
+ stac9460_put(ice, idx, new);
+ else
+ stac9460_2_put(ice, idx - 6, new);
+ }
+ }
+ return change;
+}
+
+/*
+ * DAC volume attenuation mixer control
+ */
+static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0; /* mute */
+ uinfo->value.integer.max = 0x7f; /* 0dB */
+ return 0;
+}
+
+static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int idx, id;
+ unsigned char vol;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ id = 0;
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ }
+ if (id < 6)
+ vol = stac9460_get(ice, idx) & 0x7f;
+ else
+ vol = stac9460_2_get(ice, idx - 6) & 0x7f;
+ ucontrol->value.integer.value[0] = 0x7f - vol;
+ return 0;
+}
+
+static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int idx, id;
+ unsigned char tmp, ovol, nvol;
+ int change;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ nvol = ucontrol->value.integer.value[0];
+ tmp = stac9460_get(ice, idx);
+ ovol = 0x7f - (tmp & 0x7f);
+ change = (ovol != nvol);
+ if (change) {
+ stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+ stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+ }
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ nvol = ucontrol->value.integer.value[0];
+ if (id < 6)
+ tmp = stac9460_get(ice, idx);
+ else
+ tmp = stac9460_2_get(ice, idx - 6);
+ ovol = 0x7f - (tmp & 0x7f);
+ change = (ovol != nvol);
+ if (change) {
+ if (id < 6)
+ stac9460_put(ice, idx, (0x7f - nvol) |
+ (tmp & 0x80));
+ else
+ stac9460_2_put(ice, idx-6, (0x7f - nvol) |
+ (tmp & 0x80));
+ }
+ }
+ return change;
+}
+
+/*
+ * ADC mute control
+ */
+static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int i, id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
+ ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
+ ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+ }
+ }
+ return 0;
+}
+
+static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int i, reg, id;
+ int change;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ old = stac9460_get(ice, reg);
+ new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+ (old&~0x80);
+ change = (new != old);
+ if (change)
+ stac9460_put(ice, reg, new);
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ old = stac9460_2_get(ice, reg);
+ new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+ (old&~0x80);
+ change = (new != old);
+ if (change)
+ stac9460_2_put(ice, reg, new);
+ }
+ }
+ return change;
+}
+
+/*
+ *ADC gain mixer control
+ */
+static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0; /* 0dB */
+ uinfo->value.integer.max = 0x0f; /* 22.5dB */
+ return 0;
+}
+
+static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int i, reg, id;
+ unsigned char vol;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ vol = stac9460_get(ice, reg) & 0x0f;
+ ucontrol->value.integer.value[i] = 0x0f - vol;
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ vol = stac9460_2_get(ice, reg) & 0x0f;
+ ucontrol->value.integer.value[i] = 0x0f - vol;
+ }
+ }
+ return 0;
+}
+
+static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int i, reg, id;
+ unsigned char ovol, nvol;
+ int change;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ nvol = ucontrol->value.integer.value[i];
+ ovol = 0x0f - stac9460_get(ice, reg);
+ change = ((ovol & 0x0f) != nvol);
+ if (change)
+ stac9460_put(ice, reg, (0x0f - nvol) |
+ (ovol & ~0x0f));
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ nvol = ucontrol->value.integer.value[i];
+ ovol = 0x0f - stac9460_2_get(ice, reg);
+ change = ((ovol & 0x0f) != nvol);
+ if (change)
+ stac9460_2_put(ice, reg, (0x0f - nvol) |
+ (ovol & ~0x0f));
+ }
+ }
+ return change;
+}
+
+/*
+ * MIC / LINE switch fonction
+ */
+
+static int stac9460_mic_sw_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;
+}
+
+static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0)
+ val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+ else
+ val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+ ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+ return 0;
+}
+
+static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int change, id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0)
+ old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+ else
+ old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ if (id == 0)
+ stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
+ else
+ stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
+ }
+ return change;
+}
+
+/*
+ * Control tabs
+ */
+static const struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = stac9460_dac_mute_info,
+ .get = stac9460_dac_mute_get,
+ .put = stac9460_dac_mute_put,
+ .private_value = 1
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
+ .private_value = 1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "MIC/Line switch",
+ .count = 2,
+ .info = stac9460_mic_sw_info,
+ .get = stac9460_mic_sw_get,
+ .put = stac9460_mic_sw_put,
+
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Switch",
+ .count = 8,
+ .info = stac9460_dac_mute_info,
+ .get = stac9460_dac_mute_get,
+ .put = stac9460_dac_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Volume",
+ .count = 8,
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Switch",
+ .count = 2,
+ .info = stac9460_adc_mute_info,
+ .get = stac9460_adc_mute_get,
+ .put = stac9460_adc_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Volume",
+ .count = 2,
+ .info = stac9460_adc_vol_info,
+ .get = stac9460_adc_vol_get,
+ .put = stac9460_adc_vol_put,
+
+ }
+};
+
+
+
+/*INIT*/
+static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
+ err = snd_ctl_add(ice->card,
+ snd_ctl_new1(&stac9640_controls[i], ice));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int __devinit wtm_init(struct snd_ice1712 *ice)
+{
+ static unsigned short stac_inits_prodigy[] = {
+ STAC946X_RESET, 0,
+ (unsigned short)-1
+ };
+ unsigned short *p;
+
+ /*WTM 192M*/
+ ice->num_total_dacs = 8;
+ ice->num_total_adcs = 4;
+ ice->force_rdma1 = 1;
+
+ /*initialize codec*/
+ p = stac_inits_prodigy;
+ for (; *p != (unsigned short)-1; p += 2) {
+ stac9460_put(ice, p[0], p[1]);
+ stac9460_2_put(ice, p[0], p[1]);
+ }
+ return 0;
+}
+
+
+static unsigned char wtm_eeprom[] __devinitdata = {
+ 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
+ 0x80, /* ACLINK : I2S */
+ 0xf8, /* I2S: vol; 96k, 24bit, 192k */
+ 0xc1 /*SPDIF: out-en, spidf ext out*/,
+ 0x9f, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x7f, /* GPIO_DIR2 */
+ 0x9f, /* GPIO_MASK */
+ 0xff, /* GPIO_MASK1 */
+ 0x7f, /* GPIO_MASK2 */
+ 0x16, /* GPIO_STATE */
+ 0x80, /* GPIO_STATE1 */
+ 0x00, /* GPIO_STATE2 */
+};
+
+
+/*entry point*/
+struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
+ {
+ .subvendor = VT1724_SUBDEVICE_WTM,
+ .name = "ESI Waveterminal 192M",
+ .model = "WT192M",
+ .chip_init = wtm_init,
+ .build_controls = wtm_add_controls,
+ .eeprom_size = sizeof(wtm_eeprom),
+ .eeprom_data = wtm_eeprom,
+ },
+ {} /*terminator*/
+};
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h
new file mode 100644
index 000000000000..03a394e442f1
--- /dev/null
+++ b/sound/pci/ice1712/wtm.h
@@ -0,0 +1,20 @@
+#ifndef __SOUND_WTM_H
+#define __SOUND_WTM_H
+
+/* ID */
+#define WTM_DEVICE_DESC "{EGO SYS INC,WaveTerminal 192M},"
+#define VT1724_SUBDEVICE_WTM 0x36495345 /* WT192M ver1.0 */
+
+/*
+ *chip addresses on I2C bus
+ */
+
+#define AK4114_ADDR 0x20 /*S/PDIF receiver*/
+#define STAC9460_I2C_ADDR 0x54 /* ADC*2 | DAC*6 */
+#define STAC9460_2_I2C_ADDR 0x56 /* ADC|DAC *2 */
+
+
+extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[];
+
+#endif /* __SOUND_WTM_H */
+
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 30aaa6092a84..a289abfc7172 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -71,6 +71,7 @@ static char *ac97_quirk;
static int buggy_semaphore;
static int buggy_irq = -1; /* auto-check */
static int xbox;
+static int spdif_aclink = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
@@ -86,6 +87,8 @@ module_param(buggy_irq, bool, 0444);
MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
module_param(xbox, bool, 0444);
MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
+module_param(spdif_aclink, int, 0444);
+MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
/* just for backward compatibility */
static int enable;
@@ -368,12 +371,8 @@ struct intel8x0 {
int irq;
- unsigned int mmio;
- unsigned long addr;
- void __iomem *remap_addr;
- unsigned int bm_mmio;
- unsigned long bmaddr;
- void __iomem *remap_bmaddr;
+ void __iomem *addr;
+ void __iomem *bmaddr;
struct pci_dev *pci;
struct snd_card *card;
@@ -446,72 +445,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids);
* Lowlevel I/O - busmaster
*/
-static u8 igetbyte(struct intel8x0 *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readb(chip->remap_bmaddr + offset);
- else
- return inb(chip->bmaddr + offset);
+ return ioread8(chip->bmaddr + offset);
}
-static u16 igetword(struct intel8x0 *chip, u32 offset)
+static inline u16 igetword(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readw(chip->remap_bmaddr + offset);
- else
- return inw(chip->bmaddr + offset);
+ return ioread16(chip->bmaddr + offset);
}
-static u32 igetdword(struct intel8x0 *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readl(chip->remap_bmaddr + offset);
- else
- return inl(chip->bmaddr + offset);
+ return ioread32(chip->bmaddr + offset);
}
-static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
{
- if (chip->bm_mmio)
- writeb(val, chip->remap_bmaddr + offset);
- else
- outb(val, chip->bmaddr + offset);
+ iowrite8(val, chip->bmaddr + offset);
}
-static void iputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val)
{
- if (chip->bm_mmio)
- writew(val, chip->remap_bmaddr + offset);
- else
- outw(val, chip->bmaddr + offset);
+ iowrite16(val, chip->bmaddr + offset);
}
-static void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
{
- if (chip->bm_mmio)
- writel(val, chip->remap_bmaddr + offset);
- else
- outl(val, chip->bmaddr + offset);
+ iowrite32(val, chip->bmaddr + offset);
}
/*
* Lowlevel I/O - AC'97 registers
*/
-static u16 iagetword(struct intel8x0 *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0 *chip, u32 offset)
{
- if (chip->mmio)
- return readw(chip->remap_addr + offset);
- else
- return inw(chip->addr + offset);
+ return ioread16(chip->addr + offset);
}
-static void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
{
- if (chip->mmio)
- writew(val, chip->remap_addr + offset);
- else
- outw(val, chip->addr + offset);
+ iowrite16(val, chip->addr + offset);
}
/*
@@ -1606,10 +1581,14 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip)
case DEVICE_INTEL_ICH4:
tbl = intel_pcms;
tblsize = ARRAY_SIZE(intel_pcms);
+ if (spdif_aclink)
+ tblsize--;
break;
case DEVICE_NFORCE:
tbl = nforce_pcms;
tblsize = ARRAY_SIZE(nforce_pcms);
+ if (spdif_aclink)
+ tblsize--;
break;
case DEVICE_ALI:
tbl = ali_pcms;
@@ -2068,24 +2047,26 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
};
chip->spdif_idx = -1; /* use PCMOUT (or disabled) */
- switch (chip->device_type) {
- case DEVICE_NFORCE:
- chip->spdif_idx = NVD_SPBAR;
- break;
- case DEVICE_ALI:
- chip->spdif_idx = ALID_AC97SPDIFOUT;
- break;
- case DEVICE_INTEL_ICH4:
- chip->spdif_idx = ICHD_SPBAR;
- break;
- };
+ if (!spdif_aclink) {
+ switch (chip->device_type) {
+ case DEVICE_NFORCE:
+ chip->spdif_idx = NVD_SPBAR;
+ break;
+ case DEVICE_ALI:
+ chip->spdif_idx = ALID_AC97SPDIFOUT;
+ break;
+ case DEVICE_INTEL_ICH4:
+ chip->spdif_idx = ICHD_SPBAR;
+ break;
+ };
+ }
chip->in_ac97_init = 1;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
ac97.private_free = snd_intel8x0_mixer_free_ac97;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if (chip->xbox)
ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR;
if (chip->device_type != DEVICE_ALI) {
@@ -2201,11 +2182,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20)
chip->smp20bit = 1;
}
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* 48kHz only */
chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000;
}
- if (chip->device_type == DEVICE_INTEL_ICH4) {
+ if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
/* use slot 10/11 for SPDIF */
u32 val;
val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK;
@@ -2333,7 +2314,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
/* unmute the output on SIS7012 */
iputword(chip, 0x4c, igetword(chip, 0x4c) | 1);
}
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* enable SPDIF interrupt */
unsigned int val;
pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2426,7 +2407,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
/* reset channels */
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* stop the spdif interrupt */
unsigned int val;
pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2443,10 +2424,10 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
snd_dma_free_pages(&chip->bdbars);
}
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
- if (chip->remap_bmaddr)
- iounmap(chip->remap_bmaddr);
+ if (chip->addr)
+ pci_iounmap(chip->pci, chip->addr);
+ if (chip->bmaddr)
+ pci_iounmap(chip->pci, chip->bmaddr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
@@ -2520,7 +2501,7 @@ static int intel8x0_resume(struct pci_dev *pci)
snd_intel8x0_chip_init(chip, 0);
/* re-initialize mixer stuff */
- if (chip->device_type == DEVICE_INTEL_ICH4) {
+ if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
/* enable separate SDINs for ICH4 */
iputbyte(chip, ICHREG(SDM), chip->sdm_saved);
/* use slot 10/11 for SPDIF */
@@ -2793,35 +2774,27 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
if (device_type == DEVICE_ALI) {
/* ALI5455 has no ac97 region */
- chip->bmaddr = pci_resource_start(pci, 0);
+ chip->bmaddr = pci_iomap(pci, 0, 0);
goto port_inited;
}
- if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */
- chip->mmio = 1;
- chip->addr = pci_resource_start(pci, 2);
- chip->remap_addr = ioremap_nocache(chip->addr,
- pci_resource_len(pci, 2));
- if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->addr = pci_resource_start(pci, 0);
- }
- if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */
- chip->bm_mmio = 1;
- chip->bmaddr = pci_resource_start(pci, 3);
- chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
- pci_resource_len(pci, 3));
- if (chip->remap_bmaddr == NULL) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->bmaddr = pci_resource_start(pci, 1);
+ if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+ chip->addr = pci_iomap(pci, 2, 0);
+ else
+ chip->addr = pci_iomap(pci, 0, 0);
+ if (!chip->addr) {
+ snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
+ }
+ if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+ chip->bmaddr = pci_iomap(pci, 3, 0);
+ else
+ chip->bmaddr = pci_iomap(pci, 1, 0);
+ if (!chip->bmaddr) {
+ snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
port_inited:
@@ -2964,6 +2937,29 @@ static struct shortname_table {
{ 0, NULL },
};
+static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = {
+ SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1),
+ { } /* end */
+};
+
+/* look up white/black list for SPDIF over ac-link */
+static int __devinit check_default_spdif_aclink(struct pci_dev *pci)
+{
+ const struct snd_pci_quirk *w;
+
+ w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
+ if (w) {
+ if (w->value)
+ snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
+ "AC-Link for %s\n", w->name);
+ else
+ snd_printdd(KERN_INFO "intel8x0: Using integrated "
+ "SPDIF DMA for %s\n", w->name);
+ return w->value;
+ }
+ return 0;
+}
+
static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -2976,16 +2972,18 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
if (card == NULL)
return -ENOMEM;
- switch (pci_id->driver_data) {
- case DEVICE_NFORCE:
- strcpy(card->driver, "NFORCE");
- break;
- case DEVICE_INTEL_ICH4:
- strcpy(card->driver, "ICH4");
- break;
- default:
- strcpy(card->driver, "ICH");
- break;
+ if (spdif_aclink < 0)
+ spdif_aclink = check_default_spdif_aclink(pci);
+
+ strcpy(card->driver, "ICH");
+ if (!spdif_aclink) {
+ switch (pci_id->driver_data) {
+ case DEVICE_NFORCE:
+ strcpy(card->driver, "NFORCE");
+ break;
+ case DEVICE_INTEL_ICH4:
+ strcpy(card->driver, "ICH4");
+ }
}
strcpy(card->shortname, "Intel ICH");
@@ -3025,8 +3023,8 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
snd_intel8x0_proc_init(chip);
snprintf(card->longname, sizeof(card->longname),
- "%s with %s at %#lx, irq %i", card->shortname,
- snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq);
+ "%s with %s at irq %i", card->shortname,
+ snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
if (! ac97_clock)
intel8x0_measure_ac97_clock(chip);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 09dcf923b547..c155e1f3a0e5 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -196,12 +196,8 @@ struct intel8x0m {
int irq;
- unsigned int mmio;
- unsigned long addr;
- void __iomem *remap_addr;
- unsigned int bm_mmio;
- unsigned long bmaddr;
- void __iomem *remap_bmaddr;
+ void __iomem *addr;
+ void __iomem *bmaddr;
struct pci_dev *pci;
struct snd_card *card;
@@ -253,72 +249,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
* Lowlevel I/O - busmaster
*/
-static u8 igetbyte(struct intel8x0m *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readb(chip->remap_bmaddr + offset);
- else
- return inb(chip->bmaddr + offset);
+ return ioread8(chip->bmaddr + offset);
}
-static u16 igetword(struct intel8x0m *chip, u32 offset)
+static inline u16 igetword(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readw(chip->remap_bmaddr + offset);
- else
- return inw(chip->bmaddr + offset);
+ return ioread16(chip->bmaddr + offset);
}
-static u32 igetdword(struct intel8x0m *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readl(chip->remap_bmaddr + offset);
- else
- return inl(chip->bmaddr + offset);
+ return ioread32(chip->bmaddr + offset);
}
-static void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
{
- if (chip->bm_mmio)
- writeb(val, chip->remap_bmaddr + offset);
- else
- outb(val, chip->bmaddr + offset);
+ iowrite8(val, chip->bmaddr + offset);
}
-static void iputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0m *chip, u32 offset, u16 val)
{
- if (chip->bm_mmio)
- writew(val, chip->remap_bmaddr + offset);
- else
- outw(val, chip->bmaddr + offset);
+ iowrite16(val, chip->bmaddr + offset);
}
-static void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
{
- if (chip->bm_mmio)
- writel(val, chip->remap_bmaddr + offset);
- else
- outl(val, chip->bmaddr + offset);
+ iowrite32(val, chip->bmaddr + offset);
}
/*
* Lowlevel I/O - AC'97 registers
*/
-static u16 iagetword(struct intel8x0m *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0m *chip, u32 offset)
{
- if (chip->mmio)
- return readw(chip->remap_addr + offset);
- else
- return inw(chip->addr + offset);
+ return ioread16(chip->addr + offset);
}
-static void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
{
- if (chip->mmio)
- writew(val, chip->remap_addr + offset);
- else
- outw(val, chip->addr + offset);
+ iowrite16(val, chip->addr + offset);
}
/*
@@ -858,7 +830,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock)
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
ac97.private_free = snd_intel8x0_mixer_free_ac97;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
glob_sta = igetdword(chip, ICHREG(GLOB_STA));
@@ -1019,10 +991,10 @@ static int snd_intel8x0_free(struct intel8x0m *chip)
__hw_end:
if (chip->bdbars.area)
snd_dma_free_pages(&chip->bdbars);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
- if (chip->remap_bmaddr)
- iounmap(chip->remap_bmaddr);
+ if (chip->addr)
+ pci_iounmap(chip->pci, chip->addr);
+ if (chip->bmaddr)
+ pci_iounmap(chip->pci, chip->bmaddr);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
@@ -1173,35 +1145,27 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
if (device_type == DEVICE_ALI) {
/* ALI5455 has no ac97 region */
- chip->bmaddr = pci_resource_start(pci, 0);
+ chip->bmaddr = pci_iomap(pci, 0, 0);
goto port_inited;
}
- if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */
- chip->mmio = 1;
- chip->addr = pci_resource_start(pci, 2);
- chip->remap_addr = ioremap_nocache(chip->addr,
- pci_resource_len(pci, 2));
- if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->addr = pci_resource_start(pci, 0);
+ if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+ chip->addr = pci_iomap(pci, 2, 0);
+ else
+ chip->addr = pci_iomap(pci, 0, 0);
+ if (!chip->addr) {
+ snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
- if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */
- chip->bm_mmio = 1;
- chip->bmaddr = pci_resource_start(pci, 3);
- chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
- pci_resource_len(pci, 3));
- if (chip->remap_bmaddr == NULL) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->bmaddr = pci_resource_start(pci, 1);
+ if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+ chip->bmaddr = pci_iomap(pci, 3, 0);
+ else
+ chip->bmaddr = pci_iomap(pci, 1, 0);
+ if (!chip->bmaddr) {
+ snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
port_inited:
@@ -1339,8 +1303,8 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
snd_intel8x0m_proc_init(chip);
- sprintf(card->longname, "%s at 0x%lx, irq %i",
- card->shortname, chip->addr, chip->irq);
+ sprintf(card->longname, "%s at irq %i",
+ card->shortname, chip->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 345eefeedb39..21d0899ac382 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -28,6 +28,7 @@
#include <linux/wait.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -263,7 +264,15 @@ enum MonitorModeSelector {
#define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement
// from the card after sending a command.
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
#include "korg1212-firmware.h"
+static const struct firmware static_dsp_code = {
+ .data = (u8 *)dspCode,
+ .size = sizeof dspCode
+};
+#endif
enum ClockSourceIndex {
K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz
@@ -345,8 +354,6 @@ struct snd_korg1212 {
struct snd_dma_buffer dma_rec;
struct snd_dma_buffer dma_shared;
- u32 dspCodeSize;
-
u32 DataBufsSize;
struct KorgAudioBuffer * playDataBufsPtr;
@@ -1223,8 +1230,6 @@ static int snd_korg1212_downloadDSPCode(struct snd_korg1212 *korg1212)
snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS);
- memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize);
-
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload,
UpperWordSwap(korg1212->dma_dsp.addr),
0, 0, 0);
@@ -2156,6 +2161,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
unsigned int i;
unsigned ioport_size, iomem_size, iomem2_size;
struct snd_korg1212 * korg1212;
+ const struct firmware *dsp_code;
static struct snd_device_ops ops = {
.dev_free = snd_korg1212_dev_free,
@@ -2329,8 +2335,6 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
#endif // K1212_LARGEALLOC
- korg1212->dspCodeSize = sizeof (dspCode);
-
korg1212->VolumeTablePhy = korg1212->sharedBufferPhy +
offsetof(struct KorgSharedBuffer, volumeData);
korg1212->RoutingTablePhy = korg1212->sharedBufferPhy +
@@ -2338,17 +2342,40 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy +
offsetof(struct KorgSharedBuffer, AdatTimeCode);
+ err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev);
+ if (err < 0) {
+ release_firmware(dsp_code);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ dsp_code = &static_dsp_code;
+#else
+ snd_printk(KERN_ERR "firmware not available\n");
+ snd_korg1212_free(korg1212);
+ return err;
+#endif
+ }
+
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) {
- snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
+ dsp_code->size, &korg1212->dma_dsp) < 0) {
+ snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size);
snd_korg1212_free(korg1212);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (dsp_code != &static_dsp_code)
+#endif
+ release_firmware(dsp_code);
return -ENOMEM;
}
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
- korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize,
+ korg1212->dma_dsp.area, korg1212->dma_dsp.addr, dsp_code->size,
stateName[korg1212->cardState]);
+ memcpy(korg1212->dma_dsp.area, dsp_code->data, dsp_code->size);
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (dsp_code != &static_dsp_code)
+#endif
+ release_firmware(dsp_code);
+
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0);
if (rc)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 6efe6d5ade1e..4526904e3f86 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -48,6 +49,7 @@
#include <sound/mpu401.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
+#include <asm/byteorder.h>
MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ESS Maestro3 PCI");
@@ -768,21 +770,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
/*
*/
-/* quirk lists */
-struct m3_quirk {
- const char *name; /* device name */
- u16 vendor, device; /* subsystem ids */
- int amp_gpio; /* gpio pin # for external amp, -1 = default */
- int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION
- (e.g. for IrDA on Dell Inspirons) */
-};
-
-struct m3_hv_quirk {
- u16 vendor, device, subsystem_vendor, subsystem_device;
- u32 config; /* ALLEGRO_CONFIG hardware volume bits */
- int is_omnibook; /* Do HP OmniBook GPIO magic? */
-};
-
struct m3_list {
int curlen;
int mem_addr;
@@ -830,8 +817,6 @@ struct snd_m3 {
struct snd_pcm *pcm;
struct pci_dev *pci;
- const struct m3_quirk *quirk;
- const struct m3_hv_quirk *hv_quirk;
int dacs_active;
int timer_users;
@@ -845,7 +830,11 @@ struct snd_m3 {
u8 reset_state;
int external_amp;
- int amp_gpio;
+ int amp_gpio; /* gpio pin # for external amp, -1 = default */
+ unsigned int hv_config; /* hardware-volume config bits */
+ unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION
+ (e.g. for IrDA on Dell Inspirons) */
+ unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */
/* midi */
struct snd_rawmidi *rmidi;
@@ -864,6 +853,9 @@ struct snd_m3 {
#ifdef CONFIG_PM
u16 *suspend_mem;
#endif
+
+ const struct firmware *assp_kernel_image;
+ const struct firmware *assp_minisrc_image;
};
/*
@@ -891,127 +883,104 @@ static struct pci_device_id snd_m3_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_m3_ids);
-static const struct m3_quirk m3_quirk_list[] = {
- /* panasonic CF-28 "toughbook" */
- {
- .name = "Panasonic CF-28",
- .vendor = 0x10f7,
- .device = 0x833e,
- .amp_gpio = 0x0d,
- },
- /* panasonic CF-72 "toughbook" */
- {
- .name = "Panasonic CF-72",
- .vendor = 0x10f7,
- .device = 0x833d,
- .amp_gpio = 0x0d,
- },
- /* Dell Inspiron 4000 */
- {
- .name = "Dell Inspiron 4000",
- .vendor = 0x1028,
- .device = 0x00b0,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* Dell Inspiron 8000 */
- {
- .name = "Dell Inspiron 8000",
- .vendor = 0x1028,
- .device = 0x00a4,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* Dell Inspiron 8100 */
- {
- .name = "Dell Inspiron 8100",
- .vendor = 0x1028,
- .device = 0x00e6,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* NEC LM800J/7 */
- {
- .name = "NEC LM800J/7",
- .vendor = 0x1033,
- .device = 0x80f1,
- .amp_gpio = 0x03,
- },
- /* LEGEND ZhaoYang 3100CF */
- {
- .name = "LEGEND ZhaoYang 3100CF",
- .vendor = 0x1509,
- .device = 0x1740,
- .amp_gpio = 0x03,
- },
- /* END */
- { NULL }
+static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d),
+ SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d),
+ SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
+ SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03),
+ { } /* END */
};
-/* These values came from the Windows driver. */
-static const struct m3_hv_quirk m3_hv_quirk_list[] = {
+static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1),
+ SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1),
+ SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1),
+ { } /* END */
+};
+
+/* hardware volume quirks */
+static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = {
/* Allegro chips */
- { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
- { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
+ SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x1033, 0x80F1, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x107B, 0x340A, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x107B, 0x3450, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x109F, 0x3134, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x109F, 0x3161, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3280, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3281, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC002, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC003, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1509, 0x1740, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1610, 0x0010, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE),
/* Maestro3 chips */
- { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
- { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
- { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0 }
+ SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ { } /* END */
+};
+
+/* HP Omnibook quirks */
+static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */
+ SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */
+ { } /* END */
};
/*
@@ -2050,7 +2019,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
for (i = 0; i < 5; i++) {
dir = inw(io + GPIO_DIRECTION);
- if (! chip->quirk || ! chip->quirk->irda_workaround)
+ if (!chip->irda_workaround)
dir |= 0x10; /* assuming pci bus master? */
snd_m3_remote_codec_config(io, 0);
@@ -2132,6 +2101,10 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
}
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
/*
* DSP Code images
*/
@@ -2260,6 +2233,30 @@ static const u16 assp_minisrc_image[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
+static const struct firmware assp_kernel = {
+ .data = (u8 *)assp_kernel_image,
+ .size = sizeof assp_kernel_image
+};
+static const struct firmware assp_minisrc = {
+ .data = (u8 *)assp_minisrc_image,
+ .size = sizeof assp_minisrc_image
+};
+
+#endif /* FIRMWARE_IN_THE_KERNEL */
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_m3_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_m3_convert_from_le(const struct firmware *fw)
+{
+ int i;
+ u16 *data = (u16 *)fw->data;
+
+ for (i = 0; i < fw->size / 2; ++i)
+ le16_to_cpus(&data[i]);
+}
+#endif
+
/*
* initialize ASSP
@@ -2274,6 +2271,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
static void snd_m3_assp_init(struct snd_m3 *chip)
{
unsigned int i;
+ u16 *data;
/* zero kernel data */
for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
@@ -2291,10 +2289,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
KDATA_DMA_XFER0);
/* write kernel into code memory.. */
- for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) {
+ data = (u16 *)chip->assp_kernel_image->data;
+ for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
- REV_B_CODE_MEMORY_BEGIN + i,
- assp_kernel_image[i]);
+ REV_B_CODE_MEMORY_BEGIN + i, data[i]);
}
/*
@@ -2303,10 +2301,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
* drop it there. It seems that the minisrc doesn't
* need vectors, so we won't bother with them..
*/
- for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) {
+ data = (u16 *)chip->assp_minisrc_image->data;
+ for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
- 0x400 + i,
- assp_minisrc_image[i]);
+ 0x400 + i, data[i]);
}
/*
@@ -2444,7 +2442,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
DISABLE_LEGACY);
pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
- if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
+ if (chip->is_omnibook) {
/*
* Volume buttons on some HP OmniBook laptops don't work
* correctly. This makes them work for the most part.
@@ -2461,8 +2459,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
}
pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
- if (chip->hv_quirk)
- n |= chip->hv_quirk->config;
+ n |= chip->hv_config;
/* For some reason we must always use reduced debounce. */
n |= REDUCED_DEBOUNCE;
n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
@@ -2510,7 +2507,7 @@ snd_m3_enable_ints(struct snd_m3 *chip)
/* TODO: MPU401 not supported yet */
val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
- if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+ if (chip->hv_config & HV_CTRL_ENABLE)
val |= HV_INT_ENABLE;
outw(val, io + HOST_INT_CTRL);
outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
@@ -2553,6 +2550,15 @@ static int snd_m3_free(struct snd_m3 *chip)
if (chip->iobase)
pci_release_regions(chip->pci);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->assp_kernel_image != &assp_kernel)
+#endif
+ release_firmware(chip->assp_kernel_image);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->assp_minisrc_image != &assp_minisrc)
+#endif
+ release_firmware(chip->assp_minisrc_image);
+
pci_disable_device(chip->pci);
kfree(chip);
return 0;
@@ -2665,8 +2671,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
{
struct snd_m3 *chip;
int i, err;
- const struct m3_quirk *quirk;
- const struct m3_hv_quirk *hv_quirk;
+ const struct snd_pci_quirk *quirk;
static struct snd_device_ops ops = {
.dev_free = snd_m3_dev_free,
};
@@ -2706,34 +2711,32 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
chip->pci = pci;
chip->irq = -1;
- for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
- if (pci->subsystem_vendor == quirk->vendor &&
- pci->subsystem_device == quirk->device) {
- printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
- chip->quirk = quirk;
- break;
- }
- }
-
- for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
- if (pci->vendor == hv_quirk->vendor &&
- pci->device == hv_quirk->device &&
- pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
- pci->subsystem_device == hv_quirk->subsystem_device) {
- chip->hv_quirk = hv_quirk;
- break;
- }
- }
-
chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f)
chip->amp_gpio = amp_gpio;
- else if (chip->quirk && chip->quirk->amp_gpio >= 0)
- chip->amp_gpio = chip->quirk->amp_gpio;
- else if (chip->allegro_flag)
- chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
- else /* presumably this is for all 'maestro3's.. */
- chip->amp_gpio = GPO_EXT_AMP_M3;
+ else {
+ quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
+ if (quirk) {
+ snd_printdd(KERN_INFO "maestro3: set amp-gpio "
+ "for '%s'\n", quirk->name);
+ chip->amp_gpio = quirk->value;
+ } else if (chip->allegro_flag)
+ chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
+ else /* presumably this is for all 'maestro3's.. */
+ chip->amp_gpio = GPO_EXT_AMP_M3;
+ }
+
+ quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
+ if (quirk) {
+ snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
+ "for '%s'\n", quirk->name);
+ chip->irda_workaround = 1;
+ }
+ quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
+ if (quirk)
+ chip->hv_config = quirk->value;
+ if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list))
+ chip->is_omnibook = 1;
chip->num_substreams = NR_DSPS;
chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma),
@@ -2744,6 +2747,30 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
return -ENOMEM;
}
+ err = request_firmware(&chip->assp_kernel_image,
+ "ess/maestro3_assp_kernel.fw", &pci->dev);
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->assp_kernel_image = &assp_kernel;
+#else
+ snd_m3_free(chip);
+ return err;
+#endif
+ } else
+ snd_m3_convert_from_le(chip->assp_kernel_image);
+
+ err = request_firmware(&chip->assp_minisrc_image,
+ "ess/maestro3_assp_minisrc.fw", &pci->dev);
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->assp_minisrc_image = &assp_minisrc;
+#else
+ snd_m3_free(chip);
+ return err;
+#endif
+ } else
+ snd_m3_convert_from_le(chip->assp_minisrc_image);
+
if ((err = pci_request_regions(pci, card->driver)) < 0) {
snd_m3_free(chip);
return err;
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 13de0f71d4b7..d7d15c036e02 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -389,7 +389,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
static struct snd_kcontrol_new mixart_control_analog_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -872,7 +872,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
static struct snd_kcontrol_new snd_mixart_pcm_vol =
{
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 879e31a9f9c6..03b3a4792f73 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1628,23 +1628,15 @@ __error:
}
-struct nm256_quirk {
- unsigned short vendor;
- unsigned short device;
- int type;
-};
-
enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 };
-static struct nm256_quirk nm256_quirks[] __devinitdata = {
+static struct snd_pci_quirk nm256_quirks[] __devinitdata = {
/* HP omnibook 4150 has cs4232 codec internally */
- { .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED },
- /* Sony PCG-F305 */
- { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND },
- /* Dell Latitude LS */
- { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND },
- /* Dell Latitude CSx */
- { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 },
+ SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED),
+ /* Reset workarounds to avoid lock-ups */
+ SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND),
+ SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND),
+ SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2),
{ } /* terminator */
};
@@ -1655,26 +1647,22 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci,
struct snd_card *card;
struct nm256 *chip;
int err;
- struct nm256_quirk *q;
- u16 subsystem_vendor, subsystem_device;
-
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-
- for (q = nm256_quirks; q->vendor; q++) {
- if (q->vendor == subsystem_vendor && q->device == subsystem_device) {
- switch (q->type) {
- case NM_BLACKLISTED:
- printk(KERN_INFO "nm256: The device is blacklisted. "
- "Loading stopped\n");
- return -ENODEV;
- case NM_RESET_WORKAROUND_2:
- reset_workaround_2 = 1;
- /* Fall-through */
- case NM_RESET_WORKAROUND:
- reset_workaround = 1;
- break;
- }
+ const struct snd_pci_quirk *q;
+
+ q = snd_pci_quirk_lookup(pci, nm256_quirks);
+ if (q) {
+ snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
+ switch (q->value) {
+ case NM_BLACKLISTED:
+ printk(KERN_INFO "nm256: The device is blacklisted. "
+ "Loading stopped\n");
+ return -ENODEV;
+ case NM_RESET_WORKAROUND_2:
+ reset_workaround_2 = 1;
+ /* Fall-through */
+ case NM_RESET_WORKAROUND:
+ reset_workaround = 1;
+ break;
}
}
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index b133ad9e095e..d9cc8d2beb6d 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -44,8 +44,8 @@
#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
-static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
{
@@ -195,7 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = {
#define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */
#define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
#define MORE_THAN_ONE_STREAM_LEVEL 0x000001
#define VALID_STREAM_PAN_LEVEL_MASK 0x800000
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 6383987b460e..89b3c7ff5037 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -80,6 +80,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
/* Write registers. These are defined as byte-offsets from the iobase value.
*/
#define HDSP_resetPointer 0
+#define HDSP_freqReg 0
#define HDSP_outputBufferAddress 32
#define HDSP_inputBufferAddress 36
#define HDSP_controlRegister 64
@@ -469,6 +470,7 @@ struct hdsp {
struct pci_dev *pci;
struct snd_kcontrol *spdif_ctl;
unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
+ unsigned int dds_value; /* last value written to freq register */
};
/* These tables map the ALSA channels 1..N to the channels that we
@@ -598,6 +600,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
return (64 * out) + (32 + (in));
case 0x96:
case 0x97:
+ case 0x98:
return (32 * out) + (16 + (in));
default:
return (52 * out) + (26 + (in));
@@ -611,6 +614,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
return (64 * out) + in;
case 0x96:
case 0x97:
+ case 0x98:
return (32 * out) + in;
default:
return (52 * out) + in;
@@ -938,6 +942,11 @@ static snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp)
static void hdsp_reset_hw_pointer(struct hdsp *hdsp)
{
hdsp_write (hdsp, HDSP_resetPointer, 0);
+ if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+ /* HDSP_resetPointer = HDSP_freqReg, which is strange and
+ * requires (?) to write again DDS value after a reset pointer
+ * (at least, it works like this) */
+ hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
}
static void hdsp_start_audio(struct hdsp *s)
@@ -982,6 +991,30 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
return 0;
}
+static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
+{
+ u64 n;
+ u32 r;
+
+ if (rate >= 112000)
+ rate /= 4;
+ else if (rate >= 56000)
+ rate /= 2;
+
+ /* RME says n = 104857600000000, but in the windows MADI driver, I see:
+// return 104857600000000 / rate; // 100 MHz
+ return 110100480000000 / rate; // 105 MHz
+ */
+ n = 104857600000000ULL; /* = 2^20 * 10^8 */
+ div64_32(&n, rate, &r);
+ /* n should be less than 2^32 for being written to FREQ register */
+ snd_assert((n >> 32) == 0);
+ /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
+ value to write it after a reset */
+ hdsp->dds_value = n;
+ hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
+}
+
static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
{
int reject_if_open = 0;
@@ -1090,6 +1123,10 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
hdsp->control_register |= rate_bits;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ /* For HDSP9632 rev 152, need to set DDS value in FREQ register */
+ if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+ hdsp_set_dds_value(hdsp, rate);
+
if (rate >= 128000) {
hdsp->channel_map = channel_map_H9632_qs;
} else if (rate > 48000) {
@@ -4943,6 +4980,7 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
hdsp->irq = pci->irq;
hdsp->precise_ptr = 0;
hdsp->use_midi_tasklet = 1;
+ hdsp->dds_value = 0;
if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
return err;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 0547f6f04bdc..e0215aca1193 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6,6 +6,8 @@
* code based on hdsp.c Paul Davis
* Marcus Andersson
* Thomas Charbonnel
+ * Modified 2006-06-01 for AES32 support by Remy Bruno
+ * <remy.bruno@trinnov.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -77,7 +79,8 @@ MODULE_PARM_DESC(enable_monitor,
MODULE_AUTHOR
("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, "
- "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
+ "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
+ "Remy Bruno <remy.bruno@trinnov.com>");
MODULE_DESCRIPTION("RME HDSPM");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
@@ -107,7 +110,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
/* --- Read registers. ---
These are defined as byte-offsets from the iobase value */
#define HDSPM_statusRegister 0
-#define HDSPM_statusRegister2 96
+/*#define HDSPM_statusRegister2 96 */
+/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at
+ * offset 192, for AES32 *and* MADI
+ * => need to check that offset 192 is working on MADI */
+#define HDSPM_statusRegister2 192
+#define HDSPM_timecodeRegister 128
#define HDSPM_midiDataIn0 360
#define HDSPM_midiDataIn1 364
@@ -140,37 +148,50 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */
#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */
-#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */
+#define HDSPM_QuadSpeed (1<<31) /* quad speed bit */
+#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */
#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1,
- 56channelMODE=0 */
+ 56channelMODE=0 */ /* MADI ONLY*/
+#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */
#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
- 0=off, 1=on */
+ 0=off, 1=on */ /* MADI ONLY */
+#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
-#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */
+#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/
#define HDSPM_InputSelect1 (1<<15) /* should be 0 */
#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */
-#define HDSPM_SyncRef1 (1<<17) /* should be 0 */
+#define HDSPM_SyncRef1 (1<<17) /* for AES32: SyncRefN codes the AES # */
+#define HDSPM_SyncRef2 (1<<13)
+#define HDSPM_SyncRef3 (1<<25)
+#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */
#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
AES additional bits in
lower 5 Audiodatabits ??? */
+#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */
+#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
#define HDSPM_Midi0InterruptEnable (1<<22)
#define HDSPM_Midi1InterruptEnable (1<<23)
#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
+#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
+#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
+#define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */
+
+#define HDSPM_wclk_sel (1<<30)
/* --- bit helper defines */
#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
-#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1)
+#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed)
#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1)
#define HDSPM_InputOptical 0
#define HDSPM_InputCoaxial (HDSPM_InputSelect0)
-#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1)
+#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3)
#define HDSPM_SyncRef_Word 0
#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0)
@@ -183,6 +204,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0)
#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
+#define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0)
+#define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1)
+#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
/* --- for internal discrimination */
#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */
@@ -229,7 +253,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_BIGENDIAN_MODE (1<<9)
#define HDSPM_RD_MULTIPLE (1<<10)
-/* --- Status Register bits --- */
+/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and
+ that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */
#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */
#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */
#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */
@@ -263,7 +288,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0)
-/* Status2 Register bits */
+/* Status2 Register bits */ /* MADI ONLY */
#define HDSPM_version0 (1<<0) /* not realy defined but I guess */
#define HDSPM_version1 (1<<1) /* in former cards it was ??? */
@@ -297,6 +322,56 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0)
#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2)
+/*
+ For AES32, bits for status, status2 and timecode are different
+*/
+/* status */
+#define HDSPM_AES32_wcLock 0x0200000
+#define HDSPM_AES32_wcFreq_bit 22
+/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
+ HDSPM_bit2freq */
+#define HDSPM_AES32_syncref_bit 16
+/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
+
+#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0
+#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1
+#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2
+#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3
+#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4
+#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5
+#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
+#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
+#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1
+
+/* status2 */
+/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
+#define HDSPM_LockAES 0x80
+#define HDSPM_LockAES1 0x80
+#define HDSPM_LockAES2 0x40
+#define HDSPM_LockAES3 0x20
+#define HDSPM_LockAES4 0x10
+#define HDSPM_LockAES5 0x8
+#define HDSPM_LockAES6 0x4
+#define HDSPM_LockAES7 0x2
+#define HDSPM_LockAES8 0x1
+/*
+ Timecode
+ After windows driver sources, bits 4*i to 4*i+3 give the input frequency on
+ AES i+1
+ bits 3210
+ 0001 32kHz
+ 0010 44.1kHz
+ 0011 48kHz
+ 0100 64kHz
+ 0101 88.2kHz
+ 0110 96kHz
+ 0111 128kHz
+ 1000 176.4kHz
+ 1001 192kHz
+ NB: Timecode register doesn't seem to work on AES32 card revision 230
+*/
+
/* Mixer Values */
#define UNITY_GAIN 32768 /* = 65536/2 */
#define MINUS_INFINITY_GAIN 0
@@ -314,10 +389,14 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
size is the same regardless of the number of channels, and
also the latency to use.
for one direction !!!
+ => need to mupltiply by 2!!
*/
-#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
+#define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
+/* revisions >= 230 indicate AES32 card */
+#define HDSPM_AESREVISION 230
+
struct hdspm_midi {
struct hdspm *hdspm;
int id;
@@ -336,7 +415,9 @@ struct hdspm {
struct snd_pcm_substream *playback_substream; /* and/or capture stream */
char *card_name; /* for procinfo */
- unsigned short firmware_rev; /* dont know if relevant */
+ unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
+
+ unsigned char is_aes32; /* indicates if card is AES32 */
int precise_ptr; /* use precise pointers, to be tested */
int monitor_outs; /* set up monitoring outs init flag */
@@ -453,6 +534,15 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm);
static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
unsigned int reg, int channels);
+static inline int HDSPM_bit2freq(int n)
+{
+ static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200,
+ 96000, 128000, 176400, 192000 };
+ if (n < 1 || n > 9)
+ return 0;
+ return bit2freq_tab[n];
+}
+
/* Write/read to/from HDSPM with Adresses in Bytes
not words but only 32Bit writes are allowed */
@@ -544,86 +634,105 @@ static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm)
/* check for external sample rate */
static inline int hdspm_external_sample_rate(struct hdspm * hdspm)
{
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
- unsigned int rate_bits;
- int rate = 0;
+ if (hdspm->is_aes32) {
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+ int syncref = hdspm_autosync_ref(hdspm);
+
+ if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
+ status & HDSPM_AES32_wcLock)
+ return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+ if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
+ syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
+ status2 & (HDSPM_LockAES >>
+ (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
+ return HDSPM_bit2freq((timecode >>
+ (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
+ return 0;
+ } else {
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int rate_bits;
+ int rate = 0;
- /* if wordclock has synced freq and wordclock is valid */
- if ((status2 & HDSPM_wcLock) != 0 &&
- (status & HDSPM_SelSyncRef0) == 0) {
+ /* if wordclock has synced freq and wordclock is valid */
+ if ((status2 & HDSPM_wcLock) != 0 &&
+ (status & HDSPM_SelSyncRef0) == 0) {
- rate_bits = status2 & HDSPM_wcFreqMask;
+ rate_bits = status2 & HDSPM_wcFreqMask;
- switch (rate_bits) {
- case HDSPM_wcFreq32:
- rate = 32000;
- break;
- case HDSPM_wcFreq44_1:
- rate = 44100;
- break;
- case HDSPM_wcFreq48:
- rate = 48000;
- break;
- case HDSPM_wcFreq64:
- rate = 64000;
- break;
- case HDSPM_wcFreq88_2:
- rate = 88200;
- break;
- case HDSPM_wcFreq96:
- rate = 96000;
- break;
- /* Quadspeed Bit missing ???? */
- default:
- rate = 0;
- break;
+ switch (rate_bits) {
+ case HDSPM_wcFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_wcFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_wcFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_wcFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_wcFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_wcFreq96:
+ rate = 96000;
+ break;
+ /* Quadspeed Bit missing ???? */
+ default:
+ rate = 0;
+ break;
+ }
}
- }
- /* if rate detected and Syncref is Word than have it, word has priority to MADI */
- if (rate != 0
- && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
- return rate;
+ /* if rate detected and Syncref is Word than have it, word has priority to MADI */
+ if (rate != 0 &&
+ (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+ return rate;
- /* maby a madi input (which is taken if sel sync is madi) */
- if (status & HDSPM_madiLock) {
- rate_bits = status & HDSPM_madiFreqMask;
+ /* maby a madi input (which is taken if sel sync is madi) */
+ if (status & HDSPM_madiLock) {
+ rate_bits = status & HDSPM_madiFreqMask;
- switch (rate_bits) {
- case HDSPM_madiFreq32:
- rate = 32000;
- break;
- case HDSPM_madiFreq44_1:
- rate = 44100;
- break;
- case HDSPM_madiFreq48:
- rate = 48000;
- break;
- case HDSPM_madiFreq64:
- rate = 64000;
- break;
- case HDSPM_madiFreq88_2:
- rate = 88200;
- break;
- case HDSPM_madiFreq96:
- rate = 96000;
- break;
- case HDSPM_madiFreq128:
- rate = 128000;
- break;
- case HDSPM_madiFreq176_4:
- rate = 176400;
- break;
- case HDSPM_madiFreq192:
- rate = 192000;
- break;
- default:
- rate = 0;
- break;
+ switch (rate_bits) {
+ case HDSPM_madiFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_madiFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_madiFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_madiFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_madiFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_madiFreq96:
+ rate = 96000;
+ break;
+ case HDSPM_madiFreq128:
+ rate = 128000;
+ break;
+ case HDSPM_madiFreq176_4:
+ rate = 176400;
+ break;
+ case HDSPM_madiFreq192:
+ rate = 192000;
+ break;
+ default:
+ rate = 0;
+ break;
+ }
}
+ return rate;
}
- return rate;
}
/* Latency function */
@@ -676,7 +785,8 @@ static inline void hdspm_silence_playback(struct hdspm * hdspm)
int n = hdspm->period_bytes;
void *buf = hdspm->playback_buffer;
- snd_assert(buf != NULL, return);
+ if (buf == NULL)
+ return;
for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
memset(buf, 0, n);
@@ -716,6 +826,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
int current_rate;
int rate_bits;
int not_set = 0;
+ int is_single, is_double, is_quad;
/* ASSUMPTION: hdspm->lock is either set, or there is no need for
it (e.g. during module initialization).
@@ -766,43 +877,56 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
changes in the read/write routines.
*/
+ is_single = (current_rate <= 48000);
+ is_double = (current_rate > 48000 && current_rate <= 96000);
+ is_quad = (current_rate > 96000);
+
switch (rate) {
case 32000:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency32KHz;
break;
case 44100:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency44_1KHz;
break;
case 48000:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency48KHz;
break;
case 64000:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency64KHz;
break;
case 88200:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency88_2KHz;
break;
case 96000:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency96KHz;
break;
+ case 128000:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency128KHz;
+ break;
+ case 176400:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency176_4KHz;
+ break;
+ case 192000:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency192KHz;
+ break;
default:
return -EINVAL;
}
@@ -819,7 +943,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
hdspm->control_register |= rate_bits;
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
- if (rate > 64000)
+ if (rate > 96000 /* 64000*/)
hdspm->channel_map = channel_map_madi_qs;
else if (rate > 48000)
hdspm->channel_map = channel_map_madi_ds;
@@ -1455,11 +1579,27 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm)
/* Notice that this looks at the requested sync source,
not the one actually in use.
*/
- switch (hdspm->control_register & HDSPM_SyncRefMask) {
- case HDSPM_SyncRef_Word:
- return HDSPM_SYNC_FROM_WORD;
- case HDSPM_SyncRef_MADI:
- return HDSPM_SYNC_FROM_MADI;
+ if (hdspm->is_aes32) {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ /* number gives AES index, except for 0 which
+ corresponds to WordClock */
+ case 0: return 0;
+ case HDSPM_SyncRef0: return 1;
+ case HDSPM_SyncRef1: return 2;
+ case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3;
+ case HDSPM_SyncRef2: return 4;
+ case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5;
+ case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6;
+ case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7;
+ case HDSPM_SyncRef3: return 8;
+ }
+ } else {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case HDSPM_SyncRef_Word:
+ return HDSPM_SYNC_FROM_WORD;
+ case HDSPM_SyncRef_MADI:
+ return HDSPM_SYNC_FROM_MADI;
+ }
}
return HDSPM_SYNC_FROM_WORD;
@@ -1469,15 +1609,49 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
{
hdspm->control_register &= ~HDSPM_SyncRefMask;
- switch (pref) {
- case HDSPM_SYNC_FROM_MADI:
- hdspm->control_register |= HDSPM_SyncRef_MADI;
- break;
- case HDSPM_SYNC_FROM_WORD:
- hdspm->control_register |= HDSPM_SyncRef_Word;
- break;
- default:
- return -1;
+ if (hdspm->is_aes32) {
+ switch (pref) {
+ case 0:
+ hdspm->control_register |= 0;
+ break;
+ case 1:
+ hdspm->control_register |= HDSPM_SyncRef0;
+ break;
+ case 2:
+ hdspm->control_register |= HDSPM_SyncRef1;
+ break;
+ case 3:
+ hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 4:
+ hdspm->control_register |= HDSPM_SyncRef2;
+ break;
+ case 5:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0;
+ break;
+ case 6:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1;
+ break;
+ case 7:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 8:
+ hdspm->control_register |= HDSPM_SyncRef3;
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ switch (pref) {
+ case HDSPM_SYNC_FROM_MADI:
+ hdspm->control_register |= HDSPM_SyncRef_MADI;
+ break;
+ case HDSPM_SYNC_FROM_WORD:
+ hdspm->control_register |= HDSPM_SyncRef_Word;
+ break;
+ default:
+ return -1;
+ }
}
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
return 0;
@@ -1486,18 +1660,36 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Word", "MADI" };
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
+ if (hdspm->is_aes32) {
+ static char *texts[] = { "Word", "AES1", "AES2", "AES3",
+ "AES4", "AES5", "AES6", "AES7", "AES8" };
- uinfo->value.enumerated.items = 2;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
- 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]);
+ uinfo->value.enumerated.items = 9;
+
+ 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]);
+ } else {
+ static char *texts[] = { "Word", "MADI" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ uinfo->value.enumerated.items = 2;
+
+ 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;
}
@@ -1517,7 +1709,7 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
int change, max;
unsigned int val;
- max = 2;
+ max = hdspm->is_aes32 ? 9 : 2;
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
@@ -1542,40 +1734,64 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
static int hdspm_autosync_ref(struct hdspm * hdspm)
{
- /* This looks at the autosync selected sync reference */
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
-
- switch (status2 & HDSPM_SelSyncRefMask) {
-
- case HDSPM_SelSyncRef_WORD:
- return HDSPM_AUTOSYNC_FROM_WORD;
-
- case HDSPM_SelSyncRef_MADI:
- return HDSPM_AUTOSYNC_FROM_MADI;
-
- case HDSPM_SelSyncRef_NVALID:
- return HDSPM_AUTOSYNC_FROM_NONE;
+ if (hdspm->is_aes32) {
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+ if (syncref == 0)
+ return HDSPM_AES32_AUTOSYNC_FROM_WORD;
+ if (syncref <= 8)
+ return syncref;
+ return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+ } else {
+ /* This looks at the autosync selected sync reference */
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ switch (status2 & HDSPM_SelSyncRefMask) {
+ case HDSPM_SelSyncRef_WORD:
+ return HDSPM_AUTOSYNC_FROM_WORD;
+ case HDSPM_SelSyncRef_MADI:
+ return HDSPM_AUTOSYNC_FROM_MADI;
+ case HDSPM_SelSyncRef_NVALID:
+ return HDSPM_AUTOSYNC_FROM_NONE;
+ default:
+ return 0;
+ }
- default:
return 0;
}
-
- return 0;
}
static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "WordClock", "MADI", "None" };
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- 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]);
+ if (hdspm->is_aes32) {
+ static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
+ "AES4", "AES5", "AES6", "AES7", "AES8", "None"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 10;
+ 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]);
+ }
+ else
+ {
+ static char *texts[] = { "WordClock", "MADI", "None" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ 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;
}
@@ -1841,6 +2057,195 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol,
return change;
}
+#define HDSPM_EMPHASIS(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_emphasis, \
+ .get = snd_hdspm_get_emphasis, \
+ .put = snd_hdspm_put_emphasis \
+}
+
+static int hdspm_emphasis(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0;
+}
+
+static int hdspm_set_emphasis(struct hdspm * hdspm, int emp)
+{
+ if (emp)
+ hdspm->control_register |= HDSPM_Emphasis;
+ else
+ hdspm->control_register &= ~HDSPM_Emphasis;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_emphasis(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;
+}
+
+static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_emphasis(hdspm);
+ hdspm_set_emphasis(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_DOLBY(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_dolby, \
+ .get = snd_hdspm_get_dolby, \
+ .put = snd_hdspm_put_dolby \
+}
+
+static int hdspm_dolby(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0;
+}
+
+static int hdspm_set_dolby(struct hdspm * hdspm, int dol)
+{
+ if (dol)
+ hdspm->control_register |= HDSPM_Dolby;
+ else
+ hdspm->control_register &= ~HDSPM_Dolby;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_dolby(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;
+}
+
+static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_dolby(hdspm);
+ hdspm_set_dolby(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_PROFESSIONAL(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_professional, \
+ .get = snd_hdspm_get_professional, \
+ .put = snd_hdspm_put_professional \
+}
+
+static int hdspm_professional(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Professional) ? 1 : 0;
+}
+
+static int hdspm_set_professional(struct hdspm * hdspm, int dol)
+{
+ if (dol)
+ hdspm->control_register |= HDSPM_Professional;
+ else
+ hdspm->control_register &= ~HDSPM_Professional;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_professional(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;
+}
+
+static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_professional(hdspm);
+ hdspm_set_professional(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
#define HDSPM_INPUT_SELECT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1912,6 +2317,163 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
return change;
}
+#define HDSPM_DS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_ds_wire, \
+ .get = snd_hdspm_get_ds_wire, \
+ .put = snd_hdspm_put_ds_wire \
+}
+
+static int hdspm_ds_wire(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0;
+}
+
+static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
+{
+ if (ds)
+ hdspm->control_register |= HDSPM_DS_DoubleWire;
+ else
+ hdspm->control_register &= ~HDSPM_DS_DoubleWire;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Single", "Double" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ 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_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_ds_wire(hdspm);
+ hdspm_set_ds_wire(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_QS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_qs_wire, \
+ .get = snd_hdspm_get_qs_wire, \
+ .put = snd_hdspm_put_qs_wire \
+}
+
+static int hdspm_qs_wire(struct hdspm * hdspm)
+{
+ if (hdspm->control_register & HDSPM_QS_DoubleWire)
+ return 1;
+ if (hdspm->control_register & HDSPM_QS_QuadWire)
+ return 2;
+ return 0;
+}
+
+static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
+{
+ hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire);
+ switch (mode) {
+ case 0:
+ break;
+ case 1:
+ hdspm->control_register |= HDSPM_QS_DoubleWire;
+ break;
+ case 2:
+ hdspm->control_register |= HDSPM_QS_QuadWire;
+ break;
+ }
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Single", "Double", "Quad" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+
+ 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_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0];
+ if (val < 0)
+ val = 0;
+ if (val > 2)
+ val = 2;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_qs_wire(hdspm);
+ hdspm_set_qs_wire(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
/* Simple Mixer
deprecated since to much faders ???
MIXER interface says output (source, destination, value)
@@ -2135,14 +2697,24 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
static int hdspm_wc_sync_check(struct hdspm * hdspm)
{
- int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- if (status2 & HDSPM_wcLock) {
- if (status2 & HDSPM_wcSync)
+ if (hdspm->is_aes32) {
+ int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ if (status & HDSPM_AES32_wcLock) {
+ /* I don't know how to differenciate sync from lock.
+ Doing as if sync for now */
return 2;
- else
- return 1;
+ }
+ return 0;
+ } else {
+ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ if (status2 & HDSPM_wcLock) {
+ if (status2 & HDSPM_wcSync)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
}
- return 0;
}
static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol,
@@ -2188,9 +2760,43 @@ static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol,
}
+#define HDSPM_AES_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_sync_check, \
+ .get = snd_hdspm_get_aes_sync_check \
+}
+
+static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx)
+{
+ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ if (status2 & (HDSPM_LockAES >> idx)) {
+ /* I don't know how to differenciate sync from lock.
+ Doing as if sync for now */
+ return 2;
+ }
+ return 0;
+}
+
+static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int offset;
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ offset = ucontrol->id.index - 1;
+ if (offset < 0 || offset >= 8)
+ return -EINVAL;
+
+ ucontrol->value.enumerated.item[0] =
+ hdspm_aes_sync_check(hdspm, offset);
+ return 0;
+}
-static struct snd_kcontrol_new snd_hdspm_controls[] = {
+static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
HDSPM_MIXER("Mixer", 0),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
@@ -2211,6 +2817,29 @@ static struct snd_kcontrol_new snd_hdspm_controls[] = {
HDSPM_INPUT_SELECT("Input Select", 0),
};
+static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
+
+ HDSPM_MIXER("Mixer", 0),
+/* 'Sample Clock Source' complies with the alsa control naming scheme */
+ HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+
+ HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+ HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
+ HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+/* 'External Rate' complies with the alsa control naming scheme */
+ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+ HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
+/* HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */
+ HDSPM_LINE_OUT("Line Out", 0),
+ HDSPM_EMPHASIS("Emphasis", 0),
+ HDSPM_DOLBY("Non Audio", 0),
+ HDSPM_PROFESSIONAL("Professional", 0),
+ HDSPM_C_TMS("Clear Track Marker", 0),
+ HDSPM_DS_WIRE("Double Speed Wire Mode", 0),
+ HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
+};
+
static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
@@ -2245,20 +2874,40 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
struct snd_kcontrol *kctl;
/* add control list first */
-
- for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) {
- if ((err =
- snd_ctl_add(card, kctl =
- snd_ctl_new1(&snd_hdspm_controls[idx],
- hdspm))) < 0) {
- return err;
+ if (hdspm->is_aes32) {
+ struct snd_kcontrol_new aes_sync_ctl =
+ HDSPM_AES_SYNC_CHECK("AES Lock Status", 0);
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32);
+ idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_hdspm_controls_aes32[idx],
+ hdspm));
+ if (err < 0)
+ return err;
+ }
+ for (idx = 1; idx <= 8; idx++) {
+ aes_sync_ctl.index = idx;
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&aes_sync_ctl, hdspm));
+ if (err < 0)
+ return err;
+ }
+ } else {
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi);
+ idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_hdspm_controls_madi[idx],
+ hdspm));
+ if (err < 0)
+ return err;
}
}
/* Channel playback mixer as default control
- Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
- they are accesible via special IOCTL on hwdep
- and the mixer 2dimensional mixer control */
+Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
+they are accesible via special IOCTL on hwdep
+and the mixer 2dimensional mixer control */
snd_hdspm_playback_mixer.name = "Chn";
limit = HDSPM_MAX_CHANNELS;
@@ -2289,7 +2938,8 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
------------------------------------------------------------*/
static void
-snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = (struct hdspm *) entry->private_data;
unsigned int status;
@@ -2420,11 +3070,10 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe
clock_source = "Error";
}
snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
- if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster))
system_clock_mode = "Slave";
- } else {
+ else
system_clock_mode = "Master";
- }
snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
switch (hdspm_pref_sync_ref(hdspm)) {
@@ -2484,13 +3133,213 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe
snd_iprintf(buffer, "\n");
}
+static void
+snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = (struct hdspm *) entry->private_data;
+ unsigned int status;
+ unsigned int status2;
+ unsigned int timecode;
+ int pref_syncref;
+ char *autosync_ref;
+ char *system_clock_mode;
+ char *clock_source;
+ int x;
+
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+ snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n",
+ hdspm->card_name, hdspm->card->number + 1,
+ hdspm->firmware_rev);
+
+ snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+ hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+ snd_iprintf(buffer, "--- System ---\n");
+
+ snd_iprintf(buffer,
+ "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+ status & HDSPM_audioIRQPending,
+ (status & HDSPM_midi0IRQPending) ? 1 : 0,
+ (status & HDSPM_midi1IRQPending) ? 1 : 0,
+ hdspm->irq_count);
+ snd_iprintf(buffer,
+ "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n",
+ ((status & HDSPM_BufferID) ? 1 : 0),
+ (status & HDSPM_BufferPositionMask),
+ (status & HDSPM_BufferPositionMask) % (2 *
+ (int)hdspm->
+ period_bytes),
+ ((status & HDSPM_BufferPositionMask) -
+ 64) % (2 * (int)hdspm->period_bytes),
+ (long) hdspm_hw_pointer(hdspm) * 4);
+
+ snd_iprintf(buffer,
+ "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+ snd_iprintf(buffer,
+ "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n",
+ hdspm->control_register, hdspm->control2_register,
+ status, status2, timecode);
+
+ snd_iprintf(buffer, "--- Settings ---\n");
+
+ x = 1 << (6 +
+ hdspm_decode_latency(hdspm->
+ control_register &
+ HDSPM_LatencyMask));
+
+ snd_iprintf(buffer,
+ "Size (Latency): %d samples (2 periods of %lu bytes)\n",
+ x, (unsigned long) hdspm->period_bytes);
+
+ snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n",
+ (hdspm->
+ control_register & HDSPM_LineOut) ? "on " : "off",
+ (hdspm->precise_ptr) ? "on" : "off");
+
+ snd_iprintf(buffer,
+ "ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
+ (hdspm->
+ control_register & HDSPM_clr_tms) ? "on" : "off",
+ (hdspm->
+ control_register & HDSPM_Emphasis) ? "on" : "off",
+ (hdspm->
+ control_register & HDSPM_Dolby) ? "on" : "off");
+
+ switch (hdspm_clock_source(hdspm)) {
+ case HDSPM_CLOCK_SOURCE_AUTOSYNC:
+ clock_source = "AutoSync";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
+ clock_source = "Internal 32 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
+ clock_source = "Internal 44.1 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
+ clock_source = "Internal 48 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
+ clock_source = "Internal 64 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
+ clock_source = "Internal 88.2 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
+ clock_source = "Internal 96 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
+ clock_source = "Internal 128 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
+ clock_source = "Internal 176.4 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
+ clock_source = "Internal 192 kHz";
+ break;
+ default:
+ clock_source = "Error";
+ }
+ snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster))
+ system_clock_mode = "Slave";
+ else
+ system_clock_mode = "Master";
+ snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
+
+ pref_syncref = hdspm_pref_sync_ref(hdspm);
+ if (pref_syncref == 0)
+ snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n");
+ else
+ snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n",
+ pref_syncref);
+
+ snd_iprintf(buffer, "System Clock Frequency: %d\n",
+ hdspm->system_sample_rate);
+
+ snd_iprintf(buffer, "Double speed: %s\n",
+ hdspm->control_register & HDSPM_DS_DoubleWire?
+ "Double wire" : "Single wire");
+ snd_iprintf(buffer, "Quad speed: %s\n",
+ hdspm->control_register & HDSPM_QS_DoubleWire?
+ "Double wire" :
+ hdspm->control_register & HDSPM_QS_QuadWire?
+ "Quad wire" : "Single wire");
+
+ snd_iprintf(buffer, "--- Status:\n");
+
+ snd_iprintf(buffer, "Word: %s Frequency: %d\n",
+ (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock",
+ HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
+
+ for (x = 0; x < 8; x++) {
+ snd_iprintf(buffer, "AES%d: %s Frequency: %d\n",
+ x+1,
+ (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock",
+ HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
+ }
+
+ switch (hdspm_autosync_ref(hdspm)) {
+ case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break;
+ default: autosync_ref = "---"; break;
+ }
+ snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
+
+ snd_iprintf(buffer, "\n");
+}
+
+#ifdef CONFIG_SND_DEBUG
+static void
+snd_hdspm_proc_read_debug(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = (struct hdspm *)entry->private_data;
+
+ int j,i;
+
+ for (i = 0; i < 256 /* 1024*64 */; i += j)
+ {
+ snd_iprintf(buffer, "0x%08X: ", i);
+ for (j = 0; j < 16; j += 4)
+ snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j));
+ snd_iprintf(buffer, "\n");
+ }
+}
+#endif
+
+
+
static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
{
struct snd_info_entry *entry;
if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
snd_info_set_text_ops(entry, hdspm,
- snd_hdspm_proc_read);
+ hdspm->is_aes32 ?
+ snd_hdspm_proc_read_aes32 :
+ snd_hdspm_proc_read_madi);
+#ifdef CONFIG_SND_DEBUG
+ /* debug file to read all hdspm registers */
+ if (!snd_card_proc_new(hdspm->card, "debug", &entry))
+ snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_debug);
+#endif
}
/*------------------------------------------------------------
@@ -2507,13 +3356,20 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
/* set defaults: */
- hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
- hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
- HDSPM_InputCoaxial | /* Input Coax not Optical */
- HDSPM_SyncRef_MADI | /* Madi is syncclock */
- HDSPM_LineOut | /* Analog output in */
- HDSPM_TX_64ch | /* transmit in 64ch mode */
- HDSPM_AutoInp; /* AutoInput chossing (takeover) */
+ if (hdspm->is_aes32)
+ hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+ hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
+ HDSPM_SyncRef0 | /* AES1 is syncclock */
+ HDSPM_LineOut | /* Analog output in */
+ HDSPM_Professional; /* Professional mode */
+ else
+ hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+ hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
+ HDSPM_InputCoaxial | /* Input Coax not Optical */
+ HDSPM_SyncRef_MADI | /* Madi is syncclock */
+ HDSPM_LineOut | /* Analog output in */
+ HDSPM_TX_64ch | /* transmit in 64ch mode */
+ HDSPM_AutoInp; /* AutoInput chossing (takeover) */
/* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */
/* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */
@@ -2822,6 +3678,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->playback_buffer =
(unsigned char *) substream->runtime->dma_area;
+ snd_printdd("Allocated sample buffer for playback at %p\n",
+ hdspm->playback_buffer);
} else {
hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
params_channels(params));
@@ -2831,7 +3689,15 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->capture_buffer =
(unsigned char *) substream->runtime->dma_area;
+ snd_printdd("Allocated sample buffer for capture at %p\n",
+ hdspm->capture_buffer);
}
+ /*
+ snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "playback" : "capture",
+ snd_pcm_sgbuf_get_addr(sgbuf, 0));
+ */
return 0;
}
@@ -2982,9 +3848,10 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_64000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ),
.rate_min = 32000,
- .rate_max = 96000,
+ .rate_max = 192000,
.channels_min = 1,
.channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max =
@@ -3006,9 +3873,10 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_64000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000),
.rate_min = 32000,
- .rate_max = 96000,
+ .rate_max = 192000,
.channels_min = 1,
.channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max =
@@ -3315,7 +4183,8 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
pcm = hdspm->pcm;
- wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */
+/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */
+ wanted = HDSPM_DMA_AREA_BYTES;
if ((err =
snd_pcm_lib_preallocate_pages_for_all(pcm,
@@ -3467,9 +4336,16 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp
pci_read_config_word(hdspm->pci,
PCI_CLASS_REVISION, &hdspm->firmware_rev);
- strcpy(card->driver, "HDSPM");
+ hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION);
+
strcpy(card->mixername, "Xilinx FPGA");
- hdspm->card_name = "RME HDSPM MADI";
+ if (hdspm->is_aes32) {
+ strcpy(card->driver, "HDSPAES32");
+ hdspm->card_name = "RME HDSPM AES32";
+ } else {
+ strcpy(card->driver, "HDSPM");
+ hdspm->card_name = "RME HDSPM MADI";
+ }
if ((err = pci_enable_device(pci)) < 0)
return err;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 474f2d451ae8..3bff32167f66 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2627,7 +2627,7 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2844,7 +2844,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
{
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index a572b018807f..a28992269f5e 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1699,7 +1699,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
.name = "PCM Playback Volume",
@@ -1823,7 +1823,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui
ac97.private_data = chip;
ac97.private_free = snd_via82xx_mixer_free_ac97;
ac97.pci = chip->pci;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
return err;
@@ -2357,93 +2357,59 @@ static struct via823x_info via823x_cards[] __devinitdata = {
/*
* auto detection of DXS channel supports.
*/
-struct dxs_whitelist {
- unsigned short subvendor;
- unsigned short subdevice;
- unsigned short mask;
- short action; /* new dxs_support value */
+
+static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
+ SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K),
+ SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1415, "ABIT AV8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x14ff, 0x0403, "Twinhead mobo", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x14ff, 0x0408, "Twinhead laptop", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1558, 0x4701, "Clevo D470", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1584, 0x8120, "Diverse Laptop", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1584, 0x8123, "Targa/Uniwill", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x161f, 0x202b, "Amira Notebook", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K),
+ SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC),
+ { } /* terminator */
};
static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
{
- static struct dxs_whitelist whitelist[] __devinitdata = {
- { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
- { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K },
- { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
- { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
- { .subvendor = 0x1019, .subdevice = 0xa101, .action = VIA_DXS_SRC },
- { .subvendor = 0x1019, .subdevice = 0xaa01, .action = VIA_DXS_SRC }, /* ECS K8T890-A */
- { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
- { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
- { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
- { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
- { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
- { .subvendor = 0x1043, .subdevice = 0x810d, .action = VIA_DXS_SRC }, /* ASUS */
- { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */
- { .subvendor = 0x1043, .subdevice = 0x8174, .action = VIA_DXS_SRC }, /* ASUS */
- { .subvendor = 0x1043, .subdevice = 0x81b9, .action = VIA_DXS_SRC }, /* ASUS A8V-MX */
- { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
- { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */
- { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
- { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
- { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
- { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
- { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */
- { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
- { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
- { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
- { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
- { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
- { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */
- { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
- { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
- { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */
- { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
- { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
- { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */
- { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
- { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
- { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
- { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
- { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
- { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */
- { .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */
- { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
- { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
- { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
- { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
- { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
- { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
- { .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */
- { .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */
- { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
- { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
- { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
- { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */
- { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
- { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
- { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
- { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
- { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */
- { } /* terminator */
- };
- const struct dxs_whitelist *w;
- unsigned short subsystem_vendor;
- unsigned short subsystem_device;
-
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
+ const struct snd_pci_quirk *w;
- for (w = whitelist; w->subvendor; w++) {
- if (w->subvendor != subsystem_vendor)
- continue;
- if (w->mask) {
- if ((w->mask & subsystem_device) == w->subdevice)
- return w->action;
- } else {
- if (subsystem_device == w->subdevice)
- return w->action;
- }
+ w = snd_pci_quirk_lookup(pci, dxs_whitelist);
+ if (w) {
+ snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
+ w->name);
+ return w->value;
}
/* for newer revision, default to DXS_SRC */
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 17d6b847585f..b338e15db0d9 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -900,7 +900,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip)
ac97.private_data = chip;
ac97.private_free = snd_via82xx_mixer_free_ac97;
ac97.pci = chip->pci;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
ac97.num = chip->ac97_secondary;
if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 89f58ea180b3..474eac9490ae 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -73,8 +73,8 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids);
/*
*/
-static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
static struct snd_vx_hardware vx222_old_hw = {
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 5e51950e05f9..55558bef7166 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -846,7 +846,7 @@ static void vx2_set_input_level(struct snd_vx222 *chip)
#define MIC_LEVEL_MAX 0xff
-static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
/*
* controls API for input levels
diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h
index 1b0746991669..112f2fff6c8e 100644
--- a/sound/pci/ymfpci/ymfpci_image.h
+++ b/sound/pci/ymfpci/ymfpci_image.h
@@ -1,7 +1,7 @@
#ifndef _HWMCODE_
#define _HWMCODE_
-static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
+static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
-static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
// 04/09 creat
// 04/12 stop nise fix
// 06/21 WorkingOff timming
-static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 7881944a1957..fd12674d0394 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2,12 +2,6 @@
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Routines for control of YMF724/740/744/754 chips
*
- * BUGS:
- * --
- *
- * TODO:
- * --
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,6 +20,7 @@
#include <sound/driver.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -42,10 +37,7 @@
#include <sound/mpu401.h>
#include <asm/io.h>
-
-/*
- * constants
- */
+#include <asm/byteorder.h>
/*
* common I/O routines
@@ -179,6 +171,17 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate)
return val[0];
}
+static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm)
+{
+ unsigned int value;
+ struct snd_ymfpci_pcm_mixer *mixer;
+
+ mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number];
+ value = min_t(unsigned int, mixer->left, 0x7fff) >> 1;
+ value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16;
+ snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value);
+}
+
/*
* Hardware start management
*/
@@ -290,6 +293,10 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic
snd_assert(pvoice != NULL, return -EINVAL);
snd_ymfpci_hw_stop(chip);
spin_lock_irqsave(&chip->voice_lock, flags);
+ if (pvoice->number == chip->src441_used) {
+ chip->src441_used = -1;
+ pvoice->ypcm->use_441_slot = 0;
+ }
pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
pvoice->ypcm = NULL;
pvoice->interrupt = NULL;
@@ -394,7 +401,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
- if (ypcm->voices[1] != NULL)
+ if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
ypcm->running = 1;
break;
@@ -402,7 +409,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
- if (ypcm->voices[1] != NULL)
+ if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
ypcm->running = 0;
break;
@@ -489,6 +496,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
unsigned int nbank;
u32 vol_left, vol_right;
u8 use_left, use_right;
+ unsigned long flags;
snd_assert(voice != NULL, return);
if (runtime->channels == 1) {
@@ -507,11 +515,27 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
vol_left = cpu_to_le32(0x40000000);
vol_right = cpu_to_le32(0x40000000);
}
+ spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
format = runtime->channels == 2 ? 0x00010000 : 0;
if (snd_pcm_format_width(runtime->format) == 8)
format |= 0x80000000;
+ else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
+ runtime->rate == 44100 && runtime->channels == 2 &&
+ voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
+ ypcm->chip->src441_used == voice->number)) {
+ ypcm->chip->src441_used = voice->number;
+ ypcm->use_441_slot = 1;
+ format |= 0x10000000;
+ snd_ymfpci_pcm_441_volume_set(ypcm);
+ }
+ if (ypcm->chip->src441_used == voice->number &&
+ (format & 0x10000000) == 0) {
+ ypcm->chip->src441_used = -1;
+ ypcm->use_441_slot = 0;
+ }
if (runtime->channels == 2 && (voiceidx & 1) != 0)
format |= 1;
+ spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
memset(bank, 0, sizeof(*bank));
@@ -1480,7 +1504,7 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
#define YMFPCI_DOUBLE(xname, xindex, reg) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
@@ -1722,7 +1746,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
spin_lock_irqsave(&chip->voice_lock, flags);
if (substream->runtime && substream->runtime->private_data) {
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
- ypcm->update_pcm_vol = 2;
+ if (!ypcm->use_441_slot)
+ ypcm->update_pcm_vol = 2;
+ else
+ snd_ymfpci_pcm_441_volume_set(ypcm);
}
spin_unlock_irqrestore(&chip->voice_lock, flags);
return 1;
@@ -1971,13 +1998,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip)
}
}
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
#include "ymfpci_image.h"
+static struct firmware snd_ymfpci_dsp_microcode = {
+ .size = YDSXG_DSPLENGTH,
+ .data = (u8 *)DspInst,
+};
+static struct firmware snd_ymfpci_controller_microcode = {
+ .size = YDSXG_CTRLLENGTH,
+ .data = (u8 *)CntrlInst,
+};
+static struct firmware snd_ymfpci_controller_1e_microcode = {
+ .size = YDSXG_CTRLLENGTH,
+ .data = (u8 *)CntrlInst1E,
+};
+#endif
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_ymfpci_convert_from_le(const struct firmware *fw)
+{
+ int i;
+ u32 *data = (u32 *)fw->data;
+
+ for (i = 0; i < fw->size / 4; ++i)
+ le32_to_cpus(&data[i]);
+}
+#endif
+
+static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
+{
+ int err, is_1e;
+ const char *name;
+
+ err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
+ &chip->pci->dev);
+ if (err >= 0) {
+ if (chip->dsp_microcode->size == YDSXG_DSPLENGTH)
+ snd_ymfpci_convert_from_le(chip->dsp_microcode);
+ else {
+ snd_printk(KERN_ERR "DSP microcode has wrong size\n");
+ err = -EINVAL;
+ }
+ }
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->dsp_microcode = &snd_ymfpci_dsp_microcode;
+#else
+ return err;
+#endif
+ }
+ is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
+ name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
+ err = request_firmware(&chip->controller_microcode, name,
+ &chip->pci->dev);
+ if (err >= 0) {
+ if (chip->controller_microcode->size == YDSXG_CTRLLENGTH)
+ snd_ymfpci_convert_from_le(chip->controller_microcode);
+ else {
+ snd_printk(KERN_ERR "controller microcode"
+ " has wrong size\n");
+ err = -EINVAL;
+ }
+ }
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->controller_microcode =
+ is_1e ? &snd_ymfpci_controller_1e_microcode
+ : &snd_ymfpci_controller_microcode;
+#else
+ return err;
+#endif
+ }
+ return 0;
+}
+
static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
{
int i;
u16 ctrl;
- unsigned long *inst;
+ u32 *inst;
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
snd_ymfpci_disable_dsp(chip);
@@ -1992,21 +2100,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
/* setup DSP instruction code */
+ inst = (u32 *)chip->dsp_microcode->data;
for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
- snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
+ snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]);
/* setup control instruction code */
- switch (chip->device_id) {
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- inst = CntrlInst1E;
- break;
- default:
- inst = CntrlInst;
- break;
- }
+ inst = (u32 *)chip->controller_microcode->data;
for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
@@ -2160,6 +2259,15 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
pci_disable_device(chip->pci);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode)
+#endif
+ release_firmware(chip->dsp_microcode);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->controller_microcode != &snd_ymfpci_controller_microcode &&
+ chip->controller_microcode != &snd_ymfpci_controller_1e_microcode)
+#endif
+ release_firmware(chip->controller_microcode);
kfree(chip);
return 0;
}
@@ -2180,7 +2288,7 @@ static int saved_regs_index[] = {
YDSXGR_PRIADCLOOPVOL,
YDSXGR_NATIVEDACINVOL,
YDSXGR_NATIVEDACOUTVOL,
- // YDSXGR_BUF441OUTVOL,
+ YDSXGR_BUF441OUTVOL,
YDSXGR_NATIVEADCINVOL,
YDSXGR_SPDIFLOOPVOL,
YDSXGR_SPDIFOUTVOL,
@@ -2295,6 +2403,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
chip->reg_area_phys = pci_resource_start(pci, 0);
chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
pci_set_master(pci);
+ chip->src441_used = -1;
if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
@@ -2315,6 +2424,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
return -EIO;
}
+ err = snd_ymfpci_request_firmware(chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR "firmware request failed: %d\n", err);
+ snd_ymfpci_free(chip);
+ return err;
+ }
snd_ymfpci_download_image(chip);
udelay(100); /* seems we need a delay after downloading image.. */