From: Doug Ledford <dledford@redhat.com>
To: Neale Banks <neale@lowendale.com.au>
Cc: linux-kernel@vger.kernel.org, Alan Cox <alan@redhat.com>
Subject: Re: [PATCH] i810 driver update.
Date: Mon, 28 Jan 2002 21:07:21 -0500 [thread overview]
Message-ID: <3C5603D9.3070608@redhat.com> (raw)
In-Reply-To: <Pine.LNX.4.05.10201291229220.1513-100000@marina.lowendale.com.au>
[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]
Neale Banks wrote:
> Hi Doug,
>
>
>>Marcelo,
>>
>>This is the final, cooked version of the i810 driver. It's been out long
>>enough for me to say with a good deal of certainty that it fixes quite a few
>>bugs in the existing driver and doesn't introduce any new bugs (that doesn't
>>mean it fixes all of the existing bugs though, record is still problematic
>>and full duplex isn't supported, but these aren't regressions since the
>>current driver is the same way). This was diff'ed against the latest pre
>>patch. Please apply this to your tree. Thanks.
>>
> [...]
>
> Are the fixes in this going to be applicable to 2.2 also (FWIW, 2.2's
> i810_audio #defines ``DRIVER_VERSION "0.17"'')?
I'm sure the fixes are relevant. How well they may integrate into 2.2 is
another question :-/
> If so, is there any attempt to back-port this driver to 2.2?
Aside from the new AC97 S/PDIF support, there shouldn't be much of any back
port to it. Of course, I haven't thought about 2.2 in a long while, so
maybe I'm totally misremembering what 2.2 supports in terms of driver stuff.
> I can test (at least compiling, booting and basic sound-playing), but not
> back-port.
The best I can do it to make a diff between the 0.17 driver version I have
here and the 0.21 driver version. Maybe that incremental diff will apply to
the 2.2 kernel's i810_audio.c and bring it up to date without any specific
back port needed. It's attached.
--
Doug Ledford <dledford@redhat.com> http://people.redhat.com/dledford
Please check my web site for aic7xxx updates/answers before
e-mailing me about problems
[-- Attachment #2: 2.2-i810.patch --]
[-- Type: text/plain, Size: 6922 bytes --]
--- i810_audio.c.17 Tue Jan 8 19:07:49 2002
+++ i810_audio.c.21 Mon Jan 28 17:03:47 2002
@@ -206,7 +206,7 @@ enum {
#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-#define DRIVER_VERSION "0.17"
+#define DRIVER_VERSION "0.21"
/* magic numbers to protect our data structures */
#define I810_CARD_MAGIC 0x5072696E /* "Prin" */
@@ -601,9 +601,8 @@ static unsigned int i810_set_dac_rate(st
rate = 8000;
dmabuf->rate = (rate * 48000)/clocking;
}
-
- new_rate = ac97_set_dac_rate(codec, rate);
+ new_rate=ac97_set_dac_rate(codec, rate);
if(new_rate != rate) {
dmabuf->rate = (new_rate * 48000)/clocking;
}
@@ -679,12 +678,29 @@ static inline unsigned i810_get_dma_addr
do {
civ = inb(port+OFF_CIV) & 31;
- offset = (civ + 1) * dmabuf->fragsize - bytes * inw(port_picb);
- /* CIV changed before we read PICB (very seldom) ?
- * then PICB was rubbish, so try again */
- } while (civ != (inb(port+OFF_CIV) & 31));
+ offset = inw(port_picb);
+ /* Must have a delay here! */
+ if(offset == 0)
+ udelay(1);
+ /* Reread both registers and make sure that that total
+ * offset from the first reading to the second is 0.
+ * There is an issue with SiS hardware where it will count
+ * picb down to 0, then update civ to the next value,
+ * then set the new picb to fragsize bytes. We can catch
+ * it between the civ update and the picb update, making
+ * it look as though we are 1 fragsize ahead of where we
+ * are. The next to we get the address though, it will
+ * be back in the right place, and we will suddenly think
+ * we just went forward dmasize - fragsize bytes, causing
+ * totally stupid *huge* dma overrun messages. We are
+ * assuming that the 1us delay is more than long enough
+ * that we won't have to worry about the chip still being
+ * out of sync with reality ;-)
+ */
+ } while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb));
- return (offset % dmabuf->dmasize);
+ return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
+ % dmabuf->dmasize);
}
/* Stop recording (lock held) */
@@ -1116,7 +1132,7 @@ static inline int i810_get_available_rea
return(avail);
}
-static int drain_dac(struct i810_state *state)
+static int drain_dac(struct i810_state *state, int signals_allowed)
{
DECLARE_WAITQUEUE(wait, current);
struct dmabuf *dmabuf = &state->dmabuf;
@@ -1126,12 +1142,12 @@ static int drain_dac(struct i810_state *
if (!dmabuf->ready)
return 0;
-
+ if(dmabuf->mapped) {
+ stop_dac(state);
+ return 0;
+ }
add_wait_queue(&dmabuf->wait, &wait);
for (;;) {
- /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
- every time to make the process really go to sleep */
- set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&state->card->lock, flags);
i810_update_ptr(state);
@@ -1147,17 +1163,29 @@ static int drain_dac(struct i810_state *
* have to force the setting of dmabuf->trigger to avoid
* any possible deadlocks.
*/
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- i810_update_lvi(state,0);
-
- if (signal_pending(current))
- break;
+ if(!dmabuf->enable) {
+ dmabuf->trigger = PCM_ENABLE_OUTPUT;
+ i810_update_lvi(state,0);
+ }
+ if (signal_pending(current) && signals_allowed) {
+ break;
+ }
+ /* It seems that we have to set the current state to
+ * TASK_INTERRUPTIBLE every time to make the process
+ * really go to sleep. This also has to be *after* the
+ * update_ptr() call because update_ptr is likely to
+ * do a wake_up() which will unset this before we ever
+ * try to sleep, resuling in a tight loop in this code
+ * instead of actually sleeping and waiting for an
+ * interrupt to wake us up!
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
/*
- * set the timeout to exactly twice as long as it *should*
+ * set the timeout to significantly longer than it *should*
* take for the DAC to drain the DMA buffer
*/
- tmo = (count * HZ * 2) / (dmabuf->rate * 4);
+ tmo = (count * HZ) / (dmabuf->rate);
if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
count = 0;
@@ -1166,10 +1194,9 @@ static int drain_dac(struct i810_state *
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&dmabuf->wait, &wait);
- if (count <= 0)
- stop_dac(state);
- if (signal_pending(current))
+ if(count > 0 && signal_pending(current) && signals_allowed)
return -ERESTARTSYS;
+ stop_dac(state);
return 0;
}
@@ -1348,6 +1375,15 @@ static ssize_t i810_read(struct file *fi
if (cnt > count)
cnt = count;
+ /* Lop off the last two bits to force the code to always
+ * write in full samples. This keeps software that sets
+ * O_NONBLOCK but doesn't check the return value of the
+ * write call from getting things out of state where they
+ * think a full 4 byte sample was written when really only
+ * a portion was, resulting in odd sound and stereo
+ * hysteresis.
+ */
+ cnt &= ~0x3;
if (cnt <= 0) {
unsigned long tmo;
/*
@@ -1490,6 +1526,15 @@ static ssize_t i810_write(struct file *f
#endif
if (cnt > count)
cnt = count;
+ /* Lop off the last two bits to force the code to always
+ * write in full samples. This keeps software that sets
+ * O_NONBLOCK but doesn't check the return value of the
+ * write call from getting things out of state where they
+ * think a full 4 byte sample was written when really only
+ * a portion was, resulting in odd sound and stereo
+ * hysteresis.
+ */
+ cnt &= ~0x3;
if (cnt <= 0) {
unsigned long tmo;
// There is data waiting to be played
@@ -1695,7 +1740,8 @@ static int i810_ioctl(struct inode *inod
#endif
if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
return 0;
- drain_dac(state);
+ if((val = drain_dac(state, 1)))
+ return val;
dmabuf->total_bytes = 0;
return 0;
@@ -2377,11 +2423,10 @@ static int i810_release(struct inode *in
lock_kernel();
/* stop DMA state machine and free DMA buffers/channels */
- if(dmabuf->enable & DAC_RUNNING ||
- (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
- drain_dac(state);
+ if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
+ drain_dac(state, 0);
}
- if(dmabuf->enable & ADC_RUNNING) {
+ if(dmabuf->trigger & PCM_ENABLE_INPUT) {
stop_adc(state);
}
spin_lock_irqsave(&card->lock, flags);
@@ -3080,7 +3125,7 @@ static int __init i810_init_module (void
if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
} else {
- printk("i810_audio: S/PDIF can only be locked to 32000, 441000, or 48000Hz.\n");
+ printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
spdif_locked = 0;
}
}
next prev parent reply other threads:[~2002-01-29 2:08 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-01-28 22:26 [PATCH] i810 driver update Doug Ledford
2002-01-29 1:39 ` Neale Banks
2002-01-29 2:07 ` Doug Ledford [this message]
2002-01-29 2:55 ` Neale Banks
2002-01-29 2:47 ` Doug Ledford
2002-01-29 6:18 ` Graeme Read
2002-01-29 6:20 ` bogus imode? Joe Wong
-- strict thread matches above, loose matches on Subject: below --
2002-01-28 22:28 [PATCH] i810 driver update Doug Ledford
[not found] <Pine.LNX.4.05.10201291422170.1513-200000@marina.lowendale.com.au>
2002-01-29 3:28 ` Doug Ledford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3C5603D9.3070608@redhat.com \
--to=dledford@redhat.com \
--cc=alan@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=neale@lowendale.com.au \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox