aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
authorJoseph Chan <josephchan@via.com.tw>2008-08-26 08:38:03 -0400
committerJaroslav Kysela <perex@perex.cz>2008-08-29 04:06:12 -0400
commit0e153474f47aee906107a5c1da0ae83553e5ba6a (patch)
treec9aaf92d3b847a5212549cdb01dcfdbbd7317e7a /sound/pci/hda/hda_intel.c
parentacdfc9e305b8320c5dee714a08be022441b58c44 (diff)
ALSA: hda - Fix VIA recording problem
Add a workaround for bad DMA-position reporting on VIA chipset. Signed-off-by: Joseph Chan <josephchan@via.com.tw> [modified and cleaned up by tiwai] Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c91
1 files changed, 88 insertions, 3 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 4f80248837e..52a3adfac7f 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -286,6 +286,11 @@ enum {
286#define INTEL_SCH_HDA_DEVC 0x78 286#define INTEL_SCH_HDA_DEVC 0x78
287#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) 287#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
288 288
289/* Define IN stream 0 FIFO size offset in VIA controller */
290#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
291/* Define VIA HD Audio Device ID*/
292#define VIA_HDAC_DEVICE_ID 0x3288
293
289 294
290/* 295/*
291 */ 296 */
@@ -317,6 +322,12 @@ struct azx_dev {
317 unsigned int running :1; 322 unsigned int running :1;
318 unsigned int irq_pending :1; 323 unsigned int irq_pending :1;
319 unsigned int irq_ignore :1; 324 unsigned int irq_ignore :1;
325 /*
326 * For VIA:
327 * A flag to ensure DMA position is 0
328 * when link position is not greater than FIFO size
329 */
330 unsigned int insufficient :1;
320}; 331};
321 332
322/* CORB/RIRB */ 333/* CORB/RIRB */
@@ -379,6 +390,7 @@ struct azx {
379 unsigned int polling_mode :1; 390 unsigned int polling_mode :1;
380 unsigned int msi :1; 391 unsigned int msi :1;
381 unsigned int irq_pending_warned :1; 392 unsigned int irq_pending_warned :1;
393 unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
382 394
383 /* for debugging */ 395 /* for debugging */
384 unsigned int last_cmd; /* last issued command (to sync) */ 396 unsigned int last_cmd; /* last issued command (to sync) */
@@ -818,6 +830,11 @@ static void azx_int_clear(struct azx *chip)
818/* start a stream */ 830/* start a stream */
819static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) 831static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
820{ 832{
833 /*
834 * Before stream start, initialize parameter
835 */
836 azx_dev->insufficient = 1;
837
821 /* enable SIE */ 838 /* enable SIE */
822 azx_writeb(chip, INTCTL, 839 azx_writeb(chip, INTCTL,
823 azx_readb(chip, INTCTL) | (1 << azx_dev->index)); 840 azx_readb(chip, INTCTL) | (1 << azx_dev->index));
@@ -1148,7 +1165,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
1148 1165
1149 /* enable the position buffer */ 1166 /* enable the position buffer */
1150 if (chip->position_fix == POS_FIX_POSBUF || 1167 if (chip->position_fix == POS_FIX_POSBUF ||
1151 chip->position_fix == POS_FIX_AUTO) { 1168 chip->position_fix == POS_FIX_AUTO ||
1169 chip->via_dmapos_patch) {
1152 if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) 1170 if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
1153 azx_writel(chip, DPLBASE, 1171 azx_writel(chip, DPLBASE,
1154 (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); 1172 (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1504,13 +1522,71 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1504 return 0; 1522 return 0;
1505} 1523}
1506 1524
1525/* get the current DMA position with correction on VIA chips */
1526static unsigned int azx_via_get_position(struct azx *chip,
1527 struct azx_dev *azx_dev)
1528{
1529 unsigned int link_pos, mini_pos, bound_pos;
1530 unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
1531 unsigned int fifo_size;
1532
1533 link_pos = azx_sd_readl(azx_dev, SD_LPIB);
1534 if (azx_dev->index >= 4) {
1535 /* Playback, no problem using link position */
1536 return link_pos;
1537 }
1538
1539 /* Capture */
1540 /* For new chipset,
1541 * use mod to get the DMA position just like old chipset
1542 */
1543 mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
1544 mod_dma_pos %= azx_dev->period_bytes;
1545
1546 /* azx_dev->fifo_size can't get FIFO size of in stream.
1547 * Get from base address + offset.
1548 */
1549 fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
1550
1551 if (azx_dev->insufficient) {
1552 /* Link position never gather than FIFO size */
1553 if (link_pos <= fifo_size)
1554 return 0;
1555
1556 azx_dev->insufficient = 0;
1557 }
1558
1559 if (link_pos <= fifo_size)
1560 mini_pos = azx_dev->bufsize + link_pos - fifo_size;
1561 else
1562 mini_pos = link_pos - fifo_size;
1563
1564 /* Find nearest previous boudary */
1565 mod_mini_pos = mini_pos % azx_dev->period_bytes;
1566 mod_link_pos = link_pos % azx_dev->period_bytes;
1567 if (mod_link_pos >= fifo_size)
1568 bound_pos = link_pos - mod_link_pos;
1569 else if (mod_dma_pos >= mod_mini_pos)
1570 bound_pos = mini_pos - mod_mini_pos;
1571 else {
1572 bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
1573 if (bound_pos >= azx_dev->bufsize)
1574 bound_pos = 0;
1575 }
1576
1577 /* Calculate real DMA position we want */
1578 return bound_pos + mod_dma_pos;
1579}
1580
1507static unsigned int azx_get_position(struct azx *chip, 1581static unsigned int azx_get_position(struct azx *chip,
1508 struct azx_dev *azx_dev) 1582 struct azx_dev *azx_dev)
1509{ 1583{
1510 unsigned int pos; 1584 unsigned int pos;
1511 1585
1512 if (chip->position_fix == POS_FIX_POSBUF || 1586 if (chip->via_dmapos_patch)
1513 chip->position_fix == POS_FIX_AUTO) { 1587 pos = azx_via_get_position(chip, azx_dev);
1588 else if (chip->position_fix == POS_FIX_POSBUF ||
1589 chip->position_fix == POS_FIX_AUTO) {
1514 /* use the position buffer */ 1590 /* use the position buffer */
1515 pos = le32_to_cpu(*azx_dev->posbuf); 1591 pos = le32_to_cpu(*azx_dev->posbuf);
1516 } else { 1592 } else {
@@ -1946,6 +2022,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
1946{ 2022{
1947 const struct snd_pci_quirk *q; 2023 const struct snd_pci_quirk *q;
1948 2024
2025 /* Check VIA HD Audio Controller exist */
2026 if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
2027 chip->pci->device == VIA_HDAC_DEVICE_ID) {
2028 chip->via_dmapos_patch = 1;
2029 /* Use link position directly, avoid any transfer problem. */
2030 return POS_FIX_LPIB;
2031 }
2032 chip->via_dmapos_patch = 0;
2033
1949 if (fix == POS_FIX_AUTO) { 2034 if (fix == POS_FIX_AUTO) {
1950 q = snd_pci_quirk_lookup(chip->pci, position_fix_list); 2035 q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
1951 if (q) { 2036 if (q) {