[ALSA] Fix synchronize_irq() bugs, redundancies
[safe/jmp/linux-2.6] / sound / pci / hda / hda_intel.c
index ab69833..b3a618e 100644 (file)
  * 
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include "hda_codec.h"
 
 
-static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-static char *model;
-static int position_fix;
-static int probe_mask = -1;
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *model[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS];
+static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int single_cmd;
 static int enable_msi;
 
-module_param(index, int, 0444);
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
-module_param(id, charp, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
-module_param(model, charp, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
-module_param(position_fix, int, 0444);
+module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
                 "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
-module_param(probe_mask, int, 0444);
+module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
                 "(for debugging only).");
-module_param(enable_msi, int, 0);
+module_param(enable_msi, int, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -87,10 +90,6 @@ module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
-/* just for backward compatibility */
-static int enable;
-module_param(enable, bool, 0444);
-
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH6M},"
@@ -98,12 +97,20 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
                         "{Intel, ICH9},"
+                        "{Intel, ICH10},"
+                        "{Intel, SCH},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
                         "{ATI, RS600},"
                         "{ATI, RS690},"
                         "{ATI, RS780},"
                         "{ATI, R600},"
+                        "{ATI, RV630},"
+                        "{ATI, RV610},"
+                        "{ATI, RV670},"
+                        "{ATI, RV635},"
+                        "{ATI, RV620},"
+                        "{ATI, RV770},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -179,35 +186,28 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 
 /* max number of SDs */
 /* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_CAPTURE_INDEX     0
 #define ICH6_NUM_CAPTURE       4
-#define ICH6_PLAYBACK_INDEX    4
 #define ICH6_NUM_PLAYBACK      4
 
 /* ULI has 6 playback and 5 capture */
-#define ULI_CAPTURE_INDEX      0
 #define ULI_NUM_CAPTURE                5
-#define ULI_PLAYBACK_INDEX     5
 #define ULI_NUM_PLAYBACK       6
 
 /* ATI HDMI has 1 playback and 0 capture */
-#define ATIHDMI_CAPTURE_INDEX  0
 #define ATIHDMI_NUM_CAPTURE    0
-#define ATIHDMI_PLAYBACK_INDEX 0
 #define ATIHDMI_NUM_PLAYBACK   1
 
 /* this number is statically defined for simplicity */
 #define MAX_AZX_DEV            16
 
 /* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE               PAGE_ALIGN(8192)
-#define AZX_MAX_FRAG           (BDL_SIZE / (MAX_AZX_DEV * 16))
+#define BDL_SIZE               4096
+#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
+#define AZX_MAX_FRAG           32
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE       (1024*1024*1024)
 /* max number of PCM devics per card */
-#define AZX_MAX_AUDIO_PCMS     6
-#define AZX_MAX_MODEM_PCMS     2
-#define AZX_MAX_PCMS           (AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS)
+#define AZX_MAX_PCMS           8
 
 /* RIRB int mask: overrun[2], response[0] */
 #define RIRB_INT_RESPONSE      0x01
@@ -221,6 +221,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
 #define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
+#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
+#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
 #define SD_CTL_STREAM_TAG_MASK (0xf << 20)
 #define SD_CTL_STREAM_TAG_SHIFT        20
 
@@ -269,16 +272,19 @@ enum {
 #define NVIDIA_HDA_TRANSREG_ADDR      0x4e
 #define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+
 /*
  */
 
 struct azx_dev {
-       u32 *bdl;               /* virtual address of the BDL */
-       dma_addr_t bdl_addr;    /* physical address of the BDL */
+       struct snd_dma_buffer bdl; /* BDL buffer */
        u32 *posbuf;            /* position buffer pointer */
 
        unsigned int bufsize;   /* size of the play buffer in bytes */
-       unsigned int fragsize;  /* size of each period in bytes */
        unsigned int frags;     /* number for period in the play buffer */
        unsigned int fifo_size; /* FIFO size */
 
@@ -339,7 +345,6 @@ struct azx {
        struct azx_dev *azx_dev;
 
        /* PCM */
-       unsigned int pcm_devs;
        struct snd_pcm *pcm[AZX_MAX_PCMS];
 
        /* HD codec */
@@ -350,8 +355,7 @@ struct azx {
        struct azx_rb corb;
        struct azx_rb rirb;
 
-       /* BDL, CORB/RIRB and position buffers */
-       struct snd_dma_buffer bdl;
+       /* CORB/RIRB and position buffers */
        struct snd_dma_buffer rb;
        struct snd_dma_buffer posbuf;
 
@@ -370,6 +374,7 @@ struct azx {
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
+       AZX_DRIVER_SCH,
        AZX_DRIVER_ATI,
        AZX_DRIVER_ATIHDMI,
        AZX_DRIVER_VIA,
@@ -380,6 +385,7 @@ enum {
 
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_SCH] = "HDA Intel MID",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
@@ -533,8 +539,9 @@ static void azx_update_rirb(struct azx *chip)
                if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
                        snd_hda_queue_unsol_event(chip->bus, res, res_ex);
                else if (chip->rirb.cmds) {
-                       chip->rirb.cmds--;
                        chip->rirb.res = res;
+                       smp_wmb();
+                       chip->rirb.cmds--;
                }
        }
 }
@@ -547,16 +554,25 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
  again:
        timeout = jiffies + msecs_to_jiffies(1000);
-       do {
+       for (;;) {
                if (chip->polling_mode) {
                        spin_lock_irq(&chip->reg_lock);
                        azx_update_rirb(chip);
                        spin_unlock_irq(&chip->reg_lock);
                }
-               if (!chip->rirb.cmds)
+               if (!chip->rirb.cmds) {
+                       smp_rmb();
                        return chip->rirb.res; /* the last value */
-               schedule_timeout(1);
-       } while (time_after_eq(timeout, jiffies));
+               }
+               if (time_after(jiffies, timeout))
+                       break;
+               if (codec->bus->needs_damn_long_delay)
+                       msleep(2); /* temporary workaround */
+               else {
+                       udelay(10);
+                       cond_resched();
+               }
+       }
 
        if (chip->msi) {
                snd_printk(KERN_WARNING "hda_intel: No response from codec, "
@@ -618,8 +634,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
                }
                udelay(1);
        }
-       snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
-                  azx_readw(chip, IRS), val);
+       if (printk_ratelimit())
+               snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+                          azx_readw(chip, IRS), val);
        return -EIO;
 }
 
@@ -635,8 +652,9 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
                        return azx_readl(chip, IR);
                udelay(1);
        }
-       snd_printd(SFX "get_response timeout: IRS=0x%x\n",
-                  azx_readw(chip, IRS));
+       if (printk_ratelimit())
+               snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+                          azx_readw(chip, IRS));
        return (unsigned int)-1;
 }
 
@@ -687,6 +705,9 @@ static int azx_reset(struct azx *chip)
 {
        int count;
 
+       /* clear STATESTS */
+       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
        /* reset controller */
        azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
 
@@ -848,6 +869,8 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
 
 static void azx_init_pci(struct azx *chip)
 {
+       unsigned short snoop;
+
        /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
         * TCSEL == Traffic Class Select Register, which sets PCI express QOS
         * Ensuring these bits are 0 clears playback static on some HD Audio
@@ -868,6 +891,19 @@ static void azx_init_pci(struct azx *chip)
                                NVIDIA_HDA_TRANSREG_ADDR,
                                0x0f, NVIDIA_HDA_ENABLE_COHBITS);
                break;
+       case AZX_DRIVER_SCH:
+               pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
+               if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
+                       pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \
+                               snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
+                       pci_read_config_word(chip->pci,
+                               INTEL_SCH_HDA_DEVC, &snoop);
+                       snd_printdd("HDA snoop disabled, enabling ... %s\n",\
+                               (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \
+                               ? "Failed" : "OK");
+               }
+               break;
+
         }
 }
 
@@ -925,30 +961,57 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 /*
  * set up BDL entries
  */
-static void azx_setup_periods(struct azx_dev *azx_dev)
+static int azx_setup_periods(struct snd_pcm_substream *substream,
+                            struct azx_dev *azx_dev)
 {
-       u32 *bdl = azx_dev->bdl;
-       dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;
-       int idx;
+       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+       u32 *bdl;
+       int i, ofs, periods, period_bytes;
 
        /* reset BDL address */
        azx_sd_writel(azx_dev, SD_BDLPL, 0);
        azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
+       period_bytes = snd_pcm_lib_period_bytes(substream);
+       periods = azx_dev->bufsize / period_bytes;
+
        /* program the initial BDL entries */
-       for (idx = 0; idx < azx_dev->frags; idx++) {
-               unsigned int off = idx << 2; /* 4 dword step */
-               dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;
-               /* program the address field of the BDL entry */
-               bdl[off] = cpu_to_le32((u32)addr);
-               bdl[off+1] = cpu_to_le32(upper_32bit(addr));
-
-               /* program the size field of the BDL entry */
-               bdl[off+2] = cpu_to_le32(azx_dev->fragsize);
-
-               /* program the IOC to enable interrupt when buffer completes */
-               bdl[off+3] = cpu_to_le32(0x01);
+       bdl = (u32 *)azx_dev->bdl.area;
+       ofs = 0;
+       azx_dev->frags = 0;
+       for (i = 0; i < periods; i++) {
+               int size, rest;
+               if (i >= AZX_MAX_BDL_ENTRIES) {
+                       snd_printk(KERN_ERR "Too many BDL entries: "
+                                  "buffer=%d, period=%d\n",
+                                  azx_dev->bufsize, period_bytes);
+                       /* reset */
+                       azx_sd_writel(azx_dev, SD_BDLPL, 0);
+                       azx_sd_writel(azx_dev, SD_BDLPU, 0);
+                       return -EINVAL;
+               }
+               rest = period_bytes;
+               do {
+                       dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+                       /* program the address field of the BDL entry */
+                       bdl[0] = cpu_to_le32((u32)addr);
+                       bdl[1] = cpu_to_le32(upper_32bit(addr));
+                       /* program the size field of the BDL entry */
+                       size = PAGE_SIZE - (ofs % PAGE_SIZE);
+                       if (rest < size)
+                               size = rest;
+                       bdl[2] = cpu_to_le32(size);
+                       /* program the IOC to enable interrupt
+                        * only when the whole fragment is processed
+                        */
+                       rest -= size;
+                       bdl[3] = rest ? 0 : cpu_to_le32(0x01);
+                       bdl += 4;
+                       azx_dev->frags++;
+                       ofs += size;
+               } while (rest > 0);
        }
+       return 0;
 }
 
 /*
@@ -997,14 +1060,17 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 
        /* program the BDL address */
        /* lower BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);
+       azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
        /* upper BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
+       azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr));
 
        /* enable the position buffer */
-       if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-               azx_writel(chip, DPLBASE,
-                          (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE);
+       if (chip->position_fix == POS_FIX_POSBUF ||
+           chip->position_fix == POS_FIX_AUTO) {
+               if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+                       azx_writel(chip, DPLBASE,
+                               (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+       }
 
        /* set the interrupt enable bits in the descriptor control register */
        azx_sd_writel(azx_dev, SD_CTL,
@@ -1020,6 +1086,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 
 static unsigned int azx_max_codecs[] __devinitdata = {
        [AZX_DRIVER_ICH] = 3,
+       [AZX_DRIVER_SCH] = 3,
        [AZX_DRIVER_ATI] = 4,
        [AZX_DRIVER_ATIHDMI] = 4,
        [AZX_DRIVER_VIA] = 3,           /* FIXME: correct? */
@@ -1028,7 +1095,8 @@ static unsigned int azx_max_codecs[] __devinitdata = {
        [AZX_DRIVER_NVIDIA] = 3,        /* FIXME: correct? */
 };
 
-static int __devinit azx_codec_create(struct azx *chip, const char *model)
+static int __devinit azx_codec_create(struct azx *chip, const char *model,
+                                     unsigned int codec_probe_mask)
 {
        struct hda_bus_template bus_temp;
        int c, codecs, audio_codecs, err;
@@ -1049,7 +1117,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
 
        codecs = audio_codecs = 0;
        for (c = 0; c < AZX_MAX_CODECS; c++) {
-               if ((chip->codec_mask & (1 << c)) & probe_mask) {
+               if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                        struct hda_codec *codec;
                        err = snd_hda_codec_new(chip->bus, c, &codec);
                        if (err < 0)
@@ -1062,7 +1130,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (!audio_codecs) {
                /* probe additional slots if no codec is found */
                for (; c < azx_max_codecs[chip->driver_type]; c++) {
-                       if ((chip->codec_mask & (1 << c)) & probe_mask) {
+                       if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                                err = snd_hda_codec_new(chip->bus, c, NULL);
                                if (err < 0)
                                        continue;
@@ -1115,7 +1183,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
                                 SNDRV_PCM_INFO_MMAP_VALID |
                                 /* No full-resume yet implemented */
                                 /* SNDRV_PCM_INFO_RESUME |*/
-                                SNDRV_PCM_INFO_PAUSE),
+                                SNDRV_PCM_INFO_PAUSE |
+                                SNDRV_PCM_INFO_SYNC_START),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1177,6 +1246,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 
        runtime->private_data = azx_dev;
+       snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
        return 0;
 }
@@ -1233,8 +1303,6 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
-       azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
-       azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
        azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
                                                         runtime->channels,
                                                         runtime->format,
@@ -1246,10 +1314,10 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
                return -EINVAL;
        }
 
-       snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, "
-                   "format=0x%x\n",
-                   azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
-       azx_setup_periods(azx_dev);
+       snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+                   azx_dev->bufsize, azx_dev->format_val);
+       if (azx_setup_periods(substream, azx_dev) < 0)
+               return -EINVAL;
        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;
@@ -1263,37 +1331,94 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx_dev *azx_dev = get_azx_dev(substream);
        struct azx *chip = apcm->chip;
-       int err = 0;
+       struct azx_dev *azx_dev;
+       struct snd_pcm_substream *s;
+       int start, nsync = 0, sbits = 0;
+       int nwait, timeout;
 
-       spin_lock(&chip->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
-               azx_stream_start(chip, azx_dev);
-               azx_dev->running = 1;
+               start = 1;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
-               azx_stream_stop(chip, azx_dev);
-               azx_dev->running = 0;
+               start = 0;
                break;
        default:
-               err = -EINVAL;
+               return -EINVAL;
+       }
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               azx_dev = get_azx_dev(s);
+               sbits |= 1 << azx_dev->index;
+               nsync++;
+               snd_pcm_trigger_done(s, substream);
+       }
+
+       spin_lock(&chip->reg_lock);
+       if (nsync > 1) {
+               /* first, set SYNC bits of corresponding streams */
+               azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
+       }
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               azx_dev = get_azx_dev(s);
+               if (start)
+                       azx_stream_start(chip, azx_dev);
+               else
+                       azx_stream_stop(chip, azx_dev);
+               azx_dev->running = start;
        }
        spin_unlock(&chip->reg_lock);
-       if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
-           cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
-           cmd == SNDRV_PCM_TRIGGER_STOP) {
-               int timeout = 5000;
-               while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&
-                      --timeout)
-                       ;
+       if (start) {
+               if (nsync == 1)
+                       return 0;
+               /* wait until all FIFOs get ready */
+               for (timeout = 5000; timeout; timeout--) {
+                       nwait = 0;
+                       snd_pcm_group_for_each_entry(s, substream) {
+                               if (s->pcm->card != substream->pcm->card)
+                                       continue;
+                               azx_dev = get_azx_dev(s);
+                               if (!(azx_sd_readb(azx_dev, SD_STS) &
+                                     SD_STS_FIFO_READY))
+                                       nwait++;
+                       }
+                       if (!nwait)
+                               break;
+                       cpu_relax();
+               }
+       } else {
+               /* wait until all RUN bits are cleared */
+               for (timeout = 5000; timeout; timeout--) {
+                       nwait = 0;
+                       snd_pcm_group_for_each_entry(s, substream) {
+                               if (s->pcm->card != substream->pcm->card)
+                                       continue;
+                               azx_dev = get_azx_dev(s);
+                               if (azx_sd_readb(azx_dev, SD_CTL) &
+                                   SD_CTL_DMA_START)
+                                       nwait++;
+                       }
+                       if (!nwait)
+                               break;
+                       cpu_relax();
+               }
        }
-       return err;
+       if (nsync > 1) {
+               spin_lock(&chip->reg_lock);
+               /* reset SYNC bits */
+               azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
+               spin_unlock(&chip->reg_lock);
+       }
+       return 0;
 }
 
 static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
@@ -1336,6 +1461,7 @@ static struct snd_pcm_ops azx_pcm_ops = {
        .prepare = azx_pcm_prepare,
        .trigger = azx_pcm_trigger,
        .pointer = azx_pcm_pointer,
+       .page = snd_pcm_sgbuf_ops_page,
 };
 
 static void azx_pcm_free(struct snd_pcm *pcm)
@@ -1344,7 +1470,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
 }
 
 static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-                                     struct hda_pcm *cpcm, int pcm_dev)
+                                     struct hda_pcm *cpcm)
 {
        int err;
        struct snd_pcm *pcm;
@@ -1358,7 +1484,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
 
        snd_assert(cpcm->name, return -EINVAL);
 
-       err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+       err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
                          cpcm->stream[0].substreams,
                          cpcm->stream[1].substreams,
                          &pcm);
@@ -1378,65 +1504,70 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
        if (cpcm->stream[1].substreams)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              snd_dma_pci_data(chip->pci),
                                              1024 * 64, 1024 * 1024);
-       chip->pcm[pcm_dev] = pcm;
-       if (chip->pcm_devs < pcm_dev + 1)
-               chip->pcm_devs = pcm_dev + 1;
-
+       chip->pcm[cpcm->device] = pcm;
        return 0;
 }
 
 static int __devinit azx_pcm_create(struct azx *chip)
 {
-       struct list_head *p;
+       static const char *dev_name[HDA_PCM_NTYPES] = {
+               "Audio", "SPDIF", "HDMI", "Modem"
+       };
+       /* starting device index for each PCM type */
+       static int dev_idx[HDA_PCM_NTYPES] = {
+               [HDA_PCM_TYPE_AUDIO] = 0,
+               [HDA_PCM_TYPE_SPDIF] = 1,
+               [HDA_PCM_TYPE_HDMI] = 3,
+               [HDA_PCM_TYPE_MODEM] = 6
+       };
+       /* normal audio device indices; not linear to keep compatibility */
+       static int audio_idx[4] = { 0, 2, 4, 5 };
        struct hda_codec *codec;
        int c, err;
-       int pcm_dev;
+       int num_devs[HDA_PCM_NTYPES];
 
        err = snd_hda_build_pcms(chip->bus);
        if (err < 0)
                return err;
 
        /* create audio PCMs */
-       pcm_dev = 0;
-       list_for_each(p, &chip->bus->codec_list) {
-               codec = list_entry(p, struct hda_codec, list);
-               for (c = 0; c < codec->num_pcms; c++) {
-                       if (codec->pcm_info[c].is_modem)
-                               continue; /* create later */
-                       if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {
-                               snd_printk(KERN_ERR SFX
-                                          "Too many audio PCMs\n");
-                               return -EINVAL;
-                       }
-                       err = create_codec_pcm(chip, codec,
-                                              &codec->pcm_info[c], pcm_dev);
-                       if (err < 0)
-                               return err;
-                       pcm_dev++;
-               }
-       }
-
-       /* create modem PCMs */
-       pcm_dev = AZX_MAX_AUDIO_PCMS;
-       list_for_each(p, &chip->bus->codec_list) {
-               codec = list_entry(p, struct hda_codec, list);
+       memset(num_devs, 0, sizeof(num_devs));
+       list_for_each_entry(codec, &chip->bus->codec_list, list) {
                for (c = 0; c < codec->num_pcms; c++) {
-                       if (!codec->pcm_info[c].is_modem)
-                               continue; /* already created */
-                       if (pcm_dev >= AZX_MAX_PCMS) {
-                               snd_printk(KERN_ERR SFX
-                                          "Too many modem PCMs\n");
-                               return -EINVAL;
+                       struct hda_pcm *cpcm = &codec->pcm_info[c];
+                       int type = cpcm->pcm_type;
+                       switch (type) {
+                       case HDA_PCM_TYPE_AUDIO:
+                               if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
+                                       snd_printk(KERN_WARNING
+                                                  "Too many audio devices\n");
+                                       continue;
+                               }
+                               cpcm->device = audio_idx[num_devs[type]];
+                               break;
+                       case HDA_PCM_TYPE_SPDIF:
+                       case HDA_PCM_TYPE_HDMI:
+                       case HDA_PCM_TYPE_MODEM:
+                               if (num_devs[type]) {
+                                       snd_printk(KERN_WARNING
+                                                  "%s already defined\n",
+                                                  dev_name[type]);
+                                       continue;
+                               }
+                               cpcm->device = dev_idx[type];
+                               break;
+                       default:
+                               snd_printk(KERN_WARNING
+                                          "Invalid PCM type %d\n", type);
+                               continue;
                        }
-                       err = create_codec_pcm(chip, codec,
-                                              &codec->pcm_info[c], pcm_dev);
+                       num_devs[type]++;
+                       err = create_codec_pcm(chip, codec, cpcm);
                        if (err < 0)
                                return err;
-                       chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
-                       pcm_dev++;
                }
        }
        return 0;
@@ -1463,10 +1594,7 @@ static int __devinit azx_init_stream(struct azx *chip)
         * and initialize
         */
        for (i = 0; i < chip->num_streams; i++) {
-               unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
                struct azx_dev *azx_dev = &chip->azx_dev[i];
-               azx_dev->bdl = (u32 *)(chip->bdl.area + off);
-               azx_dev->bdl_addr = chip->bdl.addr + off;
                azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
                /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
                azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
@@ -1548,13 +1676,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
        int i;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       for (i = 0; i < chip->pcm_devs; i++)
+       for (i = 0; i < AZX_MAX_PCMS; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
        if (chip->initialized)
                snd_hda_suspend(chip->bus, state);
        azx_stop_chip(chip);
        if (chip->irq >= 0) {
-               synchronize_irq(chip->irq);
                free_irq(chip->irq, chip);
                chip->irq = -1;
        }
@@ -1586,11 +1713,11 @@ static int azx_resume(struct pci_dev *pci)
        if (azx_acquire_irq(chip, 1) < 0)
                return -EIO;
        azx_init_pci(chip);
-#ifndef CONFIG_SND_HDA_POWER_SAVE
-       /* the explicit resume is needed only when POWER_SAVE isn't set */
-       azx_init_chip(chip);
+
+       if (snd_hda_codecs_inuse(chip->bus))
+               azx_init_chip(chip);
+
        snd_hda_resume(chip->bus);
-#endif
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
@@ -1602,24 +1729,26 @@ static int azx_resume(struct pci_dev *pci)
  */
 static int azx_free(struct azx *chip)
 {
+       int i;
+
        if (chip->initialized) {
-               int i;
                for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
                azx_stop_chip(chip);
        }
 
-       if (chip->irq >= 0) {
-               synchronize_irq(chip->irq);
+       if (chip->irq >= 0)
                free_irq(chip->irq, (void*)chip);
-       }
        if (chip->msi)
                pci_disable_msi(chip->pci);
        if (chip->remap_addr)
                iounmap(chip->remap_addr);
 
-       if (chip->bdl.area)
-               snd_dma_free_pages(&chip->bdl);
+       if (chip->azx_dev) {
+               for (i = 0; i < chip->num_streams; i++)
+                       if (chip->azx_dev[i].bdl.area)
+                               snd_dma_free_pages(&chip->azx_dev[i].bdl);
+       }
        if (chip->rb.area)
                snd_dma_free_pages(&chip->rb);
        if (chip->posbuf.area)
@@ -1642,6 +1771,8 @@ static int azx_dev_free(struct snd_device *device)
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
+       SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE),
+       SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE),
        {}
 };
 
@@ -1652,7 +1783,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        if (fix == POS_FIX_AUTO) {
                q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
                if (q) {
-                       snd_printdd(KERN_INFO
+                       printk(KERN_INFO
                                    "hda_intel: position_fix set to %d "
                                    "for device %04x:%04x\n",
                                    q->value, q->subvendor, q->subdevice);
@@ -1663,20 +1794,51 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 }
 
 /*
+ * black-lists for probe_mask
+ */
+static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
+       /* Thinkpad often breaks the controller communication when accessing
+        * to the non-working (or non-existing) modem codec slot.
+        */
+       SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
+       SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
+       SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
+       {}
+};
+
+static void __devinit check_probe_mask(struct azx *chip, int dev)
+{
+       const struct snd_pci_quirk *q;
+
+       if (probe_mask[dev] == -1) {
+               q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
+               if (q) {
+                       printk(KERN_INFO
+                              "hda_intel: probe_mask set to 0x%x "
+                              "for device %04x:%04x\n",
+                              q->value, q->subvendor, q->subdevice);
+                       probe_mask[dev] = q->value;
+               }
+       }
+}
+
+
+/*
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int driver_type,
+                               int dev, int driver_type,
                                struct azx **rchip)
 {
        struct azx *chip;
-       int err;
+       int i, err;
+       unsigned short gcap;
        static struct snd_device_ops ops = {
                .dev_free = azx_dev_free,
        };
 
        *rchip = NULL;
-       
+
        err = pci_enable_device(pci);
        if (err < 0)
                return err;
@@ -1696,7 +1858,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->driver_type = driver_type;
        chip->msi = enable_msi;
 
-       chip->position_fix = check_position_fix(chip, position_fix);
+       chip->position_fix = check_position_fix(chip, position_fix[dev]);
+       check_probe_mask(chip, dev);
 
        chip->single_cmd = single_cmd;
 
@@ -1737,26 +1900,38 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
-       switch (chip->driver_type) {
-       case AZX_DRIVER_ULI:
-               chip->playback_streams = ULI_NUM_PLAYBACK;
-               chip->capture_streams = ULI_NUM_CAPTURE;
-               chip->playback_index_offset = ULI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ULI_CAPTURE_INDEX;
-               break;
-       case AZX_DRIVER_ATIHDMI:
-               chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
-               chip->capture_streams = ATIHDMI_NUM_CAPTURE;
-               chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
-               break;
-       default:
-               chip->playback_streams = ICH6_NUM_PLAYBACK;
-               chip->capture_streams = ICH6_NUM_CAPTURE;
-               chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
-               chip->capture_index_offset = ICH6_CAPTURE_INDEX;
-               break;
+       gcap = azx_readw(chip, GCAP);
+       snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+
+       /* 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);
+
+       /* read number of streams from GCAP register instead of using
+        * hardcoded value
+        */
+       chip->capture_streams = (gcap >> 8) & 0x0f;
+       chip->playback_streams = (gcap >> 12) & 0x0f;
+       if (!chip->playback_streams && !chip->capture_streams) {
+               /* gcap didn't give any info, switching to old method */
+
+               switch (chip->driver_type) {
+               case AZX_DRIVER_ULI:
+                       chip->playback_streams = ULI_NUM_PLAYBACK;
+                       chip->capture_streams = ULI_NUM_CAPTURE;
+                       break;
+               case AZX_DRIVER_ATIHDMI:
+                       chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+                       chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+                       break;
+               default:
+                       chip->playback_streams = ICH6_NUM_PLAYBACK;
+                       chip->capture_streams = ICH6_NUM_CAPTURE;
+                       break;
+               }
        }
+       chip->capture_index_offset = 0;
+       chip->playback_index_offset = chip->capture_streams;
        chip->num_streams = chip->playback_streams + chip->capture_streams;
        chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
                                GFP_KERNEL);
@@ -1765,13 +1940,15 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
        }
 
-       /* allocate memory for the BDL for each stream */
-       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                 snd_dma_pci_data(chip->pci),
-                                 BDL_SIZE, &chip->bdl);
-       if (err < 0) {
-               snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
-               goto errout;
+       for (i = 0; i < chip->num_streams; i++) {
+               /* allocate memory for the BDL for each stream */
+               err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                         snd_dma_pci_data(chip->pci),
+                                         BDL_SIZE, &chip->azx_dev[i].bdl);
+               if (err < 0) {
+                       snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
+                       goto errout;
+               }
        }
        /* allocate memory for the position buffer */
        err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
@@ -1837,17 +2014,25 @@ static void power_down_all_codecs(struct azx *chip)
 static int __devinit azx_probe(struct pci_dev *pci,
                               const struct pci_device_id *pci_id)
 {
+       static int dev;
        struct snd_card *card;
        struct azx *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
        if (!card) {
                snd_printk(KERN_ERR SFX "Error creating card!\n");
                return -ENOMEM;
        }
 
-       err = azx_create(card, pci, pci_id->driver_data, &chip);
+       err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1855,7 +2040,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        card->private_data = chip;
 
        /* create codec instances */
-       err = azx_codec_create(chip, model);
+       err = azx_codec_create(chip, model[dev], probe_mask[dev]);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1887,6 +2072,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        chip->running = 1;
        power_down_all_codecs(chip);
 
+       dev++;
        return err;
 }
 
@@ -1898,35 +2084,63 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static struct pci_device_id azx_ids[] = {
-       { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
-       { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
-       { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
-       { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
-       { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
-       { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
-       { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
-       { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
-       { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
-       { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
-       { 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
-       { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */
-       { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
-       { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
-       { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
-       { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP51 */
-       { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP55 */
-       { 0x10de, 0x03e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
-       { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
-       { 0x10de, 0x044a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
-       { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
-       { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
-       { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
-       { 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
-       { 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
-       { 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-       { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-       { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
-       { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       /* ICH 6..10 */
+       { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
+       /* SCH */
+       { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       /* ATI SB 450/600 */
+       { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
+       { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+       /* ATI HDMI */
+       { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+       /* VIA VT8251/VT8237A */
+       { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+       /* SIS966 */
+       { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
+       /* ULI M5461 */
+       { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
+       /* NVIDIA MCP */
+       { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
+       { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);