[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 */