Commit beaffc39 authored by Shahin Ghazinouri's avatar Shahin Ghazinouri Committed by Takashi Iwai

ALSA: hda - Fixes distorted recording on US15W chipset

The HDA controller in US15W (Poulsbo) reports inaccurate position values
for capture streams when using the LPIB read method, resulting in
distorted recordings.

However, using the position buffer is broken for playback streams,
resulting in a fallback to the LPIB method with the current driver.
This patch works around the issue by independently detecting the read
position method for capture and playback streams.

The patch will not have any effect if the position fix method is
explicitly set.

[Code simplified by tiwai]
Signed-off-by: default avatarShahin Ghazinouri <shahin.ghazinouri@pelagicore.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 54331373
...@@ -425,7 +425,7 @@ struct azx { ...@@ -425,7 +425,7 @@ struct azx {
struct snd_dma_buffer posbuf; struct snd_dma_buffer posbuf;
/* flags */ /* flags */
int position_fix; int position_fix[2]; /* for both playback/capture streams */
int poll_count; int poll_count;
unsigned int running :1; unsigned int running :1;
unsigned int initialized :1; unsigned int initialized :1;
...@@ -1306,8 +1306,10 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) ...@@ -1306,8 +1306,10 @@ 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)); azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
/* enable the position buffer */ /* enable the position buffer */
if (chip->position_fix == POS_FIX_POSBUF || if (chip->position_fix[0] == POS_FIX_POSBUF ||
chip->position_fix == POS_FIX_AUTO || 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) { chip->via_dmapos_patch) {
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
azx_writel(chip, DPLBASE, azx_writel(chip, DPLBASE,
...@@ -1847,13 +1849,16 @@ static unsigned int azx_get_position(struct azx *chip, ...@@ -1847,13 +1849,16 @@ static unsigned int azx_get_position(struct azx *chip,
if (chip->via_dmapos_patch) if (chip->via_dmapos_patch)
pos = azx_via_get_position(chip, azx_dev); pos = azx_via_get_position(chip, azx_dev);
else if (chip->position_fix == POS_FIX_POSBUF || else {
chip->position_fix == POS_FIX_AUTO) { int stream = azx_dev->substream->stream;
/* use the position buffer */ if (chip->position_fix[stream] == POS_FIX_POSBUF ||
pos = le32_to_cpu(*azx_dev->posbuf); chip->position_fix[stream] == POS_FIX_AUTO) {
} else { /* use the position buffer */
/* read LPIB */ pos = le32_to_cpu(*azx_dev->posbuf);
pos = azx_sd_readl(azx_dev, SD_LPIB); } else {
/* read LPIB */
pos = azx_sd_readl(azx_dev, SD_LPIB);
}
} }
if (pos >= azx_dev->bufsize) if (pos >= azx_dev->bufsize)
pos = 0; pos = 0;
...@@ -1881,22 +1886,24 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -1881,22 +1886,24 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
{ {
unsigned int pos; unsigned int pos;
int stream;
if (azx_dev->start_flag && if (azx_dev->start_flag &&
time_before_eq(jiffies, azx_dev->start_jiffies)) time_before_eq(jiffies, azx_dev->start_jiffies))
return -1; /* bogus (too early) interrupt */ return -1; /* bogus (too early) interrupt */
azx_dev->start_flag = 0; azx_dev->start_flag = 0;
stream = azx_dev->substream->stream;
pos = azx_get_position(chip, azx_dev); pos = azx_get_position(chip, azx_dev);
if (chip->position_fix == POS_FIX_AUTO) { if (chip->position_fix[stream] == POS_FIX_AUTO) {
if (!pos) { if (!pos) {
printk(KERN_WARNING printk(KERN_WARNING
"hda-intel: Invalid position buffer, " "hda-intel: Invalid position buffer, "
"using LPIB read method instead.\n"); "using LPIB read method instead.\n");
chip->position_fix = POS_FIX_LPIB; chip->position_fix[stream] = POS_FIX_LPIB;
pos = azx_get_position(chip, azx_dev); pos = azx_get_position(chip, azx_dev);
} else } else
chip->position_fix = POS_FIX_POSBUF; chip->position_fix[stream] = POS_FIX_POSBUF;
} }
if (!bdl_pos_adj[chip->dev_index]) if (!bdl_pos_adj[chip->dev_index])
...@@ -2435,7 +2442,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2435,7 +2442,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->dev_index = dev; chip->dev_index = dev;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
chip->position_fix = check_position_fix(chip, position_fix[dev]); chip->position_fix[0] = chip->position_fix[1] =
check_position_fix(chip, position_fix[dev]);
check_probe_mask(chip, dev); check_probe_mask(chip, dev);
chip->single_cmd = single_cmd; chip->single_cmd = single_cmd;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment