From 6ff86a3f33e84c430aeb8ff3b7f68b1c052ec1e9 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 19 Mar 2010 11:14:36 +0100 Subject: ALSA: hda - Take internal mic as Front Mic Add new check for MIC. Do the internal DMIC as the Front MIC. It could solve the default record source index issue. [Fix the check properly using the bitmask by tiwai] Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0e76ac2b2ace..d72bcff8d271 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4218,7 +4218,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, break; case AC_JACK_MIC_IN: { int preferred, alt; - if (loc == AC_JACK_LOC_FRONT) { + if (loc == AC_JACK_LOC_FRONT || + (loc & 0x30) == AC_JACK_LOC_INTERNAL) { preferred = AUTO_PIN_FRONT_MIC; alt = AUTO_PIN_MIC; } else { -- cgit v1.2.3 From da00c24493bf6ae3772dfe7343dca033ebc75955 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 19 Mar 2010 11:23:45 +0100 Subject: ALSA: hda - Add parse customize define function for Realtek codecs Added alc_auto_parse_customize_define() to parse the Realtek-specific attributes from SKU. Also enable beep controls only when the proper attribute bit is set. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 112 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4ec57633af88..245e1afa5896 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -275,6 +275,18 @@ struct alc_mic_route { #define MUX_IDX_UNDEF ((unsigned char)-1) +struct alc_customize_define { + unsigned int sku_cfg; + unsigned char port_connectivity; + unsigned char check_sum; + unsigned char customization; + unsigned char external_amp; + unsigned int enable_pcbeep:1; + unsigned int platform_type:1; + unsigned int swap:1; + unsigned int override:1; +}; + struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -332,6 +344,7 @@ struct alc_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; + struct alc_customize_define cdefine; struct snd_array kctls; struct hda_input_mux private_imux[3]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -1247,6 +1260,62 @@ static void alc_init_auto_mic(struct hda_codec *codec) spec->unsol_event = alc_sku_unsol_event; } +static int alc_auto_parse_customize_define(struct hda_codec *codec) +{ + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; + + ass = codec->subsystem_id & 0xffff; + if (ass != codec->bus->pci->subsystem_device && (ass & 1)) + goto do_sku; + + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + + if (!(ass & 1)) { + printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n", + codec->chip_name, ass); + return -1; + } + + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return -1; + + spec->cdefine.port_connectivity = ass >> 30; + spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20; + spec->cdefine.check_sum = (ass >> 16) & 0xf; + spec->cdefine.customization = ass >> 8; +do_sku: + spec->cdefine.sku_cfg = ass; + spec->cdefine.external_amp = (ass & 0x38) >> 3; + spec->cdefine.platform_type = (ass & 0x4) >> 2; + spec->cdefine.swap = (ass & 0x2) >> 1; + spec->cdefine.override = ass & 0x1; + + snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n", + nid, spec->cdefine.sku_cfg); + snd_printd("SKU: port_connectivity=0x%x\n", + spec->cdefine.port_connectivity); + snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); + snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); + snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization); + snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp); + snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type); + snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap); + snd_printd("SKU: override=0x%x\n", spec->cdefine.override); + + return 0; +} + /* check subsystem ID and set up device-specific initialization; * return 1 if initialized, 0 if invalid SSID */ @@ -3779,7 +3848,6 @@ static struct hda_codec_ops alc_patch_ops = { .reboot_notify = alc_shutup, }; - /* * Test configuration for debugging * @@ -10267,6 +10335,8 @@ static int patch_alc882(struct hda_codec *codec) codec->spec = spec; + alc_auto_parse_customize_define(codec); + switch (codec->vendor_id) { case 0x10ec0882: case 0x10ec0885: @@ -10362,7 +10432,9 @@ static int patch_alc882(struct hda_codec *codec) } set_capture_mixer(codec); - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + + if (spec->cdefine.enable_pcbeep) + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -12146,6 +12218,7 @@ static int patch_alc262(struct hda_codec *codec) snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); } #endif + alc_auto_parse_customize_define(codec); alc_fix_pll_init(codec, 0x20, 0x0a, 10); @@ -12224,7 +12297,7 @@ static int patch_alc262(struct hda_codec *codec) } if (!spec->cap_mixer && !spec->no_analog) set_capture_mixer(codec); - if (!spec->no_analog) + if (!spec->no_analog && spec->cdefine.enable_pcbeep) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -14094,6 +14167,8 @@ static int patch_alc269(struct hda_codec *codec) codec->spec = spec; + alc_auto_parse_customize_define(codec); + alc_fix_pll_init(codec, 0x20, 0x04, 15); if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ @@ -14164,7 +14239,8 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->cap_mixer) set_capture_mixer(codec); - set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + if (spec->cdefine.enable_pcbeep) + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); spec->vmaster_nid = 0x02; @@ -18314,6 +18390,8 @@ static int patch_alc662(struct hda_codec *codec) codec->spec = spec; + alc_auto_parse_customize_define(codec); + alc_fix_pll_init(codec, 0x20, 0x04, 15); if (alc_read_coef_idx(codec, 0)==0x8020){ @@ -18373,18 +18451,20 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->cap_mixer) set_capture_mixer(codec); - switch (codec->vendor_id) { - case 0x10ec0662: - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - break; - case 0x10ec0272: - case 0x10ec0663: - case 0x10ec0665: - set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - break; - case 0x10ec0273: - set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); - break; + if (spec->cdefine.enable_pcbeep) { + switch (codec->vendor_id) { + case 0x10ec0662: + set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + break; + case 0x10ec0272: + case 0x10ec0663: + case 0x10ec0665: + set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + break; + case 0x10ec0273: + set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT); + break; + } } spec->vmaster_nid = 0x02; -- cgit v1.2.3 From c027ddcd01c852dfa5880862e47f022d7d9402f5 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 19 Mar 2010 11:33:06 +0100 Subject: ALSA: hda - Add alc_codec_rename() helper Added alc_codec_rename() helper for renaming codec->chip_name. Added Acer-specific codec naming for ALC269/662. [Clean-up and refactoring by tiwai] Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 245e1afa5896..3d37e2161a57 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3848,6 +3848,18 @@ static struct hda_codec_ops alc_patch_ops = { .reboot_notify = alc_shutup, }; +/* replace the codec chip_name with the given string */ +static int alc_codec_rename(struct hda_codec *codec, const char *name) +{ + kfree(codec->chip_name); + codec->chip_name = kstrdup(name, GFP_KERNEL); + if (!codec->chip_name) { + alc_free(codec); + return -ENOMEM; + } + return 0; +} + /* * Test configuration for debugging * @@ -14169,17 +14181,15 @@ static int patch_alc269(struct hda_codec *codec) alc_auto_parse_customize_define(codec); - alc_fix_pll_init(codec, 0x20, 0x04, 15); - if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ - kfree(codec->chip_name); - codec->chip_name = kstrdup("ALC259", GFP_KERNEL); - if (!codec->chip_name) { - alc_free(codec); - return -ENOMEM; - } + if (codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) + alc_codec_rename(codec, "ALC271X"); + else + alc_codec_rename(codec, "ALC259"); is_alc269vb = 1; - } + } else + alc_fix_pll_init(codec, 0x20, 0x04, 15); board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, alc269_models, @@ -18394,14 +18404,12 @@ static int patch_alc662(struct hda_codec *codec) alc_fix_pll_init(codec, 0x20, 0x04, 15); - if (alc_read_coef_idx(codec, 0)==0x8020){ - kfree(codec->chip_name); - codec->chip_name = kstrdup("ALC661", GFP_KERNEL); - if (!codec->chip_name) { - alc_free(codec); - return -ENOMEM; - } - } + if (alc_read_coef_idx(codec, 0) == 0x8020) + alc_codec_rename(codec, "ALC661"); + else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) && + codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) + alc_codec_rename(codec, "ALC272X"); board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, alc662_models, -- cgit v1.2.3 From 7fb5622326bf98437e629e94f8710eb12a90b30d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 22 Mar 2010 17:09:47 +0100 Subject: ALSA: hda - Fix uninitialized variable warning in alc_auto_parse_customize_define() Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3d37e2161a57..3dc2be8f3ca9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1263,7 +1263,7 @@ static void alc_init_auto_mic(struct hda_codec *codec) static int alc_auto_parse_customize_define(struct hda_codec *codec) { unsigned int ass, tmp, i; - unsigned nid; + unsigned nid = 0; struct alc_spec *spec = codec->spec; ass = codec->subsystem_id & 0xffff; -- cgit v1.2.3 From cd508fe58b07499403e806b558c7f15c90442292 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 26 Mar 2010 10:28:46 +0100 Subject: ALSA: hda-intel - add special 'hwio' model to bypass initialization Using the 'model=hwio' option, the driver bypasses any codec initialization and the reset procedure for codecs is also bypassed. This mode is usefull to enable direct access using hwdep interface (using hdaverb or hda-analyzer tools) and retain codec setup from BIOS. Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/HD-Audio.txt | 5 +++++ sound/pci/hda/hda_codec.c | 10 ++++++++-- sound/pci/hda/hda_intel.c | 20 ++++++++++++-------- 3 files changed, 25 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index f4dd3bf99d12..ecacf53a8655 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -196,6 +196,11 @@ generic parser regardless of the codec. Usually the codec-specific parser is much better than the generic parser (as now). Thus this option is more about the debugging purpose. +Another special meaning has 'model=hwio'. For this model, the driver +bypasses any codec initialization and the reset procedure for codecs +is also bypassed. This mode is usefull to enable direct access using +hwdep interface (using hdaverb or hda-analyzer tools) and retain +codec setup from BIOS. Speaker and Headphone Output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0e76ac2b2ace..cf6280bdaa19 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -609,11 +609,15 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, } EXPORT_SYMBOL_HDA(snd_hda_bus_new); +#define is_hwio_config(codec) \ + (codec->modelname && !strcmp(codec->modelname, "hwio")) #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ - (codec->modelname && !strcmp(codec->modelname, "generic")) + ((codec->modelname && !strcmp(codec->modelname, "generic")) || \ + is_hwio_config(codec)) #else -#define is_generic_config(codec) 0 +#define is_generic_config(codec) \ + is_hwio_config(codec) #endif #ifdef MODULE @@ -1113,6 +1117,8 @@ int snd_hda_codec_configure(struct hda_codec *codec) } if (is_generic_config(codec)) { + if (is_hwio_config(codec)) + goto patched; err = snd_hda_parse_generic_codec(codec); goto patched; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8b2915631cc3..8d477613bccf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -858,10 +858,13 @@ static void azx_power_notify(struct hda_bus *bus); #endif /* reset codec link */ -static int azx_reset(struct azx *chip) +static int azx_reset(struct azx *chip, int full_reset) { int count; + if (!full_reset) + goto __skip; + /* clear STATESTS */ azx_writeb(chip, STATESTS, STATESTS_INT_MASK); @@ -887,6 +890,7 @@ static int azx_reset(struct azx *chip) /* Brent Chartrand said to wait >= 540us for codecs to initialize */ msleep(1); + __skip: /* check to see if controller is ready */ if (!azx_readb(chip, GCTL)) { snd_printd(SFX "azx_reset: controller not ready!\n"); @@ -998,13 +1002,13 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) /* * reset and start the controller registers */ -static void azx_init_chip(struct azx *chip) +static void azx_init_chip(struct azx *chip, int full_reset) { if (chip->initialized) return; /* reset controller */ - azx_reset(chip); + azx_reset(chip, full_reset); /* initialize interrupts */ azx_int_clear(chip); @@ -1348,7 +1352,7 @@ static void azx_bus_reset(struct hda_bus *bus) bus->in_reset = 1; azx_stop_chip(chip); - azx_init_chip(chip); + azx_init_chip(chip, 1); #ifdef CONFIG_PM if (chip->initialized) { int i; @@ -1422,7 +1426,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) * get back to the sanity state. */ azx_stop_chip(chip); - azx_init_chip(chip); + azx_init_chip(chip, 1); } } } @@ -2112,7 +2116,7 @@ static void azx_power_notify(struct hda_bus *bus) } } if (power_on) - azx_init_chip(chip); + azx_init_chip(chip, 1); else if (chip->running && power_save_controller && !bus->power_keep_link_on) azx_stop_chip(chip); @@ -2182,7 +2186,7 @@ static int azx_resume(struct pci_dev *pci) azx_init_pci(chip); if (snd_hda_codecs_inuse(chip->bus)) - azx_init_chip(chip); + azx_init_chip(chip, 1); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2573,7 +2577,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, /* initialize chip */ azx_init_pci(chip); - azx_init_chip(chip); + azx_init_chip(chip, model[dev] == NULL || strcmp(model[dev], "hwio")); /* codec detection */ if (!chip->codec_mask) { -- cgit v1.2.3 From 0bf0e5a6f304ac1bc93a80cdd68b4d91f3519eb5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 26 Mar 2010 10:33:18 +0100 Subject: ALSA: hda-intel - AD1984 thinkpad - add analog beep input control For Lenovo Thinkpad T61/X61, the analog beep input is connected to node 0x20, index 3. Move the digital beep mute/volume controls as "Digital Beep" and create analog beep controls for mentioned node. Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index e6d1bdff1b6e..262f5b5decf1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -71,9 +71,10 @@ struct ad198x_spec { struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - unsigned int jack_present :1; - unsigned int inv_jack_detect:1; /* inverted jack-detection */ - unsigned int inv_eapd:1; /* inverted EAPD implementation */ + unsigned int jack_present: 1; + unsigned int inv_jack_detect: 1;/* inverted jack-detection */ + unsigned int inv_eapd: 1; /* inverted EAPD implementation */ + unsigned int analog_beep: 1; /* analog beep input present */ #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; @@ -165,6 +166,12 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new ad_beep2_mixer[] = { + HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), + { } /* end */ +}; + #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ #else @@ -203,7 +210,8 @@ static int ad198x_build_controls(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_BEEP if (spec->beep_amp) { struct snd_kcontrol_new *knew; - for (knew = ad_beep_mixer; knew->name; knew++) { + knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; + for ( ; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); if (!kctl) @@ -3482,6 +3490,8 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), @@ -3523,6 +3533,8 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* docking mic boost */ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* Analog PC Beeper - allow firmware/ACPI beeps */ + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, /* Analog mixer - docking mic; mute as default */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* enable EAPD bit */ @@ -3655,6 +3667,7 @@ static int patch_ad1984(struct hda_codec *codec) spec->input_mux = &ad1984_thinkpad_capture_source; spec->mixers[0] = ad1984_thinkpad_mixers; spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; + spec->analog_beep = 1; break; case AD1984_DELL_DESKTOP: spec->multiout.dig_out_nid = 0; -- cgit v1.2.3 From 10e77ddac0e1f3b9cea04dfe8180f8641f329703 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 26 Mar 2010 11:04:38 +0100 Subject: ALSA: hda-intel - remove model=hwio , use probe_only=3 instead The probe_only module parameter skips the codec initialization, too. Remove the model=hwio code and use second bit in probe_only to skip the HDA codec reset procedure. Signed-off-by: Jaroslav Kysela --- Documentation/sound/alsa/HD-Audio.txt | 3 +++ sound/pci/hda/hda_codec.c | 10 ++-------- sound/pci/hda/hda_intel.c | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index ecacf53a8655..232a90775229 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -597,6 +597,9 @@ probing, the proc file is available, so you can get the raw codec information before modified by the driver. Of course, the driver isn't usable with `probe_only=1`. But you can continue the configuration via hwdep sysfs file if hda-reconfig option is enabled. +Using `probe_only` mask 2 skips the reset of HDA codecs (use +`probe_only=3` as module option). The hwdep interface can be used +to determine the BIOS codec initialization. hda-verb diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index cf6280bdaa19..0e76ac2b2ace 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -609,15 +609,11 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, } EXPORT_SYMBOL_HDA(snd_hda_bus_new); -#define is_hwio_config(codec) \ - (codec->modelname && !strcmp(codec->modelname, "hwio")) #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ - ((codec->modelname && !strcmp(codec->modelname, "generic")) || \ - is_hwio_config(codec)) + (codec->modelname && !strcmp(codec->modelname, "generic")) #else -#define is_generic_config(codec) \ - is_hwio_config(codec) +#define is_generic_config(codec) 0 #endif #ifdef MODULE @@ -1117,8 +1113,6 @@ int snd_hda_codec_configure(struct hda_codec *codec) } if (is_generic_config(codec)) { - if (is_hwio_config(codec)) - goto patched; err = snd_hda_parse_generic_codec(codec); goto patched; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8d477613bccf..6ce673c17ff2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2577,7 +2577,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, /* initialize chip */ azx_init_pci(chip); - azx_init_chip(chip, model[dev] == NULL || strcmp(model[dev], "hwio")); + azx_init_chip(chip, (probe_only[dev] & 2) == 0); /* codec detection */ if (!chip->codec_mask) { @@ -2666,7 +2666,7 @@ static int __devinit azx_probe(struct pci_dev *pci, goto out_free; } #endif - if (!probe_only[dev]) { + if ((probe_only[dev] & 1) == 0) { err = azx_codec_configure(chip); if (err < 0) goto out_free; -- cgit v1.2.3 From 079e683ebd882655b6d6e0b17989e51bae2d77d6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 26 Mar 2010 11:16:59 +0100 Subject: ALSA: hda-intel - probe_only module option is int type now Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6ce673c17ff2..a33c1c50b310 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -84,7 +84,7 @@ module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); -module_param_array(probe_only, bool, NULL, 0444); +module_param_array(probe_only, int, NULL, 0444); MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " -- cgit v1.2.3 From 467126460818e287aa92c73232c38453ec2ab013 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Mar 2010 09:19:38 +0200 Subject: ALSA: hda - Report errors when invalid values are passed to snd_hda_amp_*() The values should be in 8 bits. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d72bcff8d271..d1424e7b9f3d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1461,6 +1461,8 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); if (!info) return 0; + if (snd_BUG_ON(mask & ~0xff)) + mask &= 0xff; val &= mask; val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; if (info->vol[ch] == val) @@ -1486,6 +1488,9 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int direction, int idx, int mask, int val) { int ch, ret = 0; + + if (snd_BUG_ON(mask & ~0xff)) + mask &= 0xff; for (ch = 0; ch < 2; ch++) ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, idx, mask, val); -- cgit v1.2.3 From ad35879aa192e783db2d41c196f48f3fc059ce22 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Mar 2010 18:00:59 +0200 Subject: ALSA: hda - Add mute LED support for HP laptop with ALC269 Some HP laptops have a mute LED that is controlled over the unused MIC2 VREF pin. Implement the LED updater like patch_sigmatel.c for this model. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1694f60631a1..9a361c2c7336 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3467,6 +3467,10 @@ static int alc_init(struct hda_codec *codec) if (spec->init_hook) spec->init_hook(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, 0x01); +#endif return 0; } @@ -3827,6 +3831,10 @@ static int alc_resume(struct hda_codec *codec) codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, 0x01); +#endif return 0; } #endif @@ -13983,6 +13991,34 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { /* NID is set in alc_build_pcms */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_mic2_for_mute_led(struct hda_codec *codec) +{ + switch (codec->subsystem_id) { + case 0x103c1586: + return 1; + } + return 0; +} + +static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) +{ + /* update mute-LED according to the speaker mute state */ + if (nid == 0x01 || nid == 0x14) { + int pinval; + if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + pinval = 0x24; + else + pinval = 0x20; + /* mic2 vref pin is used for mute LED control */ + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinval); + } + return alc_check_power_status(codec, nid); +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + /* * BIOS auto configuration */ @@ -14330,6 +14366,8 @@ static int patch_alc269(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; + if (alc269_mic2_for_mute_led(codec)) + codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; #endif return 0; -- cgit v1.2.3 From a68d5a5419d2a15161488b20f740115068e7b666 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Mar 2010 18:03:44 +0200 Subject: ALSA: hda - introduce snd_hda_codec_update_cache() Add a new helper, snd_hda_codec_update_cache(), for reducing the unneeded verbs. This function checks the cached value and skips if it's identical with the given one. Otherwise it works like snd_hda_codec_write_cache(). The alc269 code uses this function as an example. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 68 +++++++++++++++++++++++++++++++++++-------- sound/pci/hda/hda_codec.h | 3 ++ sound/pci/hda/patch_realtek.c | 5 ++-- 3 files changed, 62 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d1424e7b9f3d..a3d638c8c1fd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache) } /* query the hash. allocate an entry if not found. */ -static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, - u32 key) +static struct hda_cache_head *get_hash(struct hda_cache_rec *cache, u32 key) { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; @@ -1222,17 +1221,27 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, return info; cur = info->next; } + return NULL; +} - /* add a new hash entry */ - info = snd_array_new(&cache->buf); - if (!info) - return NULL; - cur = snd_array_index(&cache->buf, info); - info->key = key; - info->val = 0; - info->next = cache->hash[idx]; - cache->hash[idx] = cur; - +/* query the hash. allocate an entry if not found. */ +static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, + u32 key) +{ + struct hda_cache_head *info = get_hash(cache, key); + if (!info) { + u16 idx, cur; + /* add a new hash entry */ + info = snd_array_new(&cache->buf); + if (!info) + return NULL; + cur = snd_array_index(&cache->buf, info); + info->key = key; + info->val = 0; + idx = key % (u16)ARRAY_SIZE(cache->hash); + info->next = cache->hash[idx]; + cache->hash[idx] = cur; + } return info; } @@ -2721,6 +2730,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); +/** + * snd_hda_codec_update_cache - check cache and write the cmd only when needed + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * This function works like snd_hda_codec_write_cache(), but it doesn't send + * command if the parameter is already identical with the cached value. + * If not, it sends the command and refreshes the cache. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + struct hda_cache_head *c; + u32 key; + + /* parm may contain the verb stuff for get/set amp */ + verb = verb | (parm >> 8); + parm &= 0xff; + key = build_cmd_cache_key(nid, verb); + mutex_lock(&codec->bus->cmd_mutex); + c = get_hash(&codec->cmd_cache, key); + if (c && c->val == parm) { + mutex_unlock(&codec->bus->cmd_mutex); + return 0; + } + mutex_unlock(&codec->bus->cmd_mutex); + return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); + /** * snd_hda_codec_resume_cache - Resume the all commands from the cache * @codec: HD-audio codec diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b75da47571e6..49e939e7e5cd 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, const struct hda_verb *seq); +int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); void snd_hda_codec_resume_cache(struct hda_codec *codec); #else #define snd_hda_codec_write_cache snd_hda_codec_write +#define snd_hda_codec_update_cache snd_hda_codec_write #define snd_hda_sequence_write_cache snd_hda_sequence_write #endif diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a361c2c7336..8ae48061e8c7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14012,8 +14012,9 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) else pinval = 0x20; /* mic2 vref pin is used for mute LED control */ - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinval); + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); } return alc_check_power_status(codec, nid); } -- cgit v1.2.3 From 489008cd58740fe3842822681d33bf87c07c3412 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Apr 2010 09:06:00 +0200 Subject: ALSA: hda - Fix ALC882 DAC connections in auto mode Assign DACs properly to each output. Currently, the front output is bound to HP/speaker outputs blindly, but they should be assigned to individual DACs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 45 +++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c9c31c51863f..f4ca9b2d8784 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10191,21 +10191,21 @@ static int alc882_auto_create_input_ctls(struct hda_codec *codec, static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, - int dac_idx) + hda_nid_t dac) { - /* set as output */ - struct alc_spec *spec = codec->spec; int idx; + printk("XXX set output pin %x, dac %x\n", nid, dac); + /* set as output */ alc_set_pin_output(codec, nid, pin_type); - if (dac_idx >= spec->multiout.num_dacs) - return; - if (spec->multiout.dac_nids[dac_idx] == 0x25) + + if (dac == 0x25) idx = 4; + else if (dac >= 0x02 && dac <= 0x05) + idx = dac - 2; else - idx = spec->multiout.dac_nids[dac_idx] - 2; + return; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); - } static void alc882_auto_init_multi_out(struct hda_codec *codec) @@ -10218,22 +10218,29 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) int pin_type = get_pin_type(spec->autocfg.line_out_type); if (nid) alc882_auto_set_output_and_unmute(codec, nid, pin_type, - i); + spec->multiout.dac_nids[i]); } } static void alc882_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t pin; + hda_nid_t pin, dac; pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + if (pin) { + dac = spec->multiout.hp_nid; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + } pin = spec->autocfg.speaker_pins[0]; - if (pin) - alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + if (pin) { + dac = spec->multiout.extra_out_nid[0]; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + } } static void alc882_auto_init_analog_input(struct hda_codec *codec) @@ -10347,6 +10354,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); if (err < 0) return err; err = alc880_auto_create_extra_out(spec, @@ -10354,10 +10365,6 @@ static int alc882_parse_auto_config(struct hda_codec *codec) "Speaker"); if (err < 0) return err; - err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], - "Headphone"); - if (err < 0) - return err; err = alc882_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; -- cgit v1.2.3 From 25e8d9b67b206b8bf9bf11699d1a7e67c87c1a2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Apr 2010 14:53:00 +0200 Subject: ALSA: hda - Remove left-over debug printk in patch_realtek.c Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f4ca9b2d8784..836103081925 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10195,7 +10195,6 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, { int idx; - printk("XXX set output pin %x, dac %x\n", nid, dac); /* set as output */ alc_set_pin_output(codec, nid, pin_type); -- cgit v1.2.3 From 7b2bfdbc0dee5a321b5c02febe157adebd33ab3a Mon Sep 17 00:00:00 2001 From: Jens Taprogge Date: Wed, 14 Apr 2010 23:42:04 +0200 Subject: ALSA: hda - Add initial support for Thinkpad T410s HDA codec attached please find a patch that adds support for at least the T410s HDA codec. Most likely it will also add support for the T410 and T510 based models. The patch was derived from Ideapad support. Support for the laptop's and docking-station output connectors as well as the docking-station microphone connector and the laptops internal devices has been tested. Since it has been developed without a data-sheet available, support for digital outputs and the laptop's microphone input may well be incorrect. Microphone mute functionality is not included: The microphone mute button seems to be reported through thinkpad_acpi key 0000101b. The mute button LED seems to be wired to thinkpad_acpi led number 15. Signed-off-by: Jens Taprogge Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 153 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 61682e1d09da..509a1049ff40 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -115,6 +115,7 @@ struct conexant_spec { unsigned int port_d_mode; unsigned int dell_vostro:1; unsigned int ideapad:1; + unsigned int thinkpad:1; unsigned int ext_mic_present; unsigned int recording; @@ -2031,6 +2032,9 @@ static void cxt5066_update_speaker(struct hda_codec *codec) /* Port D (HP/LO) */ pinctl = ((spec->hp_present & 2) && spec->cur_eapd) ? spec->port_d_mode : 0; + /* Mute if Port A is connected on Thinkpad */ + if (spec->thinkpad && (spec->hp_present & 1)) + pinctl = 0; snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); @@ -2211,6 +2215,50 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) } } +/* toggle input of built-in digital mic and mic jack appropriately + order is: external mic -> dock mic -> interal mic */ +static void cxt5066_thinkpad_automic(struct hda_codec *codec) +{ + unsigned int ext_present, dock_present; + + static struct hda_verb ext_mic_present[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0}, + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb dock_mic_present[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb ext_mic_absent[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + + ext_present = snd_hda_jack_detect(codec, 0x1b); + dock_present = snd_hda_jack_detect(codec, 0x1a); + if (ext_present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present); + } else if (dock_present) { + snd_printdd("CXT5066: dock microphone detected\n"); + snd_hda_sequence_write(codec, dock_mic_present); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent); + } +} + /* mute internal speaker if HP is plugged */ static void cxt5066_hp_automute(struct hda_codec *codec) { @@ -2223,7 +2271,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec) /* Port D */ portD = snd_hda_jack_detect(codec, 0x1c); - spec->hp_present = !!(portA | portD); + spec->hp_present = !!(portA); + spec->hp_present |= portD ? 2 : 0; snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", portA, portD, spec->hp_present); cxt5066_update_speaker(codec); @@ -2274,6 +2323,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) } } +/* unsolicited event for jack sensing */ +static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_thinkpad_automic(codec); + break; + } +} + static const struct hda_input_mux cxt5066_analog_mic_boost = { .num_items = 5, .items = { @@ -2292,7 +2355,7 @@ static void cxt5066_set_mic_boost(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | cxt5066_analog_mic_boost.items[spec->mic_boost].index); - if (spec->ideapad) { + if (spec->ideapad || spec->thinkpad) { /* adjust the internal mic as well...it is not through 0x17 */ snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -2780,6 +2843,64 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { { } /* end */ }; +static struct hda_verb cxt5066_init_verbs_thinkpad[] = { + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ + + /* Port G: internal speakers */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* Port A: HP, Amp */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* Port B: Mic Dock */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Port C: Mic */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Port D: HP Dock, Amp */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ + + /* Audio input selector */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ + + /* SPDIF route: PCM */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* internal microphone */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ + + /* EAPD */ + {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + + /* enable unsolicited events for Port A, B, C and D */ + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + { } /* end */ +}; + static struct hda_verb cxt5066_init_verbs_portd_lo[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } /* end */ @@ -2798,6 +2919,8 @@ static int cxt5066_init(struct hda_codec *codec) cxt5066_vostro_automic(codec); else if (spec->ideapad) cxt5066_ideapad_automic(codec); + else if (spec->thinkpad) + cxt5066_thinkpad_automic(codec); } cxt5066_set_mic_boost(codec); return 0; @@ -2819,20 +2942,22 @@ static int cxt5066_olpc_init(struct hda_codec *codec) } enum { - CXT5066_LAPTOP, /* Laptops w/ EAPD support */ + CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ + CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ CXT5066_MODELS }; static const char *cxt5066_models[CXT5066_MODELS] = { - [CXT5066_LAPTOP] = "laptop", + [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", [CXT5066_DELL_VOSTO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", + [CXT5066_THINKPAD] = "thinkpad", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -2843,6 +2968,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 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(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), {} }; @@ -2947,6 +3073,22 @@ static int patch_cxt5066(struct hda_codec *codec) /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ + spec->input_mux = NULL; + break; + case CXT5066_THINKPAD: + codec->patch_ops.init = cxt5066_init; + codec->patch_ops.unsol_event = cxt5066_thinkpad_event; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; + spec->thinkpad = 1; + spec->port_d_mode = PIN_OUT; + spec->mic_boost = 2; /* default 20dB gain */ + + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ spec->input_mux = NULL; break; @@ -2969,6 +3111,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5066 }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", .patch = patch_cxt5066 }, + { .id = 0x14f15069, .name = "CX20585", + .patch = patch_cxt5066 }, {} /* terminator */ }; @@ -2977,6 +3121,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047"); MODULE_ALIAS("snd-hda-codec-id:14f15051"); MODULE_ALIAS("snd-hda-codec-id:14f15066"); MODULE_ALIAS("snd-hda-codec-id:14f15067"); +MODULE_ALIAS("snd-hda-codec-id:14f15069"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); -- cgit v1.2.3 From ef5dbbccbbfa7d2211fa8efcc095a9f4a7912dda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 May 2010 08:40:25 +0200 Subject: ALSA: hda - Remove superfluous external amp setup for ALC888 We had a fixed external amp setup enabled for ALC888, but this seems unnecessary. The amps are controlled rather by GPIOs. Let's remove it now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2078a1ac0f10..2b0131fb026d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10580,9 +10580,6 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; - if (codec->vendor_id == 0x10ec0888) - spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ - if (!spec->adc_nids && spec->input_mux) { int i, j; spec->num_adc_nids = 0; -- cgit v1.2.3 From 1965c441ecf1f9cd723dd590cbb6c191cfc13fb2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 6 May 2010 16:37:03 -0500 Subject: ALSA: hda: enable SPDIF output for Conexant 5051/Lenovo docking stations This patch enables the SPDIF output pin by default. It also enables it for quirks related to Levono docking stations (x200 and 25041, identified with the same 17aa:20f2 ID). Even though not all Lenovo docking stations have SPDIF connectors, enabling the pin by default shouldn't be a problem for anyone. Other quirks remain unmodified. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 114af8e19d80..0aa122e26dc8 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1784,6 +1784,7 @@ static struct hda_verb cxt5051_init_verbs[] = { {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, /* SPDIF route: PCM */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ @@ -1840,6 +1841,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, /* SPDIF route: PCM */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */ {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, /* EAPD */ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ @@ -1911,7 +1913,7 @@ enum { CXT5051_LAPTOP, /* Laptops w/ EAPD support */ CXT5051_HP, /* no docking */ CXT5051_HP_DV6736, /* HP without mic switch */ - CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ + CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_MODELS -- cgit v1.2.3 From beaffc399397eb9427225f37c1e56c099571b2df Mon Sep 17 00:00:00 2001 From: Shahin Ghazinouri Date: Tue, 11 May 2010 08:19:55 +0200 Subject: ALSA: hda - Fixes distorted recording on US15W chipset The HDA controller in US15W (Poulsbo) reports inaccurate position values for capture streams when using the LPIB read method, resulting in distorted recordings. However, using the position buffer is broken for playback streams, resulting in a fallback to the LPIB method with the current driver. This patch works around the issue by independently detecting the read position method for capture and playback streams. The patch will not have any effect if the position fix method is explicitly set. [Code simplified by tiwai] Signed-off-by: Shahin Ghazinouri Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 236b4caa142f..cad9b70c27a0 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -425,7 +425,7 @@ struct azx { struct snd_dma_buffer posbuf; /* flags */ - int position_fix; + int position_fix[2]; /* for both playback/capture streams */ int poll_count; unsigned int running :1; unsigned int initialized :1; @@ -1306,8 +1306,10 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); /* enable the position buffer */ - if (chip->position_fix == POS_FIX_POSBUF || - chip->position_fix == POS_FIX_AUTO || + if (chip->position_fix[0] == POS_FIX_POSBUF || + chip->position_fix[0] == POS_FIX_AUTO || + chip->position_fix[1] == POS_FIX_POSBUF || + chip->position_fix[1] == POS_FIX_AUTO || chip->via_dmapos_patch) { if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) azx_writel(chip, DPLBASE, @@ -1847,13 +1849,16 @@ static unsigned int azx_get_position(struct azx *chip, if (chip->via_dmapos_patch) pos = azx_via_get_position(chip, azx_dev); - else if (chip->position_fix == POS_FIX_POSBUF || - chip->position_fix == POS_FIX_AUTO) { - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - } else { - /* read LPIB */ - pos = azx_sd_readl(azx_dev, SD_LPIB); + else { + int stream = azx_dev->substream->stream; + if (chip->position_fix[stream] == POS_FIX_POSBUF || + chip->position_fix[stream] == POS_FIX_AUTO) { + /* use the position buffer */ + pos = le32_to_cpu(*azx_dev->posbuf); + } else { + /* read LPIB */ + pos = azx_sd_readl(azx_dev, SD_LPIB); + } } if (pos >= azx_dev->bufsize) pos = 0; @@ -1881,22 +1886,24 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { unsigned int pos; + int stream; if (azx_dev->start_flag && time_before_eq(jiffies, azx_dev->start_jiffies)) return -1; /* bogus (too early) interrupt */ azx_dev->start_flag = 0; + stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev); - if (chip->position_fix == POS_FIX_AUTO) { + if (chip->position_fix[stream] == POS_FIX_AUTO) { if (!pos) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " "using LPIB read method instead.\n"); - chip->position_fix = POS_FIX_LPIB; + chip->position_fix[stream] = POS_FIX_LPIB; pos = azx_get_position(chip, azx_dev); } else - chip->position_fix = POS_FIX_POSBUF; + chip->position_fix[stream] = POS_FIX_POSBUF; } if (!bdl_pos_adj[chip->dev_index]) @@ -2435,7 +2442,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); - chip->position_fix = check_position_fix(chip, position_fix[dev]); + chip->position_fix[0] = chip->position_fix[1] = + check_position_fix(chip, position_fix[dev]); check_probe_mask(chip, dev); chip->single_cmd = single_cmd; -- cgit v1.2.3 From e54637205b00837bf00de916b0ae361c6aa0b139 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 11 May 2010 10:21:46 +0200 Subject: [ALSA] snd-hda-intel: use WALLCLK register to check for early irqs Use 24Mhz WALLCLK register to ignore too early interrupts and wrong interrupt status. The bad timing confuses the higher ALSA layer and causes audio skipping. More information about behaviour and debugging can be found in kernel bz#15912. https://bugzilla.kernel.org/show_bug.cgi?id=15912 Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cad9b70c27a0..0a6c55bb7d6b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -174,7 +174,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define ICH6_GSTS_FSTS (1 << 1) /* flush status */ #define ICH6_REG_INTCTL 0x20 #define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALCLK 0x30 +#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ #define ICH6_REG_SYNC 0x34 #define ICH6_REG_CORBLBASE 0x40 #define ICH6_REG_CORBUBASE 0x44 @@ -340,8 +340,8 @@ struct azx_dev { unsigned int period_bytes; /* size of the period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ - unsigned long start_jiffies; /* start + minimum jiffies */ - unsigned long min_jiffies; /* minimum jiffies before position is valid */ + unsigned long start_wallclk; /* start + minimum wallclk */ + unsigned long period_wallclk; /* wallclk for period */ void __iomem *sd_addr; /* stream descriptor pointer */ @@ -361,7 +361,6 @@ struct azx_dev { unsigned int opened :1; unsigned int running :1; unsigned int irq_pending :1; - unsigned int start_flag: 1; /* stream full start flag */ /* * For VIA: * A flag to ensure DMA position is 0 @@ -1676,8 +1675,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) return err; } - azx_dev->min_jiffies = (runtime->period_size * HZ) / - (runtime->rate * 2); + /* wallclk has 24Mhz clock source */ + azx_dev->period_wallclk = (((runtime->period_size * 24000) / + runtime->rate) * 1000); azx_setup_controller(chip, azx_dev); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; @@ -1731,14 +1731,15 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (s->pcm->card != substream->pcm->card) continue; azx_dev = get_azx_dev(s); - if (rstart) { - azx_dev->start_flag = 1; - azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; - } - if (start) + if (start) { + azx_dev->start_wallclk = azx_readl(chip, WALLCLK); + if (!rstart) + azx_dev->start_wallclk -= + azx_dev->period_wallclk; azx_stream_start(chip, azx_dev); - else + } else { azx_stream_stop(chip, azx_dev); + } azx_dev->running = start; } spin_unlock(&chip->reg_lock); @@ -1885,13 +1886,14 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { + u32 wallclk; unsigned int pos; int stream; - if (azx_dev->start_flag && - time_before_eq(jiffies, azx_dev->start_jiffies)) + wallclk = azx_readl(chip, WALLCLK); + if ((wallclk - azx_dev->start_wallclk) < + (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - azx_dev->start_flag = 0; stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev); @@ -1906,13 +1908,12 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) chip->position_fix[stream] = POS_FIX_POSBUF; } - if (!bdl_pos_adj[chip->dev_index]) - return 1; /* no delayed ack */ if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) return 0; /* this shouldn't happen! */ if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) return 0; /* NG - it's below the period boundary */ + azx_dev->start_wallclk = wallclk; return 1; /* OK, it's fine */ } @@ -1922,7 +1923,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) static void azx_irq_pending_work(struct work_struct *work) { struct azx *chip = container_of(work, struct azx, irq_pending_work); - int i, pending; + int i, pending, ok; if (!chip->irq_pending_warned) { printk(KERN_WARNING @@ -1941,11 +1942,14 @@ static void azx_irq_pending_work(struct work_struct *work) !azx_dev->substream || !azx_dev->running) continue; - if (azx_position_ok(chip, azx_dev)) { + ok = azx_position_ok(chip, azx_dev); + if (ok > 0) { azx_dev->irq_pending = 0; spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); + } else if (ok < 0) { + pending = 0; /* too early */ } else pending++; } -- cgit v1.2.3 From f48f606d9f85a8b25c716082c73c36e9ff6f0cde Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 11 May 2010 12:10:47 +0200 Subject: [ALSA] snd-hda-intel: Improve azx_position_ok() Add back the zero return value (activate workqueue) when bdl_pos_adj is nonzero for position check. Do the position related check only for first next period using wallclk counter. Return -1 value (ignore interrupt) when period_bytes variable is zero. Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0a6c55bb7d6b..170610e1d7da 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1890,9 +1890,8 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) unsigned int pos; int stream; - wallclk = azx_readl(chip, WALLCLK); - if ((wallclk - azx_dev->start_wallclk) < - (azx_dev->period_wallclk * 2) / 3) + wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; + if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ stream = azx_dev->substream->stream; @@ -1910,9 +1909,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) - return 0; /* this shouldn't happen! */ - if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) - return 0; /* NG - it's below the period boundary */ + return -1; /* this shouldn't happen! */ + if (wallclk <= azx_dev->period_wallclk && + pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) + /* NG - it's below the first next period boundary */ + return bdl_pos_adj[chip->dev_index] ? 0 : -1; azx_dev->start_wallclk = wallclk; return 1; /* OK, it's fine */ } -- cgit v1.2.3 From e9abf85fe1fb0cd1da19ec231f2d6873e4af9fbd Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 14 May 2010 16:36:12 +0800 Subject: ALSA: intelhdmi - add dependency on SND_DYNAMIC_MINORS This is necessary to support >=3 HDMI playback devices starting from the CougarPoint codec. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 567348b05b5a..9194c3c1d04a 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -145,6 +145,7 @@ config SND_HDA_CODEC_NVHDMI config SND_HDA_CODEC_INTELHDMI bool "Build INTEL HDMI HD-audio codec support" + select SND_DYNAMIC_MINORS default y help Say Y here to include INTEL HDMI HD-audio codec support in -- cgit v1.2.3 From 41da2e0a01bf13986a561d8a16929d009eb9099c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 14 May 2010 16:36:13 +0800 Subject: ALSA: intelhdmi - user friendly codec name Use the full chipset codename as codec name. They are more user friendly than the spec abbrs. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 88d035104cc5..433224d28b99 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -185,14 +185,14 @@ static int patch_intel_hdmi(struct hda_codec *codec) } static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { - { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, - { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, - { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, - { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, - { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, - { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi }, - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, - {} /* terminator */ +{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, +{} /* terminator */ }; MODULE_ALIAS("snd-hda-codec-id:808629fb"); -- cgit v1.2.3 From e48b00870f269541c28bec8d457904a04545d5e5 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 14 May 2010 16:36:14 +0800 Subject: ALSA: intelhdmi - add id for the CougarPoint chipset Add id for Intel CougarPoint HDMI audio codec. CougarPoint provides 3 Audio Converters. Increase MAX_HDMI_CVTS/MAX_HDMI_PINS accordingly. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 433224d28b99..b81d23e42ace 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -40,7 +40,7 @@ * * The HDA correspondence of pipes/ports are converter/pin nodes. */ -#define MAX_HDMI_CVTS 2 +#define MAX_HDMI_CVTS 3 #define MAX_HDMI_PINS 3 #include "patch_hdmi.c" @@ -48,6 +48,7 @@ static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { "INTEL HDMI 0", "INTEL HDMI 1", + "INTEL HDMI 2", }; /* @@ -191,6 +192,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi }, { .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, { .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, +{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; @@ -200,6 +202,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801"); MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862804"); +MODULE_ALIAS("snd-hda-codec-id:80862805"); MODULE_ALIAS("snd-hda-codec-id:80860054"); MODULE_ALIAS("snd-hda-codec-id:10951392"); -- cgit v1.2.3 From 3eaead579ebc09d4f4c050c9b6ce6d67337bcb20 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 14 May 2010 16:36:15 +0800 Subject: ALSA: hdmi - dont fail on extra nodes The number of HDMI nodes is expected to go up in future. So don't fail hard on seeing extra converter/pin nodes. We can still operate safely on the nodes within MAX_HDMI_CVTS/MAX_HDMI_PINS. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2c2bafbf0258..86067ee78632 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -766,7 +766,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (spec->num_pins >= MAX_HDMI_PINS) { snd_printk(KERN_WARNING "HDMI: no space for pin %d\n", pin_nid); - return -EINVAL; + return -E2BIG; } hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); @@ -788,7 +788,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) if (spec->num_cvts >= MAX_HDMI_CVTS) { snd_printk(KERN_WARNING "HDMI: no space for converter %d\n", nid); - return -EINVAL; + return -E2BIG; } spec->cvt[spec->num_cvts] = nid; @@ -820,15 +820,13 @@ static int hdmi_parse_codec(struct hda_codec *codec) switch (type) { case AC_WID_AUD_OUT: - if (hdmi_add_cvt(codec, nid) < 0) - return -EINVAL; + hdmi_add_cvt(codec, nid); 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; + hdmi_add_pin(codec, nid); break; } } -- cgit v1.2.3 From fbc256692eac29e04cf87e45736d7ff149180a52 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 20 May 2010 10:40:55 +0200 Subject: ALSA: hda: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 80a183f99eb3..53538b0f9991 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14207,7 +14207,7 @@ enum { ALC269_FIXUP_SONY_VAIO, }; -const static struct hda_verb alc269_sony_vaio_fixup_verbs[] = { +static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, {} }; -- cgit v1.2.3