[PATCH] hda_intel: Fixes distorted recording on US15W chipset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.
Signed-off-by: Shahin Ghazinouri <shahin.ghazinouri@xxxxxxxxxxxxxx>
---
--- linux-2.6.34-rc6/sound/pci/hda/hda_intel.c	2010-04-30 05:02:05.000000000 +0200
+++ linux-2.6.34-rc6_patch/sound/pci/hda/hda_intel.c	2010-04-30 11:31:57.000000000 +0200
@@ -425,7 +425,8 @@
	struct snd_dma_buffer posbuf;

	/* flags */
-	int position_fix;
+	int playback_position_fix;
+	int capture_position_fix;
	int poll_count;
	unsigned int running :1;
	unsigned int initialized :1;
@@ -1302,8 +1303,10 @@
	azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));

	/* enable the position buffer */
-	if (chip->position_fix == POS_FIX_POSBUF ||
-	    chip->position_fix == POS_FIX_AUTO ||
+	if (chip->capture_position_fix == POS_FIX_POSBUF ||
+	    chip->capture_position_fix == POS_FIX_AUTO ||
+	    chip->playback_position_fix == POS_FIX_POSBUF ||
+	    chip->playback_position_fix == POS_FIX_AUTO ||
	    chip->via_dmapos_patch) {
		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
			azx_writel(chip, DPLBASE,
@@ -1843,13 +1846,24 @@

	if (chip->via_dmapos_patch)
		pos = azx_via_get_position(chip, azx_dev);
-	else if (chip->position_fix == POS_FIX_POSBUF ||
-		 chip->position_fix == POS_FIX_AUTO) {
-		/* use the position buffer */
-		pos = le32_to_cpu(*azx_dev->posbuf);
+	else if (azx_dev->index < chip->playback_index_offset) {
+		/* Capture stream */
+		if (chip->capture_position_fix == POS_FIX_POSBUF ||
+		    chip->capture_position_fix == 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);
	} else {
-		/* read LPIB */
-		pos = azx_sd_readl(azx_dev, SD_LPIB);
+		/* Playback stream */
+		if (chip->playback_position_fix == POS_FIX_POSBUF ||
+		    chip->playback_position_fix == 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);
	}
	if (pos >= azx_dev->bufsize)
		pos = 0;
@@ -1884,15 +1898,30 @@
	azx_dev->start_flag = 0;

	pos = azx_get_position(chip, azx_dev);
-	if (chip->position_fix == POS_FIX_AUTO) {
-		if (!pos) {
-			printk(KERN_WARNING
-			       "hda-intel: Invalid position buffer, "
-			       "using LPIB read method instead.\n");
-			chip->position_fix = POS_FIX_LPIB;
-			pos = azx_get_position(chip, azx_dev);
-		} else
-			chip->position_fix = POS_FIX_POSBUF;
+	if (azx_dev->index < chip->playback_index_offset) {
+		/* Capture stream  */
+		if (chip->capture_position_fix == POS_FIX_AUTO) {
+			if (!pos) {
+				printk(KERN_WARNING
+				       "hda-intel: Invalid position buffer, "
+				       "using LPIB read method instead.\n");
+				chip->capture_position_fix = POS_FIX_LPIB;
+				pos = azx_get_position(chip, azx_dev);
+			} else
+				chip->capture_position_fix = POS_FIX_POSBUF;
+		}
+	} else {
+		/* Playback stream */
+		if (chip->playback_position_fix == POS_FIX_AUTO) {
+			if (!pos) {
+				printk(KERN_WARNING
+				       "hda-intel: Invalid position buffer, "
+				       "using LPIB read method instead.\n");
+				chip->playback_position_fix = POS_FIX_LPIB;
+				pos = azx_get_position(chip, azx_dev);
+			} else
+				chip->playback_position_fix = POS_FIX_POSBUF;
+		}
	}

	if (!bdl_pos_adj[chip->dev_index])
@@ -2431,7 +2460,10 @@
	chip->dev_index = dev;
	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);

-	chip->position_fix = check_position_fix(chip, position_fix[dev]);
+	chip->capture_position_fix =
+	  check_position_fix(chip, position_fix[dev]);
+	chip->playback_position_fix =
+	  check_position_fix(chip, position_fix[dev]);
	check_probe_mask(chip, dev);

	chip->single_cmd = single_cmd;

_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux