Merge branch 'topic/hda-cache' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Tue, 21 Apr 2009 09:11:54 +0000 (11:11 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 21 Apr 2009 09:11:54 +0000 (11:11 +0200)
1  2 
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c

@@@ -48,7 -48,6 +48,7 @@@ static struct hda_vendor_id hda_vendor_
        { 0x1095, "Silicon Image" },
        { 0x10de, "Nvidia" },
        { 0x10ec, "Realtek" },
 +      { 0x1102, "Creative" },
        { 0x1106, "VIA" },
        { 0x111d, "IDT" },
        { 0x11c1, "LSI" },
@@@ -175,14 -174,23 +175,23 @@@ unsigned int snd_hda_codec_read(struct 
                                unsigned int verb, unsigned int parm)
  {
        struct hda_bus *bus = codec->bus;
-       unsigned int res;
+       unsigned int cmd, res;
+       int repeated = 0;
  
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
+       cmd = make_codec_cmd(codec, nid, direct, verb, parm);
        snd_hda_power_up(codec);
        mutex_lock(&bus->cmd_mutex);
-       if (!bus->ops.command(bus, res))
+  again:
+       if (!bus->ops.command(bus, cmd)) {
                res = bus->ops.get_response(bus);
-       else
+               if (res == -1 && bus->rirb_error) {
+                       if (repeated++ < 1) {
+                               snd_printd(KERN_WARNING "hda_codec: "
+                                          "Trying verb 0x%08x again\n", cmd);
+                               goto again;
+                       }
+               }
+       } else
                res = (unsigned int)-1;
        mutex_unlock(&bus->cmd_mutex);
        snd_hda_power_down(codec);
@@@ -643,21 -651,19 +652,21 @@@ static int get_codec_name(struct hda_co
   */
  static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
  {
 -      int i, total_nodes;
 +      int i, total_nodes, function_id;
        hda_nid_t nid;
  
        total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
        for (i = 0; i < total_nodes; i++, nid++) {
 -              codec->function_id = snd_hda_param_read(codec, nid,
 +              function_id = snd_hda_param_read(codec, nid,
                                                AC_PAR_FUNCTION_TYPE) & 0xff;
 -              switch (codec->function_id) {
 +              switch (function_id) {
                case AC_GRP_AUDIO_FUNCTION:
                        codec->afg = nid;
 +                      codec->function_id = function_id;
                        break;
                case AC_GRP_MODEM_FUNCTION:
                        codec->mfg = nid;
 +                      codec->function_id = function_id;
                        break;
                default:
                        break;
@@@ -1056,6 -1062,8 +1065,8 @@@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup
  /* FIXME: more better hash key? */
  #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
  #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
+ #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
+ #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
  #define INFO_AMP_CAPS (1<<0)
  #define INFO_AMP_VOL(ch)      (1 << (1 + (ch)))
  
@@@ -1146,19 -1154,32 +1157,32 @@@ int snd_hda_override_amp_caps(struct hd
  }
  EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
  
- u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+ static unsigned int
+ query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
+               unsigned int (*func)(struct hda_codec *, hda_nid_t))
  {
        struct hda_amp_info *info;
  
-       info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+       info = get_alloc_amp_hash(codec, key);
        if (!info)
                return 0;
        if (!info->head.val) {
-               info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
                info->head.val |= INFO_AMP_CAPS;
+               info->amp_caps = func(codec, nid);
        }
        return info->amp_caps;
  }
+ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+ {
+       return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+ }
+ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+ {
+       return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+                              read_pin_cap);
+ }
  EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
  
  /*
@@@ -1433,8 -1454,6 +1457,8 @@@ _snd_hda_find_mixer_ctl(struct hda_code
        memset(&id, 0, sizeof(id));
        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        id.index = idx;
 +      if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
 +              return NULL;
        strcpy(id.name, name);
        return snd_ctl_find_id(codec->bus->card, &id);
  }
@@@ -2255,11 -2274,7 +2279,11 @@@ int snd_hda_codec_write_cache(struct hd
        err = bus->ops.command(bus, res);
        if (!err) {
                struct hda_cache_head *c;
 -              u32 key = build_cmd_cache_key(nid, verb);
 +              u32 key;
 +              /* parm may contain the verb stuff for get/set amp */
 +              verb = verb | (parm >> 8);
 +              parm &= 0xff;
 +              key = build_cmd_cache_key(nid, verb);
                c = get_alloc_hash(&codec->cmd_cache, key);
                if (c)
                        c->val = parm;
@@@ -2547,6 -2562,41 +2571,41 @@@ unsigned int snd_hda_calc_stream_format
  }
  EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
  
+ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+ {
+       unsigned int val = 0;
+       if (nid != codec->afg &&
+           (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+       if (!val || val == -1)
+               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+       if (!val || val == -1)
+               return 0;
+       return val;
+ }
+ static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+ {
+       return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+                              get_pcm_param);
+ }
+ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+ {
+       unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+       if (!streams || streams == -1)
+               streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+       if (!streams || streams == -1)
+               return 0;
+       return streams;
+ }
+ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
+ {
+       return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+                              get_stream_param);
+ }
  /**
   * snd_hda_query_supported_pcm - query the supported PCM rates and formats
   * @codec: the HDA codec
@@@ -2565,15 -2615,8 +2624,8 @@@ static int snd_hda_query_supported_pcm(
  {
        unsigned int i, val, wcaps;
  
-       val = 0;
        wcaps = get_wcaps(codec, nid);
-       if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
-               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-               if (val == -1)
-                       return -EIO;
-       }
-       if (!val)
-               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+       val = query_pcm_param(codec, nid);
  
        if (ratesp) {
                u32 rates = 0;
                u64 formats = 0;
                unsigned int streams, bps;
  
-               streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-               if (streams == -1)
+               streams = query_stream_param(codec, nid);
+               if (!streams)
                        return -EIO;
-               if (!streams) {
-                       streams = snd_hda_param_read(codec, codec->afg,
-                                                    AC_PAR_STREAM);
-                       if (streams == -1)
-                               return -EIO;
-               }
  
                bps = 0;
                if (streams & AC_SUPFMT_PCM) {
@@@ -2677,17 -2714,9 +2723,9 @@@ int snd_hda_is_supported_format(struct 
        int i;
        unsigned int val = 0, rate, stream;
  
-       if (nid != codec->afg &&
-           (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
-               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-               if (val == -1)
-                       return 0;
-       }
-       if (!val) {
-               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
-               if (val == -1)
-                       return 0;
-       }
+       val = query_pcm_param(codec, nid);
+       if (!val)
+               return 0;
  
        rate = format & 0xff00;
        for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
        if (i >= AC_PAR_PCM_RATE_BITS)
                return 0;
  
-       stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-       if (stream == -1)
-               return 0;
-       if (!stream && nid != codec->afg)
-               stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
-       if (!stream || stream == -1)
+       stream = query_stream_param(codec, nid);
+       if (!stream)
                return 0;
  
        if (stream & AC_SUPFMT_PCM) {
@@@ -312,8 -312,6 +312,8 @@@ struct azx_dev 
        unsigned int period_bytes; /* size of the period in bytes */
        unsigned int frags;     /* number for period in the play buffer */
        unsigned int fifo_size; /* FIFO size */
 +      unsigned long start_jiffies;    /* start + minimum jiffies */
 +      unsigned long min_jiffies;      /* minimum jiffies before position is valid */
  
        void __iomem *sd_addr;  /* stream descriptor pointer */
  
        unsigned int opened :1;
        unsigned int running :1;
        unsigned int irq_pending :1;
 -      unsigned int irq_ignore :1;
 +      unsigned int start_flag: 1;     /* stream full start flag */
        /*
         * For VIA:
         *  A flag to ensure DMA position is 0
@@@ -606,6 -604,7 +606,7 @@@ static unsigned int azx_rirb_get_respon
                }
                if (!chip->rirb.cmds) {
                        smp_rmb();
+                       bus->rirb_error = 0;
                        return chip->rirb.res; /* the last value */
                }
                if (time_after(jiffies, timeout))
                chip->irq = -1;
                pci_disable_msi(chip->pci);
                chip->msi = 0;
-               if (azx_acquire_irq(chip, 1) < 0)
+               if (azx_acquire_irq(chip, 1) < 0) {
+                       bus->rirb_error = 1;
                        return -1;
+               }
                goto again;
        }
  
                return -1;
        }
  
-       snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-                  "switching to single_cmd mode: last cmd=0x%08x\n",
-                  chip->last_cmd);
-       chip->rirb.rp = azx_readb(chip, RIRBWP);
-       chip->rirb.cmds = 0;
-       /* switch to single_cmd mode */
-       chip->single_cmd = 1;
-       azx_free_cmd_io(chip);
+       snd_printk(KERN_ERR "hda_intel: azx_get_response timeout (ERROR): "
+                  "last cmd=0x%08x\n", chip->last_cmd);
+       spin_lock_irq(&chip->reg_lock);
+       chip->rirb.cmds = 0; /* reset the index */
+       bus->rirb_error = 1;
+       spin_unlock_irq(&chip->reg_lock);
        return -1;
  }
  
@@@ -977,7 -976,7 +978,7 @@@ static irqreturn_t azx_interrupt(int ir
        struct azx *chip = dev_id;
        struct azx_dev *azx_dev;
        u32 status;
 -      int i;
 +      int i, ok;
  
        spin_lock(&chip->reg_lock);
  
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
                        if (!azx_dev->substream || !azx_dev->running)
                                continue;
 -                      /* ignore the first dummy IRQ (due to pos_adj) */
 -                      if (azx_dev->irq_ignore) {
 -                              azx_dev->irq_ignore = 0;
 -                              continue;
 -                      }
                        /* check whether this IRQ is really acceptable */
 -                      if (azx_position_ok(chip, azx_dev)) {
 +                      ok = azx_position_ok(chip, azx_dev);
 +                      if (ok == 1) {
                                azx_dev->irq_pending = 0;
                                spin_unlock(&chip->reg_lock);
                                snd_pcm_period_elapsed(azx_dev->substream);
                                spin_lock(&chip->reg_lock);
 -                      } else if (chip->bus && chip->bus->workq) {
 +                      } else if (ok == 0 && chip->bus && chip->bus->workq) {
                                /* bogus IRQ, process it later */
                                azx_dev->irq_pending = 1;
                                queue_work(chip->bus->workq,
@@@ -1086,6 -1089,7 +1087,6 @@@ static int azx_setup_periods(struct az
        bdl = (u32 *)azx_dev->bdl.area;
        ofs = 0;
        azx_dev->frags = 0;
 -      azx_dev->irq_ignore = 0;
        pos_adj = bdl_pos_adj[chip->dev_index];
        if (pos_adj > 0) {
                struct snd_pcm_runtime *runtime = substream->runtime;
                                         &bdl, ofs, pos_adj, 1);
                        if (ofs < 0)
                                goto error;
 -                      azx_dev->irq_ignore = 1;
                }
        } else
                pos_adj = 0;
@@@ -1151,9 -1156,6 +1152,9 @@@ static void azx_stream_reset(struct az
        while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
               --timeout)
                ;
 +
 +      /* reset first position - may not be synced with hw at this time */
 +      *azx_dev->posbuf = 0;
  }
  
  /*
@@@ -1408,6 -1410,7 +1409,6 @@@ static int azx_pcm_open(struct snd_pcm_
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
  
 -      azx_stream_reset(chip, azx_dev);
        return 0;
  }
  
@@@ -1472,7 -1475,6 +1473,7 @@@ static int azx_pcm_prepare(struct snd_p
        unsigned int bufsize, period_bytes, format_val;
        int err;
  
 +      azx_stream_reset(chip, azx_dev);
        format_val = snd_hda_calc_stream_format(runtime->rate,
                                                runtime->channels,
                                                runtime->format,
                        return err;
        }
  
 +      azx_dev->min_jiffies = (runtime->period_size * HZ) /
 +                                              (runtime->rate * 2);
        azx_setup_controller(chip, azx_dev);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@@ -1519,14 -1519,13 +1520,14 @@@ static int azx_pcm_trigger(struct snd_p
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev;
        struct snd_pcm_substream *s;
 -      int start, nsync = 0, sbits = 0;
 +      int rstart = 0, start, nsync = 0, sbits = 0;
        int nwait, timeout;
  
        switch (cmd) {
 +      case SNDRV_PCM_TRIGGER_START:
 +              rstart = 1;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
 -      case SNDRV_PCM_TRIGGER_START:
                start = 1;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (s->pcm->card != substream->pcm->card)
                        continue;
                azx_dev = get_azx_dev(s);
 +              if (rstart) {
 +                      azx_dev->start_flag = 1;
 +                      azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
 +              }
                if (start)
                        azx_stream_start(chip, azx_dev);
                else
@@@ -1709,11 -1704,6 +1710,11 @@@ static int azx_position_ok(struct azx *
  {
        unsigned int pos;
  
 +      if (azx_dev->start_flag &&
 +          time_before_eq(jiffies, azx_dev->start_jiffies))
 +              return -1;      /* bogus (too early) interrupt */
 +      azx_dev->start_flag = 0;
 +
        pos = azx_get_position(chip, azx_dev);
        if (chip->position_fix == POS_FIX_AUTO) {
                if (!pos) {
@@@ -1830,7 -1820,7 +1831,7 @@@ azx_attach_pcm_stream(struct hda_bus *b
                          &pcm);
        if (err < 0)
                return err;
 -      strcpy(pcm->name, cpcm->name);
 +      strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
        apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
        if (apcm == NULL)
                return -ENOMEM;
@@@ -2271,11 -2261,11 +2272,11 @@@ static int __devinit azx_create(struct 
                gcap &= ~0x01;
  
        /* allow 64bit DMA address if supported by H/W */
 -      if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK))
 -              pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
 +      if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
 +              pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
        else {
 -              pci_set_dma_mask(pci, DMA_32BIT_MASK);
 -              pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK);
 +              pci_set_dma_mask(pci, DMA_BIT_MASK(32));
 +              pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
        }
  
        /* read number of streams from GCAP register instead of using
        }
  
        strcpy(card->driver, "HDA-Intel");
 -      strcpy(card->shortname, driver_short_names[chip->driver_type]);
 -      sprintf(card->longname, "%s at 0x%lx irq %i",
 -              card->shortname, chip->addr, chip->irq);
 +      strlcpy(card->shortname, driver_short_names[chip->driver_type],
 +              sizeof(card->shortname));
 +      snprintf(card->longname, sizeof(card->longname),
 +               "%s at 0x%lx irq %i",
 +               card->shortname, chip->addr, chip->irq);
  
        *rchip = chip;
        return 0;
@@@ -2515,11 -2503,6 +2516,11 @@@ static struct pci_device_id azx_ids[] 
        { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
        /* Teradici */
        { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
 +      /* Creative X-Fi (CA0110-IBG) */
 +      { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
 +        .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 +        .class_mask = 0xffffff,
 +        .driver_data = AZX_DRIVER_GENERIC },
        /* AMD Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@@ -188,8 -188,6 +188,8 @@@ enum 
        ALC663_ASUS_MODE4,
        ALC663_ASUS_MODE5,
        ALC663_ASUS_MODE6,
 +      ALC272_DELL,
 +      ALC272_DELL_ZM1,
        ALC662_AUTO,
        ALC662_MODEL_LAST,
  };
@@@ -1024,6 -1022,9 +1024,9 @@@ static void alc_subsystem_id(struct hda
        if (codec->vendor_id == 0x10ec0260)
                nid = 0x17;
        ass = snd_hda_codec_get_pincfg(codec, nid);
+       snd_printd("realtek: No valid SSID, "
+                  "checking pincfg 0x%08x for NID 0x%x\n",
+                  nid, ass);
        if (!(ass & 1) && !(ass & 0x100000))
                return;
        if ((ass >> 30) != 1)   /* no physical connection */
        if (((ass >> 16) & 0xf) != tmp)
                return;
  do_sku:
+       snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+                  ass & 0xffff, codec->vendor_id);
        /*
         * 0 : override
         * 1 :  Swap Jack
@@@ -8744,9 -8747,10 +8749,9 @@@ static struct snd_pci_quirk alc883_cfg_
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
 -      SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
 +      SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
                      ALC883_FUJITSU_PI2515),
 -      SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
 -      SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
 +      SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
                ALC888_FUJITSU_XA3530),
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
        SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        {}
  };
  
 +static hda_nid_t alc883_slave_dig_outs[] = {
 +      ALC1200_DIGOUT_NID, 0,
 +};
 +
  static hda_nid_t alc1200_slave_dig_outs[] = {
        ALC883_DIGOUT_NID, 0,
  };
@@@ -8814,7 -8814,6 +8819,7 @@@ static struct alc_config_preset alc883_
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
                .dig_in_nid = ALC883_DIGIN_NID,
 +              .slave_dig_outs = alc883_slave_dig_outs,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
                .channel_mode = alc883_3ST_6ch_intel_modes,
                .need_dac_fix = 1,
@@@ -12978,17 -12977,10 +12983,17 @@@ static struct snd_pci_quirk alc269_cfg_
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
        SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
                      ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
 +        SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
                      ALC269_ASUS_EEEPC_P901),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
                      ALC269_ASUS_EEEPC_P901),
 +        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
        SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
        {}
@@@ -15219,23 -15211,12 +15224,23 @@@ static hda_nid_t alc662_dac_nids[4] = 
        0x02, 0x03, 0x04
  };
  
 +static hda_nid_t alc272_dac_nids[2] = {
 +      0x02, 0x03
 +};
 +
  static hda_nid_t alc662_adc_nids[1] = {
        /* ADC1-2 */
        0x09,
  };
  
 +static hda_nid_t alc272_adc_nids[1] = {
 +      /* ADC1-2 */
 +      0x08,
 +};
 +
  static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
 +static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
 +
  
  /* input MUX */
  /* FIXME: should be a matrix-type input source selection */
@@@ -15661,7 -15642,14 +15666,7 @@@ static struct hda_verb alc662_init_verb
        /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
        /* Input mixer */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 -      {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 -      {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 -      {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 -
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 -      {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 -      {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 -      {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
  
        /* always trun on EAPD */
        {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
@@@ -15856,48 -15844,12 +15861,48 @@@ static struct hda_verb alc662_ecs_init_
        {}
  };
  
 +static struct hda_verb alc272_dell_zm1_init_verbs[] = {
 +      {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 +      {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
 +      {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 +      {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
 +      {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 +      {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 +      {}
 +};
 +
 +static struct hda_verb alc272_dell_init_verbs[] = {
 +      {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 +      {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 +      {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
 +      {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 +      {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
 +      {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 +      {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 +      {}
 +};
 +
  static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
        { } /* end */
  };
  
 +static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
 +      HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 +      HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 +      { } /* end */
 +};
 +
  static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
  {
        unsigned int present;
@@@ -16409,8 -16361,6 +16414,8 @@@ static const char *alc662_models[ALC662
  
  static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
 +      SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
 +      SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
        SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
        SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
        SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
 +      SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
 +      SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
 +      SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
        SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
        SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
 +      SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
        /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
        SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
 +      SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
 +      SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
 +      SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
 +      SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
 +      SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
        /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
        SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
 +      SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
        SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
        SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
@@@ -16701,36 -16641,6 +16706,36 @@@ static struct alc_config_preset alc662_
                .unsol_event = alc663_mode6_unsol_event,
                .init_hook = alc663_mode6_inithook,
        },
 +      [ALC272_DELL] = {
 +              .mixers = { alc663_m51va_mixer },
 +              .cap_mixer = alc272_auto_capture_mixer,
 +              .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
 +              .num_dacs = ARRAY_SIZE(alc272_dac_nids),
 +              .dac_nids = alc662_dac_nids,
 +              .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 +              .adc_nids = alc272_adc_nids,
 +              .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
 +              .capsrc_nids = alc272_capsrc_nids,
 +              .channel_mode = alc662_3ST_2ch_modes,
 +              .input_mux = &alc663_m51va_capture_source,
 +              .unsol_event = alc663_m51va_unsol_event,
 +              .init_hook = alc663_m51va_inithook,
 +      },
 +      [ALC272_DELL_ZM1] = {
 +              .mixers = { alc663_m51va_mixer },
 +              .cap_mixer = alc662_auto_capture_mixer,
 +              .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
 +              .num_dacs = ARRAY_SIZE(alc272_dac_nids),
 +              .dac_nids = alc662_dac_nids,
 +              .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 +              .adc_nids = alc662_adc_nids,
 +              .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
 +              .capsrc_nids = alc662_capsrc_nids,
 +              .channel_mode = alc662_3ST_2ch_modes,
 +              .input_mux = &alc663_m51va_capture_source,
 +              .unsol_event = alc663_m51va_unsol_event,
 +              .init_hook = alc663_m51va_inithook,
 +      },
  };