Merge branch 'fix/hda' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Wed, 19 Aug 2009 10:11:06 +0000 (12:11 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 19 Aug 2009 10:11:06 +0000 (12:11 +0200)
1  2 
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_sigmatel.c

@@@ -72,7 -72,6 +72,7 @@@ struct ad198x_spec 
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
  
        unsigned int jack_present :1;
 +      unsigned int inv_jack_detect:1;
  
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
@@@ -670,13 -669,39 +670,13 @@@ static struct hda_input_mux ad1986a_aut
        },
  };
  
 -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 +static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 -      HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
 -      {
 -              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 -              .name = "Capture Source",
 -              .info = ad198x_mux_enum_info,
 -              .get = ad198x_mux_enum_get,
 -              .put = ad198x_mux_enum_put,
 -      },
 -      {
 -              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 -              .name = "External Amplifier",
 -              .info = ad198x_eapd_info,
 -              .get = ad198x_eapd_get,
 -              .put = ad198x_eapd_put,
 -              .private_value = 0x1b | (1 << 8), /* port-D, inversed */
 -      },
        { } /* end */
  };
  
 -static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
 -      HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 -      HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 +static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        { } /* end */
  };
  
 +static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
 +      HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
 +      HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
 +      { } /* end */
 +};
 +
  /* re-connect the mic boost input according to the jack sensing */
  static void ad1986a_automic(struct hda_codec *codec)
  {
@@@ -757,9 -776,8 +757,9 @@@ static void ad1986a_hp_automute(struct 
        unsigned int present;
  
        present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
 -      /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
 -      spec->jack_present = !(present & 0x80000000);
 +      spec->jack_present = !!(present & 0x80000000);
 +      if (spec->inv_jack_detect)
 +              spec->jack_present = !spec->jack_present;
        ad1986a_update_hp(codec);
  }
  
@@@ -798,7 -816,7 +798,7 @@@ static int ad1986a_hp_master_sw_put(str
        return change;
  }
  
 -static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
 +static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .put = ad1986a_hp_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
        },
 -      HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
 -      {
 -              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 -              .name = "Capture Source",
 -              .info = ad198x_mux_enum_info,
 -              .get = ad198x_mux_enum_get,
 -              .put = ad198x_mux_enum_put,
 -      },
 -      {
 -              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 -              .name = "External Amplifier",
 -              .info = ad198x_eapd_info,
 -              .get = ad198x_eapd_get,
 -              .put = ad198x_eapd_put,
 -              .private_value = 0x1b | (1 << 8), /* port-D, inversed */
 -      },
        { } /* end */
  };
  
 +
  /*
   * initialization verbs
   */
@@@ -940,27 -981,6 +940,27 @@@ static struct hda_verb ad1986a_hp_init_
        {}
  };
  
 +static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
 +                                          unsigned int res)
 +{
 +      switch (res >> 26) {
 +      case AD1986A_HP_EVENT:
 +              ad1986a_hp_automute(codec);
 +              break;
 +      case AD1986A_MIC_EVENT:
 +              ad1986a_automic(codec);
 +              break;
 +      }
 +}
 +
 +static int ad1986a_samsung_p50_init(struct hda_codec *codec)
 +{
 +      ad198x_init(codec);
 +      ad1986a_hp_automute(codec);
 +      ad1986a_automic(codec);
 +      return 0;
 +}
 +
  
  /* models */
  enum {
        AD1986A_LAPTOP_AUTOMUTE,
        AD1986A_ULTRA,
        AD1986A_SAMSUNG,
 +      AD1986A_SAMSUNG_P50,
        AD1986A_MODELS
  };
  
@@@ -983,7 -1002,6 +983,7 @@@ static const char *ad1986a_models[AD198
        [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
        [AD1986A_ULTRA]         = "ultra",
        [AD1986A_SAMSUNG]       = "samsung",
 +      [AD1986A_SAMSUNG_P50]   = "samsung-p50",
  };
  
  static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
 +      SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
        SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
        SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
        SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
@@@ -1094,10 -1111,7 +1094,10 @@@ static int patch_ad1986a(struct hda_cod
                spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
                break;
        case AD1986A_LAPTOP_EAPD:
 -              spec->mixers[0] = ad1986a_laptop_eapd_mixers;
 +              spec->num_mixers = 3;
 +              spec->mixers[0] = ad1986a_laptop_master_mixers;
 +              spec->mixers[1] = ad1986a_laptop_eapd_mixers;
 +              spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->multiout.max_channels = 2;
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                break;
        case AD1986A_SAMSUNG:
 -              spec->mixers[0] = ad1986a_samsung_mixers;
 +              spec->num_mixers = 2;
 +              spec->mixers[0] = ad1986a_laptop_master_mixers;
 +              spec->mixers[1] = ad1986a_laptop_eapd_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_automic_verbs;
                codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
                codec->patch_ops.init = ad1986a_automic_init;
                break;
 +      case AD1986A_SAMSUNG_P50:
 +              spec->num_mixers = 2;
 +              spec->mixers[0] = ad1986a_automute_master_mixers;
 +              spec->mixers[1] = ad1986a_laptop_eapd_mixers;
 +              spec->num_init_verbs = 4;
 +              spec->init_verbs[1] = ad1986a_eapd_init_verbs;
 +              spec->init_verbs[2] = ad1986a_automic_verbs;
 +              spec->init_verbs[3] = ad1986a_hp_init_verbs;
 +              spec->multiout.max_channels = 2;
 +              spec->multiout.num_dacs = 1;
 +              spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
 +              if (!is_jack_available(codec, 0x25))
 +                      spec->multiout.dig_out_nid = 0;
 +              spec->input_mux = &ad1986a_automic_capture_source;
 +              codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
 +              codec->patch_ops.init = ad1986a_samsung_p50_init;
 +              break;
        case AD1986A_LAPTOP_AUTOMUTE:
 -              spec->mixers[0] = ad1986a_laptop_automute_mixers;
 +              spec->num_mixers = 3;
 +              spec->mixers[0] = ad1986a_automute_master_mixers;
 +              spec->mixers[1] = ad1986a_laptop_eapd_mixers;
 +              spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_hp_init_verbs;
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
                codec->patch_ops.init = ad1986a_hp_init;
 +              /* Lenovo N100 seems to report the reversed bit
 +               * for HP jack-sensing
 +               */
 +              spec->inv_jack_detect = 1;
                break;
        case AD1986A_ULTRA:
                spec->mixers[0] = ad1986a_laptop_eapd_mixers;
@@@ -2982,8 -2970,7 +2982,8 @@@ static int patch_ad1988(struct hda_code
        board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
                                                  ad1988_models, ad1988_cfg_tbl);
        if (board_config < 0) {
 -              printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
 +              printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                     codec->chip_name);
                board_config = AD1988_AUTO;
        }
  
@@@ -3836,9 -3823,11 +3836,11 @@@ static struct hda_verb ad1884a_laptop_v
        /* Port-F (int speaker) mixer - route only from analog mixer */
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Port-F (int speaker) pin */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* required for compaq 6530s/6531s speaker output */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        /* Port-C pin - internal mic-in */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
@@@ -40,8 -40,6 +40,8 @@@ enum 
        STAC_INSERT_EVENT,
        STAC_PWR_EVENT,
        STAC_HP_EVENT,
 +      STAC_LO_EVENT,
 +      STAC_MIC_EVENT,
  };
  
  enum {
@@@ -78,6 -76,7 +78,7 @@@ enum 
        STAC_92HD73XX_AUTO,
        STAC_92HD73XX_NO_JD, /* no jack-detection */
        STAC_92HD73XX_REF,
+       STAC_92HD73XX_INTEL,
        STAC_DELL_M6_AMIC,
        STAC_DELL_M6_DMIC,
        STAC_DELL_M6_BOTH,
@@@ -178,12 -177,6 +179,12 @@@ struct sigmatel_jack 
        struct snd_jack *jack;
  };
  
 +struct sigmatel_mic_route {
 +      hda_nid_t pin;
 +      unsigned char mux_idx;
 +      unsigned char dmux_idx;
 +};
 +
  struct sigmatel_spec {
        struct snd_kcontrol_new *mixers[4];
        unsigned int num_mixers;
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
        unsigned int check_volume_offset:1;
 +      unsigned int auto_mic:1;
  
        /* gpio lines */
        unsigned int eapd_mask;
        unsigned int num_dmuxes;
        hda_nid_t *smux_nids;
        unsigned int num_smuxes;
 +      unsigned int num_analog_muxes;
 +
 +      unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
 +      unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
 +      unsigned int num_caps; /* number of capture volume/switch elements */
 +
 +      struct sigmatel_mic_route ext_mic;
 +      struct sigmatel_mic_route int_mic;
 +
        const char **spdif_labels;
  
        hda_nid_t dig_in_nid;
@@@ -352,16 -335,14 +353,16 @@@ static hda_nid_t stac92hd73xx_smux_nids
        0x22, 0x23,
  };
  
 -#define STAC92HD83XXX_NUM_DMICS       2
 -static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
 -      0x11, 0x12, 0
 +#define STAC92HD73XX_NUM_CAPS 2
 +static unsigned long stac92hd73xx_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
  };
 +#define stac92hd73xx_capsws   stac92hd73xx_capvols
  
  #define STAC92HD83_DAC_COUNT 3
  
 -static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
 +static hda_nid_t stac92hd83xxx_mux_nids[2] = {
        0x17, 0x18,
  };
  
@@@ -381,12 -362,9 +382,12 @@@ static unsigned int stac92hd83xxx_pwr_m
        0x03, 0x0c, 0x20, 0x40,
  };
  
 -static hda_nid_t stac92hd83xxx_amp_nids[1] = {
 -      0xc,
 +#define STAC92HD83XXX_NUM_CAPS        2
 +static unsigned long stac92hd83xxx_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
  };
 +#define stac92hd83xxx_capsws  stac92hd83xxx_capvols
  
  static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
        0x0a, 0x0d, 0x0f
@@@ -417,13 -395,6 +418,13 @@@ static hda_nid_t stac92hd71bxx_slave_di
        0x22, 0
  };
  
 +#define STAC92HD71BXX_NUM_CAPS                2
 +static unsigned long stac92hd71bxx_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 +};
 +#define stac92hd71bxx_capsws  stac92hd71bxx_capvols
 +
  static hda_nid_t stac925x_adc_nids[1] = {
          0x03,
  };
@@@ -445,13 -416,6 +446,13 @@@ static hda_nid_t stac925x_dmux_nids[1] 
        0x14,
  };
  
 +static unsigned long stac925x_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
 +};
 +static unsigned long stac925x_capsws[] = {
 +      HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 +};
 +
  static hda_nid_t stac922x_adc_nids[2] = {
          0x06, 0x07,
  };
@@@ -460,13 -424,6 +461,13 @@@ static hda_nid_t stac922x_mux_nids[2] 
          0x12, 0x13,
  };
  
 +#define STAC922X_NUM_CAPS     2
 +static unsigned long stac922x_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
 +      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 +};
 +#define stac922x_capsws               stac922x_capvols
 +
  static hda_nid_t stac927x_slave_dig_outs[2] = {
        0x1f, 0,
  };
@@@ -496,18 -453,6 +497,18 @@@ static hda_nid_t stac927x_dmic_nids[STA
        0x13, 0x14, 0
  };
  
 +#define STAC927X_NUM_CAPS     3
 +static unsigned long stac927x_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 +      HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
 +};
 +static unsigned long stac927x_capsws[] = {
 +      HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 +};
 +
  static const char *stac927x_spdif_labels[5] = {
        "Digital Playback", "ADAT", "Analog Mux 1",
        "Analog Mux 2", "Analog Mux 3"
@@@ -534,16 -479,6 +535,16 @@@ static hda_nid_t stac9205_dmic_nids[STA
          0x17, 0x18, 0
  };
  
 +#define STAC9205_NUM_CAPS     2
 +static unsigned long stac9205_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
 +};
 +static unsigned long stac9205_capsws[] = {
 +      HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 +      HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
 +};
 +
  static hda_nid_t stac9200_pin_nids[8] = {
        0x08, 0x09, 0x0d, 0x0e, 
        0x0f, 0x10, 0x11, 0x12,
@@@ -758,35 -693,9 +759,35 @@@ static int stac92xx_mux_enum_put(struc
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 -
 -      return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 -                                   spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
 +      const struct hda_input_mux *imux = spec->input_mux;
 +      unsigned int idx, prev_idx;
 +
 +      idx = ucontrol->value.enumerated.item[0];
 +      if (idx >= imux->num_items)
 +              idx = imux->num_items - 1;
 +      prev_idx = spec->cur_mux[adc_idx];
 +      if (prev_idx == idx)
 +              return 0;
 +      if (idx < spec->num_analog_muxes) {
 +              snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
 +                                        AC_VERB_SET_CONNECT_SEL,
 +                                        imux->items[idx].index);
 +              if (prev_idx >= spec->num_analog_muxes) {
 +                      imux = spec->dinput_mux;
 +                      /* 0 = analog */
 +                      snd_hda_codec_write_cache(codec,
 +                                                spec->dmux_nids[adc_idx], 0,
 +                                                AC_VERB_SET_CONNECT_SEL,
 +                                                imux->items[0].index);
 +              }
 +      } else {
 +              imux = spec->dinput_mux;
 +              snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
 +                                        AC_VERB_SET_CONNECT_SEL,
 +                                        imux->items[idx - 1].index);
 +      }
 +      spec->cur_mux[adc_idx] = idx;
 +      return 1;
  }
  
  static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
@@@ -1016,6 -925,19 +1017,6 @@@ static struct hda_verb stac92hd71bxx_co
        {}
  };
  
 -#define HD_DISABLE_PORTF 1
 -static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 -      /* start of config #1 */
 -
 -      /* connect port 0f to audio mixer */
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
 -      /* start of config #2 */
 -
 -      /* set master volume and direct control */
 -      { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      {}
 -};
 -
  static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
        /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@@ -1148,6 -1070,12 +1149,6 @@@ static struct snd_kcontrol_new stac92hd
        HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
  
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -
        { } /* end */
  };
  
@@@ -1167,6 -1095,12 +1168,6 @@@ static struct snd_kcontrol_new stac92hd
  };
  
  static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
  
  };
  
  static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
 -
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
  
  };
  
  
 -static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
 -      HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
 -
 -      HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT),
 -      HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT),
 -
 -      HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT),
 -
 -      HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT),
 -      HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT),
 -
 -      /*
 -      HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
 -      HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
 -      */
 -      { } /* end */
 -};
 -
 -static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 -      /* analog pc-beep replaced with digital beep support */
 -      /*
 -      HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
 -      HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
 -      */
 -
 -      HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
 -      HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
 -
 -      HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
 -      HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
 -
 -      HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
 -      HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
 -
 -      HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
 -      HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
 -      { } /* end */
 -};
 -
  static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
  };
  
 -static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
 -      { } /* end */
 -};
 -
  static struct snd_kcontrol_new stac925x_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
 -      HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
 -      HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
 -      { } /* end */
 -};
 -
 -static struct snd_kcontrol_new stac9205_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
        { } /* end */
  };
  
@@@ -1218,6 -1230,29 +1219,6 @@@ static struct snd_kcontrol_new stac9205
        {}
  };
  
 -/* This needs to be generated dynamically based on sequence */
 -static struct snd_kcontrol_new stac922x_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
 -      { } /* end */
 -};
 -
 -
 -static struct snd_kcontrol_new stac927x_mixer[] = {
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
 -
 -      HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
 -      HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
 -      { } /* end */
 -};
 -
  static struct snd_kcontrol_new stac927x_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
        {}
@@@ -1275,19 -1310,16 +1276,19 @@@ static int stac92xx_build_controls(stru
        int err;
        int i;
  
 -      err = snd_hda_add_new_ctls(codec, spec->mixer);
 -      if (err < 0)
 -              return err;
 +      if (spec->mixer) {
 +              err = snd_hda_add_new_ctls(codec, spec->mixer);
 +              if (err < 0)
 +                      return err;
 +      }
  
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
                if (err < 0)
                        return err;
        }
 -      if (spec->num_dmuxes > 0) {
 +      if (!spec->auto_mic && spec->num_dmuxes > 0 &&
 +          snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
                stac_dmux_mixer.count = spec->num_dmuxes;
                err = snd_hda_ctl_add(codec,
                                  snd_ctl_new1(&stac_dmux_mixer, codec));
@@@ -1746,6 -1778,7 +1747,7 @@@ static const char *stac92hd73xx_models[
        [STAC_92HD73XX_AUTO] = "auto",
        [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
+       [STAC_92HD73XX_INTEL] = "intel",
        [STAC_DELL_M6_AMIC] = "dell-m6-amic",
        [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
        [STAC_DELL_M6_BOTH] = "dell-m6",
@@@ -1758,6 -1791,10 +1760,10 @@@ static struct snd_pci_quirk stac92hd73x
                                "DFI LanParty", STAC_92HD73XX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                                "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5002,
+                               "Intel DG45ID", STAC_92HD73XX_INTEL),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5003,
+                               "Intel DG45FC", STAC_92HD73XX_INTEL),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
                                "Dell Studio 1535", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
@@@ -1890,8 -1927,6 +1896,8 @@@ static struct snd_pci_quirk stac92hd71b
                      "HP mini 1000", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
                      "HP HDX", STAC_HP_HDX),  /* HDX16 */
 +      SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
 +                    "HP", STAC_HP_DV5),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
                                "unknown Dell", STAC_DELL_M4_1),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@@ -2607,7 -2642,8 +2613,7 @@@ static int stac92xx_hp_switch_get(struc
        return 0;
  }
  
 -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
 -                                 unsigned char type);
 +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid);
  
  static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
        /* check to be sure that the ports are upto date with
         * switch changes
         */
 -      stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 +      stac_issue_unsol_event(codec, nid);
  
        return 1;
  }
@@@ -2754,7 -2790,7 +2760,7 @@@ static int stac92xx_io_switch_put(struc
         * appropriately according to the pin direction
         */
        if (spec->hp_detect)
 -              stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 +              stac_issue_unsol_event(codec, nid);
  
          return 1;
  }
@@@ -2937,8 -2973,6 +2943,8 @@@ static int stac92xx_add_input_source(st
        struct snd_kcontrol_new *knew;
        struct hda_input_mux *imux = &spec->private_imux;
  
 +      if (spec->auto_mic)
 +              return 0; /* no need for input source */
        if (!spec->num_adcs || imux->num_items <= 1)
                return 0; /* no need for input source control */
        knew = stac_control_new(spec, &stac_input_src_temp,
@@@ -3032,7 -3066,7 +3038,7 @@@ static hda_nid_t get_unassigned_dac(str
                                           HDA_MAX_CONNECTIONS);
        for (j = 0; j < conn_len; j++) {
                wcaps = get_wcaps(codec, conn[j]);
 -              wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 +              wtype = get_wcaps_type(wcaps);
                /* we check only analog outputs */
                if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
                        continue;
@@@ -3291,21 -3325,6 +3297,21 @@@ static int create_multi_out_ctls(struc
        return 0;
  }
  
 +static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
 +                                  unsigned long sw, int idx)
 +{
 +      int err;
 +      err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
 +                                     "Capture Volume", vol);
 +      if (err < 0)
 +              return err;
 +      err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
 +                                     "Capture Switch", sw);
 +      if (err < 0)
 +              return err;
 +      return 0;
 +}
 +
  /* add playback controls from the parsed DAC table */
  static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                                               const struct auto_pin_cfg *cfg)
@@@ -3379,7 -3398,7 +3385,7 @@@ static int stac92xx_auto_create_mono_ou
                                spec->mono_nid,
                                con_lst,
                                HDA_MAX_NUM_INPUTS);
 -      if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
 +      if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
                return -EINVAL;
  
        for (i = 0; i < num_cons; i++) {
@@@ -3492,33 -3511,19 +3498,33 @@@ static int stac92xx_beep_switch_ctl(str
  static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
  {
        struct sigmatel_spec *spec = codec->spec;
 -      int wcaps, nid, i, err = 0;
 +      int i, j, err = 0;
  
        for (i = 0; i < spec->num_muxes; i++) {
 +              hda_nid_t nid;
 +              unsigned int wcaps;
 +              unsigned long val;
 +
                nid = spec->mux_nids[i];
                wcaps = get_wcaps(codec, nid);
 +              if (!(wcaps & AC_WCAP_OUT_AMP))
 +                      continue;
  
 -              if (wcaps & AC_WCAP_OUT_AMP) {
 -                      err = stac92xx_add_control_idx(spec,
 -                              STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
 -                              HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
 -                      if (err < 0)
 -                              return err;
 +              /* check whether already the same control was created as
 +               * normal Capture Volume.
 +               */
 +              val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
 +              for (j = 0; j < spec->num_caps; j++) {
 +                      if (spec->capvols[j] == val)
 +                              break;
                }
 +              if (j < spec->num_caps)
 +                      continue;
 +
 +              err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i,
 +                                             "Mux Capture Volume", val);
 +              if (err < 0)
 +                      return err;
        }
        return 0;
  };
@@@ -3539,7 -3544,7 +3545,7 @@@ static int stac92xx_auto_create_spdif_m
                                spec->smux_nids[0],
                                con_lst,
                                HDA_MAX_NUM_INPUTS);
 -      if (!num_cons)
 +      if (num_cons <= 0)
                return -EINVAL;
  
        if (!labels)
@@@ -3560,215 -3565,101 +3566,215 @@@ static const char *stac92xx_dmic_labels
        "Digital Mic 3", "Digital Mic 4"
  };
  
 +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 +                              hda_nid_t nid)
 +{
 +      hda_nid_t conn[HDA_MAX_NUM_INPUTS];
 +      int i, nums;
 +
 +      nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
 +      for (i = 0; i < nums; i++)
 +              if (conn[i] == nid)
 +                      return i;
 +      return -1;
 +}
 +
 +/* create a volume assigned to the given pin (only if supported) */
 +static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
 +                                 const char *label)
 +{
 +      unsigned int caps, nums;
 +      char name[32];
 +
 +      if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
 +              return 0;
 +      caps = query_amp_caps(codec, nid, HDA_OUTPUT);
 +      nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
 +      if (!nums)
 +              return 0;
 +      snprintf(name, sizeof(name), "%s Capture Volume", label);
 +      return stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
 +                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
 +}
 +
  /* create playback/capture controls for input pins on dmic capable codecs */
  static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
  {
        struct sigmatel_spec *spec = codec->spec;
 +      struct hda_input_mux *imux = &spec->private_imux;
        struct hda_input_mux *dimux = &spec->private_dimux;
 -      hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
 -      int err, i, j;
 -      char name[32];
 +      int err, i, active_mics;
 +      unsigned int def_conf;
  
        dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
        dimux->items[dimux->num_items].index = 0;
        dimux->num_items++;
  
 +      active_mics = 0;
 +      for (i = 0; i < spec->num_dmics; i++) {
 +              /* check the validity: sometimes it's a dead vendor-spec node */
 +              if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
 +                  != AC_WID_PIN)
 +                      continue;
 +              def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
 +              if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
 +                      active_mics++;
 +      }
 +
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
                int index;
 -              int num_cons;
 -              unsigned int wcaps;
 -              unsigned int def_conf;
 +              const char *label;
  
 -              def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
 +              nid = spec->dmic_nids[i];
 +              if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
 +                      continue;
 +              def_conf = snd_hda_codec_get_pincfg(codec, nid);
                if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
                        continue;
  
 -              nid = spec->dmic_nids[i];
 -              num_cons = snd_hda_get_connections(codec,
 -                              spec->dmux_nids[0],
 -                              con_lst,
 -                              HDA_MAX_NUM_INPUTS);
 -              for (j = 0; j < num_cons; j++)
 -                      if (con_lst[j] == nid) {
 -                              index = j;
 -                              goto found;
 -                      }
 -              continue;
 -found:
 -              wcaps = get_wcaps(codec, nid) &
 -                      (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
 +              index = get_connection_index(codec, spec->dmux_nids[0], nid);
 +              if (index < 0)
 +                      continue;
  
 -              if (wcaps) {
 -                      sprintf(name, "%s Capture Volume",
 -                              stac92xx_dmic_labels[dimux->num_items]);
 +              if (active_mics == 1)
 +                      label = "Digital Mic";
 +              else
 +                      label = stac92xx_dmic_labels[dimux->num_items];
  
 -                      err = stac92xx_add_control(spec,
 -                              STAC_CTL_WIDGET_VOL,
 -                              name,
 -                              HDA_COMPOSE_AMP_VAL(nid, 3, 0,
 -                              (wcaps & AC_WCAP_OUT_AMP) ?
 -                              HDA_OUTPUT : HDA_INPUT));
 -                      if (err < 0)
 -                              return err;
 -              }
 +              err = create_elem_capture_vol(codec, nid, label);
 +              if (err < 0)
 +                      return err;
  
 -              dimux->items[dimux->num_items].label =
 -                      stac92xx_dmic_labels[dimux->num_items];
 +              dimux->items[dimux->num_items].label = label;
                dimux->items[dimux->num_items].index = index;
                dimux->num_items++;
 +              if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
 +                      imux->items[imux->num_items].label = label;
 +                      imux->items[imux->num_items].index = index;
 +                      imux->num_items++;
 +              }
        }
  
        return 0;
  }
  
 +static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
 +                       hda_nid_t *fixed, hda_nid_t *ext)
 +{
 +      unsigned int cfg;
 +
 +      if (!nid)
 +              return 0;
 +      cfg = snd_hda_codec_get_pincfg(codec, nid);
 +      switch (get_defcfg_connect(cfg)) {
 +      case AC_JACK_PORT_FIXED:
 +              if (*fixed)
 +                      return 1; /* already occupied */
 +              *fixed = nid;
 +              break;
 +      case AC_JACK_PORT_COMPLEX:
 +              if (*ext)
 +                      return 1; /* already occupied */
 +              *ext = nid;
 +              break;
 +      }
 +      return 0;
 +}
 +
 +static int set_mic_route(struct hda_codec *codec,
 +                       struct sigmatel_mic_route *mic,
 +                       hda_nid_t pin)
 +{
 +      struct sigmatel_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int i;
 +
 +      mic->pin = pin;
 +      for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
 +              if (pin == cfg->input_pins[i])
 +                      break;
 +      if (i <= AUTO_PIN_FRONT_MIC) {
 +              /* analog pin */
 +              mic->dmux_idx = 0;
 +              i = get_connection_index(codec, spec->mux_nids[0], pin);
 +              if (i < 0)
 +                      return -1;
 +              mic->mux_idx = i;
 +      }  else if (spec->dmux_nids) {
 +              /* digital pin */
 +              mic->mux_idx = 0;
 +              i = get_connection_index(codec, spec->dmux_nids[0], pin);
 +              if (i < 0)
 +                      return -1;
 +              mic->dmux_idx = i;
 +      }
 +      return 0;
 +}
 +
 +/* return non-zero if the device is for automatic mic switch */
 +static int stac_check_auto_mic(struct hda_codec *codec)
 +{
 +      struct sigmatel_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      hda_nid_t fixed, ext;
 +      int i;
 +
 +      for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
 +              if (cfg->input_pins[i])
 +                      return 0; /* must be exclusively mics */
 +      }
 +      fixed = ext = 0;
 +      for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
 +              if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
 +                      return 0;
 +      for (i = 0; i < spec->num_dmics; i++)
 +              if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
 +                      return 0;
 +      if (!fixed || !ext)
 +              return 0;
 +      if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
 +              return 0; /* no unsol support */
 +      if (set_mic_route(codec, &spec->ext_mic, ext) ||
 +          set_mic_route(codec, &spec->int_mic, fixed))
 +              return 0; /* something is wrong */
 +      return 1;
 +}
 +
  /* create playback/capture controls for input pins */
  static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
  {
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
 -      hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
 -      int i, j, k;
 +      int i, j;
  
        for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              int index;
 +              hda_nid_t nid = cfg->input_pins[i];
 +              int index, err;
  
 -              if (!cfg->input_pins[i])
 +              if (!nid)
                        continue;
                index = -1;
                for (j = 0; j < spec->num_muxes; j++) {
 -                      int num_cons;
 -                      num_cons = snd_hda_get_connections(codec,
 -                                                         spec->mux_nids[j],
 -                                                         con_lst,
 -                                                         HDA_MAX_NUM_INPUTS);
 -                      for (k = 0; k < num_cons; k++)
 -                              if (con_lst[k] == cfg->input_pins[i]) {
 -                                      index = k;
 -                                      goto found;
 -                              }
 +                      index = get_connection_index(codec, spec->mux_nids[j],
 +                                                   nid);
 +                      if (index >= 0)
 +                              break;
                }
 -              continue;
 -      found:
 +              if (index < 0)
 +                      continue;
 +
 +              err = create_elem_capture_vol(codec, nid,
 +                                            auto_pin_cfg_labels[i]);
 +              if (err < 0)
 +                      return err;
 +
                imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
                imux->items[imux->num_items].index = index;
                imux->num_items++;
        }
 +      spec->num_analog_muxes = imux->num_items;
  
        if (imux->num_items) {
                /*
@@@ -3820,7 -3711,7 +3826,7 @@@ static int stac92xx_parse_auto_config(s
  {
        struct sigmatel_spec *spec = codec->spec;
        int hp_swap = 0;
 -      int err;
 +      int i, err;
  
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
                if (snd_hda_get_connections(codec,
                                spec->autocfg.mono_out_pin, conn_list, 1) &&
                                snd_hda_get_connections(codec, conn_list[0],
 -                              conn_list, 1)) {
 +                              conn_list, 1) > 0) {
  
                                int wcaps = get_wcaps(codec, conn_list[0]);
 -                              int wid_type = (wcaps & AC_WCAP_TYPE)
 -                                      >> AC_WCAP_TYPE_SHIFT;
 +                              int wid_type = get_wcaps_type(wcaps);
                                /* LR swap check, some stac925x have a mux that
                                 * changes the DACs output path instead of the
                                 * mono-mux path.
                spec->autocfg.line_outs = 0;
        }
  
 +      if (stac_check_auto_mic(codec)) {
 +              spec->auto_mic = 1;
 +              /* only one capture for auto-mic */
 +              spec->num_adcs = 1;
 +              spec->num_caps = 1;
 +              spec->num_muxes = 1;
 +      }
 +
 +      for (i = 0; i < spec->num_caps; i++) {
 +              err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
 +                                             spec->capsws[i], i);
 +              if (err < 0)
 +                      return err;
 +      }
 +
        err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
@@@ -4231,14 -4108,14 +4237,14 @@@ static int stac_add_event(struct sigmat
  }
  
  static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
 -                                           hda_nid_t nid, unsigned char type)
 +                                           hda_nid_t nid)
  {
        struct sigmatel_spec *spec = codec->spec;
        struct sigmatel_event *event = spec->events.list;
        int i;
  
        for (i = 0; i < spec->events.used; i++, event++) {
 -              if (event->nid == nid && event->type == type)
 +              if (event->nid == nid)
                        return event;
        }
        return NULL;
@@@ -4258,32 -4135,24 +4264,32 @@@ static struct sigmatel_event *stac_get_
        return NULL;
  }
  
 -static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
 -                            unsigned int type)
 +/* check if given nid is a valid pin and no other events are assigned
 + * to it.  If OK, assign the event, set the unsol flag, and returns 1.
 + * Otherwise, returns zero.
 + */
 +static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
 +                           unsigned int type)
  {
        struct sigmatel_event *event;
        int tag;
  
        if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
 -              return;
 -      event = stac_get_event(codec, nid, type);
 -      if (event)
 +              return 0;
 +      event = stac_get_event(codec, nid);
 +      if (event) {
 +              if (event->type != type)
 +                      return 0;
                tag = event->tag;
 -      else
 +      } else {
                tag = stac_add_event(codec->spec, nid, type, 0);
 -      if (tag < 0)
 -              return;
 +              if (tag < 0)
 +                      return 0;
 +      }
        snd_hda_codec_write_cache(codec, nid, 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
                                  AC_USRSP_EN | tag);
 +      return 1;
  }
  
  static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@@ -4376,36 -4245,20 +4382,36 @@@ static int stac92xx_init(struct hda_cod
                        hda_nid_t nid = cfg->hp_pins[i];
                        enable_pin_detect(codec, nid, STAC_HP_EVENT);
                }
 +              if (cfg->line_out_type == AUTO_PIN_LINE_OUT &&
 +                  cfg->speaker_outs > 0) {
 +                      /* enable pin-detect for line-outs as well */
 +                      for (i = 0; i < cfg->line_outs; i++) {
 +                              hda_nid_t nid = cfg->line_out_pins[i];
 +                              enable_pin_detect(codec, nid, STAC_LO_EVENT);
 +                      }
 +              }
 +
                /* force to enable the first line-out; the others are set up
                 * in unsol_event
                 */
                stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
                                AC_PINCTL_OUT_EN);
                /* fake event to set up pins */
 -              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
 -                                     STAC_HP_EVENT);
 +              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
                for (i = 0; i < cfg->hp_outs; i++)
                        stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
        }
 +      if (spec->auto_mic) {
 +              /* initialize connection to analog input */
 +              if (spec->dmux_nids)
 +                      snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
 +                                        AC_VERB_SET_CONNECT_SEL, 0);
 +              if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
 +                      stac_issue_unsol_event(codec, spec->ext_mic.pin);
 +      }
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = cfg->input_pins[i];
                if (nid) {
                        }
                        conf = snd_hda_codec_get_pincfg(codec, nid);
                        if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
 -                              enable_pin_detect(codec, nid,
 -                                                STAC_INSERT_EVENT);
 -                              stac_issue_unsol_event(codec, nid,
 -                                                     STAC_INSERT_EVENT);
 +                              if (enable_pin_detect(codec, nid,
 +                                                    STAC_INSERT_EVENT))
 +                                      stac_issue_unsol_event(codec, nid);
                        }
                }
        }
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
 -              if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
 -                      enable_pin_detect(codec, nid, STAC_PWR_EVENT);
 -                      stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
 -              }
 +              if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
 +                      stac_issue_unsol_event(codec, nid);
        }
        if (spec->dac_list)
                stac92xx_power_down(codec);
@@@ -4584,48 -4440,6 +4590,48 @@@ static int get_pin_presence(struct hda_
        return 0;
  }
  
 +static void stac92xx_line_out_detect(struct hda_codec *codec,
 +                                   int presence)
 +{
 +      struct sigmatel_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int i;
 +
 +      for (i = 0; i < cfg->line_outs; i++) {
 +              if (presence)
 +                      break;
 +              presence = get_pin_presence(codec, cfg->line_out_pins[i]);
 +              if (presence) {
 +                      unsigned int pinctl;
 +                      pinctl = snd_hda_codec_read(codec,
 +                                                  cfg->line_out_pins[i], 0,
 +                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 +                      if (pinctl & AC_PINCTL_IN_EN)
 +                              presence = 0; /* mic- or line-input */
 +              }
 +      }
 +
 +      if (presence) {
 +              /* disable speakers */
 +              for (i = 0; i < cfg->speaker_outs; i++)
 +                      stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
 +                                              AC_PINCTL_OUT_EN);
 +              if (spec->eapd_mask && spec->eapd_switch)
 +                      stac_gpio_set(codec, spec->gpio_mask,
 +                              spec->gpio_dir, spec->gpio_data &
 +                              ~spec->eapd_mask);
 +      } else {
 +              /* enable speakers */
 +              for (i = 0; i < cfg->speaker_outs; i++)
 +                      stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
 +                                              AC_PINCTL_OUT_EN);
 +              if (spec->eapd_mask && spec->eapd_switch)
 +                      stac_gpio_set(codec, spec->gpio_mask,
 +                              spec->gpio_dir, spec->gpio_data |
 +                              spec->eapd_mask);
 +      }
 +} 
 +
  /* return non-zero if the hp-pin of the given array index isn't
   * a jack-detection target
   */
@@@ -4678,6 -4492,13 +4684,6 @@@ static void stac92xx_hp_detect(struct h
                for (i = 0; i < cfg->line_outs; i++)
                        stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
                                                AC_PINCTL_OUT_EN);
 -              for (i = 0; i < cfg->speaker_outs; i++)
 -                      stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
 -                                              AC_PINCTL_OUT_EN);
 -              if (spec->eapd_mask && spec->eapd_switch)
 -                      stac_gpio_set(codec, spec->gpio_mask,
 -                              spec->gpio_dir, spec->gpio_data &
 -                              ~spec->eapd_mask);
        } else {
                /* enable lineouts */
                if (spec->hp_switch)
                for (i = 0; i < cfg->line_outs; i++)
                        stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
                                                AC_PINCTL_OUT_EN);
 -              for (i = 0; i < cfg->speaker_outs; i++)
 -                      stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
 -                                              AC_PINCTL_OUT_EN);
 -              if (spec->eapd_mask && spec->eapd_switch)
 -                      stac_gpio_set(codec, spec->gpio_mask,
 -                              spec->gpio_dir, spec->gpio_data |
 -                              spec->eapd_mask);
        }
 +      stac92xx_line_out_detect(codec, presence);
        /* toggle hp outs */
        for (i = 0; i < cfg->hp_outs; i++) {
                unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
@@@ -4772,28 -4599,10 +4778,28 @@@ static void stac92xx_report_jack(struc
        }
  }
  
 -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
 -                                 unsigned char type)
 +static void stac92xx_mic_detect(struct hda_codec *codec)
  {
 -      struct sigmatel_event *event = stac_get_event(codec, nid, type);
 +      struct sigmatel_spec *spec = codec->spec;
 +      struct sigmatel_mic_route *mic;
 +
 +      if (get_pin_presence(codec, spec->ext_mic.pin))
 +              mic = &spec->ext_mic;
 +      else
 +              mic = &spec->int_mic;
 +      if (mic->dmux_idx)
 +              snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
 +                                        AC_VERB_SET_CONNECT_SEL,
 +                                        mic->dmux_idx);
 +      else
 +              snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
 +                                        AC_VERB_SET_CONNECT_SEL,
 +                                        mic->mux_idx);
 +}
 +
 +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
 +{
 +      struct sigmatel_event *event = stac_get_event(codec, nid);
        if (!event)
                return;
        codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
@@@ -4812,18 -4621,8 +4818,18 @@@ static void stac92xx_unsol_event(struc
  
        switch (event->type) {
        case STAC_HP_EVENT:
 +      case STAC_LO_EVENT:
                stac92xx_hp_detect(codec);
 -              /* fallthru */
 +              break;
 +      case STAC_MIC_EVENT:
 +              stac92xx_mic_detect(codec);
 +              break;
 +      }
 +
 +      switch (event->type) {
 +      case STAC_HP_EVENT:
 +      case STAC_LO_EVENT:
 +      case STAC_MIC_EVENT:
        case STAC_INSERT_EVENT:
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
@@@ -4914,7 -4713,8 +4920,7 @@@ static int stac92xx_resume(struct hda_c
        snd_hda_codec_resume_cache(codec);
        /* fake event to set up pins again to override cached values */
        if (spec->hp_detect)
 -              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
 -                                     STAC_HP_EVENT);
 +              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
        return 0;
  }
  
@@@ -4954,19 -4754,6 +4960,19 @@@ static int stac92xx_hp_check_power_stat
  static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
  {
        struct sigmatel_spec *spec = codec->spec;
 +      int i;
 +      hda_nid_t nid;
 +
 +      /* reset each pin before powering down DAC/ADC to avoid click noise */
 +      nid = codec->start_nid;
 +      for (i = 0; i < codec->num_nodes; i++, nid++) {
 +              unsigned int wcaps = get_wcaps(codec, nid);
 +              unsigned int wid_type = get_wcaps_type(wcaps);
 +              if (wid_type == AC_WID_PIN)
 +                      snd_hda_codec_read(codec, nid, 0,
 +                              AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 +      }
 +
        if (spec->eapd_mask)
                stac_gpio_set(codec, spec->gpio_mask,
                                spec->gpio_dir, spec->gpio_data &
@@@ -5003,8 -4790,7 +5009,8 @@@ static int patch_stac9200(struct hda_co
                                                        stac9200_models,
                                                        stac9200_cfg_tbl);
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9200_brd_tbl[spec->board_config]);
@@@ -5076,8 -4862,8 +5082,8 @@@ static int patch_stac925x(struct hda_co
                                                        stac925x_cfg_tbl);
   again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
 -                                    "using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac925x_brd_tbl[spec->board_config]);
  
        spec->init = stac925x_core_init;
        spec->mixer = stac925x_mixer;
 +      spec->num_caps = 1;
 +      spec->capvols = stac925x_capvols;
 +      spec->capsws = stac925x_capsws;
  
        err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
        if (!err) {
        return 0;
  }
  
 -static struct hda_input_mux stac92hd73xx_dmux = {
 -      .num_items = 4,
 -      .items = {
 -              { "Analog Inputs", 0x0b },
 -              { "Digital Mic 1", 0x09 },
 -              { "Digital Mic 2", 0x0a },
 -              { "CD", 0x08 },
 -      }
 -};
 -
  static int patch_stac92hd73xx(struct hda_codec *codec)
  {
        struct sigmatel_spec *spec;
                                                        stac92hd73xx_cfg_tbl);
  again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 -                      " STAC92HD73XX, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd73xx_brd_tbl[spec->board_config]);
        spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
        spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
 -      memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
 -                      sizeof(stac92hd73xx_dmux));
 +
 +      spec->num_caps = STAC92HD73XX_NUM_CAPS;
 +      spec->capvols = stac92hd73xx_capvols;
 +      spec->capsws = stac92hd73xx_capsws;
  
        switch (spec->board_config) {
        case STAC_DELL_EQ:
                case STAC_DELL_M6_AMIC: /* Analog Mics */
                        snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
                        spec->num_dmics = 0;
 -                      spec->private_dimux.num_items = 1;
                        break;
                case STAC_DELL_M6_DMIC: /* Digital Mics */
                        snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
 -                      spec->private_dimux.num_items = 2;
                        break;
                case STAC_DELL_M6_BOTH: /* Both */
                        snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
                        snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
 -                      spec->private_dimux.num_items = 2;
                        break;
                }
                break;
                spec->num_dmics = STAC92HD73XX_NUM_DMICS;
                spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
                spec->eapd_switch = 1;
 +              break;
        }
        if (spec->board_config > STAC_92HD73XX_REF) {
                /* GPIO0 High = Enable EAPD */
                spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
                spec->gpio_data = 0x01;
        }
 -      spec->dinput_mux = &spec->private_dimux;
  
        spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
        spec->pwr_nids = stac92hd73xx_pwr_nids;
        return 0;
  }
  
 -static struct hda_input_mux stac92hd83xxx_dmux = {
 -      .num_items = 3,
 -      .items = {
 -              { "Analog Inputs", 0x03 },
 -              { "Digital Mic 1", 0x04 },
 -              { "Digital Mic 2", 0x05 },
 -      }
 -};
 -
  static int patch_stac92hd83xxx(struct hda_codec *codec)
  {
        struct sigmatel_spec *spec;
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->mono_nid = 0x19;
        spec->digbeep_nid = 0x21;
 -      spec->dmic_nids = stac92hd83xxx_dmic_nids;
 -      spec->dmux_nids = stac92hd83xxx_dmux_nids;
 +      spec->mux_nids = stac92hd83xxx_mux_nids;
 +      spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
        spec->adc_nids = stac92hd83xxx_adc_nids;
 +      spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
 -      spec->amp_nids = stac92hd83xxx_amp_nids;
        spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->multiout.dac_nids = spec->dac_nids;
  
        spec->init = stac92hd83xxx_core_init;
 -      spec->mixer = stac92hd83xxx_mixer;
        spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
 -      spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
 -      spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
 -      spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
 -      spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
 -      spec->dinput_mux = &stac92hd83xxx_dmux;
        spec->pin_nids = stac92hd83xxx_pin_nids;
 +      spec->num_caps = STAC92HD83XXX_NUM_CAPS;
 +      spec->capvols = stac92hd83xxx_capvols;
 +      spec->capsws = stac92hd83xxx_capsws;
 +
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD83XXX_MODELS,
                                                        stac92hd83xxx_models,
                                                        stac92hd83xxx_cfg_tbl);
  again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 -                      " STAC92HD83XXX, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
  
        num_dacs = snd_hda_get_connections(codec, nid,
                                conn, STAC92HD83_DAC_COUNT + 1) - 1;
 +      if (num_dacs < 0)
 +              num_dacs = STAC92HD83_DAC_COUNT;
  
        /* set port X to select the last DAC
         */
        return 0;
  }
  
 -static struct hda_input_mux stac92hd71bxx_dmux_nomixer = {
 -      .num_items = 3,
 -      .items = {
 -              { "Analog Inputs", 0x00 },
 -              { "Digital Mic 1", 0x02 },
 -              { "Digital Mic 2", 0x03 },
 -      }
 -};
 -
 -static struct hda_input_mux stac92hd71bxx_dmux_amixer = {
 -      .num_items = 4,
 -      .items = {
 -              { "Analog Inputs", 0x00 },
 -              { "Mixer", 0x01 },
 -              { "Digital Mic 1", 0x02 },
 -              { "Digital Mic 2", 0x03 },
 -      }
 -};
 -
  /* get the pin connection (fixed, none, etc) */
  static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
  {
@@@ -5434,6 -5256,7 +5440,6 @@@ static int patch_stac92hd71bxx(struct h
        struct sigmatel_spec *spec;
        struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
        int err = 0;
 -      unsigned int ndmic_nids = 0;
  
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                                                        stac92hd71bxx_cfg_tbl);
  again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 -                      " STAC92HD71BXX, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd71bxx_brd_tbl[spec->board_config]);
        spec->dmic_nids = stac92hd71bxx_dmic_nids;
        spec->dmux_nids = stac92hd71bxx_dmux_nids;
  
 +      spec->num_caps = STAC92HD71BXX_NUM_CAPS;
 +      spec->capvols = stac92hd71bxx_capvols;
 +      spec->capsws = stac92hd71bxx_capsws;
 +
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
                /* fallthru */
        case 0x111d76b4: /* 6 Port without Analog Mixer */
        case 0x111d76b5:
 -              memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
 -                     sizeof(stac92hd71bxx_dmux_nomixer));
 -              spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92hd71bxx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
 -              if (spec->num_dmics) {
 -                      spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 -                      spec->dinput_mux = &spec->private_dimux;
 -                      ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
 -              }
                break;
        case 0x111d7608: /* 5 Port with Analog Mixer */
 -              memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
 -                     sizeof(stac92hd71bxx_dmux_amixer));
 -              spec->private_dimux.num_items--;
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
  
                /* no output amps */
                spec->num_pwrs = 0;
 -              spec->mixer = stac92hd71bxx_analog_mixer;
 -              spec->dinput_mux = &spec->private_dimux;
 -
                /* disable VSW */
 -              spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
 +              spec->init = stac92hd71bxx_core_init;
                unmute_init++;
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
                spec->num_dmics = stac92hd71bxx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS - 1);
 -              spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 -              ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2;
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
                if ((codec->revision_id & 0xf) == 1)
                spec->num_pwrs = 0;
                /* fallthru */
        default:
 -              memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
 -                     sizeof(stac92hd71bxx_dmux_amixer));
 -              spec->dinput_mux = &spec->private_dimux;
 -              spec->mixer = stac92hd71bxx_analog_mixer;
 -              spec->init = stac92hd71bxx_analog_core_init;
 +              spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92hd71bxx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
 -              spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 -              ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
 +              break;
        }
  
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
  
        spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
 +      spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
        spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
  
        switch (spec->board_config) {
  #endif        
  
        spec->multiout.dac_nids = spec->dac_nids;
 -      if (spec->dinput_mux)
 -              spec->private_dimux.num_items += spec->num_dmics - ndmic_nids;
  
        err = stac92xx_parse_auto_config(codec, 0x21, 0);
        if (!err) {
@@@ -5700,8 -5541,8 +5706,8 @@@ static int patch_stac922x(struct hda_co
  
   again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
 -                      "using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac922x_brd_tbl[spec->board_config]);
        spec->num_pwrs = 0;
  
        spec->init = stac922x_core_init;
 -      spec->mixer = stac922x_mixer;
 +
 +      spec->num_caps = STAC922X_NUM_CAPS;
 +      spec->capvols = stac922x_capvols;
 +      spec->capsws = stac922x_capsws;
  
        spec->multiout.dac_nids = spec->dac_nids;
        
@@@ -5766,8 -5604,8 +5772,8 @@@ static int patch_stac927x(struct hda_co
                                                        stac927x_cfg_tbl);
   again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 -                          "STAC927x, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac927x_brd_tbl[spec->board_config]);
                spec->num_dmics = 0;
  
                spec->init = d965_core_init;
 -              spec->mixer = stac927x_mixer;
                break;
        case STAC_DELL_BIOS:
                switch (codec->subsystem_id) {
                spec->num_dmics = STAC927X_NUM_DMICS;
  
                spec->init = d965_core_init;
 -              spec->mixer = stac927x_mixer;
                spec->dmux_nids = stac927x_dmux_nids;
                spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
                break;
                spec->num_dmics = 0;
  
                spec->init = stac927x_core_init;
 -              spec->mixer = stac927x_mixer;
        }
  
 +      spec->num_caps = STAC927X_NUM_CAPS;
 +      spec->capvols = stac927x_capvols;
 +      spec->capsws = stac927x_capsws;
 +
        spec->num_pwrs = 0;
        spec->aloopback_ctl = stac927x_loopback;
        spec->aloopback_mask = 0x40;
@@@ -5902,8 -5739,7 +5908,8 @@@ static int patch_stac9205(struct hda_co
                                                        stac9205_cfg_tbl);
   again:
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9205_brd_tbl[spec->board_config]);
        spec->num_pwrs = 0;
  
        spec->init = stac9205_core_init;
 -      spec->mixer = stac9205_mixer;
        spec->aloopback_ctl = stac9205_loopback;
  
 +      spec->num_caps = STAC9205_NUM_CAPS;
 +      spec->capvols = stac9205_capvols;
 +      spec->capsws = stac9205_capsws;
 +
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
        /* Turn on/off EAPD per HP plugging */
@@@ -6002,6 -5835,12 +6008,6 @@@ static struct hda_verb stac9872_core_in
        {}
  };
  
 -static struct snd_kcontrol_new stac9872_mixer[] = {
 -      HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
 -      HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
 -      { } /* end */
 -};
 -
  static hda_nid_t stac9872_pin_nids[] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x11, 0x13, 0x14,
@@@ -6015,11 -5854,6 +6021,11 @@@ static hda_nid_t stac9872_mux_nids[] = 
        0x15
  };
  
 +static unsigned long stac9872_capvols[] = {
 +      HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
 +};
 +#define stac9872_capsws               stac9872_capvols
 +
  static unsigned int stac9872_vaio_pin_configs[9] = {
        0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
        0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
@@@ -6057,8 -5891,8 +6063,8 @@@ static int patch_stac9872(struct hda_co
                                                        stac9872_models,
                                                        stac9872_cfg_tbl);
        if (spec->board_config < 0)
 -              snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, "
 -                          "using BIOS defaults\n");
 +              snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
 +                          codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9872_brd_tbl[spec->board_config]);
        spec->adc_nids = stac9872_adc_nids;
        spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
        spec->mux_nids = stac9872_mux_nids;
 -      spec->mixer = stac9872_mixer;
        spec->init = stac9872_core_init;
 +      spec->num_caps = 1;
 +      spec->capvols = stac9872_capvols;
 +      spec->capsws = stac9872_capsws;
  
        err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
        if (err < 0) {