Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 110942
b: refs/heads/master
c: 0e15347
h: refs/heads/master
v: v3
  • Loading branch information
Joseph Chan authored and Jaroslav Kysela committed Aug 29, 2008
1 parent e357e9f commit 0372a11
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: acdfc9e305b8320c5dee714a08be022441b58c44
refs/heads/master: 0e153474f47aee906107a5c1da0ae83553e5ba6a
91 changes: 88 additions & 3 deletions trunk/sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ enum {
#define INTEL_SCH_HDA_DEVC 0x78
#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)

/* Define IN stream 0 FIFO size offset in VIA controller */
#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
/* Define VIA HD Audio Device ID*/
#define VIA_HDAC_DEVICE_ID 0x3288


/*
*/
Expand Down Expand Up @@ -317,6 +322,12 @@ struct azx_dev {
unsigned int running :1;
unsigned int irq_pending :1;
unsigned int irq_ignore :1;
/*
* For VIA:
* A flag to ensure DMA position is 0
* when link position is not greater than FIFO size
*/
unsigned int insufficient :1;
};

/* CORB/RIRB */
Expand Down Expand Up @@ -379,6 +390,7 @@ 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 */

/* for debugging */
unsigned int last_cmd; /* last issued command (to sync) */
Expand Down Expand Up @@ -818,6 +830,11 @@ static void azx_int_clear(struct azx *chip)
/* start a stream */
static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
{
/*
* Before stream start, initialize parameter
*/
azx_dev->insufficient = 1;

/* enable SIE */
azx_writeb(chip, INTCTL,
azx_readb(chip, INTCTL) | (1 << azx_dev->index));
Expand Down Expand Up @@ -1148,7 +1165,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)

/* enable the position buffer */
if (chip->position_fix == POS_FIX_POSBUF ||
chip->position_fix == POS_FIX_AUTO) {
chip->position_fix == POS_FIX_AUTO ||
chip->via_dmapos_patch) {
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
azx_writel(chip, DPLBASE,
(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
Expand Down Expand Up @@ -1504,13 +1522,71 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}

/* get the current DMA position with correction on VIA chips */
static unsigned int azx_via_get_position(struct azx *chip,
struct azx_dev *azx_dev)
{
unsigned int link_pos, mini_pos, bound_pos;
unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
unsigned int fifo_size;

link_pos = azx_sd_readl(azx_dev, SD_LPIB);
if (azx_dev->index >= 4) {
/* Playback, no problem using link position */
return link_pos;
}

/* Capture */
/* For new chipset,
* use mod to get the DMA position just like old chipset
*/
mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
mod_dma_pos %= azx_dev->period_bytes;

/* azx_dev->fifo_size can't get FIFO size of in stream.
* Get from base address + offset.
*/
fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);

if (azx_dev->insufficient) {
/* Link position never gather than FIFO size */
if (link_pos <= fifo_size)
return 0;

azx_dev->insufficient = 0;
}

if (link_pos <= fifo_size)
mini_pos = azx_dev->bufsize + link_pos - fifo_size;
else
mini_pos = link_pos - fifo_size;

/* Find nearest previous boudary */
mod_mini_pos = mini_pos % azx_dev->period_bytes;
mod_link_pos = link_pos % azx_dev->period_bytes;
if (mod_link_pos >= fifo_size)
bound_pos = link_pos - mod_link_pos;
else if (mod_dma_pos >= mod_mini_pos)
bound_pos = mini_pos - mod_mini_pos;
else {
bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
if (bound_pos >= azx_dev->bufsize)
bound_pos = 0;
}

/* Calculate real DMA position we want */
return bound_pos + mod_dma_pos;
}

static unsigned int azx_get_position(struct azx *chip,
struct azx_dev *azx_dev)
{
unsigned int pos;

if (chip->position_fix == POS_FIX_POSBUF ||
chip->position_fix == POS_FIX_AUTO) {
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 {
Expand Down Expand Up @@ -1946,6 +2022,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
{
const struct snd_pci_quirk *q;

/* Check VIA HD Audio Controller exist */
if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
chip->pci->device == VIA_HDAC_DEVICE_ID) {
chip->via_dmapos_patch = 1;
/* Use link position directly, avoid any transfer problem. */
return POS_FIX_LPIB;
}
chip->via_dmapos_patch = 0;

if (fix == POS_FIX_AUTO) {
q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
if (q) {
Expand Down

0 comments on commit 0372a11

Please sign in to comment.