Commit 2cf05d78 authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/spare/repo/linux-2.6

into redhat.com:/spare/repo/i810-audio-2.6
parents 5ea484a8 81da67b3
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/ac97_codec.h> #include <linux/ac97_codec.h>
#include <linux/bitops.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
...@@ -148,6 +149,9 @@ ...@@ -148,6 +149,9 @@
#define PCI_DEVICE_ID_AMD_8111_AC97 0x746d #define PCI_DEVICE_ID_AMD_8111_AC97 0x746d
#endif #endif
#define MODULOP2(a, b) ((a) & ((b) - 1))
#define MASKP2(a, b) ((a) & ~((b) - 1))
static int ftsodell; static int ftsodell;
static int strict_clocking; static int strict_clocking;
static unsigned int clocking; static unsigned int clocking;
...@@ -209,6 +213,7 @@ struct i810_channel ...@@ -209,6 +213,7 @@ struct i810_channel
#define ENUM_ENGINE(PRE,DIG) \ #define ENUM_ENGINE(PRE,DIG) \
enum { \ enum { \
PRE##_BASE = 0x##DIG##0, /* Base Address */ \
PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \ PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \ PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \ PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
...@@ -491,8 +496,12 @@ struct i810_card { ...@@ -491,8 +496,12 @@ struct i810_card {
/* extract register offset from codec struct */ /* extract register offset from codec struct */
#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id]) #define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
#define GET_CIV(port) MODULOP2(inb((port) + OFF_CIV), SG_LEN)
#define GET_LVI(port) MODULOP2(inb((port) + OFF_LVI), SG_LEN)
/* set LVI from CIV */ /* set LVI from CIV */
#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI) #define CIV_TO_LVI(port, off) \
outb(MODULOP2(GET_CIV((port)) + (off), SG_LEN), (port) + OFF_LVI)
static struct i810_card *devs = NULL; static struct i810_card *devs = NULL;
...@@ -762,7 +771,7 @@ static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec) ...@@ -762,7 +771,7 @@ static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
port_picb = port + OFF_PICB; port_picb = port + OFF_PICB;
do { do {
civ = inb(port+OFF_CIV) & 31; civ = GET_CIV(port);
offset = inw(port_picb); offset = inw(port_picb);
/* Must have a delay here! */ /* Must have a delay here! */
if(offset == 0) if(offset == 0)
...@@ -782,7 +791,7 @@ static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec) ...@@ -782,7 +791,7 @@ static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
* that we won't have to worry about the chip still being * that we won't have to worry about the chip still being
* out of sync with reality ;-) * out of sync with reality ;-)
*/ */
} while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb)); } while (civ != GET_CIV(port) || offset != inw(port_picb));
return (((civ + 1) * dmabuf->fragsize - (bytes * offset)) return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
% dmabuf->dmasize); % dmabuf->dmasize);
...@@ -992,6 +1001,7 @@ static int prog_dmabuf(struct i810_state *state, unsigned rec) ...@@ -992,6 +1001,7 @@ static int prog_dmabuf(struct i810_state *state, unsigned rec)
dmabuf->numfrag = SG_LEN; dmabuf->numfrag = SG_LEN;
dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag; dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
dmabuf->fragsamples = dmabuf->fragsize >> 1; dmabuf->fragsamples = dmabuf->fragsize >> 1;
dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
dmabuf->userfragsize = dmabuf->ossfragsize; dmabuf->userfragsize = dmabuf->ossfragsize;
dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize; dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
...@@ -999,16 +1009,12 @@ static int prog_dmabuf(struct i810_state *state, unsigned rec) ...@@ -999,16 +1009,12 @@ static int prog_dmabuf(struct i810_state *state, unsigned rec)
if(dmabuf->ossmaxfrags == 4) { if(dmabuf->ossmaxfrags == 4) {
fragint = 8; fragint = 8;
dmabuf->fragshift = 2;
} else if (dmabuf->ossmaxfrags == 8) { } else if (dmabuf->ossmaxfrags == 8) {
fragint = 4; fragint = 4;
dmabuf->fragshift = 3;
} else if (dmabuf->ossmaxfrags == 16) { } else if (dmabuf->ossmaxfrags == 16) {
fragint = 2; fragint = 2;
dmabuf->fragshift = 4;
} else { } else {
fragint = 1; fragint = 1;
dmabuf->fragshift = 5;
} }
/* /*
* Now set up the ring * Now set up the ring
...@@ -1072,41 +1078,41 @@ static void __i810_update_lvi(struct i810_state *state, int rec) ...@@ -1072,41 +1078,41 @@ static void __i810_update_lvi(struct i810_state *state, int rec)
{ {
struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf = &state->dmabuf;
int x, port; int x, port;
int trigger;
int count, fragsize;
void (*start)(struct i810_state *);
count = dmabuf->count;
port = state->card->iobase; port = state->card->iobase;
if(rec) if (rec) {
port += dmabuf->read_channel->port; port += dmabuf->read_channel->port;
else trigger = PCM_ENABLE_INPUT;
start = __start_adc;
count = dmabuf->dmasize - count;
} else {
port += dmabuf->write_channel->port; port += dmabuf->write_channel->port;
trigger = PCM_ENABLE_OUTPUT;
start = __start_dac;
}
/* Do not process partial fragments. */
fragsize = dmabuf->fragsize;
if (count < fragsize)
return;
/* if we are currently stopped, then our CIV is actually set to our
* *last* sg segment and we are ready to wrap to the next. However,
* if we set our LVI to the last sg segment, then it won't wrap to
* the next sg segment, it won't even get a start. So, instead, when
* we are stopped, we set both the LVI value and also we increment
* the CIV value to the next sg segment to be played so that when
* we call start_{dac,adc}, things will operate properly
*/
if (!dmabuf->enable && dmabuf->ready) { if (!dmabuf->enable && dmabuf->ready) {
if(rec && dmabuf->count < dmabuf->dmasize && if (!(dmabuf->trigger & trigger))
(dmabuf->trigger & PCM_ENABLE_INPUT)) return;
{
CIV_TO_LVI(port, 1); start(state);
__start_adc(state); while (!(inb(port + OFF_CR) & ((1<<4) | (1<<2))))
while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ; ;
} else if (!rec && dmabuf->count &&
(dmabuf->trigger & PCM_ENABLE_OUTPUT))
{
CIV_TO_LVI(port, 1);
__start_dac(state);
while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
}
} }
/* swptr - 1 is the tail of our transfer */ /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize; x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
x /= dmabuf->fragsize; x >>= dmabuf->fragshift;
outb(x, port+OFF_LVI); outb(x, port + OFF_LVI);
} }
static void i810_update_lvi(struct i810_state *state, int rec) static void i810_update_lvi(struct i810_state *state, int rec)
...@@ -1126,13 +1132,17 @@ static void i810_update_ptr(struct i810_state *state) ...@@ -1126,13 +1132,17 @@ static void i810_update_ptr(struct i810_state *state)
{ {
struct dmabuf *dmabuf = &state->dmabuf; struct dmabuf *dmabuf = &state->dmabuf;
unsigned hwptr; unsigned hwptr;
unsigned fragmask, dmamask;
int diff; int diff;
/* error handling and process wake up for DAC */ fragmask = MASKP2(~0, dmabuf->fragsize);
dmamask = MODULOP2(~0, dmabuf->dmasize);
/* error handling and process wake up for ADC */
if (dmabuf->enable == ADC_RUNNING) { if (dmabuf->enable == ADC_RUNNING) {
/* update hardware pointer */ /* update hardware pointer */
hwptr = i810_get_dma_addr(state, 1); hwptr = i810_get_dma_addr(state, 1) & fragmask;
diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; diff = (hwptr - dmabuf->hwptr) & dmamask;
#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) #if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
#endif #endif
...@@ -1144,20 +1154,20 @@ static void i810_update_ptr(struct i810_state *state) ...@@ -1144,20 +1154,20 @@ static void i810_update_ptr(struct i810_state *state)
/* this is normal for the end of a read */ /* this is normal for the end of a read */
/* only give an error if we went past the */ /* only give an error if we went past the */
/* last valid sg entry */ /* last valid sg entry */
if((inb(state->card->iobase + PI_CIV) & 31) != if (GET_CIV(state->card->iobase + PI_BASE) !=
(inb(state->card->iobase + PI_LVI) & 31)) { GET_LVI(state->card->iobase + PI_BASE)) {
printk(KERN_WARNING "i810_audio: DMA overrun on read\n"); printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
dmabuf->error++; dmabuf->error++;
} }
} }
if (dmabuf->count > dmabuf->userfragsize) if (diff)
wake_up(&dmabuf->wait); wake_up(&dmabuf->wait);
} }
/* error handling and process wake up for DAC */ /* error handling and process wake up for DAC */
if (dmabuf->enable == DAC_RUNNING) { if (dmabuf->enable == DAC_RUNNING) {
/* update hardware pointer */ /* update hardware pointer */
hwptr = i810_get_dma_addr(state, 0); hwptr = i810_get_dma_addr(state, 0) & fragmask;
diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; diff = (hwptr - dmabuf->hwptr) & dmamask;
#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) #if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
#endif #endif
...@@ -1169,18 +1179,18 @@ static void i810_update_ptr(struct i810_state *state) ...@@ -1169,18 +1179,18 @@ static void i810_update_ptr(struct i810_state *state)
/* this is normal for the end of a write */ /* this is normal for the end of a write */
/* only give an error if we went past the */ /* only give an error if we went past the */
/* last valid sg entry */ /* last valid sg entry */
if((inb(state->card->iobase + PO_CIV) & 31) != if (GET_CIV(state->card->iobase + PO_BASE) !=
(inb(state->card->iobase + PO_LVI) & 31)) { GET_LVI(state->card->iobase + PO_BASE)) {
printk(KERN_WARNING "i810_audio: DMA overrun on write\n"); printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
printk("i810_audio: CIV %d, LVI %d, hwptr %x, " printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
"count %d\n", "count %d\n",
inb(state->card->iobase + PO_CIV) & 31, GET_CIV(state->card->iobase + PO_BASE),
inb(state->card->iobase + PO_LVI) & 31, GET_LVI(state->card->iobase + PO_BASE),
dmabuf->hwptr, dmabuf->count); dmabuf->hwptr, dmabuf->count);
dmabuf->error++; dmabuf->error++;
} }
} }
if (dmabuf->count < (dmabuf->dmasize-dmabuf->userfragsize)) if (diff)
wake_up(&dmabuf->wait); wake_up(&dmabuf->wait);
} }
} }
...@@ -1197,7 +1207,6 @@ static inline int i810_get_free_write_space(struct i810_state *state) ...@@ -1197,7 +1207,6 @@ static inline int i810_get_free_write_space(struct i810_state *state)
dmabuf->swptr = dmabuf->hwptr; dmabuf->swptr = dmabuf->hwptr;
} }
free = dmabuf->dmasize - dmabuf->count; free = dmabuf->dmasize - dmabuf->count;
free -= (dmabuf->hwptr % dmabuf->fragsize);
if(free < 0) if(free < 0)
return(0); return(0);
return(free); return(free);
...@@ -1215,12 +1224,27 @@ static inline int i810_get_available_read_data(struct i810_state *state) ...@@ -1215,12 +1224,27 @@ static inline int i810_get_available_read_data(struct i810_state *state)
dmabuf->swptr = dmabuf->hwptr; dmabuf->swptr = dmabuf->hwptr;
} }
avail = dmabuf->count; avail = dmabuf->count;
avail -= (dmabuf->hwptr % dmabuf->fragsize);
if(avail < 0) if(avail < 0)
return(0); return(0);
return(avail); return(avail);
} }
static inline void fill_partial_frag(struct dmabuf *dmabuf)
{
unsigned fragsize;
unsigned swptr, len;
fragsize = dmabuf->fragsize;
swptr = dmabuf->swptr;
len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
if (len == fragsize)
return;
memset(dmabuf->rawbuf + swptr, '\0', len);
dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
dmabuf->count += len;
}
static int drain_dac(struct i810_state *state, int signals_allowed) static int drain_dac(struct i810_state *state, int signals_allowed)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -1235,30 +1259,28 @@ static int drain_dac(struct i810_state *state, int signals_allowed) ...@@ -1235,30 +1259,28 @@ static int drain_dac(struct i810_state *state, int signals_allowed)
stop_dac(state); stop_dac(state);
return 0; return 0;
} }
spin_lock_irqsave(&state->card->lock, flags);
fill_partial_frag(dmabuf);
/*
* This will make sure that our LVI is correct, that our
* pointer is updated, and that the DAC is running. We
* have to force the setting of dmabuf->trigger to avoid
* any possible deadlocks.
*/
dmabuf->trigger = PCM_ENABLE_OUTPUT;
__i810_update_lvi(state, 0);
spin_unlock_irqrestore(&state->card->lock, flags);
add_wait_queue(&dmabuf->wait, &wait); add_wait_queue(&dmabuf->wait, &wait);
for (;;) { for (;;) {
spin_lock_irqsave(&state->card->lock, flags); spin_lock_irqsave(&state->card->lock, flags);
i810_update_ptr(state); i810_update_ptr(state);
count = dmabuf->count; count = dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
if (count <= 0)
break;
/*
* This will make sure that our LVI is correct, that our
* pointer is updated, and that the DAC is running. We
* have to force the setting of dmabuf->trigger to avoid
* any possible deadlocks.
*/
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 /* It seems that we have to set the current state to
* TASK_INTERRUPTIBLE every time to make the process * TASK_INTERRUPTIBLE every time to make the process
...@@ -1269,7 +1291,17 @@ static int drain_dac(struct i810_state *state, int signals_allowed) ...@@ -1269,7 +1291,17 @@ static int drain_dac(struct i810_state *state, int signals_allowed)
* instead of actually sleeping and waiting for an * instead of actually sleeping and waiting for an
* interrupt to wake us up! * interrupt to wake us up!
*/ */
set_current_state(TASK_INTERRUPTIBLE); __set_current_state(signals_allowed ?
TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(&state->card->lock, flags);
if (count <= 0)
break;
if (signal_pending(current) && signals_allowed) {
break;
}
/* /*
* set the timeout to significantly longer than it *should* * set the timeout to significantly longer than it *should*
* take for the DAC to drain the DMA buffer * take for the DAC to drain the DMA buffer
...@@ -1350,11 +1382,10 @@ static void i810_channel_interrupt(struct i810_card *card) ...@@ -1350,11 +1382,10 @@ static void i810_channel_interrupt(struct i810_card *card)
if(status & DMA_INT_DCH) if(status & DMA_INT_DCH)
printk("DCH -"); printk("DCH -");
#endif #endif
if(dmabuf->enable & DAC_RUNNING) count = dmabuf->count;
count = dmabuf->count; if(dmabuf->enable & ADC_RUNNING)
else count = dmabuf->dmasize - count;
count = dmabuf->dmasize - dmabuf->count; if (count >= (int)dmabuf->fragsize) {
if(count > 0) {
outb(inb(port+OFF_CR) | 1, port+OFF_CR); outb(inb(port+OFF_CR) | 1, port+OFF_CR);
#ifdef DEBUG_INTERRUPTS #ifdef DEBUG_INTERRUPTS
printk(" CONTINUE "); printk(" CONTINUE ");
...@@ -1417,6 +1448,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1417,6 +1448,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
unsigned long flags; unsigned long flags;
unsigned int swptr; unsigned int swptr;
int cnt; int cnt;
int pending;
DECLARE_WAITQUEUE(waita, current); DECLARE_WAITQUEUE(waita, current);
#ifdef DEBUG2 #ifdef DEBUG2
...@@ -1442,6 +1474,8 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1442,6 +1474,8 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
return -EFAULT; return -EFAULT;
ret = 0; ret = 0;
pending = 0;
add_wait_queue(&dmabuf->wait, &waita); add_wait_queue(&dmabuf->wait, &waita);
while (count > 0) { while (count > 0) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -1455,8 +1489,8 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1455,8 +1489,8 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
} }
continue; continue;
} }
swptr = dmabuf->swptr;
cnt = i810_get_available_read_data(state); cnt = i810_get_available_read_data(state);
swptr = dmabuf->swptr;
// this is to make the copy_to_user simpler below // this is to make the copy_to_user simpler below
if(cnt > (dmabuf->dmasize - swptr)) if(cnt > (dmabuf->dmasize - swptr))
cnt = dmabuf->dmasize - swptr; cnt = dmabuf->dmasize - swptr;
...@@ -1464,15 +1498,6 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1464,15 +1498,6 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
if (cnt > count) if (cnt > count)
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) { if (cnt <= 0) {
unsigned long tmo; unsigned long tmo;
/* /*
...@@ -1526,7 +1551,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1526,7 +1551,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
goto done; goto done;
} }
swptr = (swptr + cnt) % dmabuf->dmasize; swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
...@@ -1535,7 +1560,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1535,7 +1560,7 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
continue; continue;
} }
dmabuf->swptr = swptr; dmabuf->swptr = swptr;
dmabuf->count -= cnt; pending = dmabuf->count -= cnt;
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
count -= cnt; count -= cnt;
...@@ -1543,7 +1568,9 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t * ...@@ -1543,7 +1568,9 @@ static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *
ret += cnt; ret += cnt;
} }
done: done:
i810_update_lvi(state,1); pending = dmabuf->dmasize - pending;
if (dmabuf->enable || pending >= dmabuf->userfragsize)
i810_update_lvi(state, 1);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&dmabuf->wait, &waita); remove_wait_queue(&dmabuf->wait, &waita);
...@@ -1560,7 +1587,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1560,7 +1587,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
ssize_t ret; ssize_t ret;
unsigned long flags; unsigned long flags;
unsigned int swptr = 0; unsigned int swptr = 0;
int cnt, x; int pending;
int cnt;
DECLARE_WAITQUEUE(waita, current); DECLARE_WAITQUEUE(waita, current);
#ifdef DEBUG2 #ifdef DEBUG2
...@@ -1585,6 +1613,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1585,6 +1613,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
return -EFAULT; return -EFAULT;
ret = 0; ret = 0;
pending = 0;
add_wait_queue(&dmabuf->wait, &waita); add_wait_queue(&dmabuf->wait, &waita);
while (count > 0) { while (count > 0) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
...@@ -1599,8 +1629,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1599,8 +1629,8 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
continue; continue;
} }
swptr = dmabuf->swptr;
cnt = i810_get_free_write_space(state); cnt = i810_get_free_write_space(state);
swptr = dmabuf->swptr;
/* Bound the maximum size to how much we can copy to the /* Bound the maximum size to how much we can copy to the
* dma buffer before we hit the end. If we have more to * dma buffer before we hit the end. If we have more to
* copy then it will get done in a second pass of this * copy then it will get done in a second pass of this
...@@ -1615,15 +1645,6 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1615,15 +1645,6 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
#endif #endif
if (cnt > count) if (cnt > count)
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) { if (cnt <= 0) {
unsigned long tmo; unsigned long tmo;
// There is data waiting to be played // There is data waiting to be played
...@@ -1668,7 +1689,7 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1668,7 +1689,7 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
goto ret; goto ret;
} }
swptr = (swptr + cnt) % dmabuf->dmasize; swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
spin_lock_irqsave(&state->card->lock, flags); spin_lock_irqsave(&state->card->lock, flags);
if (PM_SUSPENDED(card)) { if (PM_SUSPENDED(card)) {
...@@ -1677,19 +1698,16 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l ...@@ -1677,19 +1698,16 @@ static ssize_t i810_write(struct file *file, const char *buffer, size_t count, l
} }
dmabuf->swptr = swptr; dmabuf->swptr = swptr;
dmabuf->count += cnt; pending = dmabuf->count += cnt;
count -= cnt; count -= cnt;
buffer += cnt; buffer += cnt;
ret += cnt; ret += cnt;
spin_unlock_irqrestore(&state->card->lock, flags); spin_unlock_irqrestore(&state->card->lock, flags);
} }
if (swptr % dmabuf->fragsize) {
x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
memset(dmabuf->rawbuf + swptr, '\0', x);
}
ret: ret:
i810_update_lvi(state,0); if (dmabuf->enable || pending >= dmabuf->userfragsize)
i810_update_lvi(state, 0);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&dmabuf->wait, &waita); remove_wait_queue(&dmabuf->wait, &waita);
...@@ -2179,6 +2197,13 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -2179,6 +2197,13 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
#if defined(DEBUG) || defined(DEBUG_MMAP) #if defined(DEBUG) || defined(DEBUG_MMAP)
printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
#endif #endif
/* silently ignore invalid PCM_ENABLE_xxx bits,
* like the other drivers do
*/
if (!(file->f_mode & FMODE_READ ))
val &= ~PCM_ENABLE_INPUT;
if (!(file->f_mode & FMODE_WRITE ))
val &= ~PCM_ENABLE_OUTPUT;
if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
stop_adc(state); stop_adc(state);
} }
...@@ -2186,7 +2211,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -2186,7 +2211,7 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
stop_dac(state); stop_dac(state);
} }
dmabuf->trigger = val; dmabuf->trigger = val;
if((file->f_mode & FMODE_WRITE) && (val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) { if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
if (!dmabuf->write_channel) { if (!dmabuf->write_channel) {
dmabuf->ready = 0; dmabuf->ready = 0;
dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
...@@ -2202,12 +2227,12 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -2202,12 +2227,12 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
dmabuf->swptr = dmabuf->hwptr; dmabuf->swptr = dmabuf->hwptr;
dmabuf->count = i810_get_free_write_space(state); dmabuf->count = i810_get_free_write_space(state);
dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
__i810_update_lvi(state, 0);
spin_unlock_irqrestore(&state->card->lock, flags); spin_unlock_irqrestore(&state->card->lock, flags);
} else }
start_dac(state); i810_update_lvi(state, 0);
start_dac(state);
} }
if((file->f_mode & FMODE_READ) && (val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) { if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
if (!dmabuf->read_channel) { if (!dmabuf->read_channel) {
dmabuf->ready = 0; dmabuf->ready = 0;
dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
...@@ -3065,7 +3090,7 @@ static void __devinit i810_configure_clocking (void) ...@@ -3065,7 +3090,7 @@ static void __devinit i810_configure_clocking (void)
goto config_out; goto config_out;
} }
dmabuf->count = dmabuf->dmasize; dmabuf->count = dmabuf->dmasize;
CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31); CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, -1);
local_irq_save(flags); local_irq_save(flags);
start_dac(state); start_dac(state);
offset = i810_get_dma_addr(state, 0); offset = i810_get_dma_addr(state, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment