shithub: riscv

Download patch

ref: 42cd9d946fa0da422c16edbb85c9c29e0a2f2437
parent: c266a31572cdd704a5f9e9092e9447106e19d92c
author: cinap_lenrek <cinap_lenrek@localhost>
date: Fri May 27 09:58:55 EDT 2011

ac97: fix buffering code, games/doom: enable sound

--- a/sys/src/9/pc/audioac97.c
+++ b/sys/src/9/pc/audioac97.c
@@ -7,6 +7,7 @@
 #include "../port/error.h"
 #include "../port/audioif.h"
 
+typedef struct Ring Ring;
 typedef struct Hwdesc Hwdesc;
 typedef struct Ctlr Ctlr;
 
@@ -22,12 +23,23 @@
 
 enum {
 	Ndesc = 32,
-	Nts = 33,
 	Bufsize = 32768,	/* bytes, must be divisible by ndesc */
+	Blocksize = Bufsize/Ndesc,
 	Maxbusywait = 500000, /* microseconds, roughly */
 	BytesPerSample = 4,
 };
 
+struct Ring
+{
+	Rendez r;
+
+	uchar	*buf;
+	ulong	nbuf;
+
+	ulong	ri;
+	ulong	wi;
+};
+
 struct Ctlr {
 	/* keep these first, they want to be 8-aligned */
 	Hwdesc indesc[Ndesc];
@@ -35,37 +47,12 @@
 	Hwdesc micdesc[Ndesc];
 
 	Lock;
-	Rendez outr;
 
 	ulong port;
 	ulong mixport;
 
-	char *out;
-	char *in;
-	char *mic;
+	Ring inring, micring, outring;
 
-	char *outp;
-	char *inp;
-	char *micp;
-
-	/* shared variables, ilock to access */
-	int outavail;
-	int inavail;
-	int micavail;
-
-	/* interrupt handler alone */
-	int outciv;
-	int inciv;
-	int micciv;
-
-	int tsouti;
-	uvlong tsoutp;
-	ulong tsout[Nts];
-	int tsoutb[Nts];
-
-	ulong civstat[Ndesc];
-	ulong lvistat[Ndesc];
-
 	int sis7012;
 
 	/* for probe */
@@ -134,6 +121,76 @@
 		Casp = 1<<0,	/* set to 1 on read if zero, cleared by hardware */
 };
 
+static long
+buffered(Ring *r)
+{
+	ulong ri, wi;
+
+	ri = r->ri;
+	wi = r->wi;
+	if(wi >= ri)
+		return wi - ri;
+	else
+		return r->nbuf - (ri - wi);
+}
+
+static long
+available(Ring *r)
+{
+	long m;
+
+	m = (r->nbuf - 1) - buffered(r);
+	if(m < 0)
+		m = 0;
+	return m;
+}
+
+static long
+readring(Ring *r, uchar *p, long n)
+{
+	long n0, m;
+
+	n0 = n;
+	while(n > 0){
+		if((m = buffered(r)) <= 0)
+			break;
+		if(m > n)
+			m = n;
+		if(p){
+			if(r->ri + m > r->nbuf)
+				m = r->nbuf - r->ri;
+			memmove(p, r->buf + r->ri, m);
+			p += m;
+		}
+		r->ri = (r->ri + m) % r->nbuf;
+		n -= m;
+	}
+	return n0 - n;
+}
+
+static long
+writering(Ring *r, uchar *p, long n)
+{
+	long n0, m;
+
+	n0 = n;
+	while(n > 0){
+		if((m = available(r)) <= 0)
+			break;
+		if(m > n)
+			m = n;
+		if(p){
+			if(r->wi + m > r->nbuf)
+				m = r->nbuf - r->wi;
+			memmove(r->buf + r->wi, p, m);
+			p += m;
+		}
+		r->wi = (r->wi + m) % r->nbuf;
+		n -= m;
+	}
+	return n0 - n;
+}
+
 #define csr8r(c, r)	(inb((c)->port+(r)))
 #define csr16r(c, r)	(ins((c)->port+(r)))
 #define csr32r(c, r)	(inl((c)->port+(r)))
@@ -179,22 +236,13 @@
 	return ins(ctlr->mixport+port);
 }
 
-static int
-outavail(void *arg)
-{
-	Ctlr *ctlr;
-	ctlr = arg;
-	return ctlr->outavail > 0;
-}
-
 static void
 ac97interrupt(Ureg *, void *arg)
 {
 	Audio *adev;
 	Ctlr *ctlr;
-	int civ, n, i;
+	Ring *ring;
 	ulong stat;
-	uvlong now;
 
 	adev = arg;
 	ctlr = adev->ctlr;
@@ -206,28 +254,11 @@
 			csr16w(ctlr, Out + Picb, csr16r(ctlr, Out + Picb) & ~Dch);
 		else
 			csr16w(ctlr, Out + Sr, csr16r(ctlr, Out + Sr) & ~Dch);
-		
-		civ = csr8r(ctlr, Out + Civ);
-		n = 0;
-		while(ctlr->outciv != civ){
-			ctlr->civstat[ctlr->outciv++]++;
-			if(ctlr->outciv == Ndesc)
-				ctlr->outciv = 0;
-			n += Bufsize/Ndesc;
-		}
-
-		now = fastticks(0);
-		i = ctlr->tsouti;
-		ctlr->tsoutb[i] = n;
-		ctlr->tsout[i] = now - ctlr->tsoutp;
-		ctlr->tsouti = (i + 1) % Nts;
-		ctlr->tsoutp = now;
-		ctlr->outavail += n;
-		
-		if(ctlr->outavail > Bufsize/2)
-			wakeup(&ctlr->outr);
-		stat &= ~Point;	
+		ring = &ctlr->outring;
+		ring->ri = csr8r(ctlr, Out + Civ) * Blocksize;
 		iunlock(ctlr);
+		wakeup(&ring->r);
+		stat &= ~Point;	
 	}
 	if(stat) /* have seen 0x400, which is sdin0 resume */
 		iprint("#A%d: ac97 unhandled interrupt(s): stat 0x%lux\n",
@@ -234,72 +265,12 @@
 			adev->ctlrno, stat);
 }
 
-static int
-off2lvi(char *base, char *p)
-{
-	int lvi;
-	lvi = p - base;
-	return lvi / (Bufsize/Ndesc);
-}
-
 static long
-ac97medianoutrate(Audio *adev)
-{
-	ulong ts[Nts], t;
-	uvlong hz;
-	int i, j;
-	Ctlr *ctlr;
-	ctlr = adev->ctlr;
-	fastticks(&hz);
-	for(i = 0; i < Nts; i++)
-		if(ctlr->tsout[i] > 0)
-			ts[i] = (ctlr->tsoutb[i] * hz) / ctlr->tsout[i];
-		else
-			ts[i] = 0;
-	for(i = 1; i < Nts; i++){
-		t = ts[i];
-		j = i;
-		while(j > 0 && ts[j-1] > t){
-			ts[j] = ts[j-1];
-			j--;
-		}
-		ts[j] = t;
-	}
-	return ts[Nts/2] / BytesPerSample;
-}
-
-static long
-ac97status(Audio *adev, void *a, long n, vlong)
-{
-	char *p, *e;
-	Ctlr *ctlr;
-	int i;
-
-	ctlr = adev->ctlr;
-
-	p = a;
-	e = p + n;
-
-	p += snprint(p, e - p, "median rate %lud\n", ac97medianoutrate(adev));
-	p += snprint(p, e - p, "civ stats");
-	for(i = 0; i < Ndesc; i++)
-		p += snprint(p, e - p, " %lud", ctlr->civstat[i]);
-	p += snprint(p, e - p, "\n");
-
-	p += snprint(p, e - p, "lvi stats");
-	for(i = 0; i < Ndesc; i++)
-		p += snprint(p, e - p, " %lud", ctlr->lvistat[i]);
-	p += snprint(p, e - p, "\n");
-
-	return p - (char*)a;
-}
-
-static long
 ac97buffered(Audio *adev)
 {
 	Ctlr *ctlr;
 	ctlr = adev->ctlr;
-	return Bufsize - Bufsize/Ndesc - ctlr->outavail;
+	return buffered(&ctlr->outring);
 }
 
 static void
@@ -308,58 +279,41 @@
 	csr8w(ctlr, reg+Cr, Ioce | Rpbm);
 }
 
+static int
+outavail(void *arg)
+{
+	Ctlr *ctlr = arg;
+	return available(&ctlr->outring);
+}
+
 static long
-ac97write(Audio *adev, void *a, long nwr, vlong)
+ac97write(Audio *adev, void *vp, long n, vlong)
 {
+	uchar *p, *e;
 	Ctlr *ctlr;
-	char *p, *sp, *ep;
-	int len, lvi, olvi;
-	int t;
-	long n;
+	Ring *ring;
+	ulong oi, ni;
 
+	p = vp;
+	e = p + n;
 	ctlr = adev->ctlr;
-	ilock(ctlr);
-	p = ctlr->outp;
-	sp = a;
-	ep = ctlr->out + Bufsize;
-	olvi = off2lvi(ctlr->out, p);
-	n = nwr;
-	while(n > 0){
-		len = ep - p;
-		if(ctlr->outavail < len)
-			len = ctlr->outavail;
-		if(n < len)
-			len = n;
-		ctlr->outavail -= len;
-		iunlock(ctlr);
-		memmove(p, sp, len);
-		ilock(ctlr);
-		p += len;
-		sp += len;
-		n -= len;
-		if(p == ep)
-			p = ctlr->out;
-		lvi = off2lvi(ctlr->out, p);
-		if(olvi != lvi){
-			t = olvi;
-			while(t != lvi){
-				t = (t + 1) % Ndesc;
-				ctlr->lvistat[t]++;
-				csr8w(ctlr, Out+Lvi, t);
-				ac97kick(ctlr, Out);
-			}
-			olvi = lvi;
+	ring = &ctlr->outring;
+	while(p < e) {
+		oi = ring->wi / Blocksize;
+		if((n = writering(ring, p, e - p)) <= 0){
+			sleep(&ring->r, outavail, ctlr);
+			continue;
 		}
-		if(ctlr->outavail == 0){
-			ctlr->outp = p;
-			iunlock(ctlr);
-			sleep(&ctlr->outr, outavail, ctlr);
-			ilock(ctlr);
+		ni = ring->wi / Blocksize;
+		while(oi != ni){
+			csr8w(ctlr, Out+Lvi, oi);
+			ac97kick(ctlr, Out);
+			oi = (oi + 1) % Ndesc;
 		}
+		p += n;
 	}
-	ctlr->outp = p;
-	iunlock(ctlr);
-	return nwr;
+
+	return p - (uchar*)vp;
 }
 
 static Pcidev*
@@ -455,29 +409,36 @@
 	pcisetbme(p);
 	pcisetioe(p);
 
-	ctlr->mic = xspanalloc(Bufsize, 8, 0);
-	ctlr->in = xspanalloc(Bufsize, 8, 0);
-	ctlr->out = xspanalloc(Bufsize, 8, 0);
+	ctlr->micring.buf = xspanalloc(Bufsize, 8, 0);
+	ctlr->micring.nbuf = Bufsize;
+	ctlr->micring.ri = 0;
+	ctlr->micring.wi = 0;
 
+	ctlr->inring.buf = xspanalloc(Bufsize, 8, 0);
+	ctlr->inring.nbuf = Bufsize;
+	ctlr->inring.ri = 0;
+	ctlr->inring.wi = 0;
+
+	ctlr->outring.buf = xspanalloc(Bufsize, 8, 0);
+	ctlr->outring.nbuf = Bufsize;
+	ctlr->outring.ri = 0;
+	ctlr->outring.wi = 0;
+
 	for(i = 0; i < Ndesc; i++){
-		int size, off = i * (Bufsize/Ndesc);
+		int size, off = i * Blocksize;
 		
 		if(ctlr->sis7012)
-			size = (Bufsize/Ndesc);
+			size = Blocksize;
 		else
-			size = (Bufsize/Ndesc) / 2;
-		
-		ctlr->micdesc[i].addr = PCIWADDR(ctlr->mic + off);
+			size = Blocksize / 2;
+		ctlr->micdesc[i].addr = PCIWADDR(ctlr->micring.buf + off);
 		ctlr->micdesc[i].size = Ioc | size;
-		ctlr->indesc[i].addr = PCIWADDR(ctlr->in + off);
+		ctlr->indesc[i].addr = PCIWADDR(ctlr->inring.buf + off);
 		ctlr->indesc[i].size = Ioc | size;
-		ctlr->outdesc[i].addr = PCIWADDR(ctlr->out + off);
+		ctlr->outdesc[i].addr = PCIWADDR(ctlr->outring.buf + off);
 		ctlr->outdesc[i].size = Ioc | size;
 	}
 
-	ctlr->outavail = Bufsize - Bufsize/Ndesc;
-	ctlr->outp = ctlr->out;
-
 	ctl = csr32r(ctlr, Cnt);
 	ctl &= ~(EnaRESER | Aclso);
 
@@ -527,7 +488,6 @@
 	ac97mixreset(adev, ac97mixw, ac97mixr);
 
 	adev->write = ac97write;
-	adev->status = ac97status;
 	adev->buffered = ac97buffered;
 
 	intrenable(irq, ac97interrupt, adev, tbdf, adev->name);
--- a/sys/src/games/doom/i_system.c
+++ b/sys/src/games/doom/i_system.c
@@ -15,7 +15,7 @@
 
 void I_Init (void)
 {
-	// I_InitSound();
+	I_InitSound();
 	I_InitGraphics();
 }