/* * allocate and initialize the descriptor buffers * periods = number of periods * fragsize = period size in bytes
*/ staticint build_via_table(struct viadev *dev, struct snd_pcm_substream *substream, struct pci_dev *pci, unsignedint periods, unsignedint fragsize)
{ unsignedint i, idx, ofs, rest; struct via82xx_modem *chip = snd_pcm_substream_chip(substream);
__le32 *pgtbl;
if (dev->table.area == NULL) { /* the start of each lists must be aligned to 8 bytes, * but the kernel pages are much bigger, so we don't care
*/ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8),
&dev->table) < 0) return -ENOMEM;
} if (! dev->idx_table) {
dev->idx_table = kmalloc_array(VIA_TABLE_SIZE, sizeof(*dev->idx_table),
GFP_KERNEL); if (! dev->idx_table) return -ENOMEM;
}
/* fill the entries */
idx = 0;
ofs = 0;
pgtbl = (__le32 *)dev->table.area; for (i = 0; i < periods; i++) {
rest = fragsize; /* fill descriptors for a period. * a period can be split to several descriptors if it's * over page boundary.
*/ do { unsignedint r; unsignedint flag; unsignedint addr;
if (idx >= VIA_TABLE_SIZE) {
dev_err(&pci->dev, "too much table size!\n"); return -EINVAL;
}
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
pgtbl[idx << 1] = cpu_to_le32(addr);
r = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < r)
r = rest;
rest -= r; if (! rest) { if (i == periods - 1)
flag = VIA_TBL_BIT_EOL; /* buffer boundary */ else
flag = VIA_TBL_BIT_FLAG; /* period boundary */
} else
flag = 0; /* period continues to the next */ /* dev_dbg(&pci->dev, "tbl %d: at %d size %d (rest %d)\n", idx, ofs, r, rest);
*/
pgtbl[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
dev->idx_table[idx].size = r;
ofs += r;
idx++;
} while (rest > 0);
}
dev->tbl_entries = idx;
dev->bufsize = periods * fragsize;
dev->bufsize2 = dev->bufsize / 2; return0;
}
while (timeout-- > 0) {
val = snd_via82xx_codec_xread(chip);
val1 = val & (VIA_REG_AC97_BUSY | stat); if (val1 == stat) return val & 0xffff;
udelay(1);
} return -EIO;
}
staticvoid snd_via82xx_codec_wait(struct snd_ac97 *ac97)
{ struct via82xx_modem *chip = ac97->private_data;
__always_unused int err;
err = snd_via82xx_codec_ready(chip, ac97->num); /* here we need to wait fairly for long time.. */
msleep(500);
}
size = viadev->idx_table[idx].size;
res = viadev->idx_table[idx].offset + size - count;
/* check the validity of the calculated position */ if (size < count) {
dev_err(chip->card->dev, "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
(int)size, (int)count);
res = viadev->lastpos;
} elseif (check_invalid_pos(viadev, res)) { #ifdef POINTER_DEBUG
dev_dbg(chip->card->dev, "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n",
idx, viadev->tbl_entries, viadev->lastpos,
viadev->bufsize2, viadev->idx_table[idx].offset,
viadev->idx_table[idx].size, count); #endif if (count && size < count) {
dev_dbg(chip->card->dev, "invalid via82xx_cur_ptr, using last valid pointer\n");
res = viadev->lastpos;
} else { if (! count) /* bogus count 0 on the DMA boundary? */
res = viadev->idx_table[idx].offset; else /* count register returns full size * when end of buffer is reached
*/
res = viadev->idx_table[idx].offset + size; if (check_invalid_pos(viadev, res)) {
dev_dbg(chip->card->dev, "invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
}
}
}
viadev->lastpos = res; /* remember the last position */ if (res >= viadev->bufsize)
res -= viadev->bufsize; return res;
}
/* * get the current pointer on via686
*/ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substream)
{ struct via82xx_modem *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; unsignedint idx, ptr, count, res;
if (snd_BUG_ON(!viadev->tbl_entries)) return0; if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE)) return0;
spin_lock(&chip->reg_lock);
count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff; /* The via686a does not have the current index register, * so we need to calculate the index from CURR_PTR.
*/
ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR)); if (ptr <= (unsignedint)viadev->table.addr)
idx = 0; else/* CURR_PTR holds the address + 8 */
idx = ((ptr - (unsignedint)viadev->table.addr) / 8 - 1) %
viadev->tbl_entries;
res = calc_linear_pos(chip, viadev, idx, count);
spin_unlock(&chip->reg_lock);
snd_via82xx_channel_reset(chip, viadev); /* this must be set after channel_reset */
snd_via82xx_set_table_ptr(chip, viadev);
outb(VIA_REG_TYPE_AUTOSTART|VIA_REG_TYPE_INT_EOL|VIA_REG_TYPE_INT_FLAG,
VIADEV_REG(viadev, OFFSET_TYPE)); return0;
}
/* we may remove following constaint when we modify table entries
in interrupt */
err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) return err;
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (! (pval & VIA_ACLINK_C00_READY)) { /* codec not ready? */ /* deassert ACLink reset, force SYNC */
pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,
VIA_ACLINK_CTRL_ENABLE |
VIA_ACLINK_CTRL_RESET |
VIA_ACLINK_CTRL_SYNC);
udelay(100); #if1/* FIXME: should we do full reset here for all chip models? */
pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00);
udelay(100); #else /* deassert ACLink reset, force SYNC (warm AC'97 reset) */
pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL,
VIA_ACLINK_CTRL_RESET|VIA_ACLINK_CTRL_SYNC);
udelay(2); #endif /* ACLink on, deassert ACLink reset, VSR, SGD data out */
pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);
udelay(100);
}
pci_read_config_byte(chip->pci, VIA_ACLINK_CTRL, &pval); if ((pval & VIA_ACLINK_CTRL_INIT) != VIA_ACLINK_CTRL_INIT) { /* ACLink on, deassert ACLink reset, VSR, SGD data out */
pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT);
udelay(100);
}
/* wait until codec ready */
end_time = jiffies + msecs_to_jiffies(750); do {
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break;
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time));
val = snd_via82xx_codec_xread(chip); if (val & VIA_REG_AC97_BUSY)
dev_err(chip->card->dev, "AC'97 codec is not ready [0x%x]\n", val);
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
end_time = jiffies + msecs_to_jiffies(750);
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT)); do {
val = snd_via82xx_codec_xread(chip); if (val & VIA_REG_AC97_SECONDARY_VALID) {
chip->ac97_secondary = 1; goto __ac97_ok2;
}
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */
__ac97_ok2:
/* route FM trap to IRQ, disable FM trap */ // pci_write_config_byte(chip->pci, VIA_FM_NMI_CTRL, 0); /* disable all GPI interrupts */
outl(0, VIAREG(chip, GPI_INTR));
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->num_devs; i++)
snd_via82xx_channel_reset(chip, &chip->devs[i]);
snd_ac97_suspend(chip->ac97); return0;
}
err = snd_via82xx_chip_init(chip); if (err < 0) return err;
/* The 8233 ac97 controller does not implement the master bit * in the pci command register. IMHO this is a violation of the PCI spec.
* We call pci_set_master here because it does not hurt. */
pci_set_master(pci); return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.