Merge branch 'topic/hda-gateway' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Tue, 13 Jan 2009 16:50:46 +0000 (17:50 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Jan 2009 16:50:46 +0000 (17:50 +0100)
1  2 
sound/pci/hda/hda_codec.c
sound/pci/hda/patch_sigmatel.c

index fdad6ae7aad46f674d544fddf20b29a3259fe704,9c1af0101dde7c9f12aa6ac495cee339b6b600cf..b7bba7dc7cf15ee0e18b6147839d0c3c8ae59d3b
@@@ -46,7 -46,6 +46,7 @@@ static struct hda_vendor_id hda_vendor_
        { 0x1002, "ATI" },
        { 0x1057, "Motorola" },
        { 0x1095, "Silicon Image" },
 +      { 0x10de, "Nvidia" },
        { 0x10ec, "Realtek" },
        { 0x1106, "VIA" },
        { 0x111d, "IDT" },
@@@ -58,7 -57,6 +58,7 @@@
        { 0x1854, "LG" },
        { 0x1aec, "Wolfson Microelectronics" },
        { 0x434d, "C-Media" },
 +      { 0x8086, "Intel" },
        { 0x8384, "SigmaTel" },
        {} /* terminator */
  };
@@@ -373,7 -371,7 +373,7 @@@ int snd_hda_queue_unsol_event(struct hd
        unsol->queue[wp] = res;
        unsol->queue[wp + 1] = res_ex;
  
 -      schedule_work(&unsol->work);
 +      queue_work(bus->workq, &unsol->work);
  
        return 0;
  }
@@@ -437,17 -435,15 +437,17 @@@ static int snd_hda_bus_free(struct hda_
  
        if (!bus)
                return 0;
 -      if (bus->unsol) {
 -              flush_scheduled_work();
 +      if (bus->workq)
 +              flush_workqueue(bus->workq);
 +      if (bus->unsol)
                kfree(bus->unsol);
 -      }
        list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
                snd_hda_codec_free(codec);
        }
        if (bus->ops.private_free)
                bus->ops.private_free(bus);
 +      if (bus->workq)
 +              destroy_workqueue(bus->workq);
        kfree(bus);
        return 0;
  }
@@@ -487,7 -483,6 +487,7 @@@ int /*__devinit*/ snd_hda_bus_new(struc
  {
        struct hda_bus *bus;
        int err;
 +      char qname[8];
        static struct snd_device_ops dev_ops = {
                .dev_register = snd_hda_bus_dev_register,
                .dev_free = snd_hda_bus_dev_free,
        mutex_init(&bus->cmd_mutex);
        INIT_LIST_HEAD(&bus->codec_list);
  
 +      snprintf(qname, sizeof(qname), "hda%d", card->number);
 +      bus->workq = create_workqueue(qname);
 +      if (!bus->workq) {
 +              snd_printk(KERN_ERR "cannot create workqueue %s\n", qname);
 +              kfree(bus);
 +              return -ENOMEM;
 +      }
 +
        err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
        if (err < 0) {
                snd_hda_bus_free(bus);
@@@ -695,7 -682,7 +695,7 @@@ static void snd_hda_codec_free(struct h
                return;
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        cancel_delayed_work(&codec->power_work);
 -      flush_scheduled_work();
 +      flush_workqueue(codec->bus->workq);
  #endif
        list_del(&codec->list);
        snd_array_free(&codec->mixers);
   * Returns 0 if successful, or a negative error code.
   */
  int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
 -                              struct hda_codec **codecp)
 +                                  int do_init, struct hda_codec **codecp)
  {
        struct hda_codec *codec;
        char component[31];
        codec->bus = bus;
        codec->addr = codec_addr;
        mutex_init(&codec->spdif_mutex);
 +      mutex_init(&codec->control_mutex);
        init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
        if (bus->modelname)
                codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);
  
 -      err = snd_hda_codec_configure(codec);
 -      if (err < 0) {
 -              snd_hda_codec_free(codec);
 -              return err;
 +      if (do_init) {
 +              err = snd_hda_codec_configure(codec);
 +              if (err < 0) {
 +                      snd_hda_codec_free(codec);
 +                      return err;
 +              }
        }
        snd_hda_codec_proc_new(codec);
  
@@@ -1284,7 -1268,7 +1284,7 @@@ void snd_hda_codec_reset(struct hda_cod
  
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        cancel_delayed_work(&codec->power_work);
 -      flush_scheduled_work();
 +      flush_workqueue(codec->bus->workq);
  #endif
        snd_hda_ctls_clear(codec);
        /* relase PCMs */
        }
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
 +      codec->proc_widget_hook = NULL;
        codec->spec = NULL;
        free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
 +      init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
 +      init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        codec->num_pcms = 0;
        codec->pcm_info = NULL;
        codec->preset = NULL;
@@@ -1430,12 -1411,12 +1430,12 @@@ int snd_hda_mixer_bind_switch_get(struc
        unsigned long pval;
        int err;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        pval = kcontrol->private_value;
        kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
        err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
        kcontrol->private_value = pval;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
@@@ -1447,7 -1428,7 +1447,7 @@@ int snd_hda_mixer_bind_switch_put(struc
        unsigned long pval;
        int i, indices, err = 0, change = 0;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        pval = kcontrol->private_value;
        indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
        for (i = 0; i < indices; i++) {
                change |= err;
        }
        kcontrol->private_value = pval;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err < 0 ? err : change;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
@@@ -1474,12 -1455,12 +1474,12 @@@ int snd_hda_mixer_bind_ctls_info(struc
        struct hda_bind_ctls *c;
        int err;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        c = (struct hda_bind_ctls *)kcontrol->private_value;
        kcontrol->private_value = *c->values;
        err = c->ops->info(kcontrol, uinfo);
        kcontrol->private_value = (long)c;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
@@@ -1491,12 -1472,12 +1491,12 @@@ int snd_hda_mixer_bind_ctls_get(struct 
        struct hda_bind_ctls *c;
        int err;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        c = (struct hda_bind_ctls *)kcontrol->private_value;
        kcontrol->private_value = *c->values;
        err = c->ops->get(kcontrol, ucontrol);
        kcontrol->private_value = (long)c;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
@@@ -1509,7 -1490,7 +1509,7 @@@ int snd_hda_mixer_bind_ctls_put(struct 
        unsigned long *vals;
        int err = 0, change = 0;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        c = (struct hda_bind_ctls *)kcontrol->private_value;
        for (vals = c->values; *vals; vals++) {
                kcontrol->private_value = *vals;
                change |= err;
        }
        kcontrol->private_value = (long)c;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err < 0 ? err : change;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
@@@ -1531,12 -1512,12 +1531,12 @@@ int snd_hda_mixer_bind_tlv(struct snd_k
        struct hda_bind_ctls *c;
        int err;
  
 -      mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 +      mutex_lock(&codec->control_mutex);
        c = (struct hda_bind_ctls *)kcontrol->private_value;
        kcontrol->private_value = *c->values;
        err = c->ops->tlv(kcontrol, op_flag, size, tlv);
        kcontrol->private_value = (long)c;
 -      mutex_unlock(&codec->spdif_mutex);
 +      mutex_unlock(&codec->control_mutex);
        return err;
  }
  EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv);
@@@ -2723,6 -2704,67 +2723,67 @@@ int snd_hda_check_board_config(struct h
  }
  EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
  
+ /**
+  * snd_hda_check_board_codec_sid_config - compare the current codec
+                                         subsystem ID with the
+                                         config table
+          This is important for Gateway notebooks with SB450 HDA Audio
+          where the vendor ID of the PCI device is:
+               ATI Technologies Inc SB450 HDA Audio [1002:437b]
+          and the vendor/subvendor are found only at the codec.
+  * @codec: the HDA codec
+  * @num_configs: number of config enums
+  * @models: array of model name strings
+  * @tbl: configuration table, terminated by null entries
+  *
+  * Compares the modelname or PCI subsystem id of the current codec with the
+  * given configuration table.  If a matching entry is found, returns its
+  * config value (supposed to be 0 or positive).
+  *
+  * If no entries are matching, the function returns a negative value.
+  */
+ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
+                              int num_configs, const char **models,
+                              const struct snd_pci_quirk *tbl)
+ {
+       const struct snd_pci_quirk *q;
+       /* Search for codec ID */
+       for (q = tbl; q->subvendor; q++) {
+               unsigned long vendorid = (q->subdevice) | (q->subvendor << 16);
+               if (vendorid == codec->subsystem_id)
+                       break;
+       }
+       if (!q->subvendor)
+               return -1;
+       tbl = q;
+       if (tbl->value >= 0 && tbl->value < num_configs) {
+ #ifdef CONFIG_SND_DEBUG_DETECT
+               char tmp[10];
+               const char *model = NULL;
+               if (models)
+                       model = models[tbl->value];
+               if (!model) {
+                       sprintf(tmp, "#%d", tbl->value);
+                       model = tmp;
+               }
+               snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
+                           "for config %x:%x (%s)\n",
+                           model, tbl->subvendor, tbl->subdevice,
+                           (tbl->name ? tbl->name : "Unknown device"));
+ #endif
+               return tbl->value;
+       }
+       return -1;
+ }
+ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
  /**
   * snd_hda_add_new_ctls - create controls from the array
   * @codec: the HDA codec
@@@ -2815,7 -2857,7 +2876,7 @@@ void snd_hda_power_down(struct hda_code
                return;
        if (power_save(codec)) {
                codec->power_transition = 1; /* avoid reentrance */
 -              schedule_delayed_work(&codec->power_work,
 +              queue_delayed_work(codec->bus->workq, &codec->power_work,
                                msecs_to_jiffies(power_save(codec) * 1000));
        }
  }
index 9acf2f0a2df976a5ec4a940c8ddbe389729a4cfd,c05d4643afd51cdbeb5729a6fea7221306cabfe8..0e6fc56fa3787c37510a8554ac4c9ef073bf715b
@@@ -55,7 -55,8 +55,8 @@@ enum 
        STAC_9200_DELL_M25,
        STAC_9200_DELL_M26,
        STAC_9200_DELL_M27,
-       STAC_9200_GATEWAY,
+       STAC_9200_M4,
+       STAC_9200_M4_2,
        STAC_9200_PANASONIC,
        STAC_9200_MODELS
  };
@@@ -69,7 -70,6 +70,7 @@@ enum 
  };
  
  enum {
 +      STAC_92HD73XX_NO_JD, /* no jack-detection */
        STAC_92HD73XX_REF,
        STAC_DELL_M6_AMIC,
        STAC_DELL_M6_DMIC,
@@@ -94,9 -94,13 +95,13 @@@ enum 
  
  enum {
        STAC_925x_REF,
+       STAC_M1,
+       STAC_M1_2,
+       STAC_M2,
        STAC_M2_2,
-       STAC_MA6,
-       STAC_PA6,
+       STAC_M3,
+       STAC_M5,
+       STAC_M6,
        STAC_925x_MODELS
  };
  
@@@ -128,7 -132,6 +133,7 @@@ enum 
  };
  
  enum {
 +      STAC_D965_REF_NO_JD, /* no jack-detection */
        STAC_D965_REF,
        STAC_D965_3ST,
        STAC_D965_5ST,
@@@ -157,6 -160,8 +162,6 @@@ struct sigmatel_spec 
        int board_config;
        unsigned int eapd_switch: 1;
        unsigned int surr_switch: 1;
 -      unsigned int line_switch: 1;
 -      unsigned int mic_switch: 1;
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
        unsigned int cur_mmux;
        struct hda_multi_out multiout;
        hda_nid_t dac_nids[5];
 +      hda_nid_t hp_dacs[5];
 +      hda_nid_t speaker_dacs[5];
  
        /* capture */
        hda_nid_t *adc_nids;
        /* i/o switches */
        unsigned int io_switch[2];
        unsigned int clfe_swap;
 -      unsigned int hp_switch; /* NID of HP as line-out */
 +      hda_nid_t line_switch;  /* shared line-in for input and output */
 +      hda_nid_t mic_switch;   /* shared mic-in for input and output */
 +      hda_nid_t hp_switch; /* NID of HP as line-out */
        unsigned int aloopback;
  
        struct hda_pcm pcm_rec[2];      /* PCM information */
@@@ -291,6 -292,9 +296,6 @@@ static hda_nid_t stac92hd73xx_dmic_nids
  };
  
  #define STAC92HD73_DAC_COUNT 5
 -static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
 -      0x15, 0x16, 0x17, 0x18, 0x19,
 -};
  
  static hda_nid_t stac92hd73xx_mux_nids[4] = {
        0x28, 0x29, 0x2a, 0x2b,
@@@ -309,7 -313,11 +314,7 @@@ static hda_nid_t stac92hd83xxx_dmic_nid
        0x11, 0x12, 0
  };
  
 -#define STAC92HD81_DAC_COUNT 2
  #define STAC92HD83_DAC_COUNT 3
 -static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
 -      0x13, 0x14, 0x22,
 -};
  
  static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
        0x17, 0x18,
@@@ -351,6 -359,10 +356,6 @@@ static hda_nid_t stac92hd71bxx_smux_nid
        0x24, 0x25,
  };
  
 -static hda_nid_t stac92hd71bxx_dac_nids[1] = {
 -      0x10, /*0x11, */
 -};
 -
  #define STAC92HD71BXX_NUM_DMICS       2
  static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
        0x18, 0x19, 0
@@@ -582,12 -594,12 +587,12 @@@ static int stac92xx_smux_enum_put(struc
                else
                        nid = codec->slave_dig_outs[smux_idx - 1];
                if (spec->cur_smux[smux_idx] == smux->num_items - 1)
 -                      val = AMP_OUT_MUTE;
 +                      val = HDA_AMP_MUTE;
                else
 -                      val = AMP_OUT_UNMUTE;
 +                      val = 0;
                /* un/mute SPDIF out */
 -              snd_hda_codec_write_cache(codec, nid, 0,
 -                      AC_VERB_SET_AMP_GAIN_MUTE, val);
 +              snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 +                                       HDA_AMP_MUTE, val);
        }
        return 0;
  }
@@@ -752,6 -764,10 +757,6 @@@ static struct hda_verb stac9200_eapd_in
  static struct hda_verb stac92hd73xx_6ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* setup audio connections */
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
 -      { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
 -      { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@@ -770,6 -786,10 +775,6 @@@ static struct hda_verb dell_eq_core_ini
        /* set master volume to max value without distortion
         * and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
 -      /* setup audio connections */
 -      { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
  
  static struct hda_verb dell_m6_core_init[] = {
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* setup audio connections */
 -      { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
  static struct hda_verb stac92hd73xx_8ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* setup audio connections */
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
 -      { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
 -      { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
 -      /* connect hp ports to dac3 */
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
 -      { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
  static struct hda_verb stac92hd73xx_10ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* setup audio connections */
 -      { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
 -      { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
 -      { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
        /* dac3 is connected to import3 mux */
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
 -      /* connect hp ports to dac4 */
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
 -      { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@@ -841,17 -879,17 +846,17 @@@ static struct hda_verb stac92hd83xxx_co
  
        /* power state controls amps */
        { 0x01, AC_VERB_SET_EAPD, 1 << 2},
 +      {}
  };
  
  static struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* connect headphone jack to dac1 */
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {}
  };
  
  #define HD_DISABLE_PORTF 2
@@@ -866,6 -904,8 +871,6 @@@ static struct hda_verb stac92hd71bxx_an
  
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 -      /* connect headphone jack to dac1 */
 -      { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* unmute right and left channels for nodes 0x0a, 0xd */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@@ -1065,21 -1105,21 +1070,21 @@@ static struct snd_kcontrol_new stac92hd
        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, 0, HDA_INPUT),
 -      HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
 +      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, 0x1, HDA_INPUT),
 -      HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, 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, 0x2, HDA_INPUT),
 -      HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, 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, 0x3, HDA_INPUT),
 -      HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, 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, 0x4, HDA_INPUT),
 -      HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
 +      HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
 +      HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
        */
        { } /* end */
  };
@@@ -1256,7 -1296,7 +1261,7 @@@ static int stac92xx_build_controls(stru
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
 -              err = snd_ctl_add(codec->bus->card,
 +              err = snd_hda_ctl_add(codec,
                                  snd_ctl_new1(&stac_smux_mixer, codec));
                if (err < 0)
                        return err;
@@@ -1334,7 -1374,16 +1339,16 @@@ static unsigned int ref9200_pin_configs
        0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
  };
  
- /* 
+ static unsigned int gateway9200_m4_pin_configs[8] = {
+       0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+       0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+ };
+ static unsigned int gateway9200_m4_2_pin_configs[8] = {
+       0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+       0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+ };
+ /*
      STAC 9200 pin configs for
      102801A8
      102801DE
@@@ -1464,6 -1513,8 +1478,8 @@@ static unsigned int *stac9200_brd_tbl[S
        [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
        [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
        [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
+       [STAC_9200_M4] = gateway9200_m4_pin_configs,
+       [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs,
        [STAC_9200_PANASONIC] = ref9200_pin_configs,
  };
  
@@@ -1480,7 -1531,8 +1496,8 @@@ static const char *stac9200_models[STAC
        [STAC_9200_DELL_M25] = "dell-m25",
        [STAC_9200_DELL_M26] = "dell-m26",
        [STAC_9200_DELL_M27] = "dell-m27",
-       [STAC_9200_GATEWAY] = "gateway",
+       [STAC_9200_M4] = "gateway-m4",
+       [STAC_9200_M4_2] = "gateway-m4-2",
        [STAC_9200_PANASONIC] = "panasonic",
  };
  
@@@ -1550,11 -1602,9 +1567,9 @@@ static struct snd_pci_quirk stac9200_cf
        /* Panasonic */
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
        /* Gateway machines needs EAPD to be set on resume */
-       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
-       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
-                     STAC_9200_GATEWAY),
-       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
-                     STAC_9200_GATEWAY),
+       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
+       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
+       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
        /* OQO Mobile */
        SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
        {} /* terminator */
@@@ -1565,44 -1615,85 +1580,85 @@@ static unsigned int ref925x_pin_configs
        0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
  };
  
- static unsigned int stac925x_MA6_pin_configs[8] = {
-       0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-       0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+ static unsigned int stac925xM1_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
  };
  
- static unsigned int stac925x_PA6_pin_configs[8] = {
-       0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-       0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
+ static unsigned int stac925xM1_2_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+ };
+ static unsigned int stac925xM2_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
  };
  
  static unsigned int stac925xM2_2_pin_configs[8] = {
-       0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
-       0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+ };
+ static unsigned int stac925xM3_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
+ };
+ static unsigned int stac925xM5_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+ };
+ static unsigned int stac925xM6_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
  };
  
  static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
        [STAC_REF] = ref925x_pin_configs,
+       [STAC_M1] = stac925xM1_pin_configs,
+       [STAC_M1_2] = stac925xM1_2_pin_configs,
+       [STAC_M2] = stac925xM2_pin_configs,
        [STAC_M2_2] = stac925xM2_2_pin_configs,
-       [STAC_MA6] = stac925x_MA6_pin_configs,
-       [STAC_PA6] = stac925x_PA6_pin_configs,
+       [STAC_M3] = stac925xM3_pin_configs,
+       [STAC_M5] = stac925xM5_pin_configs,
+       [STAC_M6] = stac925xM6_pin_configs,
  };
  
  static const char *stac925x_models[STAC_925x_MODELS] = {
        [STAC_REF] = "ref",
+       [STAC_M1] = "m1",
+       [STAC_M1_2] = "m1-2",
+       [STAC_M2] = "m2",
        [STAC_M2_2] = "m2-2",
-       [STAC_MA6] = "m6",
-       [STAC_PA6] = "pa6",
+       [STAC_M3] = "m3",
+       [STAC_M5] = "m5",
+       [STAC_M6] = "m6",
+ };
+ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
+       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
+       /* Not sure about the brand name for those */
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
+       SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
+       {} /* terminator */
  };
  
  static struct snd_pci_quirk stac925x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
        SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
-       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
-       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
+       /* Default table for unknown ID */
+       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
        {} /* terminator */
  };
  
@@@ -1629,7 -1720,6 +1685,7 @@@ static unsigned int *stac92hd73xx_brd_t
  };
  
  static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
 +      [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
        [STAC_DELL_M6_AMIC] = "dell-m6-amic",
        [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
@@@ -1659,8 -1749,6 +1715,8 @@@ static struct snd_pci_quirk stac92hd73x
                                "unknown Dell", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
                                "Dell Studio 1537", STAC_DELL_M6_DMIC),
 +      SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
 +                              "Dell Studio 17", STAC_DELL_M6_DMIC),
        {} /* terminator */
  };
  
@@@ -1682,8 -1770,7 +1738,8 @@@ static const char *stac92hd83xxx_models
  static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 -                    "DFI LanParty", STAC_92HD71BXX_REF),
 +                    "DFI LanParty", STAC_92HD83XXX_REF),
 +      {} /* terminator */
  };
  
  static unsigned int ref92hd71bxx_pin_configs[11] = {
@@@ -1734,10 -1821,6 +1790,10 @@@ static struct snd_pci_quirk stac92hd71b
                      "HP dv5", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
                      "HP dv7", STAC_HP_M4),
 +      SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
 +                    "HP dv7", STAC_HP_M4),
 +      SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
 +                    "HP dv5", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
                                "unknown HP", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@@ -2053,7 -2136,6 +2109,7 @@@ static unsigned int dell_3st_pin_config
  };
  
  static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
 +      [STAC_D965_REF_NO_JD] = ref927x_pin_configs,
        [STAC_D965_REF]  = ref927x_pin_configs,
        [STAC_D965_3ST]  = d965_3st_pin_configs,
        [STAC_D965_5ST]  = d965_5st_pin_configs,
  };
  
  static const char *stac927x_models[STAC_927X_MODELS] = {
 +      [STAC_D965_REF_NO_JD]   = "ref-no-jd",
        [STAC_D965_REF]         = "ref",
        [STAC_D965_3ST]         = "3stack",
        [STAC_D965_5ST]         = "5stack",
@@@ -2387,7 -2468,7 +2443,7 @@@ static int stac92xx_capture_pcm_prepare
  
        if (spec->powerdown_adcs) {
                msleep(40);
 -              snd_hda_codec_write_cache(codec, nid, 0,
 +              snd_hda_codec_write(codec, nid, 0,
                        AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
        }
        snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
@@@ -2403,7 -2484,7 +2459,7 @@@ static int stac92xx_capture_pcm_cleanup
  
        snd_hda_codec_cleanup_stream(codec, nid);
        if (spec->powerdown_adcs)
 -              snd_hda_codec_write_cache(codec, nid, 0,
 +              snd_hda_codec_write(codec, nid, 0,
                        AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
        return 0;
  }
@@@ -2715,53 -2796,70 +2771,53 @@@ static inline int stac92xx_add_control(
        return stac92xx_add_control_idx(spec, type, 0, name, val);
  }
  
 -/* flag inputs as additional dynamic lineouts */
 -static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
 +/* check whether the line-input can be used as line-out */
 +static hda_nid_t check_line_out_switch(struct hda_codec *codec)
  {
        struct sigmatel_spec *spec = codec->spec;
 -      unsigned int wcaps, wtype;
 -      int i, num_dacs = 0;
 -      
 -      /* use the wcaps cache to count all DACs available for line-outs */
 -      for (i = 0; i < codec->num_nodes; i++) {
 -              wcaps = codec->wcaps[i];
 -              wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      hda_nid_t nid;
 +      unsigned int pincap;
  
 -              if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
 -                      num_dacs++;
 -      }
 +      if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
 +              return 0;
 +      nid = cfg->input_pins[AUTO_PIN_LINE];
 +      pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 +      if (pincap & AC_PINCAP_OUT)
 +              return nid;
 +      return 0;
 +}
  
 -      snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
 -      
 -      switch (cfg->line_outs) {
 -      case 3:
 -              /* add line-in as side */
 -              if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
 -                      cfg->line_out_pins[cfg->line_outs] =
 -                              cfg->input_pins[AUTO_PIN_LINE];
 -                      spec->line_switch = 1;
 -                      cfg->line_outs++;
 -              }
 -              break;
 -      case 2:
 -              /* add line-in as clfe and mic as side */
 -              if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
 -                      cfg->line_out_pins[cfg->line_outs] =
 -                              cfg->input_pins[AUTO_PIN_LINE];
 -                      spec->line_switch = 1;
 -                      cfg->line_outs++;
 -              }
 -              if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
 -                      cfg->line_out_pins[cfg->line_outs] =
 -                              cfg->input_pins[AUTO_PIN_MIC];
 -                      spec->mic_switch = 1;
 -                      cfg->line_outs++;
 -              }
 -              break;
 -      case 1:
 -              /* add line-in as surr and mic as clfe */
 -              if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
 -                      cfg->line_out_pins[cfg->line_outs] =
 -                              cfg->input_pins[AUTO_PIN_LINE];
 -                      spec->line_switch = 1;
 -                      cfg->line_outs++;
 -              }
 -              if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
 -                      cfg->line_out_pins[cfg->line_outs] =
 -                              cfg->input_pins[AUTO_PIN_MIC];
 -                      spec->mic_switch = 1;
 -                      cfg->line_outs++;
 +/* check whether the mic-input can be used as line-out */
 +static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
 +{
 +      struct sigmatel_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      unsigned int def_conf, pincap;
 +      unsigned int mic_pin;
 +
 +      if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
 +              return 0;
 +      mic_pin = AUTO_PIN_MIC;
 +      for (;;) {
 +              hda_nid_t nid = cfg->input_pins[mic_pin];
 +              def_conf = snd_hda_codec_read(codec, nid, 0,
 +                                            AC_VERB_GET_CONFIG_DEFAULT, 0);
 +              /* some laptops have an internal analog microphone
 +               * which can't be used as a output */
 +              if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
 +                      pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 +                      if (pincap & AC_PINCAP_OUT)
 +                              return nid;
                }
 -              break;
 +              if (mic_pin == AUTO_PIN_MIC)
 +                      mic_pin = AUTO_PIN_FRONT_MIC;
 +              else
 +                      break;
        }
 -
        return 0;
  }
  
 -
  static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
  {
        int i;
        return 0;
  }
  
 +static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 +{
 +      int i;
 +      if (is_in_dac_nids(spec, nid))
 +              return 1;
 +      for (i = 0; i < spec->autocfg.hp_outs; i++)
 +              if (spec->hp_dacs[i] == nid)
 +                      return 1;
 +      for (i = 0; i < spec->autocfg.speaker_outs; i++)
 +              if (spec->speaker_dacs[i] == nid)
 +                      return 1;
 +      return 0;
 +}
 +
 +static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
 +{
 +      struct sigmatel_spec *spec = codec->spec;
 +      int j, conn_len;
 +      hda_nid_t conn[HDA_MAX_CONNECTIONS];
 +      unsigned int wcaps, wtype;
 +
 +      conn_len = snd_hda_get_connections(codec, nid, conn,
 +                                         HDA_MAX_CONNECTIONS);
 +      for (j = 0; j < conn_len; j++) {
 +              wcaps = snd_hda_param_read(codec, conn[j],
 +                                         AC_PAR_AUDIO_WIDGET_CAP);
 +              wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 +              /* we check only analog outputs */
 +              if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
 +                      continue;
 +              /* if this route has a free DAC, assign it */
 +              if (!check_all_dac_nids(spec, conn[j])) {
 +                      if (conn_len > 1) {
 +                              /* select this DAC in the pin's input mux */
 +                              snd_hda_codec_write_cache(codec, nid, 0,
 +                                                AC_VERB_SET_CONNECT_SEL, j);
 +                      }
 +                      return conn[j];
 +              }
 +      }
 +      return 0;
 +}
 +
 +static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
 +static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
 +
  /*
   * Fill in the dac_nids table from the parsed pin configuration
   * This function only works when every pin in line_out_pins[]
   * codecs are not connected directly to a DAC, such as the 9200
   * and 9202/925x. For those, dac_nids[] must be hard-coded.
   */
 -static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
 -                                     struct auto_pin_cfg *cfg)
 +static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
  {
        struct sigmatel_spec *spec = codec->spec;
 -      int i, j, conn_len = 0; 
 -      hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
 -      unsigned int wcaps, wtype;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int i;
 +      hda_nid_t nid, dac;
        
        for (i = 0; i < cfg->line_outs; i++) {
                nid = cfg->line_out_pins[i];
 -              conn_len = snd_hda_get_connections(codec, nid, conn,
 -                                                 HDA_MAX_CONNECTIONS);
 -              for (j = 0; j < conn_len; j++) {
 -                      wcaps = snd_hda_param_read(codec, conn[j],
 -                                                 AC_PAR_AUDIO_WIDGET_CAP);
 -                      wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 -                      if (wtype != AC_WID_AUD_OUT ||
 -                          (wcaps & AC_WCAP_DIGITAL))
 -                              continue;
 -                      /* conn[j] is a DAC routed to this line-out */
 -                      if (!is_in_dac_nids(spec, conn[j]))
 -                              break;
 -              }
 -
 -              if (j == conn_len) {
 +              dac = get_unassigned_dac(codec, nid);
 +              if (!dac) {
                        if (spec->multiout.num_dacs > 0) {
                                /* we have already working output pins,
                                 * so let's drop the broken ones again
                                   __func__, nid);
                        return -ENODEV;
                }
 +              add_spec_dacs(spec, dac);
 +      }
  
 -              spec->multiout.dac_nids[i] = conn[j];
 -              spec->multiout.num_dacs++;
 -              if (conn_len > 1) {
 -                      /* select this DAC in the pin's input mux */
 -                      snd_hda_codec_write_cache(codec, nid, 0,
 -                                                AC_VERB_SET_CONNECT_SEL, j);
 +      /* add line-in as output */
 +      nid = check_line_out_switch(codec);
 +      if (nid) {
 +              dac = get_unassigned_dac(codec, nid);
 +              if (dac) {
 +                      snd_printdd("STAC: Add line-in 0x%x as output %d\n",
 +                                  nid, cfg->line_outs);
 +                      cfg->line_out_pins[cfg->line_outs] = nid;
 +                      cfg->line_outs++;
 +                      spec->line_switch = nid;
 +                      add_spec_dacs(spec, dac);
 +              }
 +      }
 +      /* add mic as output */
 +      nid = check_mic_out_switch(codec);
 +      if (nid) {
 +              dac = get_unassigned_dac(codec, nid);
 +              if (dac) {
 +                      snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
 +                                  nid, cfg->line_outs);
 +                      cfg->line_out_pins[cfg->line_outs] = nid;
 +                      cfg->line_outs++;
 +                      spec->mic_switch = nid;
 +                      add_spec_dacs(spec, dac);
 +              }
 +      }
  
 +      for (i = 0; i < cfg->hp_outs; i++) {
 +              nid = cfg->hp_pins[i];
 +              dac = get_unassigned_dac(codec, nid);
 +              if (dac) {
 +                      if (!spec->multiout.hp_nid)
 +                              spec->multiout.hp_nid = dac;
 +                      else
 +                              add_spec_extra_dacs(spec, dac);
                }
 +              spec->hp_dacs[i] = dac;
        }
  
 -      snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 +      for (i = 0; i < cfg->speaker_outs; i++) {
 +              nid = cfg->speaker_pins[i];
 +              dac = get_unassigned_dac(codec, nid);
 +              if (dac)
 +                      add_spec_extra_dacs(spec, dac);
 +              spec->speaker_dacs[i] = dac;
 +      }
 +
 +      snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   spec->multiout.num_dacs,
                   spec->multiout.dac_nids[0],
                   spec->multiout.dac_nids[1],
                   spec->multiout.dac_nids[2],
                   spec->multiout.dac_nids[3],
                   spec->multiout.dac_nids[4]);
 +
        return 0;
  }
  
@@@ -2933,7 -2959,9 +2989,7 @@@ static int create_controls(struct sigma
  
  static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
  {
 -      if (!spec->multiout.hp_nid)
 -              spec->multiout.hp_nid = nid;
 -      else if (spec->multiout.num_dacs > 4) {
 +      if (spec->multiout.num_dacs > 4) {
                printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
                return 1;
        } else {
        return 0;
  }
  
 -static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 +static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
  {
 -      if (is_in_dac_nids(spec, nid))
 -              return 1;
 +      int i;
 +      for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
 +              if (!spec->multiout.extra_out_nid[i]) {
 +                      spec->multiout.extra_out_nid[i] = nid;
 +                      return 0;
 +              }
 +      }
 +      printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
 +      return 1;
 +}
 +
 +static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
 +{
 +      int i;
 +
 +      if (spec->autocfg.line_outs != 1)
 +              return 0;
        if (spec->multiout.hp_nid == nid)
 -              return 1;
 -      return 0;
 +              return 0;
 +      for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
 +              if (spec->multiout.extra_out_nid[i] == nid)
 +                      return 0;
 +      return 1;
  }
  
  /* 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)
  {
 +      struct sigmatel_spec *spec = codec->spec;
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
        hda_nid_t nid = 0;
        int i, err;
 +      unsigned int wid_caps;
  
 -      struct sigmatel_spec *spec = codec->spec;
 -      unsigned int wid_caps, pincap;
 -
 -
 -      for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
 -              if (!spec->multiout.dac_nids[i])
 -                      continue;
 -
 +      for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
                nid = spec->multiout.dac_nids[i];
 -
                if (i == 2) {
                        /* Center/LFE */
                        err = create_controls(spec, "Center", nid, 1);
                        }
  
                } else {
 -                      err = create_controls(spec, chname[i], nid, 3);
 +                      const char *name = chname[i];
 +                      /* if it's a single DAC, assign a better name */
 +                      if (!i && is_unique_dac(spec, nid)) {
 +                              switch (cfg->line_out_type) {
 +                              case AUTO_PIN_HP_OUT:
 +                                      name = "Headphone";
 +                                      break;
 +                              case AUTO_PIN_SPEAKER_OUT:
 +                                      name = "Speaker";
 +                                      break;
 +                              }
 +                      }
 +                      err = create_controls(spec, name, nid, 3);
                        if (err < 0)
                                return err;
                }
        }
  
 -      if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
 -                      cfg->hp_outs && !spec->multiout.hp_nid)
 -              spec->multiout.hp_nid = nid;
 -
        if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
                err = stac92xx_add_control(spec,
                        STAC_CTL_WIDGET_HP_SWITCH,
        }
  
        if (spec->line_switch) {
 -              nid = cfg->input_pins[AUTO_PIN_LINE];
 -              pincap = snd_hda_param_read(codec, nid,
 -                                              AC_PAR_PIN_CAP);
 -              if (pincap & AC_PINCAP_OUT) {
 -                      err = stac92xx_add_control(spec,
 -                              STAC_CTL_WIDGET_IO_SWITCH,
 -                              "Line In as Output Switch", nid << 8);
 -                      if (err < 0)
 -                              return err;
 -              }
 +              err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
 +                                         "Line In as Output Switch",
 +                                         spec->line_switch << 8);
 +              if (err < 0)
 +                      return err;
        }
  
        if (spec->mic_switch) {
 -              unsigned int def_conf;
 -              unsigned int mic_pin = AUTO_PIN_MIC;
 -again:
 -              nid = cfg->input_pins[mic_pin];
 -              def_conf = snd_hda_codec_read(codec, nid, 0,
 -                                              AC_VERB_GET_CONFIG_DEFAULT, 0);
 -              /* some laptops have an internal analog microphone
 -               * which can't be used as a output */
 -              if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
 -                      pincap = snd_hda_param_read(codec, nid,
 -                                                      AC_PAR_PIN_CAP);
 -                      if (pincap & AC_PINCAP_OUT) {
 -                              err = stac92xx_add_control(spec,
 -                                      STAC_CTL_WIDGET_IO_SWITCH,
 -                                      "Mic as Output Switch", (nid << 8) | 1);
 -                              nid = snd_hda_codec_read(codec, nid, 0,
 -                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 -                              if (!check_in_dac_nids(spec, nid))
 -                                      add_spec_dacs(spec, nid);
 -                              if (err < 0)
 -                                      return err;
 -                      }
 -              } else if (mic_pin == AUTO_PIN_MIC) {
 -                      mic_pin = AUTO_PIN_FRONT_MIC;
 -                      goto again;
 -              }
 +              err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
 +                                         "Mic as Output Switch",
 +                                         (spec->mic_switch << 8) | 1);
 +              if (err < 0)
 +                      return err;
        }
  
        return 0;
@@@ -3057,39 -3091,55 +3113,39 @@@ static int stac92xx_auto_create_hp_ctls
  {
        struct sigmatel_spec *spec = codec->spec;
        hda_nid_t nid;
 -      int i, old_num_dacs, err;
 +      int i, err, nums;
  
 -      old_num_dacs = spec->multiout.num_dacs;
 +      nums = 0;
        for (i = 0; i < cfg->hp_outs; i++) {
 +              static const char *pfxs[] = {
 +                      "Headphone", "Headphone2", "Headphone3",
 +              };
                unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
                if (wid_caps & AC_WCAP_UNSOL_CAP)
                        spec->hp_detect = 1;
 -              nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
 -                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 -              if (check_in_dac_nids(spec, nid))
 -                      nid = 0;
 -              if (! nid)
 -                      continue;
 -              add_spec_dacs(spec, nid);
 -      }
 -      for (i = 0; i < cfg->speaker_outs; i++) {
 -              nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
 -                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 -              if (check_in_dac_nids(spec, nid))
 -                      nid = 0;
 -              if (! nid)
 +              if (nums >= ARRAY_SIZE(pfxs))
                        continue;
 -              add_spec_dacs(spec, nid);
 -      }
 -      for (i = 0; i < cfg->line_outs; i++) {
 -              nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
 -                                      AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 -              if (check_in_dac_nids(spec, nid))
 -                      nid = 0;
 -              if (! nid)
 +              nid = spec->hp_dacs[i];
 +              if (!nid)
                        continue;
 -              add_spec_dacs(spec, nid);
 +              err = create_controls(spec, pfxs[nums++], nid, 3);
 +              if (err < 0)
 +                      return err;
        }
 -      for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
 +      nums = 0;
 +      for (i = 0; i < cfg->speaker_outs; i++) {
                static const char *pfxs[] = {
                        "Speaker", "External Speaker", "Speaker2",
                };
 -              err = create_controls(spec, pfxs[i - old_num_dacs],
 -                                    spec->multiout.dac_nids[i], 3);
 -              if (err < 0)
 -                      return err;
 -      }
 -      if (spec->multiout.hp_nid) {
 -              err = create_controls(spec, "Headphone",
 -                                    spec->multiout.hp_nid, 3);
 +              if (nums >= ARRAY_SIZE(pfxs))
 +                      continue;
 +              nid = spec->speaker_dacs[i];
 +              if (!nid)
 +                      continue;
 +              err = create_controls(spec, pfxs[nums++], nid, 3);
                if (err < 0)
                        return err;
        }
 -
        return 0;
  }
  
@@@ -3427,6 -3477,7 +3483,6 @@@ static int stac92xx_parse_auto_config(s
  {
        struct sigmatel_spec *spec = codec->spec;
        int err;
 -      int hp_speaker_swap = 0;
  
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
                 * speaker_outs so that the following routines can handle
                 * HP pins as primary outputs.
                 */
 +              snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
                memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
                       sizeof(spec->autocfg.line_out_pins));
                spec->autocfg.speaker_outs = spec->autocfg.line_outs;
                memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
                       sizeof(spec->autocfg.hp_pins));
                spec->autocfg.line_outs = spec->autocfg.hp_outs;
 -              hp_speaker_swap = 1;
 +              spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
 +              spec->autocfg.hp_outs = 0;
        }
        if (spec->autocfg.mono_out_pin) {
                int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
                                         AC_PINCTL_OUT_EN);
        }
  
 -      if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
 -              return err;
 -      if (spec->multiout.num_dacs == 0)
 -              if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
 +      if (!spec->multiout.num_dacs) {
 +              err = stac92xx_auto_fill_dac_nids(codec);
 +              if (err < 0)
                        return err;
 +      }
  
        err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
  
        }
  #endif
  
 -      if (hp_speaker_swap == 1) {
 -              /* Restore the hp_outs and line_outs */
 -              memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
 -                     sizeof(spec->autocfg.line_out_pins));
 -              spec->autocfg.hp_outs = spec->autocfg.line_outs;
 -              memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
 -                     sizeof(spec->autocfg.speaker_pins));
 -              spec->autocfg.line_outs = spec->autocfg.speaker_outs;
 -              memset(spec->autocfg.speaker_pins, 0,
 -                     sizeof(spec->autocfg.speaker_pins));
 -              spec->autocfg.speaker_outs = 0;
 -      }
 -
        err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
  
        if (err < 0)
                spec->mixers[spec->num_mixers++] = spec->kctls.list;
  
        spec->input_mux = &spec->private_imux;
 -      spec->dinput_mux = &spec->private_dimux;
 +      if (!spec->dinput_mux)
 +              spec->dinput_mux = &spec->private_dimux;
        spec->sinput_mux = &spec->private_smux;
        spec->mono_mux = &spec->private_mono_mux;
        spec->amp_mux = &spec->private_amp_mux;
@@@ -3858,8 -3919,9 +3914,8 @@@ static void stac92xx_power_down(struct 
        /* power down inactive DACs */
        hda_nid_t *dac;
        for (dac = spec->dac_list; *dac; dac++)
 -              if (!is_in_dac_nids(spec, *dac) &&
 -                      spec->multiout.hp_nid != *dac)
 -                      snd_hda_codec_write_cache(codec, *dac, 0,
 +              if (!check_all_dac_nids(spec, *dac))
 +                      snd_hda_codec_write(codec, *dac, 0,
                                        AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
  }
  
@@@ -3878,7 -3940,7 +3934,7 @@@ static int stac92xx_init(struct hda_cod
        /* power down adcs initially */
        if (spec->powerdown_adcs)
                for (i = 0; i < spec->num_adcs; i++)
 -                      snd_hda_codec_write_cache(codec,
 +                      snd_hda_codec_write(codec,
                                spec->adc_nids[i], 0,
                                AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
  
        } 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);
        }
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = cfg->input_pins[i];
                if (nid) {
 -                      unsigned int pinctl;
 +                      unsigned int pinctl, conf;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
                                /* for mic pins, force to initialize */
                                pinctl = stac92xx_get_vref(codec, nid);
 +                              pinctl |= AC_PINCTL_IN_EN;
 +                              stac92xx_auto_set_pinctl(codec, nid, pinctl);
                        } else {
                                pinctl = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                                /* if PINCTL already set then skip */
 -                              if (pinctl & AC_PINCTL_IN_EN)
 -                                      continue;
 +                              if (!(pinctl & AC_PINCTL_IN_EN)) {
 +                                      pinctl |= AC_PINCTL_IN_EN;
 +                                      stac92xx_auto_set_pinctl(codec, nid,
 +                                                               pinctl);
 +                              }
 +                      }
 +                      conf = snd_hda_codec_read(codec, nid, 0,
 +                                            AC_VERB_GET_CONFIG_DEFAULT, 0);
 +                      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);
                        }
 -                      pinctl |= AC_PINCTL_IN_EN;
 -                      stac92xx_auto_set_pinctl(codec, nid, pinctl);
 -                      enable_pin_detect(codec, nid, STAC_INSERT_EVENT);
                }
        }
        for (i = 0; i < spec->num_dmics; i++)
                hda_nid_t nid = spec->pwr_nids[i];
                int pinctl, def_conf;
  
 -              if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
 +              /* power on when no jack detection is available */
 +              if (!spec->hp_detect) {
 +                      stac_toggle_power_map(codec, nid, 1);
 +                      continue;
 +              }
 +
 +              if (is_nid_hp_pin(cfg, nid))
                        continue; /* already has an unsol event */
  
                pinctl = snd_hda_codec_read(codec, nid, 0,
                 * any attempts on powering down a input port cause the
                 * referenced VREF to act quirky.
                 */
 -              if (pinctl & AC_PINCTL_IN_EN)
 +              if (pinctl & AC_PINCTL_IN_EN) {
 +                      stac_toggle_power_map(codec, nid, 1);
                        continue;
 +              }
                def_conf = snd_hda_codec_read(codec, nid, 0,
                                              AC_VERB_GET_CONFIG_DEFAULT, 0);
                def_conf = get_defcfg_connect(def_conf);
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
 -              enable_pin_detect(codec, nid, STAC_PWR_EVENT);
 -              stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
 +              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 (spec->dac_list)
                stac92xx_power_down(codec);
@@@ -4049,7 -4089,11 +4105,7 @@@ static void stac92xx_set_pinctl(struct 
                 * "xxx as Output" mixer switch
                 */
                struct sigmatel_spec *spec = codec->spec;
 -              struct auto_pin_cfg *cfg = &spec->autocfg;
 -              if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
 -                   spec->line_switch) ||
 -                  (nid == cfg->input_pins[AUTO_PIN_MIC] &&
 -                   spec->mic_switch))
 +              if (nid == spec->line_switch || nid == spec->mic_switch)
                        return;
        }
  
@@@ -4073,13 -4117,20 +4129,13 @@@ static void stac92xx_reset_pinctl(struc
                        pin_ctl & ~flag);
  }
  
 -static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 +static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
  {
        if (!nid)
                return 0;
        if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
 -          & (1 << 31)) {
 -              unsigned int pinctl;
 -              pinctl = snd_hda_codec_read(codec, nid, 0,
 -                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 -              if (pinctl & AC_PINCTL_IN_EN)
 -                      return 0; /* mic- or line-input */
 -              else
 -                      return 1; /* HP-output */
 -      }
 +          & (1 << 31))
 +              return 1;
        return 0;
  }
  
@@@ -4091,9 -4142,11 +4147,9 @@@ static int no_hp_sensing(struct sigmate
        struct auto_pin_cfg *cfg = &spec->autocfg;
  
        /* ignore sensing of shared line and mic jacks */
 -      if (spec->line_switch &&
 -          cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
 +      if (cfg->hp_pins[i] == spec->line_switch)
                return 1;
 -      if (spec->mic_switch &&
 -          cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
 +      if (cfg->hp_pins[i] == spec->mic_switch)
                return 1;
        /* ignore if the pin is set as line-out */
        if (cfg->hp_pins[i] == spec->hp_switch)
@@@ -4117,14 -4170,7 +4173,14 @@@ static void stac92xx_hp_detect(struct h
                        break;
                if (no_hp_sensing(spec, i))
                        continue;
 -              presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
 +              presence = get_pin_presence(codec, cfg->hp_pins[i]);
 +              if (presence) {
 +                      unsigned int pinctl;
 +                      pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
 +                                          AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 +                      if (pinctl & AC_PINCTL_IN_EN)
 +                              presence = 0; /* mic- or line-input */
 +              }
        }
  
        if (presence) {
@@@ -4201,7 -4247,7 +4257,7 @@@ static void stac_toggle_power_map(struc
  
  static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
  {
 -      stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
 +      stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
  }
  
  static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
                                        type = (pin_ctl & AC_PINCTL_HP_EN)
                                        ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
                                snd_jack_report(jacks->jack,
 -                                      get_hp_pin_presence(codec, nid)
 +                                      get_pin_presence(codec, nid)
                                        ? type : 0);
                        }
                        jacks++;
@@@ -4271,52 -4317,6 +4327,52 @@@ static void stac92xx_unsol_event(struc
        }
  }
  
 +#ifdef CONFIG_PROC_FS
 +static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
 +                             struct hda_codec *codec, hda_nid_t nid)
 +{
 +      if (nid == codec->afg)
 +              snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
 +                          snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
 +}
 +
 +static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
 +                                struct hda_codec *codec,
 +                                unsigned int verb)
 +{
 +      snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
 +                  snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
 +}
 +
 +/* stac92hd71bxx, stac92hd73xx */
 +static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
 +                               struct hda_codec *codec, hda_nid_t nid)
 +{
 +      stac92hd_proc_hook(buffer, codec, nid);
 +      if (nid == codec->afg)
 +              analog_loop_proc_hook(buffer, codec, 0xfa0);
 +}
 +
 +static void stac9205_proc_hook(struct snd_info_buffer *buffer,
 +                             struct hda_codec *codec, hda_nid_t nid)
 +{
 +      if (nid == codec->afg)
 +              analog_loop_proc_hook(buffer, codec, 0xfe0);
 +}
 +
 +static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 +                             struct hda_codec *codec, hda_nid_t nid)
 +{
 +      if (nid == codec->afg)
 +              analog_loop_proc_hook(buffer, codec, 0xfeb);
 +}
 +#else
 +#define stac92hd_proc_hook    NULL
 +#define stac92hd7x_proc_hook  NULL
 +#define stac9205_proc_hook    NULL
 +#define stac927x_proc_hook    NULL
 +#endif
 +
  #ifdef SND_HDA_NEEDS_RESUME
  static int stac92xx_resume(struct hda_codec *codec)
  {
@@@ -4392,7 -4392,8 +4448,8 @@@ static int patch_stac9200(struct hda_co
        spec->num_adcs = 1;
        spec->num_pwrs = 0;
  
-       if (spec->board_config == STAC_9200_GATEWAY ||
+       if (spec->board_config == STAC_9200_M4 ||
+           spec->board_config == STAC_9200_M4_2 ||
            spec->board_config == STAC_9200_OQO)
                spec->init = stac9200_eapd_init;
        else
@@@ -4427,12 -4428,22 +4484,22 @@@ static int patch_stac925x(struct hda_co
        codec->spec = spec;
        spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
-       spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+       /* Check first for codec ID */
+       spec->board_config = snd_hda_check_board_codec_sid_config(codec,
+                                                       STAC_925x_MODELS,
+                                                       stac925x_models,
+                                                       stac925x_codec_id_cfg_tbl);
+       /* Now checks for PCI ID, if codec ID is not found */
+       if (spec->board_config < 0)
+               spec->board_config = snd_hda_check_board_config(codec,
+                                                       STAC_925x_MODELS,
                                                        stac925x_models,
                                                        stac925x_cfg_tbl);
   again:
        if (spec->board_config < 0) {
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," 
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
                                      "using BIOS defaults\n");
                err = stac92xx_save_bios_config_regs(codec);
        } else
@@@ -4504,7 -4515,6 +4571,7 @@@ static int patch_stac92hd73xx(struct hd
        struct sigmatel_spec *spec;
        hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
        int err = 0;
 +      int num_dacs;
  
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@@ -4531,15 -4541,16 +4598,15 @@@ again
                return err;
        }
  
 -      spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
 +      num_dacs = snd_hda_get_connections(codec, 0x0a,
                        conn, STAC92HD73_DAC_COUNT + 2) - 1;
  
 -      if (spec->multiout.num_dacs < 0) {
 +      if (num_dacs < 3 || num_dacs > 5) {
                printk(KERN_WARNING "hda_codec: Could not determine "
                       "number of channels defaulting to DAC count\n");
 -              spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
 +              num_dacs = STAC92HD73_DAC_COUNT;
        }
 -
 -      switch (spec->multiout.num_dacs) {
 +      switch (num_dacs) {
        case 0x3: /* 6 Channel */
                spec->mixer = stac92hd73xx_6ch_mixer;
                spec->init = stac92hd73xx_6ch_core_init;
        case 0x5: /* 10 Channel */
                spec->mixer = stac92hd73xx_10ch_mixer;
                spec->init = stac92hd73xx_10ch_core_init;
 -      };
 +      }
 +      spec->multiout.dac_nids = spec->dac_nids;
  
 -      spec->multiout.dac_nids = stac92hd73xx_dac_nids;
        spec->aloopback_mask = 0x01;
        spec->aloopback_shift = 8;
  
                spec->eapd_switch = 0;
                spec->num_amps = 1;
  
 -              if (!spec->init)
 +              if (spec->board_config != STAC_DELL_EQ)
                        spec->init = dell_m6_core_init;
                switch (spec->board_config) {
                case STAC_DELL_M6_AMIC: /* Analog Mics */
                return err;
        }
  
 +      if (spec->board_config == STAC_92HD73XX_NO_JD)
 +              spec->hp_detect = 0;
 +
        codec->patch_ops = stac92xx_patch_ops;
  
 +      codec->proc_widget_hook = stac92hd7x_proc_hook;
 +
        return 0;
  }
  
@@@ -4676,15 -4682,17 +4743,15 @@@ static int patch_stac92hd83xxx(struct h
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
        spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
 -      spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
 +      spec->multiout.dac_nids = spec->dac_nids;
  
        spec->init = stac92hd83xxx_core_init;
        switch (codec->vendor_id) {
        case 0x111d7605:
 -              spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
                break;
        default:
                spec->num_pwrs--;
                spec->init++; /* switch to config #2 */
 -              spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
        }
  
        spec->mixer = stac92hd83xxx_mixer;
@@@ -4729,11 -4737,51 +4796,11 @@@ again
  
        codec->patch_ops = stac92xx_patch_ops;
  
 -      return 0;
 -}
 +      codec->proc_widget_hook = stac92hd_proc_hook;
  
 -#ifdef SND_HDA_NEEDS_RESUME
 -static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
 -{
 -      struct sigmatel_spec *spec = codec->spec;
 -      int i;
 -      snd_hda_codec_write_cache(codec, codec->afg, 0,
 -              AC_VERB_SET_POWER_STATE, pwr);
 -
 -      msleep(1);
 -      for (i = 0; i < spec->num_adcs; i++) {
 -              snd_hda_codec_write_cache(codec,
 -                      spec->adc_nids[i], 0,
 -                      AC_VERB_SET_POWER_STATE, pwr);
 -      }
 -};
 -
 -static int stac92hd71xx_resume(struct hda_codec *codec)
 -{
 -      stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
 -      return stac92xx_resume(codec);
 +      return 0;
  }
  
 -static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
 -{
 -      stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
 -      return stac92xx_suspend(codec, state);
 -};
 -
 -#endif
 -
 -static struct hda_codec_ops stac92hd71bxx_patch_ops = {
 -      .build_controls = stac92xx_build_controls,
 -      .build_pcms = stac92xx_build_pcms,
 -      .init = stac92xx_init,
 -      .free = stac92xx_free,
 -      .unsol_event = stac92xx_unsol_event,
 -#ifdef SND_HDA_NEEDS_RESUME
 -      .suspend = stac92hd71xx_suspend,
 -      .resume = stac92hd71xx_resume,
 -#endif
 -};
 -
  static struct hda_input_mux stac92hd71bxx_dmux = {
        .num_items = 4,
        .items = {
@@@ -4810,8 -4858,12 +4877,8 @@@ again
                        break;
                }
                if ((codec->revision_id & 0xf) == 0 ||
 -                              (codec->revision_id & 0xf) == 1) {
 -#ifdef SND_HDA_NEEDS_RESUME
 -                      codec->patch_ops = stac92hd71bxx_patch_ops;
 -#endif
 +                  (codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 -              }
  
                /* no output amps */
                spec->num_pwrs = 0;
                stac_change_pin_config(codec, 0xf, 0x40f000f0);
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
 -              if ((codec->revision_id & 0xf) == 1) {
 -#ifdef SND_HDA_NEEDS_RESUME
 -                      codec->patch_ops = stac92hd71bxx_patch_ops;
 -#endif
 +              if ((codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 -              }
  
                /* no output amps */
                spec->num_pwrs = 0;
                spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
        };
  
 -      spec->multiout.num_dacs = 1;
 -      spec->multiout.hp_nid = 0x11;
 -      spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
 +      spec->multiout.dac_nids = spec->dac_nids;
        if (spec->dinput_mux)
                spec->private_dimux.num_items +=
                        spec->num_dmics -
                return err;
        }
  
 +      codec->proc_widget_hook = stac92hd7x_proc_hook;
 +
        return 0;
  };
  
@@@ -5119,8 -5175,6 +5186,8 @@@ static int patch_stac927x(struct hda_co
  
        codec->patch_ops = stac92xx_patch_ops;
  
 +      codec->proc_widget_hook = stac927x_proc_hook;
 +
        /*
         * !!FIXME!!
         * The STAC927x seem to require fairly long delays for certain
         */
        codec->bus->needs_damn_long_delay = 1;
  
 +      /* no jack detecion for ref-no-jd model */
 +      if (spec->board_config == STAC_D965_REF_NO_JD)
 +              spec->hp_detect = 0;
 +
        return 0;
  }
  
@@@ -5240,8 -5290,6 +5307,8 @@@ static int patch_stac9205(struct hda_co
  
        codec->patch_ops = stac92xx_patch_ops;
  
 +      codec->proc_widget_hook = stac9205_proc_hook;
 +
        return 0;
  }
  
@@@ -5362,7 -5410,7 +5429,7 @@@ static int stac9872_vaio_init(struct hd
  
  static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
  {
 -      if (get_hp_pin_presence(codec, 0x0a)) {
 +      if (get_pin_presence(codec, 0x0a)) {
                stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
                stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
        } else {