patch-2.4.1 linux/drivers/sound/via82cxxx_audio.c
Next file: linux/drivers/sound/ymfpci.c
Previous file: linux/drivers/sound/trix.c
Back to the patch index
Back to the overall index
- Lines: 1570
- Date:
Wed Jan 24 15:30:43 2001
- Orig file:
v2.4.0/linux/drivers/sound/via82cxxx_audio.c
- Orig date:
Fri Dec 29 20:25:47 2000
diff -u --recursive --new-file v2.4.0/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
@@ -15,7 +15,7 @@
*/
-#define VIA_VERSION "1.1.14"
+#define VIA_VERSION "1.1.14a"
#include <linux/config.h>
@@ -76,8 +76,16 @@
#define VIA_COUNTER_LIMIT 100000
/* size of DMA buffers */
-#define VIA_DMA_BUFFERS 16
-#define VIA_DMA_BUF_SIZE PAGE_SIZE
+#define VIA_MAX_BUFFER_DMA_PAGES 32
+
+/* buffering default values in ms */
+#define VIA_DEFAULT_FRAG_TIME 20
+#define VIA_DEFAULT_BUFFER_TIME 500
+
+#define VIA_MAX_FRAG_SIZE PAGE_SIZE
+#define VIA_MIN_FRAG_SIZE 64
+
+#define VIA_MIN_FRAG_NUMBER 2
#ifndef AC97_PCM_LR_ADC_RATE
# define AC97_PCM_LR_ADC_RATE AC97_PCM_LR_DAC_RATE
@@ -102,7 +110,6 @@
#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01
#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02
-#define VIA_BASE0_PCM_OUT_BLOCK_COUNT 0x0C
#define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */
#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10
@@ -114,6 +121,7 @@
#define VIA_PCM_CONTROL 0x01
#define VIA_PCM_TYPE 0x02
#define VIA_PCM_TABLE_ADDR 0x04
+#define VIA_PCM_BLOCK_COUNT 0x0C
/* XXX unused DMA channel for FM PCM data */
#define VIA_BASE0_FM_OUT_CHAN 0x20
@@ -223,14 +231,14 @@
};
-struct via_sgd_data {
+struct via_buffer_pgtbl {
dma_addr_t handle;
void *cpuaddr;
};
struct via_channel {
- atomic_t n_bufs;
+ atomic_t n_frags;
atomic_t hw_ptr;
wait_queue_head_t wait;
@@ -246,11 +254,14 @@
u8 pcm_fmt; /* VIA_PCM_FMT_xxx */
unsigned rate; /* sample rate */
+ unsigned int frag_size;
+ unsigned int frag_number;
volatile struct via_sgd_table *sgtable;
dma_addr_t sgt_handle;
- struct via_sgd_data sgbuf [VIA_DMA_BUFFERS];
+ unsigned int page_number;
+ struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
long iobase;
@@ -301,17 +312,16 @@
static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int via_dsp_open (struct inode *inode, struct file *file);
static int via_dsp_release(struct inode *inode, struct file *file);
-#ifdef VIA_SUPPORT_MMAP
static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-#endif
static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
static u8 via_ac97_wait_idle (struct via_info *card);
static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_channel *chan);
+static void via_chan_clear (struct via_info *card, struct via_channel *chan);
static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
+static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
#ifdef VIA_PROC_FS
static int via_init_proc (void);
@@ -569,25 +579,53 @@
chan->pcm_fmt = VIA_PCM_FMT_MASK;
chan->is_enabled = 1;
- if (chan->is_record)
- atomic_set (&chan->n_bufs, 0);
- else
- atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);
+ chan->frag_number = 0;
+ chan->frag_size = 0;
+ atomic_set(&chan->n_frags, 0);
atomic_set (&chan->hw_ptr, 0);
}
+/**
+ * via_chan_init - Initialize PCM channel
+ * @card: Private audio chip info
+ * @chan: Channel to be initialized
+ *
+ * Performs some of the preparations necessary to begin
+ * using a PCM channel.
+ *
+ * Currently the preparations consist in
+ * setting the
+ * PCM channel to a known state.
+ */
+
+
+static void via_chan_init (struct via_info *card, struct via_channel *chan)
+{
+
+ DPRINTK ("ENTER\n");
+
+ /* bzero channel structure, and init members to defaults */
+ via_chan_init_defaults (card, chan);
+
+ /* stop any existing channel output */
+ via_chan_clear (card, chan);
+ via_chan_status_clear (chan->iobase);
+ via_chan_pcm_fmt (chan, 1);
+
+ DPRINTK ("EXIT\n");
+}
/**
- * via_chan_init - Initialize PCM channel
+ * via_chan_buffer_init - Initialize PCM channel buffer
* @card: Private audio chip info
* @chan: Channel to be initialized
*
- * Performs all the preparations necessary to begin
+ * Performs some of the preparations necessary to begin
* using a PCM channel.
*
* Currently the preparations include allocating the
- * scatter-gather DMA table and buffers, setting the
- * PCM channel to a known state, and passing the
+ * scatter-gather DMA table and buffers,
+ * and passing the
* address of the DMA table to the hardware.
*
* Note that special care is taken when passing the
@@ -596,18 +634,21 @@
* always "take" the address.
*/
-static int via_chan_init (struct via_info *card, struct via_channel *chan)
+static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
{
+ int page, offset;
int i;
DPRINTK ("ENTER\n");
- /* bzero channel structure, and init members to defaults */
- via_chan_init_defaults (card, chan);
+ if (chan->sgtable != NULL) {
+ DPRINTK ("EXIT\n");
+ return 0;
+ }
/* alloc DMA-able memory for scatter-gather table */
chan->sgtable = pci_alloc_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+ (sizeof (struct via_sgd_table) * chan->frag_number),
&chan->sgt_handle);
if (!chan->sgtable) {
printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
@@ -616,45 +657,54 @@
}
memset ((void*)chan->sgtable, 0,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS));
+ (sizeof (struct via_sgd_table) * chan->frag_number));
/* alloc DMA-able memory for scatter-gather buffers */
- for (i = 0; i < VIA_DMA_BUFFERS; i++) {
- chan->sgbuf[i].cpuaddr =
- pci_alloc_consistent (card->pdev, VIA_DMA_BUF_SIZE,
- &chan->sgbuf[i].handle);
- if (!chan->sgbuf[i].cpuaddr)
- goto err_out_nomem;
+ chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
+ (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
+
+ for (i = 0; i < chan->page_number; i++) {
+ chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
+ &chan->pgtbl[i].handle);
- if (i < (VIA_DMA_BUFFERS - 1))
- chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);
- else
- chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);
- chan->sgtable[i].addr = cpu_to_le32 (chan->sgbuf[i].handle);
+ if (!chan->pgtbl[i].cpuaddr) {
+ chan->page_number = i;
+ goto err_out_nomem;
+ }
#ifndef VIA_NDEBUG
- memset (chan->sgbuf[i].cpuaddr, 0xBC, VIA_DMA_BUF_SIZE);
+ memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
#endif
#if 1
- DPRINTK ("dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)\n",
- i, (long)chan->sgbuf[i].handle,
- (long)chan->sgtable[i].addr,
- virt_to_phys(chan->sgbuf[i].cpuaddr),
- chan->sgbuf[i].cpuaddr);
+ DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
+ i, (long)chan->pgtbl[i].handle,
+ virt_to_phys(chan->pgtbl[i].cpuaddr),
+ chan->pgtbl[i].cpuaddr);
#endif
-
- assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);
}
- /* stop any existing channel output */
- via_chan_clear (chan);
- via_chan_status_clear (chan->iobase);
- via_chan_pcm_fmt (chan, 1);
+ for (i = 0; i < chan->frag_number; i++) {
+
+ page = i / (PAGE_SIZE / chan->frag_size);
+ offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
+
+ chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
+ chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
+
+#if 1
+ DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
+ i,
+ (long)chan->sgtable[i].addr);
+#endif
+ }
+
+ /* overwrite the last buffer information */
+ chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
/* set location of DMA-able scatter-gather info table */
- DPRINTK("outl (0x%X, 0x%04lX)\n",
+ DPRINTK ("outl (0x%X, 0x%04lX)\n",
cpu_to_le32 (chan->sgt_handle),
chan->iobase + VIA_PCM_TABLE_ADDR);
@@ -664,7 +714,7 @@
udelay (20);
via_ac97_wait_idle (card);
- DPRINTK("inl (0x%lX) = %x\n",
+ DPRINTK ("inl (0x%lX) = %x\n",
chan->iobase + VIA_PCM_TABLE_ADDR,
inl(chan->iobase + VIA_PCM_TABLE_ADDR));
@@ -673,7 +723,7 @@
err_out_nomem:
printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
- via_chan_free (card, chan);
+ via_chan_buffer_free (card, chan);
DPRINTK ("EXIT\n");
return -ENOMEM;
}
@@ -695,8 +745,6 @@
static void via_chan_free (struct via_info *card, struct via_channel *chan)
{
- int i;
-
DPRINTK ("ENTER\n");
synchronize_irq();
@@ -710,23 +758,33 @@
spin_unlock_irq (&card->lock);
+ DPRINTK ("EXIT\n");
+}
+
+static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
+{
+ int i;
+
+ DPRINTK ("ENTER\n");
+
/* zero location of DMA-able scatter-gather info table */
via_ac97_wait_idle(card);
outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
- for (i = 0; i < VIA_DMA_BUFFERS; i++)
- if (chan->sgbuf[i].cpuaddr) {
- assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);
- pci_free_consistent (card->pdev, VIA_DMA_BUF_SIZE,
- chan->sgbuf[i].cpuaddr,
- chan->sgbuf[i].handle);
- chan->sgbuf[i].cpuaddr = NULL;
- chan->sgbuf[i].handle = 0;
+ for (i = 0; i < chan->page_number; i++)
+ if (chan->pgtbl[i].cpuaddr) {
+ pci_free_consistent (card->pdev, PAGE_SIZE,
+ chan->pgtbl[i].cpuaddr,
+ chan->pgtbl[i].handle);
+ chan->pgtbl[i].cpuaddr = NULL;
+ chan->pgtbl[i].handle = 0;
}
+ chan->page_number = 0;
+
if (chan->sgtable) {
pci_free_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+ (sizeof (struct via_sgd_table) * chan->frag_number),
(void*)chan->sgtable, chan->sgt_handle);
chan->sgtable = NULL;
}
@@ -771,11 +829,11 @@
if (!chan->is_record)
chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
- outb (chan->pcm_fmt, chan->iobase + 2);
+ outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
chan->pcm_fmt,
- inb (chan->iobase + 2));
+ inb (chan->iobase + VIA_PCM_TYPE));
}
@@ -787,10 +845,11 @@
* all software pointers which track DMA operation.
*/
-static void via_chan_clear (struct via_channel *chan)
+static void via_chan_clear (struct via_info *card, struct via_channel *chan)
{
DPRINTK ("ENTER\n");
via_chan_stop (chan->iobase);
+ via_chan_buffer_free(card, chan);
chan->is_active = 0;
chan->is_mapped = 0;
chan->is_enabled = 1;
@@ -798,10 +857,6 @@
chan->sw_ptr = 0;
chan->n_irqs = 0;
atomic_set (&chan->hw_ptr, 0);
- if (chan->is_record)
- atomic_set (&chan->n_bufs, 0);
- else
- atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);
DPRINTK ("EXIT\n");
}
@@ -826,7 +881,7 @@
{
DPRINTK ("ENTER, requested rate = %d\n", val);
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
val = via_set_rate (&card->ac97, chan, val);
@@ -858,7 +913,7 @@
val == AFMT_S16_LE ? "AFMT_S16_LE" :
"unknown");
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
assert (val != AFMT_QUERY); /* this case is handled elsewhere */
@@ -907,7 +962,7 @@
{
DPRINTK ("ENTER, channels = %d\n", val);
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
switch (val) {
@@ -934,6 +989,78 @@
return val;
}
+static int via_chan_set_buffering (struct via_info *card,
+ struct via_channel *chan, int val)
+{
+ int shift;
+
+ DPRINTK ("ENTER\n");
+
+ /* in both cases the buffer cannot be changed */
+ if (chan->is_active || chan->is_mapped) {
+ DPRINTK ("EXIT\n");
+ return -EINVAL;
+ }
+
+ /* called outside SETFRAGMENT */
+ /* set defaults or do nothing */
+ if (val < 0) {
+
+ if (chan->frag_size && chan->frag_number)
+ goto out;
+
+ DPRINTK ("\n");
+
+ chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate *
+ ((chan->pcm_fmt & VIA_PCM_FMT_STEREO) ? 2 : 1) *
+ ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
+
+ shift = 0;
+ while (chan->frag_size) {
+ chan->frag_size >>= 1;
+ shift++;
+ }
+ chan->frag_size = 1 << shift;
+
+ chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
+
+ DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
+ } else {
+ chan->frag_size = 1 << (val & 0xFFFF);
+ chan->frag_number = (val >> 16) & 0xFFFF;
+
+ DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
+ }
+
+ /* quake3 wants frag_number to be a power of two */
+ shift = 0;
+ while (chan->frag_number) {
+ chan->frag_number >>= 1;
+ shift++;
+ }
+ chan->frag_number = 1 << shift;
+
+ if (chan->frag_size > VIA_MAX_FRAG_SIZE)
+ chan->frag_size = VIA_MAX_FRAG_SIZE;
+ else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
+ chan->frag_size = VIA_MIN_FRAG_SIZE;
+
+ if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
+ chan->frag_number = VIA_MIN_FRAG_NUMBER;
+
+ if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
+ chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
+
+out:
+ if (chan->is_record)
+ atomic_set (&chan->n_frags, 0);
+ else
+ atomic_set (&chan->n_frags, chan->frag_number);
+
+ DPRINTK ("EXIT\n");
+
+ return 0;
+}
#ifdef VIA_CHAN_DUMP_BUFS
/**
@@ -948,7 +1075,7 @@
{
int i;
- for (i = 0; i < VIA_DMA_BUFFERS; i++) {
+ for (i = 0; i < chan->frag_number; i++) {
DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
i, chan->sgtable[i].addr,
chan->sgtable[i].count & 0x00FFFFFF,
@@ -975,15 +1102,15 @@
assert (chan->slop_len > 0);
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
chan->slop_len = 0;
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
DPRINTK ("EXIT\n");
}
@@ -1003,7 +1130,7 @@
if (!chan->is_active && chan->is_enabled) {
chan->is_active = 1;
sg_begin (chan);
- DPRINTK("starting channel %s\n", chan->name);
+ DPRINTK ("starting channel %s\n", chan->name);
}
}
@@ -1213,7 +1340,7 @@
{
DPRINTK ("ENTER\n");
- DPRINTK("EXIT, returning -ESPIPE\n");
+ DPRINTK ("EXIT, returning -ESPIPE\n");
return -ESPIPE;
}
@@ -1245,7 +1372,7 @@
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
spin_lock_irq (&card->lock);
@@ -1334,7 +1461,7 @@
card->ac97.dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
if (card->ac97.dev_mixer < 0) {
printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
- DPRINTK("EXIT, returning -EIO\n");
+ DPRINTK ("EXIT, returning -EIO\n");
return -EIO;
}
@@ -1359,21 +1486,21 @@
err_out:
unregister_sound_mixer (card->ac97.dev_mixer);
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
static void via_ac97_cleanup (struct via_info *card)
{
- DPRINTK("ENTER\n");
+ DPRINTK ("ENTER\n");
assert (card != NULL);
assert (card->ac97.dev_mixer >= 0);
unregister_sound_mixer (card->ac97.dev_mixer);
- DPRINTK("EXIT\n");
+ DPRINTK ("EXIT\n");
}
@@ -1414,24 +1541,24 @@
/* sanity check: make sure our h/w ptr doesn't have a weird value */
assert (n >= 0);
- assert (n < VIA_DMA_BUFFERS);
+ assert (n < chan->frag_number);
/* reset SGD data structure in memory to reflect a full buffer,
* and advance the h/w ptr, wrapping around to zero if needed
*/
- if (n == (VIA_DMA_BUFFERS - 1)) {
- chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_EOL);
+ if (n == (chan->frag_number - 1)) {
+ chan->sgtable[n].count = (chan->frag_size | VIA_EOL);
atomic_set (&chan->hw_ptr, 0);
} else {
- chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_FLAG);
+ chan->sgtable[n].count = (chan->frag_size | VIA_FLAG);
atomic_inc (&chan->hw_ptr);
}
/* accounting crap for SNDCTL_DSP_GETxPTR */
chan->n_irqs++;
- chan->bytes += VIA_DMA_BUF_SIZE;
+ chan->bytes += chan->frag_size;
if (chan->bytes < 0) /* handle overflow of 31-bit value */
- chan->bytes = VIA_DMA_BUF_SIZE;
+ chan->bytes = chan->frag_size;
/* wake up anyone listening to see when interrupts occur */
if (waitqueue_active (&chan->wait))
@@ -1445,25 +1572,25 @@
if (chan->is_mapped)
return;
- /* If we are recording, then n_bufs represents the number
- * of buffers waiting to be handled by userspace.
- * If we are playback, then n_bufs represents the number
- * of buffers remaining to be filled by userspace.
- * We increment here. If we reach max buffers (VIA_DMA_BUFFERS),
+ /* If we are recording, then n_frags represents the number
+ * of fragments waiting to be handled by userspace.
+ * If we are playback, then n_frags represents the number
+ * of fragments remaining to be filled by userspace.
+ * We increment here. If we reach max number of fragments,
* this indicates an underrun/overrun. For this case under OSS,
* we stop the record/playback process.
*/
- if (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS)
- atomic_inc (&chan->n_bufs);
- assert (atomic_read (&chan->n_bufs) <= VIA_DMA_BUFFERS);
+ if (atomic_read (&chan->n_frags) < chan->frag_number)
+ atomic_inc (&chan->n_frags);
+ assert (atomic_read (&chan->n_frags) <= chan->frag_number);
- if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS) {
+ if (atomic_read (&chan->n_frags) == chan->frag_number) {
chan->is_active = 0;
via_chan_stop (chan->iobase);
}
- DPRINTK ("%s intr, channel n_bufs == %d\n", chan->name,
- atomic_read (&chan->n_bufs));
+ DPRINTK ("%s intr, channel n_frags == %d\n", chan->name,
+ atomic_read (&chan->n_frags));
}
@@ -1618,9 +1745,7 @@
poll: via_dsp_poll,
llseek: via_llseek,
ioctl: via_dsp_ioctl,
-#ifdef VIA_SUPPORT_MMAP
mmap: via_dsp_mmap,
-#endif
};
@@ -1668,7 +1793,6 @@
}
-#ifdef VIA_SUPPORT_MMAP
static struct page * via_mm_nopage (struct vm_area_struct * vma,
unsigned long address, int write_access)
{
@@ -1685,8 +1809,6 @@
address,
write_access);
- assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);
-
if (address > vma->vm_end) {
DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
return NOPAGE_SIGBUS; /* Disallow mremap */
@@ -1702,7 +1824,7 @@
#ifndef VIA_NDEBUG
{
- unsigned long max_bufs = VIA_DMA_BUFFERS;
+ unsigned long max_bufs = chan->frag_number;
if (rd && wr) max_bufs *= 2;
/* via_dsp_mmap() should ensure this */
assert (pgoff < max_bufs);
@@ -1711,17 +1833,17 @@
/* if full-duplex (read+write) and we have two sets of bufs,
* then the playback buffers come first, sez soundcard.c */
- if (pgoff >= VIA_DMA_BUFFERS) {
- pgoff -= VIA_DMA_BUFFERS;
+ if (pgoff >= chan->page_number) {
+ pgoff -= chan->page_number;
chan = &card->ch_in;
} else if (!wr)
chan = &card->ch_in;
- assert ((((unsigned long)chan->sgbuf[pgoff].cpuaddr) % PAGE_SIZE) == 0);
+ assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
- dmapage = virt_to_page (chan->sgbuf[pgoff].cpuaddr);
+ dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
- dmapage, (unsigned long) chan->sgbuf[pgoff].cpuaddr);
+ dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
get_page (dmapage);
return dmapage;
}
@@ -1761,16 +1883,18 @@
vma->vm_end - vma->vm_start,
vma->vm_pgoff);
- assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);
-
max_size = 0;
- if (file->f_mode & FMODE_READ) {
+ if (vma->vm_flags & VM_READ) {
rd = 1;
- max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ via_chan_buffer_init (card, &card->ch_in);
+ max_size += card->ch_in.page_number << PAGE_SHIFT;
}
- if (file->f_mode & FMODE_WRITE) {
+ if (vma->vm_flags & VM_WRITE) {
wr = 1;
- max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ via_chan_buffer_init (card, &card->ch_out);
+ max_size += card->ch_out.page_number << PAGE_SHIFT;
}
start = vma->vm_start;
@@ -1802,10 +1926,9 @@
rc = 0;
out:
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
-#endif /* VIA_SUPPORT_MMAP */
static ssize_t via_dsp_do_read (struct via_info *card,
@@ -1831,13 +1954,13 @@
*/
n = chan->sw_ptr;
- /* n_bufs represents the number of buffers waiting
+ /* n_frags represents the number of fragments waiting
* to be copied to userland. sleep until at least
* one buffer has been read from the audio hardware.
*/
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
- assert (tmp <= VIA_DMA_BUFFERS);
+ assert (tmp <= chan->frag_number);
while (tmp == 0) {
if (nonblock || !chan->is_active)
return -EAGAIN;
@@ -1848,18 +1971,18 @@
if (signal_pending (current))
return -ERESTARTSYS;
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
}
/* Now that we have a buffer we can read from, send
* as much as sample data possible to userspace.
*/
- while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {
- size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;
+ while ((count > 0) && (chan->slop_len < chan->frag_size)) {
+ size_t slop_left = chan->frag_size - chan->slop_len;
size = (count < slop_left) ? count : slop_left;
if (copy_to_user (userbuf,
- chan->sgbuf[n].cpuaddr + chan->slop_len,
+ chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len,
size))
return -EFAULT;
@@ -1871,7 +1994,7 @@
/* If we didn't copy the buffer completely to userspace,
* stop now.
*/
- if (chan->slop_len < VIA_DMA_BUF_SIZE)
+ if (chan->slop_len < chan->frag_size)
goto out;
/*
@@ -1882,20 +2005,20 @@
/* advance channel software pointer to point to
* the next buffer from which we will copy
*/
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
/* mark one less buffer waiting to be processed */
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
/* we are at a block boundary, there is no fragment data */
chan->slop_len = 0;
- DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_bufs));
+ DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
+ n, chan->sw_ptr, atomic_read (&chan->n_frags));
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
inb (card->baseaddr + 0x00),
@@ -1941,12 +2064,18 @@
goto out_up;
}
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ rc = via_chan_buffer_init (card, &card->ch_in);
+
+ if (rc)
+ goto out_up;
+
rc = via_dsp_do_read (card, buffer, count, nonblock);
out_up:
up (&card->syscall_sem);
out:
- DPRINTK("EXIT, returning %ld\n",(long) rc);
+ DPRINTK ("EXIT, returning %ld\n",(long) rc);
return rc;
}
@@ -1966,40 +2095,40 @@
if (current->need_resched)
schedule ();
- /* grab current channel software pointer. In the case of
- * playback, this is pointing to the next buffer that
+ /* grab current channel fragment pointer. In the case of
+ * playback, this is pointing to the next fragment that
* should receive data from userland.
*/
n = chan->sw_ptr;
- /* n_bufs represents the number of buffers remaining
+ /* n_frags represents the number of fragments remaining
* to be filled by userspace. Sleep until
- * at least one buffer is available for our use.
+ * at least one fragment is available for our use.
*/
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
- assert (tmp <= VIA_DMA_BUFFERS);
+ assert (tmp <= chan->frag_number);
while (tmp == 0) {
if (nonblock || !chan->is_enabled)
return -EAGAIN;
- DPRINTK ("Sleeping on block %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
+ DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
interruptible_sleep_on (&chan->wait);
if (signal_pending (current))
return -ERESTARTSYS;
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
}
- /* Now that we have a buffer we can write to, fill it up
+ /* Now that we have at least one fragment we can write to, fill the buffer
* as much as possible with data from userspace.
*/
- while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {
- size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;
+ while ((count > 0) && (chan->slop_len < chan->frag_size)) {
+ size_t slop_left = chan->frag_size - chan->slop_len;
size = (count < slop_left) ? count : slop_left;
- if (copy_from_user (chan->sgbuf[n].cpuaddr + chan->slop_len,
+ if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
userbuf, size))
return -EFAULT;
@@ -2009,36 +2138,36 @@
}
/* If we didn't fill up the buffer with data, stop now.
- * Put a 'stop' marker in the DMA table too, to tell the
- * audio hardware to stop if it gets here.
- */
- if (chan->slop_len < VIA_DMA_BUF_SIZE) {
+ * Put a 'stop' marker in the DMA table too, to tell the
+ * audio hardware to stop if it gets here.
+ */
+ if (chan->slop_len < chan->frag_size) {
sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
goto out;
}
/*
- * If we get to this point, we have filled a buffer with
- * audio data, flush the buffer to audio hardware.
- */
+ * If we get to this point, we have filled a buffer with
+ * audio data, flush the buffer to audio hardware.
+ */
/* Record the true size for the audio hardware to notice */
- if (n == (VIA_DMA_BUFFERS - 1))
- sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);
- else
- sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);
+ if (n == (chan->frag_number - 1))
+ sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
+ else
+ sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
/* advance channel software pointer to point to
* the next buffer we will fill with data
*/
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
/* mark one less buffer as being available for userspace consumption */
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
/* we are at a block boundary, there is no fragment data */
chan->slop_len = 0;
@@ -2046,8 +2175,8 @@
/* if SGD has not yet been started, start it */
via_chan_maybe_start (chan);
- DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_bufs));
+ DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
+ n, chan->sw_ptr, atomic_read (&chan->n_frags));
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
inb (card->baseaddr + 0x00),
@@ -2093,12 +2222,18 @@
goto out_up;
}
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ rc = via_chan_buffer_init (card, &card->ch_out);
+
+ if (rc)
+ goto out_up;
+
rc = via_dsp_do_write (card, buffer, count, nonblock);
out_up:
up (&card->syscall_sem);
out:
- DPRINTK("EXIT, returning %ld\n",(long) rc);
+ DPRINTK ("EXIT, returning %ld\n",(long) rc);
return rc;
}
@@ -2117,23 +2252,27 @@
rd = (file->f_mode & FMODE_READ);
wr = (file->f_mode & FMODE_WRITE);
- if (wr && (atomic_read (&card->ch_out.n_bufs) == 0)) {
+ if (wr && (atomic_read (&card->ch_out.n_frags) == 0)) {
assert (card->ch_out.is_active);
poll_wait(file, &card->ch_out.wait, wait);
}
if (rd) {
/* XXX is it ok, spec-wise, to start DMA here? */
+ if (!card->ch_in.is_active) {
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ via_chan_buffer_init(card, &card->ch_in);
+ }
via_chan_maybe_start (&card->ch_in);
- if (atomic_read (&card->ch_in.n_bufs) == 0)
+ if (atomic_read (&card->ch_in.n_frags) == 0)
poll_wait(file, &card->ch_in.wait, wait);
}
- if (wr && (atomic_read (&card->ch_out.n_bufs) > 0))
+ if (wr && ((atomic_read (&card->ch_out.n_frags) > 0) || !card->ch_out.is_active))
mask |= POLLOUT | POLLWRNORM;
- if (rd && (atomic_read (&card->ch_in.n_bufs) > 0))
+ if (rd && (atomic_read (&card->ch_in.n_frags) > 0))
mask |= POLLIN | POLLRDNORM;
- DPRINTK("EXIT, returning %u\n", mask);
+ DPRINTK ("EXIT, returning %u\n", mask);
return mask;
}
@@ -2158,12 +2297,12 @@
if (chan->slop_len > 0)
via_chan_flush_frag (chan);
- if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS)
+ if (atomic_read (&chan->n_frags) == chan->frag_number)
goto out;
via_chan_maybe_start (chan);
- while (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) {
+ while (atomic_read (&chan->n_frags) < chan->frag_number) {
if (nonblock) {
DPRINTK ("EXIT, returning -EAGAIN\n");
return -EAGAIN;
@@ -2178,7 +2317,7 @@
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
@@ -2195,7 +2334,7 @@
printk (KERN_ERR "sleeping but not active\n");
#endif
- DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_bufs));
+ DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
interruptible_sleep_on (&chan->wait);
if (signal_pending (current)) {
@@ -2213,7 +2352,7 @@
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
@@ -2225,7 +2364,7 @@
inl (card->baseaddr + 0x80),
inl (card->baseaddr + 0x84));
- DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_bufs));
+ DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
}
#endif
@@ -2252,21 +2391,23 @@
{
audio_buf_info info;
- info.fragstotal = VIA_DMA_BUFFERS;
- info.fragsize = VIA_DMA_BUF_SIZE;
+ via_chan_set_buffering(card, chan, -1);
+
+ info.fragstotal = chan->frag_number;
+ info.fragsize = chan->frag_size;
/* number of full fragments we can read/write without blocking */
- info.fragments = atomic_read (&chan->n_bufs);
+ info.fragments = atomic_read (&chan->n_frags);
- if ((chan->slop_len > 0) && (info.fragments > 0))
+ if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
info.fragments--;
/* number of bytes that can be read or written immediately
* without blocking.
*/
- info.bytes = (info.fragments * VIA_DMA_BUF_SIZE);
- if (chan->slop_len > 0)
- info.bytes += VIA_DMA_BUF_SIZE - chan->slop_len;
+ info.bytes = (info.fragments * chan->frag_size);
+ if (chan->slop_len % chan->frag_size > 0)
+ info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
info.fragstotal,
@@ -2305,8 +2446,8 @@
if (chan->is_active) {
unsigned long extra;
- info.ptr = atomic_read (&chan->hw_ptr) * VIA_DMA_BUF_SIZE;
- extra = VIA_DMA_BUF_SIZE - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);
+ info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
+ extra = chan->frag_size - inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
info.ptr += extra;
info.bytes += extra;
} else {
@@ -2386,13 +2527,13 @@
/* OSS API version. XXX unverified */
case OSS_GETVERSION:
- DPRINTK("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
+ DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
rc = put_user (SOUND_VERSION, (int *)arg);
break;
/* list of supported PCM data formats */
case SNDCTL_DSP_GETFMTS:
- DPRINTK("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
+ DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
rc = put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg);
break;
@@ -2402,20 +2543,19 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETFMT, val==%d\n", val);
+ DPRINTK ("DSP_SETFMT, val==%d\n", val);
if (val != AFMT_QUERY) {
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_fmt (card, &card->ch_in, val);
- if (rc == 0 && wr)
+
+ if (rc >= 0 && wr)
rc = via_chan_set_fmt (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
@@ -2424,7 +2564,7 @@
else
val = AFMT_U8;
}
- DPRINTK("SETFMT EXIT, returning %d\n", val);
+ DPRINTK ("SETFMT EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
@@ -2434,18 +2574,19 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_CHANNELS, val==%d\n", val);
+ DPRINTK ("DSP_CHANNELS, val==%d\n", val);
if (val != 0) {
rc = 0;
- if (rc == 0 && rd)
+
+ if (rd)
rc = via_chan_set_stereo (card, &card->ch_in, val);
- if (rc == 0 && wr)
+
+ if (rc >= 0 && wr)
rc = via_chan_set_stereo (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) ||
@@ -2454,7 +2595,7 @@
else
val = 1;
}
- DPRINTK("CHANNELS EXIT, returning %d\n", val);
+ DPRINTK ("CHANNELS EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
@@ -2464,21 +2605,21 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_STEREO, val==%d\n", val);
+ DPRINTK ("DSP_STEREO, val==%d\n", val);
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
- if (rc == 0 && wr)
+ if (rc >= 0 && wr)
rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
- DPRINTK("STEREO EXIT, returning %d\n", val);
- rc = 0;
+
+ val = rc - 1;
+
+ DPRINTK ("STEREO EXIT, returning %d\n", val);
+ rc = put_user(val, (int *) arg);
break;
/* query or set sampling rate */
@@ -2487,7 +2628,7 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SPEED, val==%d\n", val);
+ DPRINTK ("DSP_SPEED, val==%d\n", val);
if (val < 0) {
rc = -EINVAL;
break;
@@ -2495,16 +2636,14 @@
if (val > 0) {
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_speed (card, &card->ch_in, val);
- if (rc == 0 && wr)
+ if (rc >= 0 && wr)
rc = via_chan_set_speed (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if (rd)
@@ -2514,7 +2653,7 @@
else
val = 0;
}
- DPRINTK("SPEED EXIT, returning %d\n", val);
+ DPRINTK ("SPEED EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
@@ -2522,7 +2661,7 @@
case SNDCTL_DSP_SYNC:
DPRINTK ("DSP_SYNC\n");
if (wr) {
- DPRINTK("SYNC EXIT (after calling via_dsp_drain_playback)\n");
+ DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
}
break;
@@ -2531,12 +2670,19 @@
case SNDCTL_DSP_RESET:
DPRINTK ("DSP_RESET\n");
if (rd) {
- via_chan_clear (&card->ch_in);
+ via_chan_clear (card, &card->ch_in);
via_chan_pcm_fmt (&card->ch_in, 1);
+ card->ch_in.frag_number = 0;
+ card->ch_in.frag_size = 0;
+ atomic_set(&card->ch_in.n_frags, 0);
}
+
if (wr) {
- via_chan_clear (&card->ch_out);
+ via_chan_clear (card, &card->ch_out);
via_chan_pcm_fmt (&card->ch_out, 1);
+ card->ch_out.frag_number = 0;
+ card->ch_out.frag_size = 0;
+ atomic_set(&card->ch_out.n_frags, 0);
}
rc = 0;
@@ -2544,40 +2690,47 @@
/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
case SNDCTL_DSP_GETCAPS:
- DPRINTK("DSP_GETCAPS\n");
+ DPRINTK ("DSP_GETCAPS\n");
rc = put_user(VIA_DSP_CAP, (int *)arg);
break;
- /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
+ /* obtain buffer fragment size */
case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK("DSP_GETBLKSIZE\n");
- rc = put_user(VIA_DMA_BUF_SIZE, (int *)arg);
+ DPRINTK ("DSP_GETBLKSIZE\n");
+
+ if (rd) {
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ rc = put_user(card->ch_in.frag_size, (int *)arg);
+ } else if (wr) {
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ rc = put_user(card->ch_out.frag_size, (int *)arg);
+ }
break;
/* obtain information about input buffering */
case SNDCTL_DSP_GETISPACE:
- DPRINTK("DSP_GETISPACE\n");
+ DPRINTK ("DSP_GETISPACE\n");
if (rd)
rc = via_dsp_ioctl_space (card, &card->ch_in, (void*) arg);
break;
/* obtain information about output buffering */
case SNDCTL_DSP_GETOSPACE:
- DPRINTK("DSP_GETOSPACE\n");
+ DPRINTK ("DSP_GETOSPACE\n");
if (wr)
rc = via_dsp_ioctl_space (card, &card->ch_out, (void*) arg);
break;
/* obtain information about input hardware pointer */
case SNDCTL_DSP_GETIPTR:
- DPRINTK("DSP_GETIPTR\n");
+ DPRINTK ("DSP_GETIPTR\n");
if (rd)
rc = via_dsp_ioctl_ptr (card, &card->ch_in, (void*) arg);
break;
/* obtain information about output hardware pointer */
case SNDCTL_DSP_GETOPTR:
- DPRINTK("DSP_GETOPTR\n");
+ DPRINTK ("DSP_GETOPTR\n");
if (wr)
rc = via_dsp_ioctl_ptr (card, &card->ch_out, (void*) arg);
break;
@@ -2585,25 +2738,29 @@
/* return number of bytes remaining to be played by DMA engine */
case SNDCTL_DSP_GETODELAY:
{
- DPRINTK("DSP_GETODELAY\n");
+ DPRINTK ("DSP_GETODELAY\n");
chan = &card->ch_out;
if (!wr)
break;
- val = VIA_DMA_BUFFERS - atomic_read (&chan->n_bufs);
+ if (chan->is_active) {
- if (val > 0) {
- val *= VIA_DMA_BUF_SIZE;
- val -= VIA_DMA_BUF_SIZE -
- inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);
- }
- val += chan->slop_len;
+ val = chan->frag_number - atomic_read (&chan->n_frags);
- assert (val <= (VIA_DMA_BUF_SIZE * VIA_DMA_BUFFERS));
+ if (val > 0) {
+ val *= chan->frag_size;
+ val -= chan->frag_size -
+ inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
+ }
+ val += chan->slop_len % chan->frag_size;
+ } else
+ val = 0;
- DPRINTK("GETODELAY EXIT, val = %d bytes\n", val);
+ assert (val <= (chan->frag_size * chan->frag_number));
+
+ DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
rc = put_user (val, (int *)arg);
break;
}
@@ -2617,7 +2774,7 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
+ DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
rd, wr, card->ch_in.is_active, card->ch_out.is_active,
card->ch_in.is_enabled, card->ch_out.is_enabled);
@@ -2625,6 +2782,7 @@
if (rd)
rc = via_dsp_ioctl_trigger (&card->ch_in, val);
+
if (!rc && wr)
rc = via_dsp_ioctl_trigger (&card->ch_out, val);
@@ -2634,7 +2792,7 @@
* with O_RDWR, this is mainly a no-op that always returns success.
*/
case SNDCTL_DSP_SETDUPLEX:
- DPRINTK("DSP_SETDUPLEX\n");
+ DPRINTK ("DSP_SETDUPLEX\n");
if (!rd || !wr)
break;
rc = 0;
@@ -2646,7 +2804,13 @@
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETFRAGMENT, val==%d\n", val);
+ DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
+
+ if (rd)
+ rc = via_chan_set_buffering(card, &card->ch_in, val);
+
+ if (wr)
+ rc = via_chan_set_buffering(card, &card->ch_out, val);
DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
val & 0xFFFF,
@@ -2654,13 +2818,12 @@
(val >> 16) & 0xFFFF,
(val >> 16) & 0xFFFF);
- /* just to shut up some programs */
rc = 0;
break;
/* inform device of an upcoming pause in input (or output). */
case SNDCTL_DSP_POST:
- DPRINTK("DSP_POST\n");
+ DPRINTK ("DSP_POST\n");
if (wr) {
if (card->ch_out.slop_len > 0)
via_chan_flush_frag (&card->ch_out);
@@ -2678,15 +2841,14 @@
}
up (&card->syscall_sem);
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
static int via_dsp_open (struct inode *inode, struct file *file)
{
- int rc, minor = MINOR(inode->i_rdev);
- int got_read_chan = 0;
+ int minor = MINOR(inode->i_rdev);
struct via_info *card;
struct pci_dev *pdev;
struct via_channel *chan;
@@ -2733,17 +2895,13 @@
}
file->private_data = card;
- DPRINTK("file->f_mode == 0x%x\n", file->f_mode);
+ DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
/* handle input from analog source */
if (file->f_mode & FMODE_READ) {
chan = &card->ch_in;
- rc = via_chan_init (card, chan);
- if (rc)
- goto err_out;
-
- got_read_chan = 1;
+ via_chan_init (card, chan);
/* why is this forced to 16-bit stereo in all drivers? */
chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
@@ -2756,30 +2914,28 @@
if (file->f_mode & FMODE_WRITE) {
chan = &card->ch_out;
- rc = via_chan_init (card, chan);
- if (rc)
- goto err_out_read_chan;
+ via_chan_init (card, chan);
- if ((minor & 0xf) == SND_DEV_DSP16) {
- chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
- via_set_rate (&card->ac97, chan, 44100);
+ if (file->f_mode & FMODE_READ) {
+ /* if in duplex mode make the recording and playback channels
+ have the same settings */
+ chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 44100);
} else {
- via_set_rate (&card->ac97, chan, 8000);
+ if ((minor & 0xf) == SND_DEV_DSP16) {
+ chan->pcm_fmt = VIA_PCM_FMT_16BIT;
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 44100);
+ } else {
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 8000);
+ }
}
-
- via_chan_pcm_fmt (chan, 0);
}
DPRINTK ("EXIT, returning 0\n");
return 0;
-
-err_out_read_chan:
- if (got_read_chan)
- via_chan_free (card, &card->ch_in);
-err_out:
- up (&card->open_sem);
- DPRINTK("ERROR EXIT, returning %d\n", rc);
- return rc;
}
@@ -2807,15 +2963,18 @@
printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
via_chan_free (card, &card->ch_out);
+ via_chan_buffer_free(card, &card->ch_out);
}
- if (file->f_mode & FMODE_READ)
+ if (file->f_mode & FMODE_READ) {
via_chan_free (card, &card->ch_in);
+ via_chan_buffer_free (card, &card->ch_in);
+ }
up (&card->syscall_sem);
up (&card->open_sem);
- DPRINTK("EXIT, returning 0\n");
+ DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -2934,9 +3093,9 @@
tmp &= 0xF0;
tmp |= pdev->irq;
pci_write_config_byte (pdev, 0x3C, tmp);
- DPRINTK("new 0x3c==0x%02x\n", tmp);
+ DPRINTK ("new 0x3c==0x%02x\n", tmp);
} else {
- DPRINTK("IRQ reg 0x3c==0x%02x, irq==%d\n",
+ DPRINTK ("IRQ reg 0x3c==0x%02x, irq==%d\n",
tmp, tmp & 0x0F);
}
@@ -3036,12 +3195,12 @@
static void __exit cleanup_via82cxxx_audio(void)
{
- DPRINTK("ENTER\n");
+ DPRINTK ("ENTER\n");
pci_unregister_driver (&via_driver);
via_cleanup_proc ();
- DPRINTK("EXIT\n");
+ DPRINTK ("EXIT\n");
}
@@ -3133,7 +3292,7 @@
);
- DPRINTK("EXIT, returning %d\n", len);
+ DPRINTK ("EXIT, returning %d\n", len);
return len;
#undef YN
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)