ALSA: HDA: Add position_fix=3 module option, and refactor related code
David Henningsson [Thu, 30 Sep 2010 08:12:50 +0000 (10:12 +0200)]
What was previously known as via_dmapos_patch, and hard-coded to be
used for VIA and ATI controllers, is now configurable through a module
option. The background is that some VIA controllers seem to prefer
via_dmapos_patch to be turned off.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Documentation/sound/alsa/HD-Audio.txt
sound/pci/hda/hda_intel.c

index 278cc21..c82beb0 100644 (file)
@@ -57,9 +57,11 @@ dead.  However, this detection isn't perfect on some devices.  In such
 a case, you can change the default method via `position_fix` option.
 
 `position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer.  0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above.  If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers.  0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above.  If you get a problem of repeated sounds, this option might
 help.
 
 In addition to that, every controller is known to be broken regarding
index ec07e47..38b063e 100644 (file)
@@ -78,8 +78,8 @@ 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, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-                "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+                "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -305,6 +305,7 @@ enum {
        POS_FIX_AUTO,
        POS_FIX_LPIB,
        POS_FIX_POSBUF,
+       POS_FIX_VIACOMBO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -433,7 +434,6 @@ struct azx {
        unsigned int polling_mode :1;
        unsigned int msi :1;
        unsigned int irq_pending_warned :1;
-       unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
        unsigned int probing :1; /* codec probing phase */
 
        /* for debugging */
@@ -1309,11 +1309,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
        /* enable the position buffer */
-       if (chip->position_fix[0] == POS_FIX_POSBUF ||
-           chip->position_fix[0] == POS_FIX_AUTO ||
-           chip->position_fix[1] == POS_FIX_POSBUF ||
-           chip->position_fix[1] == POS_FIX_AUTO ||
-           chip->via_dmapos_patch) {
+       if (chip->position_fix[0] != POS_FIX_LPIB ||
+           chip->position_fix[1] != POS_FIX_LPIB) {
                if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
                        azx_writel(chip, DPLBASE,
                                (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1852,20 +1849,21 @@ static unsigned int azx_get_position(struct azx *chip,
                                     struct azx_dev *azx_dev)
 {
        unsigned int pos;
+       int stream = azx_dev->substream->stream;
 
-       if (chip->via_dmapos_patch)
+       switch (chip->position_fix[stream]) {
+       case POS_FIX_LPIB:
+               /* read LPIB */
+               pos = azx_sd_readl(azx_dev, SD_LPIB);
+               break;
+       case POS_FIX_VIACOMBO:
                pos = azx_via_get_position(chip, azx_dev);
-       else {
-               int stream = azx_dev->substream->stream;
-               if (chip->position_fix[stream] == POS_FIX_POSBUF ||
-                   chip->position_fix[stream] == POS_FIX_AUTO) {
-                       /* use the position buffer */
-                       pos = le32_to_cpu(*azx_dev->posbuf);
-               } else {
-                       /* read LPIB */
-                       pos = azx_sd_readl(azx_dev, SD_LPIB);
-               }
+               break;
+       default:
+               /* use the position buffer */
+               pos = le32_to_cpu(*azx_dev->posbuf);
        }
+
        if (pos >= azx_dev->bufsize)
                pos = 0;
        return pos;
@@ -2313,6 +2311,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        switch (fix) {
        case POS_FIX_LPIB:
        case POS_FIX_POSBUF:
+       case POS_FIX_VIACOMBO:
                return fix;
        }
 
@@ -2320,11 +2319,9 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        switch (chip->driver_type) {
        case AZX_DRIVER_VIA:
        case AZX_DRIVER_ATI:
-               chip->via_dmapos_patch = 1;
                /* Use link position directly, avoid any transfer problem. */
-               return POS_FIX_LPIB;
+               return POS_FIX_VIACOMBO;
        }
-       chip->via_dmapos_patch = 0;
 
        q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
        if (q) {