]> err.no Git - linux-2.6/commitdiff
[ALSA] Add position_fix module option
authorTakashi Iwai <tiwai@suse.de>
Thu, 12 May 2005 12:26:27 +0000 (14:26 +0200)
committerJaroslav Kysela <perex@suse.cz>
Sun, 29 May 2005 08:08:30 +0000 (10:08 +0200)
Documentation,HDA Intel driver
Added position_fix module option to HDA-intel driver for fixing up
the DMA position (possibly hardware-) bugs.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Documentation/sound/alsa/ALSA-Configuration.txt
sound/pci/hda/hda_intel.c

index c69581ca2a345f5f9594ac7c1cac9629703fd6d9..ef07506e583cf9718227a47779b28d8fd5bae860 100644 (file)
@@ -618,6 +618,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for Intel HD Audio (ICH6, ICH6M, ICH7)
 
     model      - force the model name
+    position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)
 
     Module supports up to 8 cards.
 
@@ -643,6 +644,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          full_dig      6-jack in back, 2-jack in front, SPDIF I/O
          allout        5-jack in back, 2-jack in front, SPDIF out
 
+    Note 2: If you get click noises on output, try the module option
+           position_fix=1 or 2.  position_fix=1 will use the SD_LPIB
+           register value without FIFO size correction as the current
+           DMA pointer.  position_fix=2 will make the driver to use
+           the position buffer instead of reading SD_LPIB register.
+           (Usually SD_LPLIB register is more accurate than the
+           position buffer.)
+
   Module snd-hdsp
   ---------------
 
index cbc9ca73c2abde64d1a52524d32893ef08c18c52..104593fa08eb96f97ebdcbb2b6a0970d053f95d6 100644 (file)
@@ -51,6 +51,7 @@ 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];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -60,6 +61,8 @@ 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_array(position_fix, bool, NULL, 0444);
+MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF).");
 
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
@@ -183,6 +186,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define ICH6_MAX_CORB_ENTRIES  256
 #define ICH6_MAX_RIRB_ENTRIES  256
 
+/* position fix mode */
+enum {
+       POS_FIX_FIFO,
+       POS_FIX_NONE,
+       POS_FIX_POSBUF
+};
 
 /*
  * Use CORB/RIRB for communication from/to codecs.
@@ -190,12 +199,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
  */
 #define USE_CORB_RIRB
 
-/*
- * Define this if use the position buffer instead of reading SD_LPIB
- * It's not used as default since SD_LPIB seems to give more accurate position
- */
-/* #define USE_POSBUF */
-
 /*
  */
 
@@ -271,6 +274,9 @@ struct snd_azx {
        struct snd_dma_buffer bdl;
        struct snd_dma_buffer rb;
        struct snd_dma_buffer posbuf;
+
+       /* flags */
+       int position_fix;
 };
 
 /*
@@ -657,11 +663,11 @@ static void azx_init_chip(azx_t *chip)
        /* initialize the codec command I/O */
        azx_init_cmd_io(chip);
 
-#ifdef USE_POSBUF
-       /* program the position buffer */
-       azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
-       azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
-#endif
+       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));
+       }
 }
 
 
@@ -791,11 +797,12 @@ 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));
 
-#ifdef USE_POSBUF
-       /* enable the position buffer */
-       if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-               azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
-#endif
+       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);
+       }
+
        /* 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);
 
@@ -1036,16 +1043,20 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 
 static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
 {
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       azx_t *chip = apcm->chip;
        azx_dev_t *azx_dev = get_azx_dev(substream);
        unsigned int pos;
 
-#ifdef USE_POSBUF
-       /* use the position buffer */
-       pos = *azx_dev->posbuf;
-#else
-       /* read LPIB */
-       pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size;
-#endif
+       if (chip->position_fix == POS_FIX_POSBUF) {
+               /* use the position buffer */
+               pos = *azx_dev->posbuf;
+       } else {
+               /* read LPIB */
+               pos = azx_sd_readl(azx_dev, SD_LPIB);
+               if (chip->position_fix == POS_FIX_FIFO)
+                       pos += azx_dev->fifo_size;
+       }
        if (pos >= azx_dev->bufsize)
                pos = 0;
        return bytes_to_frames(substream->runtime, pos);
@@ -1155,9 +1166,8 @@ 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;
-#ifdef USE_POSBUF
-               azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
-#endif
+               if (chip->position_fix == POS_FIX_POSBUF)
+                       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 */
@@ -1237,10 +1247,8 @@ static int azx_free(azx_t *chip)
                snd_dma_free_pages(&chip->bdl);
        if (chip->rb.area)
                snd_dma_free_pages(&chip->rb);
-#ifdef USE_POSBUF
        if (chip->posbuf.area)
                snd_dma_free_pages(&chip->posbuf);
-#endif
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
@@ -1256,7 +1264,8 @@ static int azx_dev_free(snd_device_t *device)
 /*
  * constructor
  */
-static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip)
+static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
+                               int posfix, azx_t **rchip)
 {
        azx_t *chip;
        int err = 0;
@@ -1283,6 +1292,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r
        chip->pci = pci;
        chip->irq = -1;
 
+       chip->position_fix = posfix;
+
        if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
                kfree(chip);
                pci_disable_device(pci);
@@ -1314,14 +1325,14 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r
                snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
                goto errout;
        }
-#ifdef USE_POSBUF
-       /* allocate memory for the position buffer */
-       if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                      MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
-               snd_printk(KERN_ERR SFX "cannot allocate posbuf\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),
+                                              MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+                       snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
+                       goto errout;
+               }
        }
-#endif
        /* allocate CORB/RIRB */
        if ((err = azx_alloc_cmd_io(chip)) < 0)
                goto errout;
@@ -1372,7 +1383,7 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
                return -ENOMEM;
        }
 
-       if ((err = azx_create(card, pci, &chip)) < 0) {
+       if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
                snd_card_free(card);
                return err;
        }