Re: i810 audio patch

Doug Ledford
2001-12-05T03:05:58Z

[-- Attachment #1: Type: text/plain, Size: 544 bytes --]

Nathan Bryant wrote:

> Nathan Bryant wrote:
>
>> glquake.glx doesn't: "i810_audio: drain_dac, dma timeout?"
>
>
> Turns out this has been broken for a while; stock 2.4.17pre1 has a
> broken mmap too...
>

Two questions:

1) This is a timeout on close. Does it work up until then?

2) Does the attached patch (against the 0.08 driver) help?

--

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: foo --]
[-- Type: text/plain, Size: 3129 bytes --]

--- i810_audio.c.08 Tue Dec 4 18:43:22 2001
+++ i810_audio.c.08b Tue Dec 4 22:04:05 2001
@@ -664,26 +664,26 @@
return offset;
}

-//static void resync_dma_ptrs(struct i810_state *state, int rec)
-//{
-// struct dmabuf *dmabuf = &state->dmabuf;
-// struct i810_channel *c;
-// int offset;
-//
-// if(rec) {
-// c = dmabuf->read_channel;
-// } else {
-// c = dmabuf->write_channel;
-// }
-// if(c==NULL)
-// return;
-// offset = inb(state->card->iobase+c->port+OFF_CIV);
-// if(offset == inb(state->card->iobase+c->port+OFF_LVI))
-// offset++;
-// offset *= dmabuf->fragsize;
-//
-// dmabuf->hwptr=dmabuf->swptr = offset;
-//}
+static void resync_dma_ptrs(struct i810_state *state, int rec)
+{
+ struct dmabuf *dmabuf = &state->dmabuf;
+ struct i810_channel *c;
+ int offset;
+
+ if(rec) {
+ c = dmabuf->read_channel;
+ } else {
+ c = dmabuf->write_channel;
+ }
+ if(c==NULL)
+ return;
+ offset = inb(state->card->iobase+c->port+OFF_CIV);
+ if(offset == inb(state->card->iobase+c->port+OFF_LVI))
+ offset++;
+ offset *= dmabuf->fragsize;
+
+ dmabuf->hwptr=dmabuf->swptr = offset;
+}

/* Stop recording (lock held) */
static inline void __stop_adc(struct i810_state *state)
@@ -1094,13 +1094,13 @@
return(avail);
}

-static int drain_dac(struct i810_state *state, int nonblock)
+static int drain_dac(struct i810_state *state)
{
DECLARE_WAITQUEUE(wait, current);
struct dmabuf *dmabuf = &state->dmabuf;
unsigned long flags;
unsigned long tmo;
- int count;
+ int count, timeout=0;

if (!dmabuf->ready)
return 0;
@@ -1119,30 +1119,29 @@
if (count <= 0)
break;

- if (signal_pending(current))
- break;
-
- i810_update_lvi(state,0);
if (dmabuf->enable != DAC_RUNNING)
start_dac(state);

- if (nonblock) {
- remove_wait_queue(&dmabuf->wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
+ if (signal_pending(current))
+ break;

- tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
- tmo >>= 1;
+ /* set the timeout to exactly twice as long as it *should*
+ * take for the DAC to drain the DMA buffer
+ */
+ tmo = (count * HZ * 2) / dmabuf->rate;
if (!schedule_timeout(tmo ? tmo : 1) && tmo){
printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
+ timeout = 1;
break;
}
}
- stop_dac(state);
- synchronize_irq();
remove_wait_queue(&dmabuf->wait, &wait);
set_current_state(TASK_RUNNING);
+ if(count <= 0 || timeout) {
+ stop_dac(state);
+ synchronize_irq();
+ resync_dma_ptrs(state, 0 /* record channel */);
+ }
if (signal_pending(current))
return -ERESTARTSYS;

@@ -1651,7 +1650,7 @@
#endif
if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
return 0;
- drain_dac(state, 0);
+ drain_dac(state);
dmabuf->ready = 0;
dmabuf->swptr = dmabuf->hwptr = 0;
dmabuf->count = dmabuf->total_bytes = 0;
@@ -2324,7 +2323,7 @@
/* stop DMA state machine and free DMA buffers/channels */
if(dmabuf->enable & DAC_RUNNING ||
(dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
- drain_dac(state,0);
+ drain_dac(state);
}
if(dmabuf->enable & ADC_RUNNING) {
stop_adc(state);