[parisc-linux-cvs] linux grundler
Grant Grundler
grundler@dsl2.external.hp.com
Tue, 15 Oct 2002 22:55:58 -0600
Grant Grundler wrote:
> drivers/sound : ad1889.c ad1889.h
>
> Log message:
> DMA now works - but still no sound.
> Suspect needs more chip initialization.
no rev change since I didn't break anything that wasn't already broken.
fixed the DMA for this driver but still no sound.
I think the chip needs more initialization.
grant
Index: ad1889.c
===================================================================
RCS file: /var/cvs/linux/drivers/sound/ad1889.c,v
retrieving revision 1.1
diff -u -p -r1.1 ad1889.c
--- ad1889.c 21 Jul 2002 01:54:00 -0000 1.1
+++ ad1889.c 16 Oct 2002 04:13:22 -0000
@@ -104,54 +104,90 @@ static inline void ad1889_set_adc_fmt(ad
static void ad1889_start_wav(ad1889_state_t *state)
{
- u16 tmp;
+ long cnt;
unsigned long flags;
struct dmabuf *dmabuf = &state->dmabuf;
- int cnt;
+ u16 tmp;
/* setup dma */
spin_lock_irqsave(&state->card->lock, flags);
cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
+
+ if (cnt == 0) /* done - don't need to do anything */
+ return;
+
+ if (dmabuf->ready) /* DMA already in flight */
+ return;
+
+ /* If the wr_ptr has wrapped, only map to the end */
if (cnt < 0)
cnt = DMA_SIZE - dmabuf->rd_ptr;
- dmabuf->dma_handle = pci_map_single(ad1889_dev->pci, dmabuf->rawbuf,
- cnt, PCI_DMA_TODEVICE);
- dmabuf->dma_end = dmabuf->rd_ptr + cnt;
+
+ dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
+ dmabuf->rawbuf + dmabuf->rd_ptr,
+ cnt, PCI_DMA_TODEVICE);
+ dmabuf->dma_len = cnt;
dmabuf->ready = 1;
- spin_unlock_irqrestore(&state->card->lock, flags);
/* load up the current register set */
AD1889_WRITEL(ad1889_dev, AD_DMAWAVCC, cnt);
AD1889_WRITEL(ad1889_dev, AD_DMAWAVICC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMAWAVCA, dmabuf->dma_handle + dmabuf->rd_ptr);
+ AD1889_WRITEL(ad1889_dev, AD_DMAWAVCA, dmabuf->dma_handle);
/* TODO: for now we load the base registers with the same thing */
AD1889_WRITEL(ad1889_dev, AD_DMAWAVBC, cnt);
AD1889_WRITEL(ad1889_dev, AD_DMAWAVIBC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMAWAVBA, dmabuf->dma_handle + dmabuf->rd_ptr);
+ AD1889_WRITEL(ad1889_dev, AD_DMAWAVBA, dmabuf->dma_handle);
/* and we're off to the races... */
AD1889_WRITEL(ad1889_dev, AD_DMACHSS, 0x8);
tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
tmp |= 0x0400; /* set WAEN */
AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+ (void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+
+ dmabuf->enable |= DAC_RUNNING;
+
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
+
static void ad1889_stop_wav(ad1889_state_t *state)
{
- u16 tmp;
unsigned long flags;
+ struct dmabuf *dmabuf = &state->dmabuf;
+ u16 tmp;
spin_lock_irqsave(&state->card->lock, flags);
- tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
- state->dmabuf.enable &= ~DAC_RUNNING;
- tmp &= ~0x0400; /* clear WAEN */
- AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+ if (dmabuf->enable & DAC_RUNNING) {
+ tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+ tmp &= ~0x0400; /* clear WAEN */
+ AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+ (void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+
+ dmabuf->enable &= ~DAC_RUNNING;
+ }
+
+ if (dmabuf->ready) {
+ unsigned long cnt = dmabuf->dma_len;
+
+ /* update dma pointers */
+ dmabuf->rd_ptr += cnt;
+ dmabuf->rd_ptr &= (DMA_SIZE - 1);
+
+ pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle,
+ cnt, PCI_DMA_TODEVICE);
+ dmabuf->dma_handle = 0;
+ dmabuf->dma_len = 0;
+ dmabuf->ready = 0;
+ }
spin_unlock_irqrestore(&state->card->lock, flags);
}
+
+#if 0
static void ad1889_startstop_adc(ad1889_state_t *state, int start)
{
u16 tmp;
@@ -171,6 +207,7 @@ static void ad1889_startstop_adc(ad1889_
spin_unlock_irqrestore(&state->card->lock, flags);
}
+#endif
static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
{
@@ -190,13 +227,15 @@ static ad1889_dev_t *ad1889_alloc_dev(st
init_waitqueue_head(&dev->state[i].dmabuf.wait);
}
- /* allocate dma */
+ /* allocate dma buffer */
for (i = 0; i < AD_MAX_STATES; i++) {
dmabuf = &dev->state[i].dmabuf;
if ((dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA)) == NULL)
return NULL;
- dmabuf->bytes_left = DMA_SIZE;
+ dmabuf->rawbuf_size = DMA_SIZE;
+ dmabuf->dma_handle = 0;
+ dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
}
return dev;
@@ -222,7 +261,7 @@ static void ad1889_free_dev(ad1889_dev_t
kfree(dev);
}
-static void ad1889_trigger_playback(ad1889_dev_t *dev)
+static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
{
#if 0
u32 val;
@@ -311,10 +350,8 @@ int ad1889_read_proc (char *page, char *
(unsigned int)dev->state[i].dmabuf.rd_ptr);
out += sprintf(out, "\twrite ptr: offset %u\n",
(unsigned int)dev->state[i].dmabuf.wr_ptr);
- out += sprintf(out, "\tdma end: offset %u\n",
- (unsigned int)dev->state[i].dmabuf.dma_end);
- out += sprintf(out, "\tbytes left %u\n",
- (unsigned int)dev->state[i].dmabuf.bytes_left);
+ out += sprintf(out, "\tdma len: offset %u\n",
+ (unsigned int)dev->state[i].dmabuf.dma_len);
}
len = out - page - off;
@@ -399,21 +436,20 @@ static ssize_t ad1889_write(struct file
{
ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
ad1889_state_t *state = &dev->state[AD_WAV_STATE];
- struct dmabuf *dmabuf = &state->dmabuf;
+ volatile struct dmabuf *dmabuf = &state->dmabuf;
ssize_t ret;
- volatile int cnt, rem;
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
if (ppos != &file->f_pos)
return -ESPIPE;
down(&state->sem);
+#if 0
if (dmabuf->mapped) {
ret = -ENXIO;
goto out;
}
-
+#endif
if (!access_ok(VERIFY_READ, buffer, count)) {
ret = -EFAULT;
goto out;
@@ -424,10 +460,16 @@ static ssize_t ad1889_write(struct file
/* start filling dma buffer.... */
while (count > 0) {
- cnt = state->dmabuf.bytes_left;
- if (cnt <= 0) {
- /* underrun */
- /* start dma and hope it flushes things out */
+ int cnt = count;
+ unsigned int rem;
+ unsigned long flags;
+
+ /* check for full buffer first */
+ rem = (dmabuf->rd_ptr - dmabuf->wr_ptr) & (DMA_SIZE - 1);
+ if (1 == rem) {
+ /* dma buffer full.
+ ** start dma and hope it flushes things out
+ */
DBG("buffer full; trying to playback\n");
ad1889_trigger_playback(dev);
if (file->f_flags & O_NONBLOCK) {
@@ -443,52 +485,36 @@ static ssize_t ad1889_write(struct file
continue;
}
- if (cnt > count)
- cnt = count;
+ /* watch out for wrapping around static buffer */
+ rem = DMA_SIZE - dmabuf->wr_ptr;
+ if (cnt > rem)
+ cnt = rem;
/* ok, now everything's good to go, start the buffer xfer */
- DBG("Writing %d bytes to page at offset %lu\n",
+ DBG("Writing 0x%x bytes to +0x%lx\n",
cnt, dmabuf->wr_ptr);
- rem = DMA_SIZE - dmabuf->wr_ptr;
- if (cnt > rem) {
- /* wraparound, transfer first bit */
- if (copy_from_user(dmabuf->rawbuf +
- dmabuf->wr_ptr, buffer, rem)) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- cnt -= rem;
-
- count -= rem;
- buffer += rem;
- ret += rem;
- state->dmabuf.bytes_left -= rem;
-
- dmabuf->wr_ptr = 0;
- }
- /* transfer second (or whole, unwrapped) chunk */
+ /* transfer unwrapped chunk */
if (copy_from_user(dmabuf->rawbuf + dmabuf->wr_ptr, buffer, cnt)) {
if (!ret) ret = -EFAULT;
break;
}
- state->dmabuf.bytes_left -= cnt;
+
+ /* update counters */
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
/* update dma pointers */
spin_lock_irqsave(&state->card->lock, flags);
dmabuf->wr_ptr += cnt;
+ dmabuf->wr_ptr &= DMA_SIZE - 1; /* wrap ptr if necessary */
spin_unlock_irqrestore(&state->card->lock, flags);
- /* update counters */
- count -= cnt;
- buffer += cnt;
- ret += cnt;
+ /* we have something to play - go play it! */
+ ad1889_trigger_playback(dev);
}
- /* XXX: may cause clicks... */
- ad1889_trigger_playback(dev);
-
out:
up(&state->sem);
remove_wait_queue(&state->dmabuf.wait, &wait);
@@ -827,30 +853,39 @@ static int ad1889_aclink_reset(struct pc
AD1889_WRITEW(dev, AD_DSCCS, 0x8000); /* turn on clock */
AD1889_READW(dev, AD_DSCCS);
- WAIT_10MS(); /* sigh */
+ WAIT_10MS();
stat = AD1889_READW(dev, AD_ACIC);
- stat = stat | 0x0002; /* reset disable */
+ stat |= 0x0002; /* Reset Disable */
AD1889_WRITEW(dev, AD_ACIC, stat);
- AD1889_READW(dev, AD_ACIC);
+ (void) AD1889_READW(dev, AD_ACIC); /* flush posted write */
- WAIT_10MS();
+ udelay(10);
stat = AD1889_READW(dev, AD_ACIC);
- stat = stat | 0x0001; /* codec enable */
+ stat |= 0x0001; /* Interface Enable */
AD1889_WRITEW(dev, AD_ACIC, stat);
do {
- stat = AD1889_READW(dev, AD_ACIC);
- if ((AD1889_READW(dev, AD_ACIC) & 0x8000) != 0)
- return 0;
+ if (AD1889_READW(dev, AD_ACIC) & 0x8000) /* Ready */
+ break;
WAIT_10MS();
retry--;
} while (retry > 0);
-
- printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
- AD1889_READW(dev, AD_ACIC));
- return -EBUSY;
+
+ if (!retry) {
+ printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
+ AD1889_READW(dev, AD_ACIC));
+ return -EBUSY;
+ }
+
+ /* TODO reset AC97 codec */
+ /* TODO set wave/adc pci ctrl status */
+
+ stat = AD1889_READW(dev, AD_ACIC);
+ stat |= 0x0004; /* Audio Stream Output Enable */
+ AD1889_WRITEW(dev, AD_ACIC, stat);
+ return 0;
}
/************************* PCI interfaces ****************************** */
@@ -866,7 +901,6 @@ static void ad1889_interrupt(int irq, vo
{
u32 stat;
ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
- struct dmabuf *dmabuf;
stat = AD1889_READL(dev, AD_DMADISR);
DBG("In %s; stat = 0x%x\n", __FUNCTION__, stat);
@@ -878,18 +912,8 @@ static void ad1889_interrupt(int irq, vo
DBG("WAV interrupt\n");
dev->stats.wav_intrs++;
- /* update dma pointers */
- dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
-
- dmabuf->ready = 0;
- dmabuf->bytes_left += (dmabuf->dma_end - dmabuf->rd_ptr);
- dmabuf->rd_ptr = dmabuf->dma_end % DMA_SIZE;
-
- ad1889_stop_wav(&dev->state[AD_WAV_STATE]);
-
- pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle,
- dmabuf->dma_end - dmabuf->rd_ptr, PCI_DMA_TODEVICE);
- dmabuf->dma_handle = 0;
+ ad1889_stop_wav(&dev->state[AD_WAV_STATE]); /* clean up */
+ ad1889_start_wav(&dev->state[AD_WAV_STATE]); /* start new */
}
if (stat & 0x2 && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
Index: ad1889.h
===================================================================
RCS file: /var/cvs/linux/drivers/sound/ad1889.h,v
retrieving revision 1.1
diff -u -p -r1.1 ad1889.h
--- ad1889.h 21 Jul 2002 01:54:00 -0000 1.1
+++ ad1889.h 16 Oct 2002 04:13:22 -0000
@@ -82,14 +82,13 @@ typedef struct ad1889_state {
unsigned char fmt, enable;
/* buf management */
+ size_t rawbuf_size;
void *rawbuf;
- dma_addr_t dma_handle;
- u8 dma_flags;
- unsigned int bytes_left;
+ dma_addr_t dma_handle; /* mapped address */
+ unsigned long dma_len; /* number of bytes mapped */
- /* buffer ptrs */
- unsigned long rd_ptr, wr_ptr;
- unsigned long dma_end;
+ /* indexes into rawbuf for setting up DMA engine */
+ volatile unsigned long rd_ptr, wr_ptr;
wait_queue_head_t wait; /* to wait for buf servicing */