]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/hda/hda_intel.c
[PATCH] PCI: removed unneeded .owner field from struct pci_driver
[linux-2.6-omap-h63xx.git] / sound / pci / hda / hda_intel.c
index 15107df1f490808ebc52dfc5e1a977ee7dc83d08..ed525c03c996fd6b6f5209b369d2e1fdd66a5e53 100644 (file)
 #include "hda_codec.h"
 
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static char *model[SNDRV_CARDS];
-static int position_fix[SNDRV_CARDS];
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+static char *model;
+static int position_fix;
 
-module_param_array(index, int, NULL, 0444);
+module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
-module_param_array(id, charp, NULL, 0444);
+module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
-module_param_array(model, charp, NULL, 0444);
+module_param(model, charp, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
-module_param_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF).");
+module_param(position_fix, int, 0444);
+MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
+
+/* just for backward compatibility */
+static int enable;
+module_param(enable, bool, 0444);
 
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
@@ -164,7 +165,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 /* 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_PCMS           8
+#define AZX_MAX_AUDIO_PCMS     6
+#define AZX_MAX_MODEM_PCMS     2
+#define AZX_MAX_PCMS           (AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS)
 
 /* RIRB int mask: overrun[2], response[0] */
 #define RIRB_INT_RESPONSE      0x01
@@ -211,15 +214,19 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 
 /* position fix mode */
 enum {
-       POS_FIX_FIFO,
+       POS_FIX_AUTO,
        POS_FIX_NONE,
-       POS_FIX_POSBUF
+       POS_FIX_POSBUF,
+       POS_FIX_FIFO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
 #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
 #define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
 
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
 /*
  * Use CORB/RIRB for communication from/to codecs.
@@ -243,6 +250,7 @@ struct snd_azx_dev {
        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 */
+       unsigned int last_pos;          /* last updated period position */
 
        void __iomem *sd_addr;          /* stream descriptor pointer */
 
@@ -256,6 +264,7 @@ struct snd_azx_dev {
 
        unsigned int opened: 1;
        unsigned int running: 1;
+       unsigned int period_updating: 1;
 };
 
 /* CORB/RIRB */
@@ -323,6 +332,7 @@ enum {
        AZX_DRIVER_VIA,
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
+       AZX_DRIVER_NVIDIA,
 };
 
 static char *driver_short_names[] __devinitdata = {
@@ -330,7 +340,8 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
        [AZX_DRIVER_SIS] = "HDA SIS966",
-       [AZX_DRIVER_ULI] = "HDA ULI M5461"
+       [AZX_DRIVER_ULI] = "HDA ULI M5461",
+       [AZX_DRIVER_NVIDIA] = "HDA NVidia",
 };
 
 /*
@@ -705,14 +716,14 @@ static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev)
  */
 static void azx_init_chip(azx_t *chip)
 {
-       unsigned char tcsel_reg, ati_misc_cntl2;
+       unsigned char reg;
 
        /* 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 codecs
         */
-       pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &tcsel_reg);
-       pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, tcsel_reg & 0xf8);
+       pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &reg);
+       pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8);
 
        /* reset controller */
        azx_reset(chip);
@@ -724,19 +735,25 @@ static void azx_init_chip(azx_t *chip)
        /* initialize the codec command I/O */
        azx_init_cmd_io(chip);
 
-       if (chip->position_fix == POS_FIX_POSBUF) {
-               /* program the position buffer */
-               azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
-               azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
-       }
+       /* program the position buffer */
+       azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+       azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
 
-       /* For ATI SB450 azalia HD audio, we need to enable snoop */
-       if (chip->driver_type == AZX_DRIVER_ATI) {
+       switch (chip->driver_type) {
+       case AZX_DRIVER_ATI:
+               /* For ATI SB450 azalia HD audio, we need to enable snoop */
                pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
-                                    &ati_misc_cntl2);
+                                    &reg);
                pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
-                                     (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP);
-       }
+                                     (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+               break;
+       case AZX_DRIVER_NVIDIA:
+               /* For NVIDIA HDA, enable snoop */
+               pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, &reg);
+               pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR,
+                                     (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS);
+               break;
+        }
 }
 
 
@@ -763,9 +780,11 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
                if (status & azx_dev->sd_int_sta_mask) {
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
                        if (azx_dev->substream && azx_dev->running) {
+                               azx_dev->period_updating = 1;
                                spin_unlock(&chip->reg_lock);
                                snd_pcm_period_elapsed(azx_dev->substream);
                                spin_lock(&chip->reg_lock);
+                               azx_dev->period_updating = 0;
                        }
                }
        }
@@ -866,11 +885,9 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev)
        /* upper BDL address */
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
 
-       if (chip->position_fix == POS_FIX_POSBUF) {
-               /* enable the position buffer */
-               if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-                       azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
-       }
+       /* enable the position buffer */
+       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, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
@@ -1078,6 +1095,7 @@ static int azx_pcm_prepare(snd_pcm_substream_t *substream)
                azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
        else
                azx_dev->fifo_size = 0;
+       azx_dev->last_pos = 0;
 
        return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
                                  azx_dev->format_val, substream);
@@ -1133,6 +1151,31 @@ static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
                pos = azx_sd_readl(azx_dev, SD_LPIB);
                if (chip->position_fix == POS_FIX_FIFO)
                        pos += azx_dev->fifo_size;
+#if 0 /* disabled temprarily, auto-correction doesn't work well... */
+               else if (chip->position_fix == POS_FIX_AUTO && azx_dev->period_updating) {
+                       /* check the validity of DMA position */
+                       unsigned int diff = 0;
+                       azx_dev->last_pos += azx_dev->fragsize;
+                       if (azx_dev->last_pos > pos)
+                               diff = azx_dev->last_pos - pos;
+                       if (azx_dev->last_pos >= azx_dev->bufsize) {
+                               if (pos < azx_dev->fragsize)
+                                       diff = 0;
+                               azx_dev->last_pos = 0;
+                       }
+                       if (diff > 0 && diff <= azx_dev->fifo_size)
+                               pos += azx_dev->fifo_size;
+                       else {
+                               snd_printdd(KERN_INFO "hda_intel: DMA position fix %d, switching to posbuf\n", diff);
+                               chip->position_fix = POS_FIX_POSBUF;
+                               pos = *azx_dev->posbuf;
+                       }
+                       azx_dev->period_updating = 0;
+               }
+#else
+               else if (chip->position_fix == POS_FIX_AUTO)
+                       pos += azx_dev->fifo_size;
+#endif
        }
        if (pos >= azx_dev->bufsize)
                pos = 0;
@@ -1203,17 +1246,39 @@ static int __devinit azx_pcm_create(azx_t *chip)
        if ((err = snd_hda_build_pcms(chip->bus)) < 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);
+               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 PCMs\n");
+                               snd_printk(KERN_ERR SFX "Too many modem PCMs\n");
                                return -EINVAL;
                        }
                        err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
                        if (err < 0)
                                return err;
+                       chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
                        pcm_dev++;
                }
        }
@@ -1244,8 +1309,7 @@ static int __devinit azx_init_stream(azx_t *chip)
                azx_dev_t *azx_dev = &chip->azx_dev[i];
                azx_dev->bdl = (u32 *)(chip->bdl.area + off);
                azx_dev->bdl_addr = chip->bdl.addr + off;
-               if (chip->position_fix == POS_FIX_POSBUF)
-                       azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
+               azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
                /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
                azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
                /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
@@ -1358,7 +1422,7 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
        if ((err = pci_enable_device(pci)) < 0)
                return err;
 
-       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        
        if (NULL == chip) {
                snd_printk(KERN_ERR SFX "cannot allocate chip\n");
@@ -1437,13 +1501,11 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
                snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
                goto errout;
        }
-       if (chip->position_fix == POS_FIX_POSBUF) {
-               /* allocate memory for the position buffer */
-               if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                              chip->num_streams * 8, &chip->posbuf)) < 0) {
-                       snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
-                       goto errout;
-               }
+       /* allocate memory for the position buffer */
+       if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+                                      chip->num_streams * 8, &chip->posbuf)) < 0) {
+               snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
+               goto errout;
        }
        /* allocate CORB/RIRB */
        if ((err = azx_alloc_cmd_io(chip)) < 0)
@@ -1483,32 +1545,24 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
 
 static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 {
-       static int dev;
        snd_card_t *card;
        azx_t *chip;
        int err = 0;
 
-       if (dev >= SNDRV_CARDS)
-               return -ENODEV;
-       if (! enable[dev]) {
-               dev++;
-               return -ENOENT;
-       }
-
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       card = snd_card_new(index, id, THIS_MODULE, 0);
        if (NULL == card) {
                snd_printk(KERN_ERR SFX "Error creating card!\n");
                return -ENOMEM;
        }
 
-       if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data,
+       if ((err = azx_create(card, pci, position_fix, pci_id->driver_data,
                              &chip)) < 0) {
                snd_card_free(card);
                return err;
        }
 
        /* create codec instances */
-       if ((err = azx_codec_create(chip, model[dev])) < 0) {
+       if ((err = azx_codec_create(chip, model)) < 0) {
                snd_card_free(card);
                return err;
        }
@@ -1534,7 +1588,6 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
        }
 
        pci_set_drvdata(pci, card);
-       dev++;
 
        return err;
 }
@@ -1554,6 +1607,8 @@ static struct pci_device_id azx_ids[] = {
        { 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 026c */
+       { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);