|
@@ -51,6 +51,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
|
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
|
|
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
|
|
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
|
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
|
static char *model[SNDRV_CARDS];
|
|
static char *model[SNDRV_CARDS];
|
|
|
|
+static int position_fix[SNDRV_CARDS];
|
|
|
|
|
|
module_param_array(index, int, NULL, 0444);
|
|
module_param_array(index, int, NULL, 0444);
|
|
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
|
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
|
@@ -60,6 +61,8 @@ module_param_array(enable, bool, NULL, 0444);
|
|
MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
|
|
MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
|
|
module_param_array(model, charp, NULL, 0444);
|
|
module_param_array(model, charp, NULL, 0444);
|
|
MODULE_PARM_DESC(model, "Use the given board model.");
|
|
MODULE_PARM_DESC(model, "Use the given board model.");
|
|
|
|
+module_param_array(position_fix, bool, NULL, 0444);
|
|
|
|
+MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF).");
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
|
|
MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
|
|
@@ -183,6 +186,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
|
#define ICH6_MAX_CORB_ENTRIES 256
|
|
#define ICH6_MAX_CORB_ENTRIES 256
|
|
#define ICH6_MAX_RIRB_ENTRIES 256
|
|
#define ICH6_MAX_RIRB_ENTRIES 256
|
|
|
|
|
|
|
|
+/* position fix mode */
|
|
|
|
+enum {
|
|
|
|
+ POS_FIX_FIFO,
|
|
|
|
+ POS_FIX_NONE,
|
|
|
|
+ POS_FIX_POSBUF
|
|
|
|
+};
|
|
|
|
|
|
/*
|
|
/*
|
|
* Use CORB/RIRB for communication from/to codecs.
|
|
* Use CORB/RIRB for communication from/to codecs.
|
|
@@ -190,12 +199,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
|
*/
|
|
*/
|
|
#define USE_CORB_RIRB
|
|
#define USE_CORB_RIRB
|
|
|
|
|
|
-/*
|
|
|
|
- * Define this if use the position buffer instead of reading SD_LPIB
|
|
|
|
- * It's not used as default since SD_LPIB seems to give more accurate position
|
|
|
|
- */
|
|
|
|
-/* #define USE_POSBUF */
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
*/
|
|
*/
|
|
|
|
|
|
@@ -271,6 +274,9 @@ struct snd_azx {
|
|
struct snd_dma_buffer bdl;
|
|
struct snd_dma_buffer bdl;
|
|
struct snd_dma_buffer rb;
|
|
struct snd_dma_buffer rb;
|
|
struct snd_dma_buffer posbuf;
|
|
struct snd_dma_buffer posbuf;
|
|
|
|
+
|
|
|
|
+ /* flags */
|
|
|
|
+ int position_fix;
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -657,11 +663,11 @@ static void azx_init_chip(azx_t *chip)
|
|
/* initialize the codec command I/O */
|
|
/* initialize the codec command I/O */
|
|
azx_init_cmd_io(chip);
|
|
azx_init_cmd_io(chip);
|
|
|
|
|
|
-#ifdef USE_POSBUF
|
|
|
|
- /* program the position buffer */
|
|
|
|
- azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
|
|
|
|
- azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
|
|
|
|
-#endif
|
|
|
|
|
|
+ if (chip->position_fix == POS_FIX_POSBUF) {
|
|
|
|
+ /* program the position buffer */
|
|
|
|
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
|
|
|
|
+ azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -791,11 +797,12 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev)
|
|
/* upper BDL address */
|
|
/* upper BDL address */
|
|
azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
|
|
azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
|
|
|
|
|
|
-#ifdef USE_POSBUF
|
|
|
|
- /* enable the position buffer */
|
|
|
|
- if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
|
|
|
|
- azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
|
|
|
|
-#endif
|
|
|
|
|
|
+ if (chip->position_fix == POS_FIX_POSBUF) {
|
|
|
|
+ /* enable the position buffer */
|
|
|
|
+ if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
|
|
|
|
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
|
|
|
|
+ }
|
|
|
|
+
|
|
/* set the interrupt enable bits in the descriptor control register */
|
|
/* set the interrupt enable bits in the descriptor control register */
|
|
azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
|
|
azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
|
|
|
|
|
|
@@ -1036,16 +1043,20 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
|
|
|
|
|
|
static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
|
|
static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
|
|
{
|
|
{
|
|
|
|
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
|
|
|
+ azx_t *chip = apcm->chip;
|
|
azx_dev_t *azx_dev = get_azx_dev(substream);
|
|
azx_dev_t *azx_dev = get_azx_dev(substream);
|
|
unsigned int pos;
|
|
unsigned int pos;
|
|
|
|
|
|
-#ifdef USE_POSBUF
|
|
|
|
- /* use the position buffer */
|
|
|
|
- pos = *azx_dev->posbuf;
|
|
|
|
-#else
|
|
|
|
- /* read LPIB */
|
|
|
|
- pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size;
|
|
|
|
-#endif
|
|
|
|
|
|
+ if (chip->position_fix == POS_FIX_POSBUF) {
|
|
|
|
+ /* use the position buffer */
|
|
|
|
+ pos = *azx_dev->posbuf;
|
|
|
|
+ } else {
|
|
|
|
+ /* read LPIB */
|
|
|
|
+ pos = azx_sd_readl(azx_dev, SD_LPIB);
|
|
|
|
+ if (chip->position_fix == POS_FIX_FIFO)
|
|
|
|
+ pos += azx_dev->fifo_size;
|
|
|
|
+ }
|
|
if (pos >= azx_dev->bufsize)
|
|
if (pos >= azx_dev->bufsize)
|
|
pos = 0;
|
|
pos = 0;
|
|
return bytes_to_frames(substream->runtime, pos);
|
|
return bytes_to_frames(substream->runtime, pos);
|
|
@@ -1155,9 +1166,8 @@ static int __devinit azx_init_stream(azx_t *chip)
|
|
azx_dev_t *azx_dev = &chip->azx_dev[i];
|
|
azx_dev_t *azx_dev = &chip->azx_dev[i];
|
|
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
|
|
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
|
|
azx_dev->bdl_addr = chip->bdl.addr + off;
|
|
azx_dev->bdl_addr = chip->bdl.addr + off;
|
|
-#ifdef USE_POSBUF
|
|
|
|
- azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
|
|
|
|
-#endif
|
|
|
|
|
|
+ if (chip->position_fix == POS_FIX_POSBUF)
|
|
|
|
+ azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
|
|
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
|
/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
|
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
|
azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
|
|
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
|
/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
|
|
@@ -1237,10 +1247,8 @@ static int azx_free(azx_t *chip)
|
|
snd_dma_free_pages(&chip->bdl);
|
|
snd_dma_free_pages(&chip->bdl);
|
|
if (chip->rb.area)
|
|
if (chip->rb.area)
|
|
snd_dma_free_pages(&chip->rb);
|
|
snd_dma_free_pages(&chip->rb);
|
|
-#ifdef USE_POSBUF
|
|
|
|
if (chip->posbuf.area)
|
|
if (chip->posbuf.area)
|
|
snd_dma_free_pages(&chip->posbuf);
|
|
snd_dma_free_pages(&chip->posbuf);
|
|
-#endif
|
|
|
|
pci_release_regions(chip->pci);
|
|
pci_release_regions(chip->pci);
|
|
pci_disable_device(chip->pci);
|
|
pci_disable_device(chip->pci);
|
|
kfree(chip);
|
|
kfree(chip);
|
|
@@ -1256,7 +1264,8 @@ static int azx_dev_free(snd_device_t *device)
|
|
/*
|
|
/*
|
|
* constructor
|
|
* constructor
|
|
*/
|
|
*/
|
|
-static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip)
|
|
|
|
|
|
+static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
|
|
|
|
+ int posfix, azx_t **rchip)
|
|
{
|
|
{
|
|
azx_t *chip;
|
|
azx_t *chip;
|
|
int err = 0;
|
|
int err = 0;
|
|
@@ -1283,6 +1292,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r
|
|
chip->pci = pci;
|
|
chip->pci = pci;
|
|
chip->irq = -1;
|
|
chip->irq = -1;
|
|
|
|
|
|
|
|
+ chip->position_fix = posfix;
|
|
|
|
+
|
|
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
|
|
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
|
|
kfree(chip);
|
|
kfree(chip);
|
|
pci_disable_device(pci);
|
|
pci_disable_device(pci);
|
|
@@ -1314,14 +1325,14 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r
|
|
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
|
|
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
|
|
goto errout;
|
|
goto errout;
|
|
}
|
|
}
|
|
-#ifdef USE_POSBUF
|
|
|
|
- /* allocate memory for the position buffer */
|
|
|
|
- if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
|
|
|
|
- MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
|
|
|
|
- snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
|
|
|
|
- goto errout;
|
|
|
|
|
|
+ if (chip->position_fix == POS_FIX_POSBUF) {
|
|
|
|
+ /* allocate memory for the position buffer */
|
|
|
|
+ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
|
|
|
|
+ MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
|
|
|
|
+ snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
|
|
|
|
+ goto errout;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
/* allocate CORB/RIRB */
|
|
/* allocate CORB/RIRB */
|
|
if ((err = azx_alloc_cmd_io(chip)) < 0)
|
|
if ((err = azx_alloc_cmd_io(chip)) < 0)
|
|
goto errout;
|
|
goto errout;
|
|
@@ -1372,7 +1383,7 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((err = azx_create(card, pci, &chip)) < 0) {
|
|
|
|
|
|
+ if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
|
|
snd_card_free(card);
|
|
snd_card_free(card);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|