diff options
Diffstat (limited to 'sound/pci')
60 files changed, 1578 insertions, 1052 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1caf5e3c1f6..e68c98ef404 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1852,12 +1852,14 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 73b17d526c8..6320bf084e4 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -22,7 +22,6 @@ * */ -#include <linux/slab.h> #include <linux/mutex.h> #include <sound/core.h> diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index d75cf7b0642..6cf1de8042e 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -68,7 +68,6 @@ #include <asm/io.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/gameport.h> #include <linux/moduleparam.h> #include <linux/dma-mapping.h> diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c index 296123ab74f..8afd8b5d1ac 100644 --- a/sound/pci/aw2/aw2-saa7146.c +++ b/sound/pci/aw2/aw2-saa7146.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <asm/system.h> diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 8f443a9d61e..85fd315d999 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -63,7 +63,6 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> #include <sound/initval.h> diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 0470461cc03..ba96428c9f4 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -63,7 +63,6 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> #include <sound/initval.h> diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1ded64e0564..329968edca9 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -941,13 +941,21 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci struct snd_pcm_substream *substream) { size_t ptr; - unsigned int reg; + unsigned int reg, rem, tries; + if (!rec->running) return 0; #if 1 // this seems better.. reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; - ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1); - ptr >>= rec->shift; + for (tries = 0; tries < 3; tries++) { + rem = snd_cmipci_read_w(cm, reg); + if (rem < rec->dma_size) + goto ok; + } + printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem); + return SNDRV_PCM_POS_XRUN; +ok: + ptr = (rec->dma_size - (rem + 1)) >> rec->shift; #else reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1; ptr = snd_cmipci_read(cm, reg) - rec->offset; diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index 207479a641c..bc07e275d4d 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -39,6 +39,7 @@ #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/pci.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/sb.h> #include <sound/initval.h> diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 0f48a871f17..f16bc8aad6e 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -23,7 +23,6 @@ */ #include <linux/init.h> -#include <linux/slab.h> #include <linux/pci.h> #include <sound/core.h> #include <sound/control.h> diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 564c33b6095..a3301cc4ab8 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -19,7 +19,6 @@ */ #include <linux/init.h> -#include <linux/slab.h> #include <linux/pci.h> #include <linux/delay.h> #include <sound/core.h> diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 480cb1e905b..1bff80cde0a 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -24,6 +24,7 @@ #include "ctdaio.h" #include "cttimer.h" #include <linux/delay.h> +#include <linux/slab.h> #include <sound/pcm.h> #include <sound/control.h> #include <sound/asoundef.h> diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index d0dc227fbdd..85ab43e8921 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -17,6 +17,7 @@ #include "ctpcm.h" #include "cttimer.h" +#include <linux/slab.h> #include <sound/pcm.h> /* Hardware descriptions for playback */ diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index a65bafe0800..fe7ad64dccd 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -40,9 +40,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 0a6c50bcd75..d1fd34b1a8e 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -44,9 +44,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index f5142796989..1dffdc54416 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -51,9 +51,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 8dab82d7d19..668a5ec0449 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2184,10 +2184,9 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, goto ctl_error; #endif - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); + err = snd_card_register(card); + if (err < 0) goto ctl_error; - } snd_printk(KERN_INFO "Card registered: %s\n", card->longname); pci_set_drvdata(pci, chip); diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index 2364f8a1bc2..050e54aa693 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -44,9 +44,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index 616b55825a1..5748fc6d29d 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -50,9 +50,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 776175c0bda..4ae5e35cb5f 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -42,9 +42,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 8816b0bd2ba..3550715bab1 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -42,9 +42,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index b1e3652f2f4..19b191fd012 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c @@ -42,10 +42,10 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/io.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index 1035125336d..a9fcedf317a 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -43,9 +43,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index 60b7cb2753c..bcdfac63212 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c @@ -43,10 +43,10 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/io.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 8c3f5c5b530..d3a98c5dac8 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -49,9 +49,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index ed1cc0abc2b..2a1dca6dce1 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -51,9 +51,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index cc2bbfc6532..9cdf14cfdd7 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -50,9 +50,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 3e7e01824b4..1047be405eb 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -48,9 +48,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/firmware.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/info.h> #include <sound/control.h> diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 6a47672f930..ffb1ddb8dc2 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -22,6 +22,7 @@ */ #include <linux/pci.h> +#include <linux/gfp.h> #include <linux/time.h> #include <linux/mutex.h> diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 556cff937be..567348b05b5 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -157,7 +157,7 @@ config SND_HDA_CODEC_INTELHDMI config SND_HDA_ELD def_bool y - depends on SND_HDA_CODEC_INTELHDMI + depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI config SND_HDA_CODEC_CIRRUS bool "Build Cirrus Logic codec support" diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 315a1c4f899..24bc195b02d 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -3,7 +3,7 @@ snd-hda-intel-objs := hda_intel.o snd-hda-codec-y := hda_codec.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o -# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o +snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o @@ -18,7 +18,7 @@ snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o -snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o +snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o # common driver obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e4581a42ace..29714c818b5 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -21,6 +21,7 @@ #include <linux/input.h> #include <linux/pci.h> +#include <linux/slab.h> #include <linux/workqueue.h> #include <sound/core.h> #include "hda_beep.h" diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 76d3c4c049d..0e76ac2b2ac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -978,8 +978,9 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp) +int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, + unsigned int codec_addr, + struct hda_codec **codecp) { struct hda_codec *codec; char component[31]; @@ -1186,7 +1187,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); */ /* FIXME: more better hash key? */ -#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) +#define HDA_HASH_KEY(nid, dir, idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) @@ -1356,7 +1357,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) if (!codec->no_trigger_sense) { pincap = snd_hda_query_pin_caps(codec, nid); if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_SENSE, 0); } return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); @@ -1372,8 +1374,8 @@ EXPORT_SYMBOL_HDA(snd_hda_pin_sense); */ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) { - u32 sense = snd_hda_pin_sense(codec, nid); - return !!(sense & AC_PINSENSE_PRESENCE); + u32 sense = snd_hda_pin_sense(codec, nid); + return !!(sense & AC_PINSENSE_PRESENCE); } EXPORT_SYMBOL_HDA(snd_hda_jack_detect); @@ -1804,6 +1806,8 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, item->nid = nid; return 0; } + printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n", + kctl->id.name, kctl->id.index, index); return -EINVAL; } EXPORT_SYMBOL_HDA(snd_hda_add_nid); @@ -1952,7 +1956,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; - + for (s = slaves; *s; s++) { struct snd_kcontrol *sctl; int i = 0; @@ -2439,27 +2443,27 @@ static struct snd_kcontrol_new dig_mixes[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_cmask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_pmask_get, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_default_get, .put = snd_hda_spdif_default_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), .info = snd_hda_spdif_out_switch_info, .get = snd_hda_spdif_out_switch_get, .put = snd_hda_spdif_out_switch_put, @@ -2610,7 +2614,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new dig_in_ctls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), .info = snd_hda_spdif_in_switch_info, .get = snd_hda_spdif_in_switch_get, .put = snd_hda_spdif_in_switch_put, @@ -2618,7 +2622,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_in_status_get, }, @@ -2882,8 +2886,8 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) { - printk(KERN_ERR "hda_codec: cannot build controls" - "for #%d (error %d)\n", codec->addr, err); + printk(KERN_ERR "hda_codec: cannot build controls " + "for #%d (error %d)\n", codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { printk(KERN_ERR @@ -2979,8 +2983,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, val |= channels - 1; switch (snd_pcm_format_width(format)) { - case 8: val |= 0x00; break; - case 16: val |= 0x10; break; + case 8: + val |= 0x00; + break; + case 16: + val |= 0x10; + break; case 20: case 24: case 32: @@ -3298,7 +3306,8 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) return audio_idx[type][i]; - snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]); + snd_printk(KERN_WARNING "Too many %s devices\n", + snd_hda_pcm_type_name[type]); return -EAGAIN; } @@ -3336,7 +3345,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) err = codec->patch_ops.build_pcms(codec); if (err < 0) { printk(KERN_ERR "hda_codec: cannot build PCMs" - "for #%d (error %d)\n", codec->addr, err); + "for #%d (error %d)\n", codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { printk(KERN_ERR @@ -3466,8 +3475,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** * snd_hda_check_board_codec_sid_config - compare the current codec - subsystem ID with the - config table + subsystem ID with the + config table This is important for Gateway notebooks with SB450 HDA Audio where the vendor ID of the PCI device is: @@ -3607,7 +3616,7 @@ void snd_hda_update_power_acct(struct hda_codec *codec) * * Increment the power-up counter and power up the hardware really when * not turned on yet. - */ + */ void snd_hda_power_up(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; @@ -3636,7 +3645,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up); * * Decrement the power-up counter and schedules the power-off work if * the counter rearches to zero. - */ + */ void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; @@ -3662,7 +3671,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_down); * * This function is supposed to be set or called from the check_power_status * patch ops. - */ + */ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid) @@ -3830,7 +3839,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, { /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) - set_dig_out_convert(codec, nid, + set_dig_out_convert(codec, nid, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); @@ -4089,13 +4098,13 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) /* * Sort an associated group of pins according to their sequence numbers. */ -static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, +static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, int num_pins) { int i, j; short seq; hda_nid_t nid; - + for (i = 0; i < num_pins; i++) { for (j = i + 1; j < num_pins; j++) { if (sequences[i] > sequences[j]) { @@ -4123,7 +4132,7 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. - * + * * The analog input pins are assigned to input_pins array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. @@ -4186,9 +4195,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); - if (! assoc) + if (!assoc) continue; - if (! assoc_speaker) + if (!assoc_speaker) assoc_speaker = assoc; else if (assoc_speaker != assoc) continue; @@ -4286,7 +4295,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->speaker_outs); sort_pins_by_sequence(cfg->hp_pins, sequences_hp, cfg->hp_outs); - + /* if we have only one mic, make it AUTO_PIN_MIC */ if (!cfg->input_pins[AUTO_PIN_MIC] && cfg->input_pins[AUTO_PIN_FRONT_MIC]) { @@ -4436,7 +4445,7 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); /** * snd_array_new - get a new element from the given array * @array: the array object - * + * * Get a new element from the given array. If it exceeds the * pre-allocated array size, re-allocate the array. * diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 4228f2fe595..d8da18a9e98 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -22,6 +22,7 @@ */ #include <linux/init.h> +#include <linux/slab.h> #include <sound/core.h> #include <asm/unaligned.h> #include "hda_codec.h" @@ -331,6 +332,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, AC_DIPSIZE_ELD_BUF); } +EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size); int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) @@ -366,6 +368,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, kfree(buf); return ret; } +EXPORT_SYMBOL_HDA(snd_hdmi_get_eld); static void hdmi_show_short_audio_desc(struct cea_sad *a) { @@ -404,6 +407,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) } buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_HDA(snd_print_channel_allocation); void snd_hdmi_show_eld(struct hdmi_eld *e) { @@ -422,6 +426,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); } +EXPORT_SYMBOL_HDA(snd_hdmi_show_eld); #ifdef CONFIG_PROC_FS @@ -580,6 +585,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, return 0; } +EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new); void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) { @@ -588,5 +594,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) eld->proc_entry = NULL; } } +EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); #endif /* CONFIG_PROC_FS */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d5c93ad852e..cec68152dcb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -267,7 +267,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define RIRB_INT_MASK 0x05 /* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 4 +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 #define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) /* SD_CTL bits */ @@ -1367,6 +1368,7 @@ static void azx_bus_reset(struct hda_bus *bus) /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { + [AZX_DRIVER_NVIDIA] = 8, [AZX_DRIVER_TERA] = 1, }; @@ -1399,7 +1401,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) - max_slots = AZX_MAX_CODECS; + max_slots = AZX_DEFAULT_CODECS; /* First try to probe all given codec slots */ for (c = 0; c < max_slots; c++) { @@ -2263,10 +2265,16 @@ static int azx_dev_free(struct snd_device *device) static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; @@ -2354,6 +2362,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) static struct snd_pci_quirk msi_black_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */ + SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */ + SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */ + SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */ {} }; @@ -2372,6 +2383,13 @@ static void __devinit check_msi(struct azx *chip) "hda_intel: msi for device %04x:%04x set to %d\n", q->subvendor, q->subdevice, q->value); chip->msi = q->value; + return; + } + + /* NVidia chipsets seem to cause troubles with MSI */ + if (chip->driver_type == AZX_DRIVER_NVIDIA) { + printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n"); + chip->msi = 0; } } @@ -2700,6 +2718,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, /* PCH */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, + { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH }, /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index e6d1bdff1b6..e9fdfc4b1c5 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -519,14 +519,6 @@ static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) ad198x_power_eapd(codec); return 0; } - -static int ad198x_resume(struct hda_codec *codec) -{ - ad198x_init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - return 0; -} #endif static struct hda_codec_ops ad198x_patch_ops = { @@ -539,7 +531,6 @@ static struct hda_codec_ops ad198x_patch_ops = { #endif #ifdef SND_HDA_NEEDS_RESUME .suspend = ad198x_suspend, - .resume = ad198x_resume, #endif .reboot_notify = ad198x_shutup, }; @@ -1896,6 +1887,14 @@ static int patch_ad1981(struct hda_codec *codec) case AD1981_THINKPAD: spec->mixers[0] = ad1981_thinkpad_mixers; spec->input_mux = &ad1981_thinkpad_capture_source; + /* set the upper-limit for mixer amp to 0dB for avoiding the + * possible damage by overloading + */ + snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); break; case AD1981_TOSHIBA: spec->mixers[0] = ad1981_hp_mixers; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 7de782a5b8f..350ee8ac415 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -766,7 +766,7 @@ static int build_input(struct hda_codec *codec) for (n = 0; n < AUTO_PIN_LAST; n++) { if (!spec->adc_nid[n]) continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]); + err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 194a28c5499..d8213e2231a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1195,9 +1195,10 @@ static int patch_cxt5045(struct hda_codec *codec) switch (codec->subsystem_id >> 16) { case 0x103c: + case 0x1631: case 0x1734: - /* HP & Fujitsu-Siemens laptops have really bad sound over 0dB - * on NID 0x17. Fix max PCM level to 0 dB + /* HP, Packard Bell, & Fujitsu-Siemens laptops have really bad + * sound over 0dB on NID 0x17. Fix max PCM level to 0 dB * (originally it has 0x2b steps with 0dB offset 0x14) */ snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, @@ -1591,6 +1592,21 @@ static int patch_cxt5047(struct hda_codec *codec) #endif } spec->vmaster_nid = 0x13; + + switch (codec->subsystem_id >> 16) { + case 0x103c: + /* HP laptops have really bad sound over 0 dB on NID 0x10. + * Fix max PCM level to 0 dB (originally it has 0x1e steps + * with 0 dB offset 0x17) + */ + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + } + return 0; } @@ -2827,6 +2843,10 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), + SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), {} }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c new file mode 100644 index 00000000000..2c2bafbf025 --- /dev/null +++ b/sound/pci/hda/patch_hdmi.c @@ -0,0 +1,849 @@ +/* + * + * patch_hdmi.c - routines for HDMI/DisplayPort codecs + * + * Copyright(c) 2008-2010 Intel Corporation. All rights reserved. + * + * Authors: + * Wu Fengguang <wfg@linux.intel.com> + * + * Maintained by: + * Wu Fengguang <wfg@linux.intel.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 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. + */ + + +struct hdmi_spec { + int num_cvts; + int num_pins; + hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */ + hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */ + + /* + * source connection for each pin + */ + hda_nid_t pin_cvt[MAX_HDMI_PINS+1]; + + /* + * HDMI sink attached to each pin + */ + struct hdmi_eld sink_eld[MAX_HDMI_PINS]; + + /* + * export one pcm per pipe + */ + struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; + + /* + * nvhdmi specific + */ + struct hda_multi_out multiout; + unsigned int codec_type; +}; + + +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; /* PB0 */ + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; + u8 reserved[5]; /* PB6 - PB10 */ +}; + +/* + * CEA speaker placement: + * + * FLH FCH FRH + * FLW FL FLC FC FRC FR FRW + * + * LFE + * TC + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ + FLW = (1 << 11), /* Front Left Wide */ + FRW = (1 << 12), /* Front Right Wide */ + FLH = (1 << 13), /* Front Left High */ + FCH = (1 << 14), /* Front Center High */ + FRH = (1 << 15), /* Front Right High */ + TC = (1 << 16), /* Top Center */ +}; + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = FLW | FRW, + [8] = FLH | FRH, + [9] = TC, + [10] = FCH, +}; + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; + +/* + * ALSA sequence is: + * + * surround40 surround41 surround50 surround51 surround71 + * ch0 front left = = = = + * ch1 front right = = = = + * ch2 rear left = = = = + * ch3 rear right = = = = + * ch4 LFE center center center + * ch5 LFE LFE + * ch6 side left + * ch7 side right + * + * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR} + */ +static int hdmi_channel_mapping[0x32][8] = { + /* stereo */ + [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* 2.1 */ + [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* Dolby Surround */ + [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* surround40 */ + [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 }, + /* 4ch */ + [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, + /* surround41 */ + [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 }, + /* surround50 */ + [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, + /* surround51 */ + [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 }, + /* 7.1 */ + [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 }, +}; + +/* + * This is an ordered list! + * + * The preceding ones have better chances to be selected by + * hdmi_setup_channel_allocation(). + */ +static struct cea_channel_speaker_allocation channel_allocations[] = { +/* channel: 7 6 5 4 3 2 1 0 */ +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, + /* 2.1 */ +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, + /* Dolby Surround */ +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, + /* surround40 */ +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, + /* surround41 */ +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, + /* surround50 */ +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* surround51 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, + /* surround71 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, + +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, +}; + + +/* + * HDMI routines + */ + +static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) +{ + int i; + + for (i = 0; nids[i]; i++) + if (nids[i] == nid) + return i; + + snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); + return -EINVAL; +} + +static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld) +{ + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + snd_hdmi_show_eld(eld); +} + +#ifdef BE_PARANOID +static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, + int *packet_index, int *byte_index) +{ + int val; + + val = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_INDEX, 0); + + *packet_index = val >> 5; + *byte_index = val & 0x1f; +} +#endif + +static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, + unsigned char val) +{ + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); +} + +static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) +{ + /* Unmute */ + if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + /* Enable pin out */ + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); +} + +static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) +{ + return 1 + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CVT_CHAN_COUNT, 0); +} + +static void hdmi_set_channel_count(struct hda_codec *codec, + hda_nid_t nid, int chs) +{ + if (chs != hdmi_get_channel_count(codec, nid)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); +} + + +/* + * Channel mapping routines + */ + +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct cea_channel_speaker_allocation *p; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. +*/ +static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, + struct hdmi_audio_infoframe *ai) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld; + int i; + int spk_mask = 0; + int channels = 1 + (ai->CC02_CT47 & 0x7); + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + /* + * CA defaults to 0 for basic stereo audio + */ + if (channels <= 2) + return 0; + + i = hda_node_index(spec->pin_cvt, nid); + if (i < 0) + return 0; + eld = &spec->sink_eld[i]; + + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!eld->spk_alloc) + eld->spk_alloc = 0xffff; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by Audio InfoFrame. + */ + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (eld->spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ai->CA = channel_allocations[i].ca_index; + break; + } + } + + snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); + snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", + ai->CA, channels, buf); + + return ai->CA; +} + +static void hdmi_debug_channel_mapping(struct hda_codec *codec, + hda_nid_t pin_nid) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int slot; + + for (i = 0; i < 8; i++) { + slot = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, i); + printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", + slot >> 4, slot & 0xf); + } +#endif +} + + +static void hdmi_setup_channel_mapping(struct hda_codec *codec, + hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) +{ + int i; + int ca = ai->CA; + int err; + + if (hdmi_channel_mapping[ca][1] == 0) { + for (i = 0; i < channel_allocations[ca].channels; i++) + hdmi_channel_mapping[ca][i] = i | (i << 4); + for (; i < 8; i++) + hdmi_channel_mapping[ca][i] = 0xf | (i << 4); + } + + for (i = 0; i < 8; i++) { + err = snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + hdmi_channel_mapping[ca][i]); + if (err) { + snd_printdd(KERN_NOTICE + "HDMI: channel mapping failed\n"); + break; + } + } + + hdmi_debug_channel_mapping(codec, pin_nid); +} + + +/* + * Audio InfoFrame routines + */ + +/* + * Enable Audio InfoFrame Transmission + */ +static void hdmi_start_infoframe_trans(struct hda_codec *codec, + hda_nid_t pin_nid) +{ + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_BEST); +} + +/* + * Disable Audio InfoFrame Transmission + */ +static void hdmi_stop_infoframe_trans(struct hda_codec *codec, + hda_nid_t pin_nid) +{ + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_DISABLE); +} + +static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int size; + + size = snd_hdmi_get_eld_size(codec, pin_nid); + printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); + + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); + } +#endif +} + +static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) +{ +#ifdef BE_PARANOID + int i, j; + int size; + int pi, bi; + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + if (size == 0) + continue; + + hdmi_set_dip_index(codec, pin_nid, i, 0x0); + for (j = 1; j < 1000; j++) { + hdmi_write_dip_byte(codec, pin_nid, 0x0); + hdmi_get_dip_index(codec, pin_nid, &pi, &bi); + if (pi != i) + snd_printd(KERN_INFO "dip index %d: %d != %d\n", + bi, pi, i); + if (bi == 0) /* byte index wrapped around */ + break; + } + snd_printd(KERN_INFO + "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); + } +#endif +} + +static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) +{ + u8 *bytes = (u8 *)ai; + u8 sum = 0; + int i; + + ai->checksum = 0; + + for (i = 0; i < sizeof(*ai); i++) + sum += bytes[i]; + + ai->checksum = -sum; +} + +static void hdmi_fill_audio_infoframe(struct hda_codec *codec, + hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) +{ + u8 *bytes = (u8 *)ai; + int i; + + hdmi_debug_dip_size(codec, pin_nid); + hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ + + hdmi_checksum_audio_infoframe(ai); + + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + for (i = 0; i < sizeof(*ai); i++) + hdmi_write_dip_byte(codec, pin_nid, bytes[i]); +} + +static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) +{ + u8 *bytes = (u8 *)ai; + u8 val; + int i; + + if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0) + != AC_DIPXMIT_BEST) + return false; + + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + for (i = 0; i < sizeof(*ai); i++) { + val = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_DATA, 0); + if (val != bytes[i]) + return false; + } + + return true; +} + +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid; + int i; + struct hdmi_audio_infoframe ai = { + .type = 0x84, + .ver = 0x01, + .len = 0x0a, + .CC02_CT47 = substream->runtime->channels - 1, + }; + + hdmi_setup_channel_allocation(codec, nid, &ai); + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!spec->sink_eld[i].monitor_present) + continue; + + pin_nid = spec->pin[i]; + if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { + snd_printdd("hdmi_setup_audio_infoframe: " + "cvt=%d pin=%d channels=%d\n", + nid, pin_nid, + substream->runtime->channels); + hdmi_setup_channel_mapping(codec, pin_nid, &ai); + hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_fill_audio_infoframe(codec, pin_nid, &ai); + hdmi_start_infoframe_trans(codec, pin_nid); + } + } +} + + +/* + * Unsolicited events + */ + +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + struct hdmi_spec *spec = codec->spec; + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; + int pind = !!(res & AC_UNSOL_RES_PD); + int eldv = !!(res & AC_UNSOL_RES_ELDV); + int index; + + printk(KERN_INFO + "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + tag, pind, eldv); + + index = hda_node_index(spec->pin, tag); + if (index < 0) + return; + + spec->sink_eld[index].monitor_present = pind; + spec->sink_eld[index].eld_valid = eldv; + + if (pind && eldv) { + hdmi_get_show_eld(codec, spec->pin[index], + &spec->sink_eld[index]); + /* TODO: do real things about ELD */ + } +} + +static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); + int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); + + printk(KERN_INFO + "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + tag, + subtag, + cp_state, + cp_ready); + + /* TODO */ + if (cp_state) + ; + if (cp_ready) + ; +} + + +static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct hdmi_spec *spec = codec->spec; + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + + if (hda_node_index(spec->pin, tag) < 0) { + snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); + return; + } + + if (subtag == 0) + hdmi_intrinsic_event(codec, res); + else + hdmi_non_intrinsic_event(codec, res); +} + +/* + * Callbacks + */ + +static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int format) +{ + int tag; + int fmt; + + tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; + fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); + + snd_printdd("hdmi_setup_stream: " + "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", + nid, + tag == stream_tag ? "" : "new-", + stream_tag, + fmt == format ? "" : "new-", + format); + + if (tag != stream_tag) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, + stream_tag << 4); + if (fmt != format) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_STREAM_FORMAT, format); +} + +/* + * HDA/HDMI auto parsing + */ + +static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int conn_len, curr; + int index; + + if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { + snd_printk(KERN_WARNING + "HDMI: pin %d wcaps %#x " + "does not support connection list\n", + pin_nid, get_wcaps(codec, pin_nid)); + return -EINVAL; + } + + conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, + HDA_MAX_CONNECTIONS); + if (conn_len > 1) + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + else + curr = 0; + + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) + return -EINVAL; + + spec->pin_cvt[index] = conn_list[curr]; + + return 0; +} + +static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld) +{ + int present = snd_hda_pin_sense(codec, pin_nid); + + eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); + eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + + if (present & AC_PINSENSE_ELDV) + hdmi_get_show_eld(codec, pin_nid, eld); +} + +static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->num_pins >= MAX_HDMI_PINS) { + snd_printk(KERN_WARNING + "HDMI: no space for pin %d\n", pin_nid); + return -EINVAL; + } + + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); + + spec->pin[spec->num_pins] = pin_nid; + spec->num_pins++; + + /* + * It is assumed that converter nodes come first in the node list and + * hence have been registered and usable now. + */ + return hdmi_read_pin_conn(codec, pin_nid); +} + +static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->num_cvts >= MAX_HDMI_CVTS) { + snd_printk(KERN_WARNING + "HDMI: no space for converter %d\n", nid); + return -EINVAL; + } + + spec->cvt[spec->num_cvts] = nid; + spec->num_cvts++; + + return 0; +} + +static int hdmi_parse_codec(struct hda_codec *codec) +{ + hda_nid_t nid; + int i, nodes; + + nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); + if (!nid || nodes < 0) { + snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); + return -EINVAL; + } + + for (i = 0; i < nodes; i++, nid++) { + unsigned int caps; + unsigned int type; + + caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + switch (type) { + case AC_WID_AUD_OUT: + if (hdmi_add_cvt(codec, nid) < 0) + return -EINVAL; + break; + case AC_WID_PIN: + caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) + continue; + if (hdmi_add_pin(codec, nid) < 0) + return -EINVAL; + break; + } + } + + /* + * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event + * can be lost and presence sense verb will become inaccurate if the + * HDA link is powered off at hot plug or hw initialization time. + */ +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & + AC_PWRST_EPSS)) + codec->bus->power_keep_link_on = 1; +#endif + + return 0; +} + diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 918f40378d5..88d035104cc 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -40,815 +40,20 @@ * * The HDA correspondence of pipes/ports are converter/pin nodes. */ -#define INTEL_HDMI_CVTS 2 -#define INTEL_HDMI_PINS 3 +#define MAX_HDMI_CVTS 2 +#define MAX_HDMI_PINS 3 -static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { +#include "patch_hdmi.c" + +static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { "INTEL HDMI 0", "INTEL HDMI 1", }; -struct intel_hdmi_spec { - int num_cvts; - int num_pins; - hda_nid_t cvt[INTEL_HDMI_CVTS+1]; /* audio sources */ - hda_nid_t pin[INTEL_HDMI_PINS+1]; /* audio sinks */ - - /* - * source connection for each pin - */ - hda_nid_t pin_cvt[INTEL_HDMI_PINS+1]; - - /* - * HDMI sink attached to each pin - */ - struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; - - /* - * export one pcm per pipe - */ - struct hda_pcm pcm_rec[INTEL_HDMI_CVTS]; -}; - -struct hdmi_audio_infoframe { - u8 type; /* 0x84 */ - u8 ver; /* 0x01 */ - u8 len; /* 0x0a */ - - u8 checksum; /* PB0 */ - u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ - u8 SS01_SF24; - u8 CXT04; - u8 CA; - u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ -}; - -/* - * CEA speaker placement: - * - * FLH FCH FRH - * FLW FL FLC FC FRC FR FRW - * - * LFE - * TC - * - * RL RLC RC RRC RR - * - * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to - * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. - */ -enum cea_speaker_placement { - FL = (1 << 0), /* Front Left */ - FC = (1 << 1), /* Front Center */ - FR = (1 << 2), /* Front Right */ - FLC = (1 << 3), /* Front Left Center */ - FRC = (1 << 4), /* Front Right Center */ - RL = (1 << 5), /* Rear Left */ - RC = (1 << 6), /* Rear Center */ - RR = (1 << 7), /* Rear Right */ - RLC = (1 << 8), /* Rear Left Center */ - RRC = (1 << 9), /* Rear Right Center */ - LFE = (1 << 10), /* Low Frequency Effect */ - FLW = (1 << 11), /* Front Left Wide */ - FRW = (1 << 12), /* Front Right Wide */ - FLH = (1 << 13), /* Front Left High */ - FCH = (1 << 14), /* Front Center High */ - FRH = (1 << 15), /* Front Right High */ - TC = (1 << 16), /* Top Center */ -}; - -/* - * ELD SA bits in the CEA Speaker Allocation data block - */ -static int eld_speaker_allocation_bits[] = { - [0] = FL | FR, - [1] = LFE, - [2] = FC, - [3] = RL | RR, - [4] = RC, - [5] = FLC | FRC, - [6] = RLC | RRC, - /* the following are not defined in ELD yet */ - [7] = FLW | FRW, - [8] = FLH | FRH, - [9] = TC, - [10] = FCH, -}; - -struct cea_channel_speaker_allocation { - int ca_index; - int speakers[8]; - - /* derived values, just for convenience */ - int channels; - int spk_mask; -}; - -/* - * ALSA sequence is: - * - * surround40 surround41 surround50 surround51 surround71 - * ch0 front left = = = = - * ch1 front right = = = = - * ch2 rear left = = = = - * ch3 rear right = = = = - * ch4 LFE center center center - * ch5 LFE LFE - * ch6 side left - * ch7 side right - * - * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR} - */ -static int hdmi_channel_mapping[0x32][8] = { - /* stereo */ - [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* 2.1 */ - [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* Dolby Surround */ - [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* surround40 */ - [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 }, - /* 4ch */ - [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, - /* surround41 */ - [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 }, - /* surround50 */ - [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, - /* surround51 */ - [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 }, - /* 7.1 */ - [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 }, -}; - -/* - * This is an ordered list! - * - * The preceding ones have better chances to be selected by - * hdmi_setup_channel_allocation(). - */ -static struct cea_channel_speaker_allocation channel_allocations[] = { -/* channel: 7 6 5 4 3 2 1 0 */ -{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, - /* 2.1 */ -{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, - /* Dolby Surround */ -{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, - /* surround40 */ -{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, - /* surround41 */ -{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, - /* surround50 */ -{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, - /* surround51 */ -{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, - /* 6.1 */ -{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, - /* surround71 */ -{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, - -{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, -{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, -{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, -{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, -}; - -/* - * HDA/HDMI auto parsing - */ - -static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) -{ - int i; - - for (i = 0; nids[i]; i++) - if (nids[i] == nid) - return i; - - snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); - return -EINVAL; -} - -static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) -{ - struct intel_hdmi_spec *spec = codec->spec; - hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; - int conn_len, curr; - int index; - - if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { - snd_printk(KERN_WARNING - "HDMI: pin %d wcaps %#x " - "does not support connection list\n", - pin_nid, get_wcaps(codec, pin_nid)); - return -EINVAL; - } - - conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, - HDA_MAX_CONNECTIONS); - if (conn_len > 1) - curr = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONNECT_SEL, 0); - else - curr = 0; - - index = hda_node_index(spec->pin, pin_nid); - if (index < 0) - return -EINVAL; - - spec->pin_cvt[index] = conn_list[curr]; - - return 0; -} - -static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld) -{ - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) - snd_hdmi_show_eld(eld); -} - -static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld) -{ - int present = snd_hda_pin_sense(codec, pin_nid); - - eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); - eld->eld_valid = !!(present & AC_PINSENSE_ELDV); - - if (present & AC_PINSENSE_ELDV) - hdmi_get_show_eld(codec, pin_nid, eld); -} - -static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) -{ - struct intel_hdmi_spec *spec = codec->spec; - - if (spec->num_pins >= INTEL_HDMI_PINS) { - snd_printk(KERN_WARNING - "HDMI: no space for pin %d \n", pin_nid); - return -EINVAL; - } - - hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); - - spec->pin[spec->num_pins] = pin_nid; - spec->num_pins++; - - /* - * It is assumed that converter nodes come first in the node list and - * hence have been registered and usable now. - */ - return intel_hdmi_read_pin_conn(codec, pin_nid); -} - -static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) -{ - struct intel_hdmi_spec *spec = codec->spec; - - if (spec->num_cvts >= INTEL_HDMI_CVTS) { - snd_printk(KERN_WARNING - "HDMI: no space for converter %d \n", nid); - return -EINVAL; - } - - spec->cvt[spec->num_cvts] = nid; - spec->num_cvts++; - - return 0; -} - -static int intel_hdmi_parse_codec(struct hda_codec *codec) -{ - hda_nid_t nid; - int i, nodes; - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); - if (!nid || nodes < 0) { - snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); - return -EINVAL; - } - - for (i = 0; i < nodes; i++, nid++) { - unsigned int caps; - unsigned int type; - - caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); - type = get_wcaps_type(caps); - - if (!(caps & AC_WCAP_DIGITAL)) - continue; - - switch (type) { - case AC_WID_AUD_OUT: - if (intel_hdmi_add_cvt(codec, nid) < 0) - return -EINVAL; - break; - case AC_WID_PIN: - caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) - continue; - if (intel_hdmi_add_pin(codec, nid) < 0) - return -EINVAL; - break; - } - } - - /* - * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event - * can be lost and presence sense verb will become inaccurate if the - * HDA link is powered off at hot plug or hw initialization time. - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & - AC_PWRST_EPSS)) - codec->bus->power_keep_link_on = 1; -#endif - - return 0; -} - -/* - * HDMI routines - */ - -#ifdef BE_PARANOID -static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, - int *packet_index, int *byte_index) -{ - int val; - - val = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_INDEX, 0); - - *packet_index = val >> 5; - *byte_index = val & 0x1f; -} -#endif - -static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, - int packet_index, int byte_index) -{ - int val; - - val = (packet_index << 5) | (byte_index & 0x1f); - - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); -} - -static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, - unsigned char val) -{ - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); -} - -static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) -{ - /* Unmute */ - if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Enable pin out */ - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); -} - -/* - * Enable Audio InfoFrame Transmission - */ -static void hdmi_start_infoframe_trans(struct hda_codec *codec, - hda_nid_t pin_nid) -{ - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, - AC_DIPXMIT_BEST); -} - -/* - * Disable Audio InfoFrame Transmission - */ -static void hdmi_stop_infoframe_trans(struct hda_codec *codec, - hda_nid_t pin_nid) -{ - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, - AC_DIPXMIT_DISABLE); -} - -static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) -{ - return 1 + snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CVT_CHAN_COUNT, 0); -} - -static void hdmi_set_channel_count(struct hda_codec *codec, - hda_nid_t nid, int chs) -{ - if (chs != hdmi_get_channel_count(codec, nid)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); -} - -static void hdmi_debug_channel_mapping(struct hda_codec *codec, - hda_nid_t pin_nid) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int slot; - - for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", - slot >> 4, slot & 0xf); - } -#endif -} - - -/* - * Audio InfoFrame routines - */ - -static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int size; - - size = snd_hdmi_get_eld_size(codec, pin_nid); - printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); - - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); - } -#endif -} - -static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) -{ -#ifdef BE_PARANOID - int i, j; - int size; - int pi, bi; - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - if (size == 0) - continue; - - hdmi_set_dip_index(codec, pin_nid, i, 0x0); - for (j = 1; j < 1000; j++) { - hdmi_write_dip_byte(codec, pin_nid, 0x0); - hdmi_get_dip_index(codec, pin_nid, &pi, &bi); - if (pi != i) - snd_printd(KERN_INFO "dip index %d: %d != %d\n", - bi, pi, i); - if (bi == 0) /* byte index wrapped around */ - break; - } - snd_printd(KERN_INFO - "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", - i, size, j); - } -#endif -} - -static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) -{ - u8 *bytes = (u8 *)ai; - u8 sum = 0; - int i; - - ai->checksum = 0; - - for (i = 0; i < sizeof(*ai); i++) - sum += bytes[i]; - - ai->checksum = - sum; -} - -static void hdmi_fill_audio_infoframe(struct hda_codec *codec, - hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) -{ - u8 *bytes = (u8 *)ai; - int i; - - hdmi_debug_dip_size(codec, pin_nid); - hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ - - hdmi_checksum_audio_infoframe(ai); - - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(*ai); i++) - hdmi_write_dip_byte(codec, pin_nid, bytes[i]); -} - -/* - * Compute derived values in channel_allocations[]. - */ -static void init_channel_allocations(void) -{ - int i, j; - struct cea_channel_speaker_allocation *p; - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - p = channel_allocations + i; - p->channels = 0; - p->spk_mask = 0; - for (j = 0; j < ARRAY_SIZE(p->speakers); j++) - if (p->speakers[j]) { - p->channels++; - p->spk_mask |= p->speakers[j]; - } - } -} - -/* - * The transformation takes two steps: - * - * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask - * spk_mask => (channel_allocations[]) => ai->CA - * - * TODO: it could select the wrong CA from multiple candidates. -*/ -static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, - struct hdmi_audio_infoframe *ai) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld; - int i; - int spk_mask = 0; - int channels = 1 + (ai->CC02_CT47 & 0x7); - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - - /* - * CA defaults to 0 for basic stereo audio - */ - if (channels <= 2) - return 0; - - i = hda_node_index(spec->pin_cvt, nid); - if (i < 0) - return 0; - eld = &spec->sink_eld[i]; - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!eld->spk_alloc) - eld->spk_alloc = 0xffff; - - /* - * expand ELD's speaker allocation mask - * - * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by Audio InfoFrame. - */ - for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (eld->spk_alloc & (1 << i)) - spk_mask |= eld_speaker_allocation_bits[i]; - } - - /* search for the first working match in the CA table */ - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channels == channel_allocations[i].channels && - (spk_mask & channel_allocations[i].spk_mask) == - channel_allocations[i].spk_mask) { - ai->CA = channel_allocations[i].ca_index; - break; - } - } - - snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); - snd_printdd(KERN_INFO - "HDMI: select CA 0x%x for %d-channel allocation: %s\n", - ai->CA, channels, buf); - - return ai->CA; -} - -static void hdmi_setup_channel_mapping(struct hda_codec *codec, - hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) -{ - int i; - int ca = ai->CA; - int err; - - if (hdmi_channel_mapping[ca][1] == 0) { - for (i = 0; i < channel_allocations[ca].channels; i++) - hdmi_channel_mapping[ca][i] = i | (i << 4); - for (; i < 8; i++) - hdmi_channel_mapping[ca][i] = 0xf | (i << 4); - } - - for (i = 0; i < 8; i++) { - err = snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - hdmi_channel_mapping[ca][i]); - if (err) { - snd_printdd(KERN_INFO "HDMI: channel mapping failed\n"); - break; - } - } - - hdmi_debug_channel_mapping(codec, pin_nid); -} - -static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) -{ - u8 *bytes = (u8 *)ai; - u8 val; - int i; - - if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0) - != AC_DIPXMIT_BEST) - return false; - - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(*ai); i++) { - val = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_DATA, 0); - if (val != bytes[i]) - return false; - } - - return true; -} - -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, - struct snd_pcm_substream *substream) -{ - struct intel_hdmi_spec *spec = codec->spec; - hda_nid_t pin_nid; - int i; - struct hdmi_audio_infoframe ai = { - .type = 0x84, - .ver = 0x01, - .len = 0x0a, - .CC02_CT47 = substream->runtime->channels - 1, - }; - - hdmi_setup_channel_allocation(codec, nid, &ai); - - for (i = 0; i < spec->num_pins; i++) { - if (spec->pin_cvt[i] != nid) - continue; - if (!spec->sink_eld[i].monitor_present) - continue; - - pin_nid = spec->pin[i]; - if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { - hdmi_setup_channel_mapping(codec, pin_nid, &ai); - hdmi_stop_infoframe_trans(codec, pin_nid); - hdmi_fill_audio_infoframe(codec, pin_nid, &ai); - hdmi_start_infoframe_trans(codec, pin_nid); - } - } -} - - /* - * Unsolicited events + * HDMI callbacks */ -static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) -{ - struct intel_hdmi_spec *spec = codec->spec; - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int pind = !!(res & AC_UNSOL_RES_PD); - int eldv = !!(res & AC_UNSOL_RES_ELDV); - int index; - - printk(KERN_INFO - "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - tag, pind, eldv); - - index = hda_node_index(spec->pin, tag); - if (index < 0) - return; - - spec->sink_eld[index].monitor_present = pind; - spec->sink_eld[index].eld_valid = eldv; - - if (pind && eldv) { - hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]); - /* TODO: do real things about ELD */ - } -} - -static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) -{ - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); - int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - - printk(KERN_INFO - "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - tag, - subtag, - cp_state, - cp_ready); - - /* TODO */ - if (cp_state) - ; - if (cp_ready) - ; -} - - -static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct intel_hdmi_spec *spec = codec->spec; - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - - if (hda_node_index(spec->pin, tag) < 0) { - snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); - return; - } - - if (subtag == 0) - hdmi_intrinsic_event(codec, res); - else - hdmi_non_intrinsic_event(codec, res); -} - -/* - * Callbacks - */ - -static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, int format) -{ - int tag; - int fmt; - - tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; - fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); - - snd_printdd("hdmi_setup_stream: " - "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", - nid, - tag == stream_tag ? "" : "new-", - stream_tag, - fmt == format ? "" : "new-", - format); - - if (tag != stream_tag) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, stream_tag << 4); - if (fmt != format) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); -} - static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -882,7 +87,7 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { static int intel_hdmi_build_pcms(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; struct hda_pcm *info = spec->pcm_rec; int i; @@ -908,7 +113,7 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) static int intel_hdmi_build_controls(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int err; int i; @@ -923,7 +128,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) static int intel_hdmi_init(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; for (i = 0; spec->pin[i]; i++) { @@ -937,7 +142,7 @@ static int intel_hdmi_init(struct hda_codec *codec) static void intel_hdmi_free(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; for (i = 0; i < spec->num_pins; i++) @@ -951,12 +156,12 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .free = intel_hdmi_free, .build_pcms = intel_hdmi_build_pcms, .build_controls = intel_hdmi_build_controls, - .unsol_event = intel_hdmi_unsol_event, + .unsol_event = hdmi_unsol_event, }; static int patch_intel_hdmi(struct hda_codec *codec) { - struct intel_hdmi_spec *spec; + struct hdmi_spec *spec; int i; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -964,7 +169,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; - if (intel_hdmi_parse_codec(codec) < 0) { + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec); return -EINVAL; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 6afdab09bab..3c10c0b149f 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -29,13 +29,23 @@ #include "hda_codec.h" #include "hda_local.h" +#define MAX_HDMI_CVTS 1 +#define MAX_HDMI_PINS 1 + +#include "patch_hdmi.c" + +static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = { + "NVIDIA HDMI", +}; + /* define below to restrict the supported rates and formats */ /* #define LIMITED_RATE_FMT_SUPPORT */ -struct nvhdmi_spec { - struct hda_multi_out multiout; - - struct hda_pcm pcm_rec; +enum HDACodec { + HDA_CODEC_NVIDIA_MCP7X, + HDA_CODEC_NVIDIA_MCP89, + HDA_CODEC_NVIDIA_GT21X, + HDA_CODEC_INVALID }; #define Nv_VERB_SET_Channel_Allocation 0xF79 @@ -43,15 +53,18 @@ struct nvhdmi_spec { #define Nv_VERB_SET_Audio_Protection_On 0xF98 #define Nv_VERB_SET_Audio_Protection_Off 0xF99 -#define Nv_Master_Convert_nid 0x04 -#define Nv_Master_Pin_nid 0x05 +#define nvhdmi_master_con_nid_7x 0x04 +#define nvhdmi_master_pin_nid_7x 0x05 -static hda_nid_t nvhdmi_convert_nids[4] = { +#define nvhdmi_master_con_nid_89 0x04 +#define nvhdmi_master_pin_nid_89 0x05 + +static hda_nid_t nvhdmi_con_nids_7x[4] = { /*front, rear, clfe, rear_surr */ 0x6, 0x8, 0xa, 0xc, }; -static struct hda_verb nvhdmi_basic_init[] = { +static struct hda_verb nvhdmi_basic_init_7x[] = { /* set audio protect on */ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ @@ -84,22 +97,60 @@ static struct hda_verb nvhdmi_basic_init[] = { */ static int nvhdmi_build_controls(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int err; + int i; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->cvt[i]); + if (err < 0) + return err; + } + } else { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + } return 0; } static int nvhdmi_init(struct hda_codec *codec) { - snd_hda_sequence_write(codec, nvhdmi_basic_init); + struct hdmi_spec *spec = codec->spec; + int i; + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + for (i = 0; spec->pin[i]; i++) { + hdmi_enable_output(codec, spec->pin[i]); + snd_hda_codec_write(codec, spec->pin[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | spec->pin[i]); + } + } else { + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x); + } return 0; } +static void nvhdmi_free(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); + } + + kfree(spec); +} + /* * Digital out */ @@ -107,25 +158,25 @@ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_open(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo, +static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; - snd_hda_codec_write(codec, Nv_Master_Convert_nid, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); for (i = 0; i < 4; i++) { /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_CHANNEL_STREAMID, 0); /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_STREAM_FORMAT, 0); } @@ -136,10 +187,25 @@ static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_close(codec, &spec->multiout); } +static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + hdmi_set_channel_count(codec, hinfo->nid, + substream->runtime->channels); + + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); + + hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); + return 0; +} + static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -181,29 +247,29 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); /* set the stream format */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_STREAM_FORMAT, format); /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); } @@ -220,19 +286,19 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | channel_id); /* set the stream format */ snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_STREAM_FORMAT, format); @@ -241,12 +307,12 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); } @@ -261,28 +327,47 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, return 0; } +static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + return 0; +} + static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, format, substream); } -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = { +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { + .substreams = 1, + .channels_min = 2, + .rates = SUPPORTED_RATES, + .maxbps = SUPPORTED_MAXBPS, + .formats = SUPPORTED_FORMATS, + .ops = { + .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, + .cleanup = nvhdmi_playback_pcm_cleanup, + }, +}; + +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = { .substreams = 1, .channels_min = 2, .channels_max = 8, - .nid = Nv_Master_Convert_nid, + .nid = nvhdmi_master_con_nid_7x, .rates = SUPPORTED_RATES, .maxbps = SUPPORTED_MAXBPS, .formats = SUPPORTED_FORMATS, .ops = { .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_8ch, + .close = nvhdmi_dig_playback_pcm_close_8ch_7x, .prepare = nvhdmi_dig_playback_pcm_prepare_8ch }, }; @@ -291,7 +376,7 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = Nv_Master_Convert_nid, + .nid = nvhdmi_master_con_nid_7x, .rates = SUPPORTED_RATES, .maxbps = SUPPORTED_MAXBPS, .formats = SUPPORTED_FORMATS, @@ -302,10 +387,36 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { }, }; -static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) +static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + int i; + + codec->num_pcms = spec->num_cvts; + codec->pcm_info = info; + + for (i = 0; i < codec->num_pcms; i++, info++) { + unsigned int chans; + + chans = get_wcaps(codec, spec->cvt[i]); + chans = get_wcaps_channels(chans); + + info->name = nvhdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] + = nvhdmi_pcm_digital_playback_8ch_89; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; + } + + return 0; +} + +static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; codec->num_pcms = 1; codec->pcm_info = info; @@ -313,15 +424,15 @@ static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) info->name = "NVIDIA HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_8ch; + = nvhdmi_pcm_digital_playback_8ch_7x; return 0; } static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; codec->num_pcms = 1; codec->pcm_info = info; @@ -334,14 +445,17 @@ static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) return 0; } -static void nvhdmi_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} +static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = { + .build_controls = nvhdmi_build_controls, + .build_pcms = nvhdmi_build_pcms_8ch_89, + .init = nvhdmi_init, + .free = nvhdmi_free, + .unsol_event = hdmi_unsol_event, +}; -static struct hda_codec_ops nvhdmi_patch_ops_8ch = { +static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_8ch, + .build_pcms = nvhdmi_build_pcms_8ch_7x, .init = nvhdmi_init, .free = nvhdmi_free, }; @@ -353,9 +467,36 @@ static struct hda_codec_ops nvhdmi_patch_ops_2ch = { .free = nvhdmi_free, }; -static int patch_nvhdmi_8ch(struct hda_codec *codec) +static int patch_nvhdmi_8ch_89(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int i; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + spec->codec_type = HDA_CODEC_NVIDIA_MCP89; + + if (hdmi_parse_codec(codec) < 0) { + codec->spec = NULL; + kfree(spec); + return -EINVAL; + } + codec->patch_ops = nvhdmi_patch_ops_8ch_89; + + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); + + init_channel_allocations(); + + return 0; +} + +static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) { - struct nvhdmi_spec *spec; + struct hdmi_spec *spec; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -365,16 +506,17 @@ static int patch_nvhdmi_8ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; + spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; - codec->patch_ops = nvhdmi_patch_ops_8ch; + codec->patch_ops = nvhdmi_patch_ops_8ch_7x; return 0; } static int patch_nvhdmi_2ch(struct hda_codec *codec) { - struct nvhdmi_spec *spec; + struct hdmi_spec *spec; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -384,7 +526,8 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; + spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; codec->patch_ops = nvhdmi_patch_ops_2ch; @@ -395,11 +538,24 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0005, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0002, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0003, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0005, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0006, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0007, .name = "MCP79/7A HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de000a, .name = "GT220 HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000b, .name = "GT21x HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000c, .name = "MCP89 HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000d, .name = "GT240 HDMI", + .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, {} /* terminator */ @@ -410,11 +566,15 @@ MODULE_ALIAS("snd-hda-codec-id:10de0003"); MODULE_ALIAS("snd-hda-codec-id:10de0005"); MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); +MODULE_ALIAS("snd-hda-codec-id:10de000a"); +MODULE_ALIAS("snd-hda-codec-id:10de000b"); +MODULE_ALIAS("snd-hda-codec-id:10de000c"); +MODULE_ALIAS("snd-hda-codec-id:10de000d"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); +MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec"); static struct hda_codec_preset_list nvhdmi_list = { .preset = snd_hda_preset_nvhdmi, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e8cbe216e91..886d8e46bb3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -230,6 +230,7 @@ enum { ALC888_ACER_ASPIRE_7730G, ALC883_MEDION, ALC883_MEDION_MD2, + ALC883_MEDION_WIM2160, ALC883_LAPTOP_EAPD, ALC883_LENOVO_101E_2ch, ALC883_LENOVO_NB0763, @@ -411,6 +412,8 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); if (mux_idx >= spec->num_mux_defs) mux_idx = 0; + if (!spec->input_mux[mux_idx].num_items && mux_idx > 0) + mux_idx = 0; return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); } @@ -439,6 +442,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { @@ -1385,22 +1390,31 @@ struct alc_fixup { static void alc_pick_fixup(struct hda_codec *codec, const struct snd_pci_quirk *quirk, - const struct alc_fixup *fix) + const struct alc_fixup *fix, + int pre_init) { const struct alc_pincfg *cfg; quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); if (!quirk) return; - fix += quirk->value; cfg = fix->pins; - if (cfg) { + if (pre_init && cfg) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n", + codec->chip_name, quirk->name); +#endif for (; cfg->nid; cfg++) snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); } - if (fix->verbs) + if (!pre_init && fix->verbs) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n", + codec->chip_name, quirk->name); +#endif add_verb(codec->spec, fix->verbs); + } } static int alc_read_coef_idx(struct hda_codec *codec, @@ -1617,6 +1631,11 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { */ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +/* Route to built-in subwoofer as well as speakers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Bias voltage on for external mic port */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, /* Front Mic: set to PIN_IN (empty by default) */ @@ -1628,10 +1647,12 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { /* Enable speaker output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, /* Enable headphone output */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; @@ -2528,8 +2549,6 @@ static int alc_build_controls(struct hda_codec *codec) return err; } - alc_free_kctls(codec); /* no longer needed */ - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); if (!kctl) @@ -2598,6 +2617,9 @@ static int alc_build_controls(struct hda_codec *codec) } } } + + alc_free_kctls(codec); /* no longer needed */ + return 0; } @@ -4121,7 +4143,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), @@ -4796,6 +4818,25 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec) } } +static void alc880_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + unsigned int mux_idx; + const struct hda_input_mux *imux; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; + if (imux) + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); + } +} + /* 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 @@ -4874,6 +4915,7 @@ static void alc880_auto_init(struct hda_codec *codec) alc880_auto_init_multi_out(codec); alc880_auto_init_extra_out(codec); alc880_auto_init_analog_input(codec); + alc880_auto_init_input_src(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -4915,7 +4957,7 @@ static void fixup_automic_adc(struct hda_codec *codec) static void fixup_single_adc(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t pin; + hda_nid_t pin = 0; int i; /* search for the input pin; there must be only one */ @@ -4979,6 +5021,70 @@ static void set_capture_mixer(struct hda_codec *codec) } } +/* fill adc_nids (and capsrc_nids) containing all active input pins */ +static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, + int num_nids) +{ + struct alc_spec *spec = codec->spec; + int n; + hda_nid_t fallback_adc = 0, fallback_cap = 0; + + for (n = 0; n < num_nids; n++) { + hda_nid_t adc, cap; + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int nconns, i, j; + + adc = nids[n]; + if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN) + continue; + cap = adc; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + if (nconns == 1) { + cap = conn[0]; + nconns = snd_hda_get_connections(codec, cap, conn, + ARRAY_SIZE(conn)); + } + if (nconns <= 0) + continue; + if (!fallback_adc) { + fallback_adc = adc; + fallback_cap = cap; + } + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = spec->autocfg.input_pins[i]; + if (!nid) + continue; + for (j = 0; j < nconns; j++) { + if (conn[j] == nid) + break; + } + if (j >= nconns) + break; + } + if (i >= AUTO_PIN_LAST) { + int num_adcs = spec->num_adc_nids; + spec->private_adc_nids[num_adcs] = adc; + spec->private_capsrc_nids[num_adcs] = cap; + spec->num_adc_nids++; + spec->adc_nids = spec->private_adc_nids; + if (adc != cap) + spec->capsrc_nids = spec->private_capsrc_nids; + } + } + if (!spec->num_adc_nids) { + printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" + " using fallback 0x%x\n", + codec->chip_name, fallback_adc); + spec->private_adc_nids[0] = fallback_adc; + spec->adc_nids = spec->private_adc_nids; + if (fallback_adc != fallback_cap) { + spec->private_capsrc_nids[0] = fallback_cap; + spec->capsrc_nids = spec->private_adc_nids; + } + } +} + #ifdef CONFIG_SND_HDA_INPUT_BEEP #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) @@ -6321,6 +6427,8 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec) } } +#define alc260_auto_init_input_src alc880_auto_init_input_src + /* * generic initialization of ADC, input mixers and output mixers */ @@ -6407,6 +6515,7 @@ static void alc260_auto_init(struct hda_codec *codec) struct alc_spec *spec = codec->spec; alc260_auto_init_multi_out(codec); alc260_auto_init_analog_input(codec); + alc260_auto_init_input_src(codec); if (spec->unsol_event) alc_inithook(codec); } @@ -6473,7 +6582,7 @@ static struct alc_config_preset alc260_presets[] = { .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_adc_nids, + .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -8379,6 +8488,42 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; + +static struct hda_verb alc883_medion_wim2160_verbs[] = { + /* Unmute front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Set speaker pin to front mixer */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Init headphone pin */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + + { } /* end */ +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_medion_wim2160_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x15; +} + static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -8393,9 +8538,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, 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), @@ -9090,6 +9233,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", + [ALC883_MEDION_WIM2160] = "medion-wim2160", [ALC883_LAPTOP_EAPD] = "laptop-eapd", [ALC883_LENOVO_101E_2ch] = "lenovo-101e", [ALC883_LENOVO_NB0763] = "lenovo-nb0763", @@ -9191,6 +9335,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { 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, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), @@ -9200,10 +9345,12 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), @@ -9231,7 +9378,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), {} }; @@ -9742,6 +9889,21 @@ static struct alc_config_preset alc882_presets[] = { .setup = alc883_medion_md2_setup, .init_hook = alc_automute_amp, }, + [ALC883_MEDION_WIM2160] = { + .mixers = { alc883_medion_wim2160_mixer }, + .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_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 = alc_automute_amp_unsol_event, + .setup = alc883_medion_wim2160_setup, + .init_hook = alc_automute_amp, + }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, @@ -10034,6 +10196,8 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, int idx; alc_set_pin_output(codec, nid, pin_type); + if (dac_idx >= spec->multiout.num_dacs) + return; if (spec->multiout.dac_nids[dac_idx] == 0x25) idx = 4; else @@ -10105,6 +10269,8 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) continue; mux_idx = c >= spec->num_mux_defs ? 0 : c; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; for (idx = 0; idx < conns; idx++) { /* if the current connection is the selected one, * unmute it as default - otherwise mute it @@ -10283,7 +10449,8 @@ static int patch_alc882(struct hda_codec *codec) board_config = ALC882_AUTO; } - alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups); + if (board_config == ALC882_AUTO) + alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1); if (board_config == ALC882_AUTO) { /* automatic parse from the BIOS config */ @@ -10356,6 +10523,9 @@ static int patch_alc882(struct hda_codec *codec) set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (board_config == ALC882_AUTO) + alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0); + spec->vmaster_nid = 0x0c; codec->patch_ops = alc_patch_ops; @@ -12447,11 +12617,11 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) unsigned char bits; present = snd_hda_jack_detect(codec, 0x15); - bits = present ? AMP_IN_MUTE(0) : 0; + bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); } static void alc268_acer_lc_unsol_event(struct hda_codec *codec, @@ -12736,6 +12906,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, dac = 0x02; break; case 0x15: + case 0x21: /* ALC269vb has this pin, too */ dac = 0x03; break; default: @@ -13201,7 +13372,7 @@ static int patch_alc268(struct hda_codec *codec) if (board_config < 0 || board_config >= ALC268_MODEL_LAST) board_config = snd_hda_check_board_codec_sid_config(codec, - ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); + ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", @@ -13321,9 +13492,9 @@ static hda_nid_t alc269vb_capsrc_nids[1] = { 0x22, }; -/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24), - * not a mux! - */ +static hda_nid_t alc269_adc_candidates[] = { + 0x08, 0x09, 0x07, +}; #define alc269_modes alc260_modes #define alc269_capture_source alc880_lg_lw_capture_source @@ -13470,11 +13641,11 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) unsigned char bits; present = snd_hda_jack_detect(codec, 0x15); - bits = present ? AMP_IN_MUTE(0) : 0; + bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -13499,11 +13670,11 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec) /* Check port replicator headphone socket */ present |= snd_hda_jack_detect(codec, 0x1a); - bits = present ? AMP_IN_MUTE(0) : 0; + bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -13561,6 +13732,8 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec, static void alc269_quanta_fl1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -13632,11 +13805,11 @@ static void alc269_speaker_automute(struct hda_codec *codec) unsigned char bits; present = snd_hda_jack_detect(codec, nid); - bits = present ? AMP_IN_MUTE(0) : 0; + bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); } /* unsolicited event for HP jack sensing */ @@ -13653,29 +13826,35 @@ static void alc269_laptop_unsol_event(struct hda_codec *codec, } } -static void alc269_laptop_dmic_setup(struct hda_codec *codec) +static void alc269_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 5; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; spec->auto_mic = 1; } -static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +static void alc269_laptop_dmic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 6; + spec->int_mic.mux_idx = 5; spec->auto_mic = 1; } -static void alc269_laptop_amic_setup(struct hda_codec *codec) +static void alc269vb_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -13683,6 +13862,18 @@ static void alc269_laptop_amic_setup(struct hda_codec *codec) spec->auto_mic = 1; } +static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; +} + static void alc269_laptop_inithook(struct hda_codec *codec) { alc269_speaker_automute(codec); @@ -13822,7 +14013,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int err; static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; - hda_nid_t real_capsrc_nids; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc269_ignore); @@ -13846,18 +14036,19 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) { add_verb(spec, alc269vb_init_verbs); - real_capsrc_nids = alc269vb_capsrc_nids[0]; alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); } else { add_verb(spec, alc269_init_verbs); - real_capsrc_nids = alc269_capsrc_nids[0]; alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); } spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; + fillup_priv_adc_nids(codec, alc269_adc_candidates, + sizeof(alc269_adc_candidates)); + /* set default input source */ - snd_hda_codec_write_cache(codec, real_capsrc_nids, + snd_hda_codec_write_cache(codec, spec->capsrc_nids[0], 0, AC_VERB_SET_CONNECT_SEL, spec->input_mux->items[0].index); @@ -13887,6 +14078,27 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } +enum { + ALC269_FIXUP_SONY_VAIO, +}; + +const static struct hda_verb alc269_sony_vaio_fixup_verbs[] = { + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + {} +}; + +static const struct alc_fixup alc269_fixups[] = { + [ALC269_FIXUP_SONY_VAIO] = { + .verbs = alc269_sony_vaio_fixup_verbs + }, +}; + +static struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + {} +}; + + /* * configuration and preset */ @@ -13946,7 +14158,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { ALC269_DMIC), SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC), - SND_PCI_QUIRK(0x104d, 0x9071, "SONY XTB", ALC269_DMIC), + SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC), SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), @@ -14020,7 +14232,7 @@ static struct alc_config_preset alc269_presets[] = { .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, .unsol_event = alc269_laptop_unsol_event, - .setup = alc269_laptop_amic_setup, + .setup = alc269vb_laptop_amic_setup, .init_hook = alc269_laptop_inithook, }, [ALC269VB_DMIC] = { @@ -14100,6 +14312,9 @@ static int patch_alc269(struct hda_codec *codec) board_config = ALC269_AUTO; } + if (board_config == ALC269_AUTO) + alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1); + if (board_config == ALC269_AUTO) { /* automatic parse from the BIOS config */ err = alc269_parse_auto_config(codec); @@ -14136,20 +14351,25 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture; - if (!is_alc269vb) { - spec->adc_nids = alc269_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); - spec->capsrc_nids = alc269_capsrc_nids; - } else { - spec->adc_nids = alc269vb_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); - spec->capsrc_nids = alc269vb_capsrc_nids; + if (!spec->adc_nids) { /* wasn't filled automatically? use default */ + if (!is_alc269vb) { + spec->adc_nids = alc269_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; + } else { + spec->adc_nids = alc269vb_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids); + spec->capsrc_nids = alc269vb_capsrc_nids; + } } if (!spec->cap_mixer) set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + if (board_config == ALC269_AUTO) + alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0); + spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; @@ -15238,7 +15458,8 @@ static int patch_alc861(struct hda_codec *codec) board_config = ALC861_AUTO; } - alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups); + if (board_config == ALC861_AUTO) + alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1); if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ @@ -15275,6 +15496,9 @@ static int patch_alc861(struct hda_codec *codec) spec->vmaster_nid = 0x03; + if (board_config == ALC861_AUTO) + alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0); + codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) { spec->init_hook = alc861_auto_init; @@ -16209,7 +16433,8 @@ static int patch_alc861vd(struct hda_codec *codec) board_config = ALC861VD_AUTO; } - alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups); + if (board_config == ALC861VD_AUTO) + alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1); if (board_config == ALC861VD_AUTO) { /* automatic parse from the BIOS config */ @@ -16257,6 +16482,9 @@ static int patch_alc861vd(struct hda_codec *codec) spec->vmaster_nid = 0x02; + if (board_config == ALC861VD_AUTO) + alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0); + codec->patch_ops = alc_patch_ops; if (board_config == ALC861VD_AUTO) @@ -17095,9 +17323,9 @@ static void alc663_m51va_speaker_automute(struct hda_codec *codec) present = snd_hda_jack_detect(codec, 0x21); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); } static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) @@ -17108,13 +17336,13 @@ static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) present = snd_hda_jack_detect(codec, 0x21); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); } static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) @@ -17125,13 +17353,13 @@ static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) present = snd_hda_jack_detect(codec, 0x15); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); + HDA_AMP_MUTE, bits); } static void alc662_f5z_speaker_automute(struct hda_codec *codec) @@ -17170,14 +17398,14 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) if (present1 || present2) { snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), AMP_IN_MUTE(0)); + HDA_AMP_MUTE, HDA_AMP_MUTE); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), AMP_IN_MUTE(0)); + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), 0); + HDA_AMP_MUTE, 0); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), 0); + HDA_AMP_MUTE, 0); } } @@ -17643,7 +17871,6 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ALC662_3ST_6ch_DIG), SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", ALC663_ASUS_H13), - SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG), {} }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8c416bb18a5..12825aa0310 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1544,11 +1544,9 @@ static unsigned int alienware_m17x_pin_configs[13] = { 0x904601b0, }; -static unsigned int intel_dg45id_pin_configs[14] = { +static unsigned int intel_dg45id_pin_configs[13] = { 0x02214230, 0x02A19240, 0x01013214, 0x01014210, - 0x01A19250, 0x01011212, 0x01016211, 0x40f000f0, - 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x014510A0, - 0x074510B0, 0x40f000f0 + 0x01A19250, 0x01011212, 0x01016211 }; static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { @@ -1607,6 +1605,10 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio 1555", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, + "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, + "Dell Studio 1558", STAC_DELL_M6_BOTH), {} /* terminator */ }; @@ -1730,6 +1732,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP HDX", STAC_HP_HDX), /* HDX16 */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620, "HP dv6", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061, + "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 9ddc37300f6..73453814e09 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -476,7 +476,7 @@ static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, knew->name = kstrdup(tmpl->name, GFP_KERNEL); if (!knew->name) return NULL; - return 0; + return knew; } static void via_free_kctls(struct hda_codec *codec) @@ -1215,14 +1215,13 @@ static struct snd_kcontrol_new via_hp_mixer[2] = { }, }; -static int via_hp_build(struct via_spec *spec) +static int via_hp_build(struct hda_codec *codec) { + struct via_spec *spec = codec->spec; struct snd_kcontrol_new *knew; hda_nid_t nid; - - knew = via_clone_control(spec, &via_hp_mixer[0]); - if (knew == NULL) - return -ENOMEM; + int nums; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; switch (spec->codec_type) { case VT1718S: @@ -1239,6 +1238,14 @@ static int via_hp_build(struct via_spec *spec) break; } + nums = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); + if (nums <= 1) + return 0; + + knew = via_clone_control(spec, &via_hp_mixer[0]); + if (knew == NULL) + return -ENOMEM; + knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; knew->private_value = nid; @@ -2561,7 +2568,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); return 1; @@ -3087,7 +3094,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); return 1; @@ -3654,7 +3661,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); return 1; @@ -4140,7 +4147,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); return 1; @@ -4510,7 +4517,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); return 1; } @@ -4930,7 +4937,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); @@ -5425,7 +5432,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); via_smart51_build(spec); @@ -5781,7 +5788,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); return 1; } @@ -6000,12 +6007,12 @@ static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, /* Line-Out: PortE */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Master Front Playback Volume", + "Front Playback Volume", HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, - "Master Front Playback Switch", + "Front Playback Switch", HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -6130,7 +6137,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux[0]; if (spec->hp_mux) - via_hp_build(spec); + via_hp_build(codec); return 1; } diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index 03391da8c8c..90d560c3df1 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include <linux/init.h> #include <sound/core.h> #include <sound/initval.h> diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 6da21a2bcad..e328cfb7620 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -25,7 +25,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/slab.h> #include <sound/core.h> #include "ice1712.h" diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 7f9674b641c..4c551e147c0 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -25,7 +25,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/slab.h> #include <sound/core.h> #include "ice1712.h" diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 5af9e84456d..e618f789026 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -29,7 +29,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/slab.h> #include <sound/core.h> #include "ice1712.h" diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 0cca56038cd..ef9af3f4ace 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -26,6 +26,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/slab.h> #include <sound/initval.h> #include <sound/control.h> diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index b64e78139d6..b56e3367678 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -849,6 +849,7 @@ struct snd_m3 { struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; struct tasklet_struct hwvol_tq; + unsigned int in_suspend; #ifdef CONFIG_PM u16 *suspend_mem; @@ -884,6 +885,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { MODULE_DEVICE_TABLE(pci, snd_m3_ids); static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), 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), @@ -1613,6 +1615,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data) outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); + /* Ignore spurious HV interrupts during suspend / resume, this avoids + mistaking them for a mute button press. */ + if (chip->in_suspend) + return; + if (!chip->master_switch || !chip->master_volume) return; @@ -2424,6 +2431,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) if (chip->suspend_mem == NULL) return 0; + chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2497,6 +2505,7 @@ static int m3_resume(struct pci_dev *pci) snd_m3_hv_init(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); + chip->in_suspend = 0; return 0; } #endif /* CONFIG_PM */ diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 7e8e7da592a..3be8f97c8bc 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -27,6 +27,7 @@ #include <linux/dma-mapping.h> #include <linux/moduleparam.h> #include <linux/mutex.h> +#include <linux/slab.h> #include <sound/core.h> #include <sound/initval.h> @@ -1161,13 +1162,15 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private unsigned long count, unsigned long pos) { struct mixart_mgr *mgr = entry->private_data; + unsigned long maxsize; - count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ - if(count <= 0) + if (pos >= MIXART_BA0_SIZE) return 0; - if(pos + count > MIXART_BA0_SIZE) - count = (long)(MIXART_BA0_SIZE - pos); - if(copy_to_user_fromio(buf, MIXART_MEM( mgr, pos ), count)) + maxsize = MIXART_BA0_SIZE - pos; + if (count > maxsize) + count = maxsize; + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) return -EFAULT; return count; } @@ -1180,13 +1183,15 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private unsigned long count, unsigned long pos) { struct mixart_mgr *mgr = entry->private_data; + unsigned long maxsize; - count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ - if(count <= 0) + if (pos > MIXART_BA1_SIZE) return 0; - if(pos + count > MIXART_BA1_SIZE) - count = (long)(MIXART_BA1_SIZE - pos); - if(copy_to_user_fromio(buf, MIXART_REG( mgr, pos ), count)) + maxsize = MIXART_BA1_SIZE - pos; + if (count > maxsize) + count = maxsize; + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) return -EFAULT; return count; } diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 4cf4cd8c939..bf2696aa5d4 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -24,6 +24,7 @@ #include <linux/pci.h> #include <linux/firmware.h> #include <linux/vmalloc.h> +#include <linux/slab.h> #include <asm/io.h> #include <sound/core.h> #include "mixart.h" diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9c5e6450eeb..fad03d64e3a 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/pci.h> +#include <linux/slab.h> #include <sound/ac97_codec.h> #include <sound/asoundef.h> #include <sound/core.h> diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 7754db166d9..dbc4b89d74e 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -68,7 +68,7 @@ static void wm8776_write(struct oxygen *chip, OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); if (reg < ARRAY_SIZE(data->wm8776_regs)) { - if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) + if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) value &= ~WM8776_UPDATE; data->wm8776_regs[reg] = value; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 960a227eb65..ad446267761 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1974,9 +1974,9 @@ snd_riptide_proc_read(struct snd_info_entry *entry, } snd_iprintf(buffer, "Paths:\n"); i = getpaths(cif, p); - while (i--) { - snd_iprintf(buffer, "%x->%x ", p[i - 1], p[i]); - i--; + while (i >= 2) { + i -= 2; + snd_iprintf(buffer, "%x->%x ", p[i], p[i + 1]); } snd_iprintf(buffer, "\n"); } diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index d5e1c6eb7b7..3c04524de37 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -70,10 +70,10 @@ #include <linux/delay.h> +#include <linux/gfp.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 9d5252bc870..d19dc052c39 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 52c6eb57cc3..b92adef8e81 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/pci.h> #include <linux/firmware.h> #include <linux/moduleparam.h> diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3d72c1effee..547b713d720 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2479,7 +2479,7 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, on MADICARD - playback mixer matrix: [channelout+64] [output] [value] - input(thru) mixer matrix: [channelin] [output] [value] - (better do 2 kontrols for seperation ?) + (better do 2 kontrols for separation ?) */ #define HDSPM_MIXER(xname, xindex) \ diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 44a3e2d8c55..c492af5b25f 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 7e3e8fbc90f..9cc1b5aa014 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/time.h> +#include <linux/slab.h> #include <linux/moduleparam.h> #include <linux/interrupt.h> #include <linux/delay.h> |