lkml.org 
[lkml]   [2001]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectPATCH: via audio 1.1.15-pre1
Attached is a patch against kernel 2.4.6-pre1 which includes fixes for
via audio. It -should- patch against kernel 2.4.3 or later, though.

I'm interested in feedback from people having via audio problems, if
this patch fixes them. I am of course also interested in general
testing, to ensure I did not break anything in the process of fixing
things. :)

--
Jeff Garzik | Andre the Giant has a posse.
Building 1024 |
MandrakeSoft |Index: linux_2_4/drivers/sound/via82cxxx_audio.c
diff -u linux_2_4/drivers/sound/via82cxxx_audio.c:1.1.1.19 linux_2_4/drivers/sound/via82cxxx_audio.c:1.1.1.19.2.2
--- linux_2_4/drivers/sound/via82cxxx_audio.c:1.1.1.19 Mon Jun 4 19:43:41 2001
+++ linux_2_4/drivers/sound/via82cxxx_audio.c Thu Jun 7 13:04:28 2001
@@ -15,7 +15,7 @@
*/


-#define VIA_VERSION "1.1.14b"
+#define VIA_VERSION "1.1.15-pre1"


#include <linux/config.h>
@@ -92,6 +92,7 @@
#endif

/* 82C686 function 5 (audio codec) PCI configuration registers */
+#define VIA_ACLINK_STATUS 0x40
#define VIA_ACLINK_CTRL 0x41
#define VIA_FUNC_ENABLE 0x42
#define VIA_PNP_CONTROL 0x43
@@ -187,6 +188,7 @@
/* controller base 0 register bitmasks */
#define VIA_INT_DISABLE_MASK (~(0x01|0x02))
#define VIA_SGD_STOPPED (1 << 2)
+#define VIA_SGD_PAUSED (1 << 6)
#define VIA_SGD_ACTIVE (1 << 7)
#define VIA_SGD_TERMINATE (1 << 6)
#define VIA_SGD_FLAG (1 << 0)
@@ -381,7 +383,7 @@
*
*/

-static inline void via_chan_stop (int iobase)
+static inline void via_chan_stop (long iobase)
{
if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
@@ -402,7 +404,7 @@
*
*/

-static inline void via_chan_status_clear (int iobase)
+static inline void via_chan_status_clear (long iobase)
{
u8 tmp = inb (iobase + VIA_PCM_STATUS);

@@ -425,6 +427,19 @@
}


+static int sg_active (long iobase)
+{
+ u8 tmp = inb (iobase + VIA_PCM_STATUS);
+ if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) {
+ printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n");
+ return 0;
+ }
+ if (tmp & VIA_SGD_ACTIVE)
+ return 1;
+ return 0;
+}
+
+
/****************************************************************
*
* Miscellaneous debris
@@ -467,6 +482,8 @@

static void via_stop_everything (struct via_info *card)
{
+ u8 tmp, new_tmp;
+
DPRINTK ("ENTER\n");

assert (card != NULL);
@@ -486,11 +503,32 @@
via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);

/*
- * clear any enabled interrupt bits, reset to 8-bit mono PCM mode
+ * clear any enabled interrupt bits
*/
- outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
- outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
- outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
+ tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
+ new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
+ if (tmp != new_tmp)
+ outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
+
+ tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
+ new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
+ if (tmp != new_tmp)
+ outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
+
+ tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
+ new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
+ if (tmp != new_tmp)
+ outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
+
+ udelay(10);
+
+ /*
+ * clear any existing flags
+ */
+ via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
+ via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
+ via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+
DPRINTK ("EXIT\n");
}

@@ -515,6 +553,8 @@

DPRINTK ("ENTER, rate = %d\n", rate);

+ if (chan->rate == rate)
+ goto out;
if (card->locked_rate) {
chan->rate = 48000;
goto out;
@@ -762,17 +802,17 @@
{
DPRINTK ("ENTER\n");

- synchronize_irq();
-
spin_lock_irq (&card->lock);

/* stop any existing channel output */
+ via_chan_status_clear (chan->iobase);
via_chan_stop (chan->iobase);
via_chan_status_clear (chan->iobase);
- via_chan_pcm_fmt (chan, 1);

spin_unlock_irq (&card->lock);

+ synchronize_irq();
+
DPRINTK ("EXIT\n");
}

@@ -840,7 +880,7 @@
/* if we are recording, enable recording fifo bit */
if (chan->is_record)
chan->pcm_fmt |= VIA_PCM_REC_FIFO;
- /* set interrupt select bits where applicable (PCM & FM out channels) */
+ /* set interrupt select bits where applicable (PCM in & out channels) */
if (!chan->is_record)
chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;

@@ -1142,6 +1182,8 @@

static inline void via_chan_maybe_start (struct via_channel *chan)
{
+ assert (chan->is_active == sg_active(chan->iobase));
+
if (!chan->is_active && chan->is_enabled) {
chan->is_active = 1;
sg_begin (chan);
@@ -1405,20 +1447,43 @@
#endif

/*
- * reset AC97 controller: enable, disable, enable
- * pause after each command for good luck
+ * Reset AC97 controller: enable, disable, enable,
+ * pausing after each command for good luck. Only
+ * do this if the codec is not ready, because it causes
+ * loud pops and such due to such a hard codec reset.
*/
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL, VIA_CR41_AC97_ENABLE |
- VIA_CR41_AC97_RESET | VIA_CR41_AC97_WAKEUP);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE | VIA_CR41_PCM_ENABLE |
- VIA_CR41_VRA | VIA_CR41_AC97_RESET);
- udelay (100);
+ pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);
+ if ((tmp8 & VIA_CR40_AC97_READY) == 0) {
+ pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
+ VIA_CR41_AC97_ENABLE |
+ VIA_CR41_AC97_RESET |
+ VIA_CR41_AC97_WAKEUP);
+ udelay (100);
+
+ pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
+ udelay (100);
+
+ pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
+ VIA_CR41_AC97_ENABLE |
+ VIA_CR41_PCM_ENABLE |
+ VIA_CR41_VRA | VIA_CR41_AC97_RESET);
+ udelay (100);
+ }
+
+ /* Make sure VRA is enabled, in case we didn't do a
+ * complete codec reset, above
+ */
+ pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
+ if (((tmp8 & VIA_CR41_VRA) == 0) ||
+ ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||
+ ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||
+ ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {
+ pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
+ VIA_CR41_AC97_ENABLE |
+ VIA_CR41_PCM_ENABLE |
+ VIA_CR41_VRA | VIA_CR41_AC97_RESET);
+ udelay (100);
+ }

#if 0 /* this breaks on K7M */
/* disable legacy stuff */
@@ -1435,20 +1500,10 @@

/* WARNING: this line is magic. Remove this
* and things break. */
- /* enable variable rate, variable rate MIC ADC */
- /*
- * If we cannot enable VRA, we have a locked-rate codec.
- * We try again to enable VRA before assuming so, however.
- */
+ /* enable variable rate */
tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
+ if ((tmp16 & 1) == 0)
via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
- tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
- card->locked_rate = 1;
- printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
- }
- }

DPRINTK ("EXIT, returning 0\n");
return 0;
@@ -1496,10 +1551,24 @@
goto err_out;
}

- /* enable variable rate, variable rate MIC ADC */
+ /* enable variable rate */
tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);

+ /*
+ * If we cannot enable VRA, we have a locked-rate codec.
+ * We try again to enable VRA before assuming so, however.
+ */
+ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
+ if ((tmp16 & 1) == 0) {
+ via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
+ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
+ if ((tmp16 & 1) == 0) {
+ card->locked_rate = 1;
+ printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
+ }
+ }
+
DPRINTK ("EXIT, returning 0\n");
return 0;

@@ -1649,47 +1718,6 @@


/**
- * via_interrupt_disable - Disable all interrupt-generating sources
- * @card: Private info for specified board
- *
- * Disables all interrupt-generation flags in the Via
- * audio hardware registers.
- */
-
-static void via_interrupt_disable (struct via_info *card)
-{
- u8 tmp8;
- unsigned long flags;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- spin_lock_irqsave (&card->lock, flags);
-
- pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
- if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
- tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
- pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
- }
-
- outb (inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE) &
- VIA_INT_DISABLE_MASK,
- card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
- outb (inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE) &
- VIA_INT_DISABLE_MASK,
- card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
- outb (inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE) &
- VIA_INT_DISABLE_MASK,
- card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-
- spin_unlock_irqrestore (&card->lock, flags);
-
- DPRINTK ("EXIT\n");
-}
-
-
-/**
* via_interrupt_init - Initialize interrupt handling
* @card: Private info for specified board
*
@@ -1700,6 +1728,8 @@

static int via_interrupt_init (struct via_info *card)
{
+ u8 tmp8;
+
DPRINTK ("ENTER\n");

assert (card != NULL);
@@ -1713,6 +1743,13 @@
return -EIO;
}

+ /* make sure FM irq is not routed to us */
+ pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
+ if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
+ tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
+ pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
+ }
+
if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {
printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
card->pdev->irq);
@@ -1720,38 +1757,11 @@
return -EBUSY;
}

- /* we don't want interrupts until we're opened */
- via_interrupt_disable (card);
-
DPRINTK ("EXIT, returning 0\n");
return 0;
}


-/**
- * via_interrupt_cleanup - Shutdown driver interrupt handling
- * @card: Private info for specified board
- *
- * Disable any potential interrupt sources in the Via audio
- * hardware, and then release (un-reserve) the IRQ line
- * in the kernel core.
- */
-
-static void via_interrupt_cleanup (struct via_info *card)
-{
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->pdev != NULL);
-
- via_interrupt_disable (card);
-
- free_irq (card->pdev->irq, card);
-
- DPRINTK ("EXIT\n");
-}
-
-
/****************************************************************
*
* OSS DSP device
@@ -1983,17 +1993,16 @@
tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
assert (tmp <= chan->frag_number);
- while (tmp == 0) {
+ if (tmp == 0) {
+ int ret;
if (nonblock || !chan->is_active)
return -EAGAIN;

DPRINTK ("Sleeping on block %d\n", n);
- interruptible_sleep_on (&chan->wait);
-
- if (signal_pending (current))
- return -ERESTARTSYS;
-
- tmp = atomic_read (&chan->n_frags);
+ ret = wait_event_interruptible(chan->wait,
+ (tmp = atomic_read(&chan->n_frags)));
+ if (ret < 0)
+ return ret;
}

/* Now that we have a buffer we can read from, send
@@ -2001,10 +2010,12 @@
*/
while ((count > 0) && (chan->slop_len < chan->frag_size)) {
size_t slop_left = chan->frag_size - chan->slop_len;
+ void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;
+ unsigned ofs = n % (PAGE_SIZE / chan->frag_size);

size = (count < slop_left) ? count : slop_left;
if (copy_to_user (userbuf,
- chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len,
+ base + ofs + chan->slop_len,
size))
return -EFAULT;

@@ -2130,17 +2141,16 @@
tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
assert (tmp <= chan->frag_number);
- while (tmp == 0) {
+ if (tmp == 0) {
+ int ret;
if (nonblock || !chan->is_enabled)
return -EAGAIN;

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_frags);
+ ret = wait_event_interruptible(chan->wait,
+ (tmp = atomic_read(&chan->n_frags)));
+ if (ret < 0)
+ return ret;
}

/* Now that we have at least one fragment we can write to, fill the buffer
@@ -2263,36 +2273,30 @@
static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
{
struct via_info *card;
- unsigned int mask = 0, rd, wr;
+ struct via_channel *chan;
+ unsigned int mask = 0;

DPRINTK ("ENTER\n");

assert (file != NULL);
card = file->private_data;
assert (card != NULL);
-
- rd = (file->f_mode & FMODE_READ);
- wr = (file->f_mode & FMODE_WRITE);

- 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_frags) == 0)
- poll_wait(file, &card->ch_in.wait, wait);
+ if (file->f_mode & FMODE_READ) {
+ chan = &card->ch_in;
+ if (sg_active (chan->iobase))
+ poll_wait(file, &chan->wait, wait);
+ if (atomic_read (&chan->n_frags) > 0)
+ mask |= POLLIN | POLLRDNORM;
}

- 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_frags) > 0))
- mask |= POLLIN | POLLRDNORM;
+ if (file->f_mode & FMODE_WRITE) {
+ chan = &card->ch_out;
+ if (sg_active (chan->iobase))
+ poll_wait(file, &chan->wait, wait);
+ if (atomic_read (&chan->n_frags) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ }

DPRINTK ("EXIT, returning %u\n", mask);
return mask;
@@ -2324,7 +2328,8 @@

via_chan_maybe_start (chan);

- while (atomic_read (&chan->n_frags) < chan->frag_number) {
+ if (atomic_read (&chan->n_frags) < chan->frag_number) {
+ int ret;
if (nonblock) {
DPRINTK ("EXIT, returning -EAGAIN\n");
return -EAGAIN;
@@ -2357,11 +2362,11 @@
#endif

DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
- interruptible_sleep_on (&chan->wait);
-
- if (signal_pending (current)) {
+ ret = wait_event_interruptible(chan->wait,
+ (atomic_read (&chan->n_frags) >= chan->frag_number));
+ if (ret < 0) {
DPRINTK ("EXIT, returning -ERESTARTSYS\n");
- return -ERESTARTSYS;
+ return ret;
}
}

@@ -2950,7 +2955,7 @@
via_chan_pcm_fmt (chan, 0);
via_set_rate (&card->ac97, chan, 44100);
} else {
- via_chan_pcm_fmt (chan, 0);
+ via_chan_pcm_fmt (chan, 1);
via_set_rate (&card->ac97, chan, 8000);
}
}
@@ -3020,25 +3024,19 @@
if (printed_version++ == 0)
printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n");

- if (pci_enable_device (pdev)) {
- rc = -EIO;
- goto err_out_none;
- }
-
- if (!request_region (pci_resource_start (pdev, 0),
- pci_resource_len (pdev, 0),
- VIA_MODULE_NAME)) {
- printk (KERN_ERR PFX "unable to obtain I/O resources, aborting\n");
- rc = -EBUSY;
+ rc = pci_enable_device (pdev);
+ if (rc)
goto err_out;
- }

+ rc = pci_request_regions (pdev, "via82cxxx_audio");
+ if (rc)
+ goto err_out;

card = kmalloc (sizeof (*card), GFP_KERNEL);
if (!card) {
printk (KERN_ERR PFX "out of memory, aborting\n");
rc = -ENOMEM;
- goto err_out_none;
+ goto err_out_res;
}

pci_set_drvdata (pdev, card);
@@ -3143,8 +3128,8 @@
#endif
kfree (card);

-err_out_none:
- release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));
+err_out_res:
+ pci_release_regions (pdev);
err_out:
pci_set_drvdata (pdev, NULL);
DPRINTK ("EXIT - returning %d\n", rc);
@@ -3162,12 +3147,12 @@
card = pci_get_drvdata (pdev);
assert (card != NULL);

- via_interrupt_cleanup (card);
+ free_irq (card->pdev->irq, card);
via_card_cleanup_proc (card);
via_dsp_cleanup (card);
via_ac97_cleanup (card);

- release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));
+ pci_release_regions (pdev);

#ifndef VIA_NDEBUG
memset (card, 0xAB, sizeof (*card)); /* poison memory */
\
 
 \ /
  Last update: 2005-03-22 12:55    [W:0.070 / U:0.248 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site