summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Henningsson <david.henningsson@canonical.com>2010-09-30 10:12:50 +0200
committerTakashi Iwai <tiwai@suse.de>2010-09-30 14:16:11 +0200
commit4cb36310848fd17766aa72afd1f2873f54b4e055 (patch)
treebdd58b3ab4085de265086417d0dbcc53a31eeb45
parentc123e5e437a0e61e364c1cbad3ef9a7384975fb2 (diff)
downloadlwn-4cb36310848fd17766aa72afd1f2873f54b4e055.tar.gz
lwn-4cb36310848fd17766aa72afd1f2873f54b4e055.zip
ALSA: HDA: Add position_fix=3 module option, and refactor related code
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>
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt8
-rw-r--r--sound/pci/hda/hda_intel.c41
2 files changed, 24 insertions, 25 deletions
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 278cc2122ea0..c82beb007634 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -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
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index ec07e4700e3b..38b063eb80e9 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -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) {