Commit 9e4ce164 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda' into for-linus

parents 627b7962 f2cbba76
...@@ -42,19 +42,7 @@ ALC260 ...@@ -42,19 +42,7 @@ ALC260
ALC262 ALC262
====== ======
fujitsu Fujitsu Laptop N/A
benq Benq ED8
benq-t31 Benq T31
hippo Hippo (ATI) with jack detection, Sony UX-90s
hippo_1 Hippo (Benq) with jack detection
toshiba-s06 Toshiba S06
toshiba-rx1 Toshiba RX1
tyan Tyan Thunder n6650W (S2915-E)
ultra Samsung Q1 Ultra Vista model
lenovo-3000 Lenovo 3000 y410
nec NEC Versa S9100
basic fixed pin assignment w/o SPDIF
auto auto-config reading BIOS (default)
ALC267/268 ALC267/268
========== ==========
...@@ -350,7 +338,6 @@ STAC92HD83* ...@@ -350,7 +338,6 @@ STAC92HD83*
mic-ref Reference board with power management for ports mic-ref Reference board with power management for ports
dell-s14 Dell laptop dell-s14 Dell laptop
dell-vostro-3500 Dell Vostro 3500 laptop dell-vostro-3500 Dell Vostro 3500 laptop
hp HP laptops with (inverted) mute-LED
hp-dv7-4000 HP dv-7 4000 hp-dv7-4000 HP dv-7 4000
auto BIOS setup (default) auto BIOS setup (default)
......
...@@ -227,4 +227,12 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master, ...@@ -227,4 +227,12 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
} }
/*
* Helper functions for jack-detection controls
*/
struct snd_kcontrol *
snd_kctl_jack_new(const char *name, int idx, void *private_data);
void snd_kctl_jack_report(struct snd_card *card,
struct snd_kcontrol *kctl, bool status);
#endif /* __SOUND_CONTROL_H */ #endif /* __SOUND_CONTROL_H */
...@@ -217,6 +217,9 @@ config SND_PCM_XRUN_DEBUG ...@@ -217,6 +217,9 @@ config SND_PCM_XRUN_DEBUG
config SND_VMASTER config SND_VMASTER
bool bool
config SND_KCTL_JACK
bool
config SND_DMA_SGBUF config SND_DMA_SGBUF
def_bool y def_bool y
depends on X86 depends on X86
......
...@@ -7,6 +7,7 @@ snd-y := sound.o init.o memory.o info.o control.o misc.o device.o ...@@ -7,6 +7,7 @@ snd-y := sound.o init.o memory.o info.o control.o misc.o device.o
snd-$(CONFIG_ISA_DMA_API) += isadma.o snd-$(CONFIG_ISA_DMA_API) += isadma.o
snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
snd-$(CONFIG_SND_VMASTER) += vmaster.o snd-$(CONFIG_SND_VMASTER) += vmaster.o
snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o
snd-$(CONFIG_SND_JACK) += jack.o snd-$(CONFIG_SND_JACK) += jack.o
snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
......
/*
* Helper functions for jack-detection kcontrols
*
* Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
#define jack_detect_kctl_info snd_ctl_boolean_mono_info
static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = kcontrol->private_value;
return 0;
}
static struct snd_kcontrol_new jack_detect_kctl = {
/* name is filled later */
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.info = jack_detect_kctl_info,
.get = jack_detect_kctl_get,
};
struct snd_kcontrol *
snd_kctl_jack_new(const char *name, int idx, void *private_data)
{
struct snd_kcontrol *kctl;
kctl = snd_ctl_new1(&jack_detect_kctl, private_data);
if (!kctl)
return NULL;
snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name);
kctl->id.index = idx;
kctl->private_value = 0;
return kctl;
}
EXPORT_SYMBOL_GPL(snd_kctl_jack_new);
void snd_kctl_jack_report(struct snd_card *card,
struct snd_kcontrol *kctl, bool status)
{
if (kctl->private_value == status)
return;
kctl->private_value = status;
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
}
EXPORT_SYMBOL_GPL(snd_kctl_jack_report);
...@@ -2,6 +2,7 @@ menuconfig SND_HDA_INTEL ...@@ -2,6 +2,7 @@ menuconfig SND_HDA_INTEL
tristate "Intel HD Audio" tristate "Intel HD Audio"
select SND_PCM select SND_PCM
select SND_VMASTER select SND_VMASTER
select SND_KCTL_JACK
help help
Say Y here to include support for Intel "High Definition Say Y here to include support for Intel "High Definition
Audio" (Azalia) and its compatible devices. Audio" (Azalia) and its compatible devices.
......
snd-hda-intel-objs := hda_intel.o snd-hda-intel-objs := hda_intel.o
snd-hda-codec-y := hda_codec.o snd-hda-codec-y := hda_codec.o hda_jack.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
......
This diff is collapsed.
...@@ -26,8 +26,6 @@ enum { ...@@ -26,8 +26,6 @@ enum {
ALC880_CLEVO, ALC880_CLEVO,
ALC880_TCL_S700, ALC880_TCL_S700,
ALC880_LG, ALC880_LG,
ALC880_LG_LW,
ALC880_MEDION_RIM,
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
ALC880_TEST, ALC880_TEST,
#endif #endif
...@@ -1052,163 +1050,6 @@ static void alc880_lg_setup(struct hda_codec *codec) ...@@ -1052,163 +1050,6 @@ static void alc880_lg_setup(struct hda_codec *codec)
alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
} }
/*
* LG LW20
*
* Pin assignment:
* Speaker-out: 0x14
* Mic-In: 0x18
* Built-in Mic-In: 0x19
* Line-In: 0x1b
* HP-Out: 0x1a
* SPDIF-Out: 0x1e
*/
static const struct hda_input_mux alc880_lg_lw_capture_source = {
.num_items = 3,
.items = {
{ "Mic", 0x0 },
{ "Internal Mic", 0x1 },
{ "Line In", 0x2 },
},
};
#define alc880_lg_lw_modes alc880_threestack_modes
static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
.info = alc_ch_mode_info,
.get = alc_ch_mode_get,
.put = alc_ch_mode_put,
},
{ } /* end */
};
static const struct hda_verb alc880_lg_lw_init_verbs[] = {
{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
/* set capture source to mic-in */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
/* speaker-out */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* HP-out */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* mic-in to input */
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* built-in mic */
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* jack sense */
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
{ }
};
/* toggle speaker-output according to the hp-jack state */
static void alc880_lg_lw_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
spec->autocfg.hp_pins[0] = 0x1b;
spec->autocfg.speaker_pins[0] = 0x14;
alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
}
static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
static const struct hda_input_mux alc880_medion_rim_capture_source = {
.num_items = 2,
.items = {
{ "Mic", 0x0 },
{ "Internal Mic", 0x1 },
},
};
static const struct hda_verb alc880_medion_rim_init_verbs[] = {
{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Mic1 (rear panel) pin widget for input and vref at 80% */
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Mic2 (as headphone out) for HP output */
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
/* Internal Speaker */
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
{ }
};
/* toggle speaker-output according to the hp-jack state */
static void alc880_medion_rim_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
alc_hp_automute(codec);
/* toggle EAPD */
if (spec->hp_jack_present)
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
else
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
}
static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
unsigned int res)
{
/* Looks like the unsol event is incompatible with the standard
* definition. 4bit tag is placed at 28 bit!
*/
if ((res >> 28) == ALC_HP_EVENT)
alc880_medion_rim_automute(codec);
}
static void alc880_medion_rim_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
spec->autocfg.hp_pins[0] = 0x14;
spec->autocfg.speaker_pins[0] = 0x1b;
alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
static const struct hda_amp_list alc880_lg_loopbacks[] = { static const struct hda_amp_list alc880_lg_loopbacks[] = {
{ 0x0b, HDA_INPUT, 1 }, { 0x0b, HDA_INPUT, 1 },
...@@ -1505,8 +1346,6 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = { ...@@ -1505,8 +1346,6 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = {
[ALC880_FUJITSU] = "fujitsu", [ALC880_FUJITSU] = "fujitsu",
[ALC880_F1734] = "F1734", [ALC880_F1734] = "F1734",
[ALC880_LG] = "lg", [ALC880_LG] = "lg",
[ALC880_LG_LW] = "lg-lw",
[ALC880_MEDION_RIM] = "medion",
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = "test", [ALC880_TEST] = "test",
#endif #endif
...@@ -1557,18 +1396,15 @@ static const struct snd_pci_quirk alc880_cfg_tbl[] = { ...@@ -1557,18 +1396,15 @@ static const struct snd_pci_quirk alc880_cfg_tbl[] = {
SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), 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), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
...@@ -1848,35 +1684,6 @@ static const struct alc_config_preset alc880_presets[] = { ...@@ -1848,35 +1684,6 @@ static const struct alc_config_preset alc880_presets[] = {
.loopbacks = alc880_lg_loopbacks, .loopbacks = alc880_lg_loopbacks,
#endif #endif
}, },
[ALC880_LG_LW] = {
.mixers = { alc880_lg_lw_mixer },
.init_verbs = { alc880_volume_init_verbs,
alc880_lg_lw_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_dac_nids),
.dac_nids = alc880_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
.channel_mode = alc880_lg_lw_modes,
.input_mux = &alc880_lg_lw_capture_source,
.unsol_event = alc_sku_unsol_event,
.setup = alc880_lg_lw_setup,
.init_hook = alc_hp_automute,
},
[ALC880_MEDION_RIM] = {
.mixers = { alc880_medion_rim_mixer },
.init_verbs = { alc880_volume_init_verbs,
alc880_medion_rim_init_verbs,
alc_gpio2_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_dac_nids),
.dac_nids = alc880_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
.channel_mode = alc880_2_jack_modes,
.input_mux = &alc880_medion_rim_capture_source,
.unsol_event = alc880_medion_rim_unsol_event,
.setup = alc880_medion_rim_setup,
.init_hook = alc880_medion_rim_automute,
},
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = { [ALC880_TEST] = {
.mixers = { alc880_test_mixer }, .mixers = { alc880_test_mixer },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
...@@ -547,9 +547,6 @@ enum { ...@@ -547,9 +547,6 @@ enum {
/* max. codec address */ /* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f #define HDA_MAX_CODEC_ADDRESS 0x0f
/* max number of PCM devics per card */
#define HDA_MAX_PCMS 10
/* /*
* generic arrays * generic arrays
*/ */
...@@ -869,6 +866,9 @@ struct hda_codec { ...@@ -869,6 +866,9 @@ struct hda_codec {
void (*proc_widget_hook)(struct snd_info_buffer *buffer, void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid); struct hda_codec *codec, hda_nid_t nid);
/* jack detection */
struct snd_array jacktbl;
#ifdef CONFIG_SND_HDA_INPUT_JACK #ifdef CONFIG_SND_HDA_INPUT_JACK
/* jack detection */ /* jack detection */
struct snd_array jacks; struct snd_array jacks;
......
...@@ -407,6 +407,14 @@ struct azx_rb { ...@@ -407,6 +407,14 @@ struct azx_rb {
u32 res[AZX_MAX_CODECS]; /* last read value */ u32 res[AZX_MAX_CODECS]; /* last read value */
}; };
struct azx_pcm {
struct azx *chip;
struct snd_pcm *pcm;
struct hda_codec *codec;
struct hda_pcm_stream *hinfo[2];
struct list_head list;
};
struct azx { struct azx {
struct snd_card *card; struct snd_card *card;
struct pci_dev *pci; struct pci_dev *pci;
...@@ -434,7 +442,7 @@ struct azx { ...@@ -434,7 +442,7 @@ struct azx {
struct azx_dev *azx_dev; struct azx_dev *azx_dev;
/* PCM */ /* PCM */
struct snd_pcm *pcm[HDA_MAX_PCMS]; struct list_head pcm_list; /* azx_pcm list */
/* HD codec */ /* HD codec */
unsigned short codec_mask; unsigned short codec_mask;
...@@ -479,6 +487,7 @@ enum { ...@@ -479,6 +487,7 @@ enum {
AZX_DRIVER_SCH, AZX_DRIVER_SCH,
AZX_DRIVER_ATI, AZX_DRIVER_ATI,
AZX_DRIVER_ATIHDMI, AZX_DRIVER_ATIHDMI,
AZX_DRIVER_ATIHDMI_NS,
AZX_DRIVER_VIA, AZX_DRIVER_VIA,
AZX_DRIVER_SIS, AZX_DRIVER_SIS,
AZX_DRIVER_ULI, AZX_DRIVER_ULI,
...@@ -525,6 +534,7 @@ static char *driver_short_names[] __devinitdata = { ...@@ -525,6 +534,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_SCH] = "HDA Intel MID", [AZX_DRIVER_SCH] = "HDA Intel MID",
[AZX_DRIVER_ATI] = "HDA ATI SB", [AZX_DRIVER_ATI] = "HDA ATI SB",
[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
[AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI",
[AZX_DRIVER_VIA] = "HDA VIA VT82xx", [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
[AZX_DRIVER_SIS] = "HDA SIS966", [AZX_DRIVER_SIS] = "HDA SIS966",
[AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_ULI] = "HDA ULI M5461",
...@@ -1143,16 +1153,6 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, ...@@ -1143,16 +1153,6 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
static void azx_init_pci(struct azx *chip) static void azx_init_pci(struct azx *chip)
{ {
/* force to non-snoop mode for a new VIA controller when BIOS is set */
if (chip->snoop && chip->driver_type == AZX_DRIVER_VIA) {
u8 snoop;
pci_read_config_byte(chip->pci, 0x42, &snoop);
if (!(snoop & 0x80) && chip->pci->revision == 0x30) {
chip->snoop = 0;
snd_printdd(SFX "Force to non-snoop mode\n");
}
}
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS * TCSEL == Traffic Class Select Register, which sets PCI express QOS
* Ensuring these bits are 0 clears playback static on some HD Audio * Ensuring these bits are 0 clears playback static on some HD Audio
...@@ -1486,10 +1486,9 @@ static void azx_bus_reset(struct hda_bus *bus) ...@@ -1486,10 +1486,9 @@ static void azx_bus_reset(struct hda_bus *bus)
azx_init_chip(chip, 1); azx_init_chip(chip, 1);
#ifdef CONFIG_PM #ifdef CONFIG_PM
if (chip->initialized) { if (chip->initialized) {
int i; struct azx_pcm *p;
list_for_each_entry(p, &chip->pcm_list, list)
for (i = 0; i < HDA_MAX_PCMS; i++) snd_pcm_suspend_all(p->pcm);
snd_pcm_suspend_all(chip->pcm[i]);
snd_hda_suspend(chip->bus); snd_hda_suspend(chip->bus);
snd_hda_resume(chip->bus); snd_hda_resume(chip->bus);
} }
...@@ -1667,12 +1666,6 @@ static struct snd_pcm_hardware azx_pcm_hw = { ...@@ -1667,12 +1666,6 @@ static struct snd_pcm_hardware azx_pcm_hw = {
.fifo_size = 0, .fifo_size = 0,
}; };
struct azx_pcm {
struct azx *chip;
struct hda_codec *codec;
struct hda_pcm_stream *hinfo[2];
};
static int azx_pcm_open(struct snd_pcm_substream *substream) static int azx_pcm_open(struct snd_pcm_substream *substream)
{ {
struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
...@@ -2197,7 +2190,7 @@ static void azx_pcm_free(struct snd_pcm *pcm) ...@@ -2197,7 +2190,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
{ {
struct azx_pcm *apcm = pcm->private_data; struct azx_pcm *apcm = pcm->private_data;
if (apcm) { if (apcm) {
apcm->chip->pcm[pcm->device] = NULL; list_del(&apcm->list);
kfree(apcm); kfree(apcm);
} }
} }
...@@ -2215,14 +2208,11 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, ...@@ -2215,14 +2208,11 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
unsigned int size; unsigned int size;
int s, err; int s, err;
if (pcm_dev >= HDA_MAX_PCMS) { list_for_each_entry(apcm, &chip->pcm_list, list) {
snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", if (apcm->pcm->device == pcm_dev) {
pcm_dev); snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
return -EINVAL; return -EBUSY;
} }
if (chip->pcm[pcm_dev]) {
snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
return -EBUSY;
} }
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
...@@ -2235,12 +2225,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, ...@@ -2235,12 +2225,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
if (apcm == NULL) if (apcm == NULL)
return -ENOMEM; return -ENOMEM;
apcm->chip = chip; apcm->chip = chip;
apcm->pcm = pcm;
apcm->codec = codec; apcm->codec = codec;
pcm->private_data = apcm; pcm->private_data = apcm;
pcm->private_free = azx_pcm_free; pcm->private_free = azx_pcm_free;
if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
chip->pcm[pcm_dev] = pcm; list_add_tail(&apcm->list, &chip->pcm_list);
cpcm->pcm = pcm; cpcm->pcm = pcm;
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
apcm->hinfo[s] = &cpcm->stream[s]; apcm->hinfo[s] = &cpcm->stream[s];
...@@ -2370,12 +2361,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) ...@@ -2370,12 +2361,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
{ {
struct snd_card *card = pci_get_drvdata(pci); struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data; struct azx *chip = card->private_data;
int i; struct azx_pcm *p;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip); azx_clear_irq_pending(chip);
for (i = 0; i < HDA_MAX_PCMS; i++) list_for_each_entry(p, &chip->pcm_list, list)
snd_pcm_suspend_all(chip->pcm[i]); snd_pcm_suspend_all(p->pcm);
if (chip->initialized) if (chip->initialized)
snd_hda_suspend(chip->bus); snd_hda_suspend(chip->bus);
azx_stop_chip(chip); azx_stop_chip(chip);
...@@ -2502,7 +2493,6 @@ static int azx_dev_free(struct snd_device *device) ...@@ -2502,7 +2493,6 @@ static int azx_dev_free(struct snd_device *device)
static struct snd_pci_quirk position_fix_list[] __devinitdata = { static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), 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, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
...@@ -2633,6 +2623,35 @@ static void __devinit check_msi(struct azx *chip) ...@@ -2633,6 +2623,35 @@ static void __devinit check_msi(struct azx *chip)
} }
} }
/* check the snoop mode availability */
static void __devinit azx_check_snoop_available(struct azx *chip)
{
bool snoop = chip->snoop;
switch (chip->driver_type) {
case AZX_DRIVER_VIA:
/* force to non-snoop mode for a new VIA controller
* when BIOS is set
*/
if (snoop) {
u8 val;
pci_read_config_byte(chip->pci, 0x42, &val);
if (!(val & 0x80) && chip->pci->revision == 0x30)
snoop = false;
}
break;
case AZX_DRIVER_ATIHDMI_NS:
/* new ATI HDMI requires non-snoop */
snoop = false;
break;
}
if (snoop != chip->snoop) {
snd_printk(KERN_INFO SFX "Force to %s mode\n",
snoop ? "snoop" : "non-snoop");
chip->snoop = snoop;
}
}
/* /*
* constructor * constructor
...@@ -2671,6 +2690,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2671,6 +2690,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
check_msi(chip); check_msi(chip);
chip->dev_index = dev; chip->dev_index = dev;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&chip->pcm_list);
chip->position_fix[0] = chip->position_fix[1] = chip->position_fix[0] = chip->position_fix[1] =
check_position_fix(chip, position_fix[dev]); check_position_fix(chip, position_fix[dev]);
...@@ -2678,6 +2698,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2678,6 +2698,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->single_cmd = single_cmd; chip->single_cmd = single_cmd;
chip->snoop = hda_snoop; chip->snoop = hda_snoop;
azx_check_snoop_available(chip);
if (bdl_pos_adj[dev] < 0) { if (bdl_pos_adj[dev] < 0) {
switch (chip->driver_type) { switch (chip->driver_type) {
...@@ -2776,6 +2797,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2776,6 +2797,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->capture_streams = ULI_NUM_CAPTURE; chip->capture_streams = ULI_NUM_CAPTURE;
break; break;
case AZX_DRIVER_ATIHDMI: case AZX_DRIVER_ATIHDMI:
case AZX_DRIVER_ATIHDMI_NS:
chip->playback_streams = ATIHDMI_NUM_PLAYBACK; chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
chip->capture_streams = ATIHDMI_NUM_CAPTURE; chip->capture_streams = ATIHDMI_NUM_CAPTURE;
break; break;
...@@ -2970,7 +2992,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { ...@@ -2970,7 +2992,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* SCH */ /* SCH */
{ PCI_DEVICE(0x8086, 0x811b), { PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
AZX_DCAPS_BUFSIZE}, AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */
{ PCI_DEVICE(0x8086, 0x080a),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */
/* ICH */
{ PCI_DEVICE(0x8086, 0x2668), { PCI_DEVICE(0x8086, 0x2668),
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
AZX_DCAPS_BUFSIZE }, /* ICH6 */ AZX_DCAPS_BUFSIZE }, /* ICH6 */
...@@ -3037,6 +3063,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { ...@@ -3037,6 +3063,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaa48), { PCI_DEVICE(0x1002, 0xaa48),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0x9902),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaaa0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaaa8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaab0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
/* VIA VT8251/VT8237A */ /* VIA VT8251/VT8237A */
{ PCI_DEVICE(0x1106, 0x3288), { PCI_DEVICE(0x1106, 0x3288),
.driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
......
/*
* Jack-detection handling for HD-audio
*
* Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_jack.h"
/* execute pin sense measurement */
static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
{
u32 pincap;
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);
}
return snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
}
/**
* snd_hda_jack_tbl_get - query the jack-table entry for the given NID
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
int i;
if (!nid || !jack)
return NULL;
for (i = 0; i < codec->jacktbl.used; i++, jack++)
if (jack->nid == nid)
return jack;
return NULL;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);
/**
* snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
int i;
if (!tag || !jack)
return NULL;
for (i = 0; i < codec->jacktbl.used; i++, jack++)
if (jack->tag == tag)
return jack;
return NULL;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag);
/**
* snd_hda_jack_tbl_new - create a jack-table entry for the given NID
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
if (jack)
return jack;
snd_array_init(&codec->jacktbl, sizeof(*jack), 16);
jack = snd_array_new(&codec->jacktbl);
if (!jack)
return NULL;
jack->nid = nid;
jack->jack_dirty = 1;
jack->tag = codec->jacktbl.used;
return jack;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_new);
void snd_hda_jack_tbl_clear(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
/* free jack instances manually when clearing/reconfiguring */
if (!codec->bus->shutdown && codec->jacktbl.list) {
struct hda_jack_tbl *jack = codec->jacktbl.list;
int i;
for (i = 0; i < codec->jacktbl.used; i++, jack++) {
if (jack->jack)
snd_device_free(codec->bus->card, jack->jack);
}
}
#endif
snd_array_free(&codec->jacktbl);
}
/* update the cached value and notification flag if needed */
static void jack_detect_update(struct hda_codec *codec,
struct hda_jack_tbl *jack)
{
if (jack->jack_dirty || !jack->jack_detect) {
jack->pin_sense = read_pin_sense(codec, jack->nid);
jack->jack_dirty = 0;
}
}
/**
* snd_hda_set_dirty_all - Mark all the cached as dirty
*
* This function sets the dirty flag to all entries of jack table.
* It's called from the resume path in hda_codec.c.
*/
void snd_hda_jack_set_dirty_all(struct hda_codec *codec)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
int i;
for (i = 0; i < codec->jacktbl.used; i++, jack++)
if (jack->nid)
jack->jack_dirty = 1;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all);
/**
* snd_hda_pin_sense - execute pin sense measurement
* @codec: the CODEC to sense
* @nid: the pin NID to sense
*
* Execute necessary pin sense measurement and return its Presence Detect,
* Impedance, ELD Valid etc. status bits.
*/
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
if (jack) {
jack_detect_update(codec, jack);
return jack->pin_sense;
}
return read_pin_sense(codec, nid);
}
EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
/**
* snd_hda_jack_detect - query pin Presence Detect status
* @codec: the CODEC to sense
* @nid: the pin NID to sense
*
* Query and return the pin's Presence Detect status.
*/
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
{
u32 sense = snd_hda_pin_sense(codec, nid);
return get_jack_plug_state(sense);
}
EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
/**
* snd_hda_jack_detect_enable - enable the jack-detection
*/
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
unsigned char action)
{
struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
if (!jack)
return -ENOMEM;
if (jack->jack_detect)
return 0; /* already registered */
jack->jack_detect = 1;
if (action)
jack->action = action;
return snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | jack->tag);
}
EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
/**
* snd_hda_jack_report_sync - sync the states of all jacks and report if changed
*/
void snd_hda_jack_report_sync(struct hda_codec *codec)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
int i, state;
for (i = 0; i < codec->jacktbl.used; i++, jack++)
if (jack->nid) {
jack_detect_update(codec, jack);
if (!jack->kctl)
continue;
state = get_jack_plug_state(jack->pin_sense);
snd_kctl_jack_report(codec->bus->card, jack->kctl, state);
#ifdef CONFIG_SND_HDA_INPUT_JACK
if (jack->jack)
snd_jack_report(jack->jack,
state ? jack->type : 0);
#endif
}
}
EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
#ifdef CONFIG_SND_HDA_INPUT_JACK
/* guess the jack type from the pin-config */
static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
switch (get_defcfg_device(def_conf)) {
case AC_JACK_LINE_OUT:
case AC_JACK_SPEAKER:
return SND_JACK_LINEOUT;
case AC_JACK_HP_OUT:
return SND_JACK_HEADPHONE;
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
return SND_JACK_AVOUT;
case AC_JACK_MIC_IN:
return SND_JACK_MICROPHONE;
default:
return SND_JACK_LINEIN;
}
}
static void hda_free_jack_priv(struct snd_jack *jack)
{
struct hda_jack_tbl *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
#endif
/**
* snd_hda_jack_add_kctl - Add a kctl for the given pin
*
* This assigns a jack-detection kctl to the given pin. The kcontrol
* will have the given name and index.
*/
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, int idx)
{
struct hda_jack_tbl *jack;
struct snd_kcontrol *kctl;
int err, state;
jack = snd_hda_jack_tbl_new(codec, nid);
if (!jack)
return 0;
if (jack->kctl)
return 0; /* already created */
kctl = snd_kctl_jack_new(name, idx, codec);
if (!kctl)
return -ENOMEM;
err = snd_hda_ctl_add(codec, nid, kctl);
if (err < 0)
return err;
jack->kctl = kctl;
state = snd_hda_jack_detect(codec, nid);
snd_kctl_jack_report(codec->bus->card, kctl, state);
#ifdef CONFIG_SND_HDA_INPUT_JACK
jack->type = get_input_jack_type(codec, nid);
err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack);
if (err < 0)
return err;
jack->jack->private_data = jack;
jack->jack->private_free = hda_free_jack_priv;
snd_jack_report(jack->jack, state ? jack->type : 0);
#endif
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl);
static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg)
{
unsigned int def_conf, conn;
char name[44];
int idx, err;
if (!nid)
return 0;
if (!is_jack_detectable(codec, nid))
return 0;
def_conf = snd_hda_codec_get_pincfg(codec, nid);
conn = get_defcfg_connect(def_conf);
if (conn != AC_JACK_PORT_COMPLEX)
return 0;
snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
err = snd_hda_jack_add_kctl(codec, nid, name, idx);
if (err < 0)
return err;
return snd_hda_jack_detect_enable(codec, nid, 0);
}
/**
* snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
*/
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
const hda_nid_t *p;
int i, err;
for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
err = add_jack_kctl(codec, *p, cfg);
if (err < 0)
return err;
}
for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
if (*p == *cfg->line_out_pins) /* might be duplicated */
break;
err = add_jack_kctl(codec, *p, cfg);
if (err < 0)
return err;
}
for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
if (*p == *cfg->line_out_pins) /* might be duplicated */
break;
err = add_jack_kctl(codec, *p, cfg);
if (err < 0)
return err;
}
for (i = 0; i < cfg->num_inputs; i++) {
err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg);
if (err < 0)
return err;
}
for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
err = add_jack_kctl(codec, *p, cfg);
if (err < 0)
return err;
}
err = add_jack_kctl(codec, cfg->dig_in_pin, cfg);
if (err < 0)
return err;
err = add_jack_kctl(codec, cfg->mono_out_pin, cfg);
if (err < 0)
return err;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
/*
* Jack-detection handling for HD-audio
*
* Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __SOUND_HDA_JACK_H
#define __SOUND_HDA_JACK_H
struct hda_jack_tbl {
hda_nid_t nid;
unsigned char action; /* event action (0 = none) */
unsigned char tag; /* unsol event tag */
unsigned int private_data; /* arbitrary data */
/* jack-detection stuff */
unsigned int pin_sense; /* cached pin-sense value */
unsigned int jack_detect:1; /* capable of jack-detection? */
unsigned int jack_dirty:1; /* needs to update? */
struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */
#ifdef CONFIG_SND_HDA_INPUT_JACK
int type;
struct snd_jack *jack;
#endif
};
struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);
struct hda_jack_tbl *
snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_jack_tbl_clear(struct hda_codec *codec);
/**
* snd_hda_jack_get_action - get jack-tbl entry for the tag
*
* Call this from the unsol event handler to get the assigned action for the
* event. This will mark the dirty flag for the later reporting, too.
*/
static inline unsigned char
snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag)
{
struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (jack) {
jack->jack_dirty = 1;
return jack->action;
}
return 0;
}
void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
unsigned char action);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
return false;
if (!codec->ignore_misc_bit &&
(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE))
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
return false;
return true;
}
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, int idx);
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg);
void snd_hda_jack_report_sync(struct hda_codec *codec);
#endif /* __SOUND_HDA_JACK_H */
...@@ -394,11 +394,12 @@ struct auto_pin_cfg_item { ...@@ -394,11 +394,12 @@ struct auto_pin_cfg_item {
}; };
struct auto_pin_cfg; struct auto_pin_cfg;
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
int check_location);
const char *hda_get_autocfg_input_label(struct hda_codec *codec, const char *hda_get_autocfg_input_label(struct hda_codec *codec,
const struct auto_pin_cfg *cfg, const struct auto_pin_cfg *cfg,
int input); int input);
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
char *label, int maxlen, int *indexp);
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
int index, int *type_index_ret); int index, int *type_index_ret);
...@@ -487,7 +488,12 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) ...@@ -487,7 +488,12 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
} }
/* get the widget type from widget capability bits */ /* get the widget type from widget capability bits */
#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) static inline int get_wcaps_type(unsigned int wcaps)
{
if (!wcaps)
return -1; /* invalid type */
return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
}
static inline unsigned int get_wcaps_channels(u32 wcaps) static inline unsigned int get_wcaps_channels(u32 wcaps)
{ {
...@@ -505,21 +511,6 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, ...@@ -505,21 +511,6 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
unsigned int caps); unsigned int caps);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
return false;
if (!codec->ignore_misc_bit &&
(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE))
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
return false;
return true;
}
/* flags for hda_nid_item */ /* flags for hda_nid_item */
#define HDA_NID_ITEM_AMP (1<<0) #define HDA_NID_ITEM_AMP (1<<0)
...@@ -688,28 +679,4 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec, ...@@ -688,28 +679,4 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
/*
* Input-jack notification support
*/
#ifdef CONFIG_SND_HDA_INPUT_JACK
int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
const char *name);
void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_input_jack_free(struct hda_codec *codec);
#else /* CONFIG_SND_HDA_INPUT_JACK */
static inline int snd_hda_input_jack_add(struct hda_codec *codec,
hda_nid_t nid, int type,
const char *name)
{
return 0;
}
static inline void snd_hda_input_jack_report(struct hda_codec *codec,
hda_nid_t nid)
{
}
static inline void snd_hda_input_jack_free(struct hda_codec *codec)
{
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */
#endif /* __SOUND_HDA_LOCAL_H */ #endif /* __SOUND_HDA_LOCAL_H */
...@@ -54,6 +54,8 @@ static const char *get_wid_type_name(unsigned int wid_value) ...@@ -54,6 +54,8 @@ static const char *get_wid_type_name(unsigned int wid_value)
[AC_WID_BEEP] = "Beep Generator Widget", [AC_WID_BEEP] = "Beep Generator Widget",
[AC_WID_VENDOR] = "Vendor Defined Widget", [AC_WID_VENDOR] = "Vendor Defined Widget",
}; };
if (wid_value == -1)
return "UNKNOWN Widget";
wid_value &= 0xf; wid_value &= 0xf;
if (names[wid_value]) if (names[wid_value])
return names[wid_value]; return names[wid_value];
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
#include "hda_beep.h" #include "hda_beep.h"
#include "hda_jack.h"
struct ad198x_spec { struct ad198x_spec {
const struct snd_kcontrol_new *mixers[6]; const struct snd_kcontrol_new *mixers[6];
......
...@@ -41,7 +41,7 @@ struct ca0110_spec { ...@@ -41,7 +41,7 @@ struct ca0110_spec {
hda_nid_t dig_out; hda_nid_t dig_out;
hda_nid_t dig_in; hda_nid_t dig_in;
unsigned int num_inputs; unsigned int num_inputs;
const char *input_labels[AUTO_PIN_LAST]; char input_labels[AUTO_PIN_LAST][32];
struct hda_pcm pcm_rec[2]; /* PCM information */ struct hda_pcm pcm_rec[2]; /* PCM information */
}; };
...@@ -476,7 +476,9 @@ static void parse_input(struct hda_codec *codec) ...@@ -476,7 +476,9 @@ static void parse_input(struct hda_codec *codec)
if (j >= cfg->num_inputs) if (j >= cfg->num_inputs)
continue; continue;
spec->input_pins[n] = pin; spec->input_pins[n] = pin;
spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1); snd_hda_get_pin_label(codec, pin, cfg,
spec->input_labels[n],
sizeof(spec->input_labels[n]), NULL);
spec->adcs[n] = nid; spec->adcs[n] = nid;
n++; n++;
} }
......
This diff is collapsed.
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
#include "hda_beep.h" #include "hda_beep.h"
#include "hda_jack.h"
#define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_IN 0x00
#define CXT_PIN_DIR_OUT 0x01 #define CXT_PIN_DIR_OUT 0x01
...@@ -415,40 +416,6 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, ...@@ -415,40 +416,6 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
&spec->cur_mux[adc_idx]); &spec->cur_mux[adc_idx]);
} }
static int conexant_init_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
int i;
for (i = 0; i < spec->num_init_verbs; i++) {
const struct hda_verb *hv;
hv = spec->init_verbs[i];
while (hv->nid) {
int err = 0;
switch (hv->param ^ AC_USRSP_EN) {
case CONEXANT_HP_EVENT:
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_HEADPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
case CXT5051_PORTC_EVENT:
case CONEXANT_MIC_EVENT:
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
}
if (err < 0)
return err;
++hv;
}
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state) unsigned int power_state)
{ {
...@@ -474,7 +441,6 @@ static int conexant_init(struct hda_codec *codec) ...@@ -474,7 +441,6 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec)
{ {
snd_hda_input_jack_free(codec);
snd_hda_detach_beep_device(codec); snd_hda_detach_beep_device(codec);
kfree(codec->spec); kfree(codec->spec);
} }
...@@ -1120,8 +1086,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { ...@@ -1120,8 +1086,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
CXT5045_LAPTOP_HPSENSE),
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
...@@ -1750,7 +1714,6 @@ static void cxt5051_hp_automute(struct hda_codec *codec) ...@@ -1750,7 +1714,6 @@ static void cxt5051_hp_automute(struct hda_codec *codec)
static void cxt5051_hp_unsol_event(struct hda_codec *codec, static void cxt5051_hp_unsol_event(struct hda_codec *codec,
unsigned int res) unsigned int res)
{ {
int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
switch (res >> 26) { switch (res >> 26) {
case CONEXANT_HP_EVENT: case CONEXANT_HP_EVENT:
cxt5051_hp_automute(codec); cxt5051_hp_automute(codec);
...@@ -1762,7 +1725,6 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, ...@@ -1762,7 +1725,6 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
cxt5051_portc_automic(codec); cxt5051_portc_automic(codec);
break; break;
} }
snd_hda_input_jack_report(codec, nid);
} }
static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { static const struct snd_kcontrol_new cxt5051_playback_mixers[] = {
...@@ -1901,8 +1863,6 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, ...@@ -1901,8 +1863,6 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE, AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | event); AC_USRSP_EN | event);
snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, nid);
} }
static const struct hda_verb cxt5051_ideapad_init_verbs[] = { static const struct hda_verb cxt5051_ideapad_init_verbs[] = {
...@@ -1918,7 +1878,6 @@ static int cxt5051_init(struct hda_codec *codec) ...@@ -1918,7 +1878,6 @@ static int cxt5051_init(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
conexant_init(codec); conexant_init(codec);
conexant_init_jacks(codec);
if (spec->auto_mic & AUTO_MIC_PORTB) if (spec->auto_mic & AUTO_MIC_PORTB)
cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT);
...@@ -3450,7 +3409,6 @@ static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) ...@@ -3450,7 +3409,6 @@ static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
hda_nid_t nid = pins[i]; hda_nid_t nid = pins[i];
if (!nid || !is_jack_detectable(codec, nid)) if (!nid || !is_jack_detectable(codec, nid))
break; break;
snd_hda_input_jack_report(codec, nid);
present |= snd_hda_jack_detect(codec, nid); present |= snd_hda_jack_detect(codec, nid);
} }
return present; return present;
...@@ -3755,8 +3713,7 @@ static void cx_auto_automic(struct hda_codec *codec) ...@@ -3755,8 +3713,7 @@ static void cx_auto_automic(struct hda_codec *codec)
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
{ {
int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; switch (snd_hda_jack_get_action(codec, res >> 26)) {
switch (res >> 26) {
case CONEXANT_HP_EVENT: case CONEXANT_HP_EVENT:
cx_auto_hp_automute(codec); cx_auto_hp_automute(codec);
break; break;
...@@ -3765,9 +3722,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -3765,9 +3722,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
break; break;
case CONEXANT_MIC_EVENT: case CONEXANT_MIC_EVENT:
cx_auto_automic(codec); cx_auto_automic(codec);
snd_hda_input_jack_report(codec, nid);
break; break;
} }
snd_hda_jack_report_sync(codec);
} }
/* check whether the pin config is suitable for auto-mic switching; /* check whether the pin config is suitable for auto-mic switching;
...@@ -3979,13 +3936,11 @@ static void mute_outputs(struct hda_codec *codec, int num_nids, ...@@ -3979,13 +3936,11 @@ static void mute_outputs(struct hda_codec *codec, int num_nids,
} }
static void enable_unsol_pins(struct hda_codec *codec, int num_pins, static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
hda_nid_t *pins, unsigned int tag) hda_nid_t *pins, unsigned int action)
{ {
int i; int i;
for (i = 0; i < num_pins; i++) for (i = 0; i < num_pins; i++)
snd_hda_codec_write(codec, pins[i], 0, snd_hda_jack_detect_enable(codec, pins[i], action);
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | tag);
} }
static void cx_auto_init_output(struct hda_codec *codec) static void cx_auto_init_output(struct hda_codec *codec)
...@@ -4060,16 +4015,14 @@ static void cx_auto_init_input(struct hda_codec *codec) ...@@ -4060,16 +4015,14 @@ static void cx_auto_init_input(struct hda_codec *codec)
if (spec->auto_mic) { if (spec->auto_mic) {
if (spec->auto_mic_ext >= 0) { if (spec->auto_mic_ext >= 0) {
snd_hda_codec_write(codec, snd_hda_jack_detect_enable(codec,
cfg->inputs[spec->auto_mic_ext].pin, 0, cfg->inputs[spec->auto_mic_ext].pin,
AC_VERB_SET_UNSOLICITED_ENABLE, CONEXANT_MIC_EVENT);
AC_USRSP_EN | CONEXANT_MIC_EVENT);
} }
if (spec->auto_mic_dock >= 0) { if (spec->auto_mic_dock >= 0) {
snd_hda_codec_write(codec, snd_hda_jack_detect_enable(codec,
cfg->inputs[spec->auto_mic_dock].pin, 0, cfg->inputs[spec->auto_mic_dock].pin,
AC_VERB_SET_UNSOLICITED_ENABLE, CONEXANT_MIC_EVENT);
AC_USRSP_EN | CONEXANT_MIC_EVENT);
} }
cx_auto_automic(codec); cx_auto_automic(codec);
} else { } else {
...@@ -4097,6 +4050,7 @@ static int cx_auto_init(struct hda_codec *codec) ...@@ -4097,6 +4050,7 @@ static int cx_auto_init(struct hda_codec *codec)
cx_auto_init_output(codec); cx_auto_init_output(codec);
cx_auto_init_input(codec); cx_auto_init_input(codec);
cx_auto_init_digital(codec); cx_auto_init_digital(codec);
snd_hda_jack_report_sync(codec);
return 0; return 0;
} }
...@@ -4326,6 +4280,7 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) ...@@ -4326,6 +4280,7 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
static int cx_auto_build_controls(struct hda_codec *codec) static int cx_auto_build_controls(struct hda_codec *codec)
{ {
struct conexant_spec *spec = codec->spec;
int err; int err;
err = cx_auto_build_output_controls(codec); err = cx_auto_build_output_controls(codec);
...@@ -4334,7 +4289,13 @@ static int cx_auto_build_controls(struct hda_codec *codec) ...@@ -4334,7 +4289,13 @@ static int cx_auto_build_controls(struct hda_codec *codec)
err = cx_auto_build_input_controls(codec); err = cx_auto_build_input_controls(codec);
if (err < 0) if (err < 0)
return err; return err;
return conexant_build_controls(codec); err = conexant_build_controls(codec);
if (err < 0)
return err;
err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
if (err < 0)
return err;
return 0;
} }
static int cx_auto_search_adcs(struct hda_codec *codec) static int cx_auto_search_adcs(struct hda_codec *codec)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <sound/jack.h> #include <sound/jack.h>
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
#include "hda_jack.h"
static bool static_hdmi_pcm; static bool static_hdmi_pcm;
module_param(static_hdmi_pcm, bool, 0644); module_param(static_hdmi_pcm, bool, 0644);
...@@ -48,8 +49,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); ...@@ -48,8 +49,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
* *
* The HDA correspondence of pipes/ports are converter/pin nodes. * The HDA correspondence of pipes/ports are converter/pin nodes.
*/ */
#define MAX_HDMI_CVTS 4 #define MAX_HDMI_CVTS 8
#define MAX_HDMI_PINS 4 #define MAX_HDMI_PINS 8
struct hdmi_spec_per_cvt { struct hdmi_spec_per_cvt {
hda_nid_t cvt_nid; hda_nid_t cvt_nid;
...@@ -754,10 +755,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); ...@@ -754,10 +755,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT; int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
int pin_nid;
int pd = !!(res & AC_UNSOL_RES_PD); int pd = !!(res & AC_UNSOL_RES_PD);
int eldv = !!(res & AC_UNSOL_RES_ELDV); int eldv = !!(res & AC_UNSOL_RES_ELDV);
int pin_idx; int pin_idx;
struct hda_jack_tbl *jack;
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!jack)
return;
pin_nid = jack->nid;
jack->jack_dirty = 1;
printk(KERN_INFO printk(KERN_INFO
"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
...@@ -768,6 +777,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) ...@@ -768,6 +777,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
return; return;
hdmi_present_sense(&spec->pins[pin_idx], 1); hdmi_present_sense(&spec->pins[pin_idx], 1);
snd_hda_jack_report_sync(codec);
} }
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
...@@ -795,11 +805,10 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) ...@@ -795,11 +805,10 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) 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 tag = res >> AC_UNSOL_RES_TAG_SHIFT;
int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
if (pin_nid_to_pin_index(spec, tag) < 0) { if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
return; return;
} }
...@@ -996,8 +1005,6 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) ...@@ -996,8 +1005,6 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
msecs_to_jiffies(300)); msecs_to_jiffies(300));
} }
} }
snd_hda_input_jack_report(codec, pin_nid);
} }
static void hdmi_repoll_eld(struct work_struct *work) static void hdmi_repoll_eld(struct work_struct *work)
...@@ -1126,12 +1133,12 @@ static int hdmi_parse_codec(struct hda_codec *codec) ...@@ -1126,12 +1133,12 @@ static int hdmi_parse_codec(struct hda_codec *codec)
/* /*
*/ */
static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = { static char *get_hdmi_pcm_name(int idx)
"HDMI 0", {
"HDMI 1", static char names[MAX_HDMI_PINS][8];
"HDMI 2", sprintf(&names[idx][0], "HDMI %d", idx);
"HDMI 3", return &names[idx][0];
}; }
/* /*
* HDMI callbacks * HDMI callbacks
...@@ -1209,7 +1216,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -1209,7 +1216,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
struct hda_pcm_stream *pstr; struct hda_pcm_stream *pstr;
info = &spec->pcm_rec[pin_idx]; info = &spec->pcm_rec[pin_idx];
info->name = generic_hdmi_pcm_names[pin_idx]; info->name = get_hdmi_pcm_name(pin_idx);
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
...@@ -1226,21 +1233,15 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -1226,21 +1233,15 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
{ {
int err; char hdmi_str[32] = "HDMI/DP";
char hdmi_str[32];
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
int pcmdev = spec->pcm_rec[pin_idx].device; int pcmdev = spec->pcm_rec[pin_idx].device;
snprintf(hdmi_str, sizeof(hdmi_str), "HDMI/DP,pcm=%d", pcmdev); if (pcmdev > 0)
sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
err = snd_hda_input_jack_add(codec, per_pin->pin_nid,
SND_JACK_VIDEOOUT, pcmdev > 0 ? hdmi_str : NULL);
if (err < 0)
return err;
hdmi_present_sense(per_pin, 0); return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0);
return 0;
} }
static int generic_hdmi_build_controls(struct hda_codec *codec) static int generic_hdmi_build_controls(struct hda_codec *codec)
...@@ -1270,6 +1271,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) ...@@ -1270,6 +1271,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
if (err < 0) if (err < 0)
return err; return err;
hdmi_present_sense(per_pin, 0);
} }
return 0; return 0;
...@@ -1286,14 +1289,13 @@ static int generic_hdmi_init(struct hda_codec *codec) ...@@ -1286,14 +1289,13 @@ static int generic_hdmi_init(struct hda_codec *codec)
struct hdmi_eld *eld = &per_pin->sink_eld; struct hdmi_eld *eld = &per_pin->sink_eld;
hdmi_init_pin(codec, pin_nid); hdmi_init_pin(codec, pin_nid);
snd_hda_codec_write(codec, pin_nid, 0, snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | pin_nid);
per_pin->codec = codec; per_pin->codec = codec;
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
snd_hda_eld_proc_new(codec, eld, pin_idx); snd_hda_eld_proc_new(codec, eld, pin_idx);
} }
snd_hda_jack_report_sync(codec);
return 0; return 0;
} }
...@@ -1309,7 +1311,6 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -1309,7 +1311,6 @@ static void generic_hdmi_free(struct hda_codec *codec)
cancel_delayed_work(&per_pin->work); cancel_delayed_work(&per_pin->work);
snd_hda_eld_proc_free(codec, eld); snd_hda_eld_proc_free(codec, eld);
} }
snd_hda_input_jack_free(codec);
flush_workqueue(codec->bus->workq); flush_workqueue(codec->bus->workq);
kfree(spec); kfree(spec);
...@@ -1364,7 +1365,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec) ...@@ -1364,7 +1365,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
chans = get_wcaps(codec, spec->cvts[i].cvt_nid); chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
chans = get_wcaps_channels(chans); chans = get_wcaps_channels(chans);
info->name = generic_hdmi_pcm_names[i]; info->name = get_hdmi_pcm_name(i);
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
snd_BUG_ON(!spec->pcm_playback); snd_BUG_ON(!spec->pcm_playback);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment