ref: b74418c2ce5c64ba39473e2eb50ea1112be63109
parent: e7e04b5cbbedfb1411fcc38b7e7f67db98a251c2
author: cinap_lenrek <cinap_lenrek@localhost>
date: Wed May 18 15:57:31 EDT 2011
sb16: new approach, works in qemu
--- a/sys/src/9/pc/audiosb16.c
+++ b/sys/src/9/pc/audiosb16.c
@@ -9,8 +9,9 @@
#include "io.h"
#include "../port/error.h"
-typedef struct AQueue AQueue;
-typedef struct Buf Buf;
+typedef struct Ring Ring;
+typedef struct Blaster Blaster;
+typedef struct Ctlr Ctlr;
enum
{
@@ -31,40 +32,44 @@
Speed = 44100,
Ncmd = 50, /* max volume command words */
-};
-enum
-{
- Bufsize = 1024, /* 5.8 ms each, must be power of two */
- Nbuf = 128, /* .74 seconds total */
- SBswab = 0,
+ Blocksize = 4096,
+ Blocks = 65536/Blocksize,
};
-#define CACHELINESZ 8
-#define UNCACHED(type, v) (type*)((ulong)(v))
-
-struct Buf
+struct Ring
{
- uchar* virt;
- ulong phys;
- Buf* next;
+ uchar *buf;
+ ulong nbuf;
+
+ ulong ri;
+ ulong wi;
};
-struct AQueue
+struct Blaster
{
Lock;
- Buf* first;
- Buf* last;
+ int reset; /* io ports to the sound blaster */
+ int read;
+ int write;
+ int wstatus;
+ int rstatus;
+ int mixaddr;
+ int mixdata;
+ int clri8;
+ int clri16;
+ int clri401;
+ int dma;
+
+ void (*startdma)(Ctlr*);
+ void (*intr)(Ctlr*);
};
-static struct
+struct Ctlr
{
QLock;
Rendez vous;
- int buffered; /* number of bytes en route */
- int curcount; /* how much data in current buffer */
int active; /* boolean dma running */
- int intr; /* boolean an interrupt has happened */
int rivol[Nvol]; /* right/left input/output volumes */
int livol[Nvol];
int rovol[Nvol];
@@ -73,134 +78,172 @@
int minor; /* SB16 minor version number */
ulong totcount; /* how many bytes processed since open */
vlong tottime; /* time at which totcount bytes were processed */
+ Ring ring; /* dma ring buffer */
+ Blaster blaster;
+ Audio *adev;
+};
- Buf buf[Nbuf]; /* buffers and queues */
- AQueue empty;
- AQueue full;
- Buf* current;
- Buf* filling;
-
- int probed;
- int ctlrno;
-} audio;
-
-static struct
+static struct
{
char* name;
int flag;
int ilval; /* initial values */
int irval;
-} volumes[] =
-{
-[Vaudio] "audio", Fout, 50, 50,
-[Vsynth] "synth", Fin|Fout, 0, 0,
-[Vcd] "cd", Fin|Fout, 0, 0,
-[Vline] "line", Fin|Fout, 0, 0,
-[Vmic] "mic", Fin|Fout|Fmono, 0, 0,
-[Vspeaker] "speaker", Fout|Fmono, 0, 0,
+} volumes[] = {
+ [Vaudio] "audio", Fout, 50, 50,
+ [Vsynth] "synth", Fin|Fout, 0, 0,
+ [Vcd] "cd", Fin|Fout, 0, 0,
+ [Vline] "line", Fin|Fout, 0, 0,
+ [Vmic] "mic", Fin|Fout|Fmono, 0, 0,
+ [Vspeaker] "speaker", Fout|Fmono, 0, 0,
-[Vtreb] "treb", Fout, 50, 50,
-[Vbass] "bass", Fout, 50, 50,
+ [Vtreb] "treb", Fout, 50, 50,
+ [Vbass] "bass", Fout, 50, 50,
-[Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed,
- 0
+ [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed,
+ 0
};
-static struct
+static char Emajor[] = "soundblaster not responding/wrong version";
+static char Emode[] = "illegal open mode";
+static char Evolume[] = "illegal volume specifier";
+
+
+static long
+buffered(Ring *r)
{
- Lock;
- int reset; /* io ports to the sound blaster */
- int read;
- int write;
- int wstatus;
- int rstatus;
- int mixaddr;
- int mixdata;
- int clri8;
- int clri16;
- int clri401;
- int dma;
+ ulong ri, wi;
- void (*startdma)(void);
- void (*intr)(void);
-} blaster;
+ ri = r->ri;
+ wi = r->wi;
+ if(wi >= ri)
+ return wi - ri;
+ else
+ return r->nbuf - (ri - wi);
+}
-static void swab(uchar*);
+static long
+available(Ring *r)
+{
+ long m;
-static char Emajor[] = "soundblaster not responding/wrong version";
-static char Emode[] = "illegal open mode";
-static char Evolume[] = "illegal volume specifier";
+ 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;
+}
+
static int
-sbcmd(int val)
+sbcmd(Blaster *blaster, int val)
{
int i, s;
for(i=1<<16; i!=0; i--) {
- s = inb(blaster.wstatus);
+ s = inb(blaster->wstatus);
if((s & 0x80) == 0) {
- outb(blaster.write, val);
+ outb(blaster->write, val);
return 0;
}
}
- print("#A%d: sbcmd (%#.2x) timeout\n", audio.ctlrno, val); /**/
return 1;
}
static int
-sbread(void)
+sbread(Blaster *blaster)
{
int i, s;
for(i=1<<16; i!=0; i--) {
- s = inb(blaster.rstatus);
+ s = inb(blaster->rstatus);
if((s & 0x80) != 0) {
- return inb(blaster.read);
+ return inb(blaster->read);
}
}
- print("#A%d: sbread did not respond\n", audio.ctlrno); /**/
return -1;
}
static int
-ess1688w(int reg, int val)
+ess1688w(Blaster *blaster, int reg, int val)
{
- if(sbcmd(reg) || sbcmd(val))
+ if(sbcmd(blaster, reg) || sbcmd(blaster, val))
return 1;
-
return 0;
}
static int
-ess1688r(int reg)
+ess1688r(Blaster *blaster, int reg)
{
- if(sbcmd(0xC0) || sbcmd(reg))
+ if(sbcmd(blaster, 0xC0) || sbcmd(blaster, reg))
return -1;
-
- return sbread();
+ return sbread(blaster);
}
static int
-mxcmd(int addr, int val)
+mxcmd(Blaster *blaster, int addr, int val)
{
-
- outb(blaster.mixaddr, addr);
- outb(blaster.mixdata, val);
+ outb(blaster->mixaddr, addr);
+ outb(blaster->mixdata, val);
return 1;
}
static int
-mxread(int addr)
+mxread(Blaster *blaster, int addr)
{
int s;
- outb(blaster.mixaddr, addr);
- s = inb(blaster.mixdata);
+ outb(blaster->mixaddr, addr);
+ s = inb(blaster->mixdata);
return s;
}
static void
-mxcmds(int s, int v)
+mxcmds(Blaster *blaster, int s, int v)
{
if(v > 100)
@@ -207,23 +250,23 @@
v = 100;
if(v < 0)
v = 0;
- mxcmd(s, (v*255)/100);
+ mxcmd(blaster, s, (v*255)/100);
}
static void
-mxcmdt(int s, int v)
+mxcmdt(Blaster *blaster, int s, int v)
{
if(v > 100)
v = 100;
if(v <= 0)
- mxcmd(s, 0);
+ mxcmd(blaster, s, 0);
else
- mxcmd(s, 255-100+v);
+ mxcmd(blaster, s, 255-100+v);
}
static void
-mxcmdu(int s, int v)
+mxcmdu(Blaster *blaster, int s, int v)
{
if(v > 100)
@@ -230,53 +273,56 @@
v = 100;
if(v <= 0)
v = 0;
- mxcmd(s, 128-50+v);
+ mxcmd(blaster, s, 128-50+v);
}
static void
-mxvolume(void)
+mxvolume(Ctlr *ctlr)
{
+ Blaster *blaster;
int *left, *right;
int source;
if(0){
- left = audio.livol;
- right = audio.rivol;
+ left = ctlr->livol;
+ right = ctlr->rivol;
}else{
- left = audio.lovol;
- right = audio.rovol;
+ left = ctlr->lovol;
+ right = ctlr->rovol;
}
- ilock(&blaster);
+ blaster = &ctlr->blaster;
- mxcmd(0x30, 255); /* left master */
- mxcmd(0x31, 255); /* right master */
- mxcmd(0x3f, 0); /* left igain */
- mxcmd(0x40, 0); /* right igain */
- mxcmd(0x41, 0); /* left ogain */
- mxcmd(0x42, 0); /* right ogain */
+ ilock(blaster);
- mxcmds(0x32, left[Vaudio]);
- mxcmds(0x33, right[Vaudio]);
+ mxcmd(blaster, 0x30, 255); /* left master */
+ mxcmd(blaster, 0x31, 255); /* right master */
+ mxcmd(blaster, 0x3f, 0); /* left igain */
+ mxcmd(blaster, 0x40, 0); /* right igain */
+ mxcmd(blaster, 0x41, 0); /* left ogain */
+ mxcmd(blaster, 0x42, 0); /* right ogain */
- mxcmds(0x34, left[Vsynth]);
- mxcmds(0x35, right[Vsynth]);
+ mxcmds(blaster, 0x32, left[Vaudio]);
+ mxcmds(blaster, 0x33, right[Vaudio]);
- mxcmds(0x36, left[Vcd]);
- mxcmds(0x37, right[Vcd]);
+ mxcmds(blaster, 0x34, left[Vsynth]);
+ mxcmds(blaster, 0x35, right[Vsynth]);
- mxcmds(0x38, left[Vline]);
- mxcmds(0x39, right[Vline]);
+ mxcmds(blaster, 0x36, left[Vcd]);
+ mxcmds(blaster, 0x37, right[Vcd]);
- mxcmds(0x3a, left[Vmic]);
- mxcmds(0x3b, left[Vspeaker]);
+ mxcmds(blaster, 0x38, left[Vline]);
+ mxcmds(blaster, 0x39, right[Vline]);
- mxcmdu(0x44, left[Vtreb]);
- mxcmdu(0x45, right[Vtreb]);
+ mxcmds(blaster, 0x3a, left[Vmic]);
+ mxcmds(blaster, 0x3b, left[Vspeaker]);
- mxcmdu(0x46, left[Vbass]);
- mxcmdu(0x47, right[Vbass]);
+ mxcmdu(blaster, 0x44, left[Vtreb]);
+ mxcmdu(blaster, 0x45, right[Vtreb]);
+ mxcmdu(blaster, 0x46, left[Vbass]);
+ mxcmdu(blaster, 0x47, right[Vbass]);
+
source = 0;
if(left[Vsynth])
source |= 1<<6;
@@ -293,85 +339,34 @@
if(left[Vmic])
source |= 1<<0;
if(0)
- mxcmd(0x3c, 0); /* output switch */
+ mxcmd(blaster, 0x3c, 0); /* output switch */
else
- mxcmd(0x3c, source);
- mxcmd(0x3d, source); /* input left switch */
- mxcmd(0x3e, source); /* input right switch */
- iunlock(&blaster);
+ mxcmd(blaster, 0x3c, source);
+ mxcmd(blaster, 0x3d, source); /* input left switch */
+ mxcmd(blaster, 0x3e, source); /* input right switch */
+ iunlock(blaster);
}
-static Buf*
-getbuf(AQueue *q)
-{
- Buf *b;
-
- ilock(q);
- b = q->first;
- if(b)
- q->first = b->next;
- iunlock(q);
-
- return b;
-}
-
static void
-putbuf(AQueue *q, Buf *b)
+contindma(Ctlr *ctlr)
{
+ Blaster *blaster;
+ Ring *ring;
- ilock(q);
- b->next = 0;
- if(q->first)
- q->last->next = b;
- else
- q->first = b;
- q->last = b;
- iunlock(q);
-}
+ blaster = &ctlr->blaster;
+ ring = &ctlr->ring;
+ if(buffered(ring) >= Blocksize){
+ ring->ri = ring->nbuf - dmacount(blaster->dma);
-/*
- * move the dma to the next buffer
- */
-static void
-contindma(void)
-{
- Buf *b;
-
- if(!audio.active)
- goto shutdown;
-
- b = audio.current;
- if(b){
- audio.totcount += Bufsize;
- audio.tottime = todget(nil);
+ ctlr->totcount += Blocksize;
+ ctlr->tottime = todget(nil);
+ }else{
+ dmaend(blaster->dma);
+ sbcmd(blaster, 0xd9); /* exit at end of count */
+ sbcmd(blaster, 0xd5); /* pause */
+ ctlr->active = 0;
}
- if(0) {
- if(b){
- putbuf(&audio.full, b);
- audio.buffered += Bufsize;
- }
- b = getbuf(&audio.empty);
- } else {
- if(b){
- putbuf(&audio.empty, b);
- audio.buffered -= Bufsize;
- }
- b = getbuf(&audio.full);
- }
- audio.current = b;
- if(b == 0)
- goto shutdown;
- if(dmasetup(blaster.dma, b->virt, Bufsize, 0) >= 0)
- return;
- print("#A%d: dmasetup fail\n", audio.ctlrno);
- putbuf(&audio.empty, b);
-
-shutdown:
- dmaend(blaster.dma);
- sbcmd(0xd9); /* exit at end of count */
- sbcmd(0xd5); /* pause */
- audio.curcount = 0;
- audio.active = 0;
+ wakeup(&ctlr->vous);
}
/*
@@ -379,60 +374,64 @@
* start first dma
*/
static void
-sb16startdma(void)
+sb16startdma(Ctlr *ctlr)
{
- ulong count;
+ Blaster *blaster;
+ Ring *ring;
+ long count;
int speed;
- ilock(&blaster);
- dmaend(blaster.dma);
+ blaster = &ctlr->blaster;
+ ring = &ctlr->ring;
+ ilock(blaster);
+ dmaend(blaster->dma);
if(0) {
- sbcmd(0x42); /* input sampling rate */
- speed = audio.livol[Vspeed];
+ sbcmd(blaster, 0x42); /* input sampling rate */
+ speed = ctlr->livol[Vspeed];
} else {
- sbcmd(0x41); /* output sampling rate */
- speed = audio.lovol[Vspeed];
+ sbcmd(blaster, 0x41); /* output sampling rate */
+ speed = ctlr->lovol[Vspeed];
}
- sbcmd(speed>>8);
- sbcmd(speed);
+ sbcmd(blaster, speed>>8);
+ sbcmd(blaster, speed);
if(0)
- sbcmd(0xbe); /* A/D, autoinit */
+ sbcmd(blaster, 0xbe); /* A/D, autoinit */
else
- sbcmd(0xb6); /* D/A, autoinit */
- sbcmd(0x30); /* stereo, signed 16 bit */
+ sbcmd(blaster, 0xb6); /* D/A, autoinit */
- /*
- * not really sure if this is correct, but
- * it works in bochs
- */
- count = (Bufsize >> 2) - 1;
- sbcmd(count);
- sbcmd(count>>8);
+ sbcmd(blaster, 0x30); /* stereo, signed 16 bit */
- audio.active = 1;
- contindma();
- iunlock(&blaster);
+ count = (Blocksize>>1) - 1;
+ sbcmd(blaster, count);
+ sbcmd(blaster, count>>8);
+
+ ctlr->active = 1;
+ if(dmasetup(blaster->dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
+ ctlr->active = 0;
+ print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
+ }
+ iunlock(blaster);
}
static int
-ess1688reset(void)
+ess1688reset(Blaster *blaster, int ctlrno)
{
int i;
- outb(blaster.reset, 3);
+ outb(blaster->reset, 3);
delay(1); /* >3 υs */
- outb(blaster.reset, 0);
+ outb(blaster->reset, 0);
delay(1);
- i = sbread();
+ i = sbread(blaster);
if(i != 0xAA) {
- print("#A%d: no response %#.2x\n", audio.ctlrno, i);
+ print("#A%d: no response %#.2x\n", ctlrno, i);
return 1;
}
- if(sbcmd(0xC6)){ /* extended mode */
- print("#A%d: barf 3\n", audio.ctlrno);
+ if(sbcmd(blaster, 0xC6)){ /* extended mode */
+ print("#A%d: barf 3\n", ctlrno);
return 1;
}
@@ -440,23 +439,28 @@
}
static void
-ess1688startdma(void)
+ess1688startdma(Ctlr *ctlr)
{
+ Blaster *blaster;
+ Ring *ring;
ulong count;
int speed, x;
- ilock(&blaster);
- dmaend(blaster.dma);
+ blaster = &ctlr->blaster;
+ ring = &ctlr->ring;
- ess1688reset();
+ ilock(blaster);
+ dmaend(blaster->dma);
+ ess1688reset(blaster, ctlr->adev->ctlrno);
+
/*
* Set the speed.
*/
if(0)
- speed = audio.livol[Vspeed];
+ speed = ctlr->livol[Vspeed];
else
- speed = audio.lovol[Vspeed];
+ speed = ctlr->lovol[Vspeed];
if(speed < 4000)
speed = 4000;
else if(speed > 48000)
@@ -466,308 +470,211 @@
x = 0x80|(256-(795500+speed/2)/speed);
else
x = 128-(397700+speed/2)/speed;
- ess1688w(0xA1, x & 0xFF);
+ ess1688w(blaster, 0xA1, x & 0xFF);
speed = (speed * 9) / 20;
x = 256 - 7160000 / (speed * 82);
- ess1688w(0xA2, x & 0xFF);
+ ess1688w(blaster, 0xA2, x & 0xFF);
if(0)
- ess1688w(0xB8, 0x0E); /* A/D, autoinit */
+ ess1688w(blaster, 0xB8, 0x0E); /* A/D, autoinit */
else
- ess1688w(0xB8, 0x04); /* D/A, autoinit */
- x = ess1688r(0xA8) & ~0x03;
- ess1688w(0xA8, x|0x01); /* 2 channels */
- ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */
+ ess1688w(blaster, 0xB8, 0x04); /* D/A, autoinit */
+ x = ess1688r(blaster, 0xA8) & ~0x03;
+ ess1688w(blaster, 0xA8, x|0x01); /* 2 channels */
+ ess1688w(blaster, 0xB9, 2); /* demand mode, 4 bytes per request */
if(1)
- ess1688w(0xB6, 0); /* for output */
+ ess1688w(blaster, 0xB6, 0); /* for output */
- ess1688w(0xB7, 0x71);
- ess1688w(0xB7, 0xBC);
+ ess1688w(blaster, 0xB7, 0x71);
+ ess1688w(blaster, 0xB7, 0xBC);
- x = ess1688r(0xB1) & 0x0F;
- ess1688w(0xB1, x|0x50);
- x = ess1688r(0xB2) & 0x0F;
- ess1688w(0xB2, x|0x50);
+ x = ess1688r(blaster, 0xB1) & 0x0F;
+ ess1688w(blaster, 0xB1, x|0x50);
+ x = ess1688r(blaster, 0xB2) & 0x0F;
+ ess1688w(blaster, 0xB2, x|0x50);
if(1)
- sbcmd(0xD1); /* speaker on */
+ sbcmd(blaster, 0xD1); /* speaker on */
- count = -Bufsize;
- ess1688w(0xA4, count & 0xFF);
- ess1688w(0xA5, (count>>8) & 0xFF);
- x = ess1688r(0xB8);
- ess1688w(0xB8, x|0x05);
+ count = -Blocksize;
+ ess1688w(blaster, 0xA4, count & 0xFF);
+ ess1688w(blaster, 0xA5, (count>>8) & 0xFF);
+ x = ess1688r(blaster, 0xB8);
+ ess1688w(blaster, 0xB8, x|0x05);
- audio.active = 1;
- contindma();
- iunlock(&blaster);
+ ctlr->active = 1;
+ if(dmasetup(blaster->dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
+ ctlr->active = 0;
+ print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
+ }
+ iunlock(blaster);
}
-/*
- * if audio is stopped,
- * start it up again.
- */
-static void
-pokeaudio(void)
-{
- if(!audio.active)
- blaster.startdma();
-}
-
static void
-sb16intr(void)
+sb16intr(Ctlr *ctlr)
{
+ Blaster *blaster;
int stat;
- stat = mxread(0x82); /* get irq status */
- if(stat & 7) {
- ilock(&blaster);
+ blaster = &ctlr->blaster;
+ ilock(blaster);
+ stat = mxread(blaster, 0x82); /* get irq status */
+ if(stat & 3){
+ contindma(ctlr);
if(stat & 2)
- inb(blaster.clri16);
+ inb(blaster->clri16);
else if(stat & 1)
- inb(blaster.clri8);
- if(stat & 3){
- contindma();
- iunlock(&blaster);
-
- audio.intr = 1;
- wakeup(&audio.vous);
- }
- if(stat & 4)
- inb(blaster.clri401);
- }
+ inb(blaster->clri8);
+ } else if(stat & 4)
+ inb(blaster->clri401);
+ iunlock(blaster);
}
static void
-ess1688intr(void)
+ess1688intr(Ctlr *ctlr)
{
- if(audio.active){
- ilock(&blaster);
- contindma();
- inb(blaster.clri8);
- iunlock(&blaster);
- audio.intr = 1;
- wakeup(&audio.vous);
- return;
- }
- print("#A%d: unexpected ess1688 interrupt\n", audio.ctlrno);
-}
+ Blaster *blaster;
-void
-audiosbintr(void)
-{
- /*
- * Carrera interrupt interface.
- */
- blaster.intr();
+ blaster = &ctlr->blaster;
+ ilock(blaster);
+ contindma(ctlr);
+ inb(blaster->clri8);
+ iunlock(blaster);
}
static void
-pcaudiosbintr(Ureg*, void*)
+audiointr(Ureg *, void *arg)
{
- /*
- * x86 interrupt interface.
- */
- blaster.intr();
-}
+ Audio *adev;
+ Ctlr *ctlr;
-static int
-anybuf(void*)
-{
- return audio.intr;
-}
-
-/*
- * wait for some output to get
- * empty buffers back.
- */
-static int
-waitaudio(void)
-{
-
- audio.intr = 0;
- pokeaudio();
- tsleep(&audio.vous, anybuf, 0, 10000);
- if(audio.intr == 0) {
- audio.active = 0;
- print("#A%d: audio timeout\n", audio.ctlrno); /**/
- return -1;
+ adev = arg;
+ ctlr = adev->ctlr;
+ if(!ctlr->active){
+ iprint("#A%d: unexpected %s interrupt\n",
+ ctlr->adev->ctlrno, ctlr->adev->name);
+ return;
}
- return 0;
+ ctlr->blaster.intr(ctlr);
}
-static void
-swab(uchar *a)
+static void
+setempty(Ctlr *ctlr)
{
- ulong *p, *ep, b;
-
- if(!SBswab){
- USED(a);
- return;
- }
- p = (ulong*)a;
- ep = p + (Bufsize>>2);
- while(p < ep) {
- b = *p;
- b = (b>>24) | (b<<24) |
- ((b&0xff0000) >> 8) |
- ((b&0x00ff00) << 8);
- *p++ = b;
- }
+ ilock(&ctlr->blaster);
+ ctlr->ring.ri = 0;
+ ctlr->ring.wi = 0;
+ ctlr->totcount = 0;
+ ctlr->tottime = 0LL;
+ iunlock(&ctlr->blaster);
}
static void
-sbbufinit(void)
+resetlevel(Ctlr *ctlr)
{
int i;
- uchar *p;
- p = (uchar*)(((ulong)xalloc((Nbuf+1) * Bufsize) + Bufsize-1) &
- ~(Bufsize-1));
- if (p == nil)
- panic("sbbufinit: no memory");
- for(i=0; i<Nbuf; i++) {
- dcflush(p, Bufsize);
- audio.buf[i].virt = UNCACHED(uchar, p);
- audio.buf[i].phys = (ulong)PADDR(p);
- p += Bufsize;
+ for(i=0; volumes[i].name; i++) {
+ ctlr->lovol[i] = volumes[i].ilval;
+ ctlr->rovol[i] = volumes[i].irval;
+ ctlr->livol[i] = volumes[i].ilval;
+ ctlr->rivol[i] = volumes[i].irval;
}
}
-static void
-setempty(void)
+static long
+audiobuffered(Audio *adev)
{
- int i;
-
- ilock(&blaster);
- audio.empty.first = 0;
- audio.empty.last = 0;
- audio.full.first = 0;
- audio.full.last = 0;
- audio.current = 0;
- audio.filling = 0;
- audio.buffered = 0;
- for(i=0; i<Nbuf; i++)
- putbuf(&audio.empty, &audio.buf[i]);
- audio.totcount = 0;
- audio.tottime = 0LL;
- iunlock(&blaster);
+ return buffered(&((Ctlr*)adev->ctlr)->ring);
}
-static void
-resetlevel(void)
+static long
+audiostatus(Audio *adev, void *a, long n, vlong off)
{
- int i;
+ char buf[300];
+ Ctlr *ctlr;
- for(i=0; volumes[i].name; i++) {
- audio.lovol[i] = volumes[i].ilval;
- audio.rovol[i] = volumes[i].irval;
- audio.livol[i] = volumes[i].ilval;
- audio.rivol[i] = volumes[i].irval;
- }
+ ctlr = adev->ctlr;
+ snprint(buf, sizeof(buf),
+ "buffered %.4lx/%.4lx offset %10lud time %19lld\n",
+ buffered(&ctlr->ring), available(&ctlr->ring),
+ ctlr->totcount, ctlr->tottime);
+ return readstr(off, a, n, buf);
}
-static long
-audiobuffered(Audio *)
+static int
+inactive(void *arg)
{
- return audio.buffered;
+ Ctlr *ctlr = arg;
+
+ return !ctlr->active;
}
-static long
-audiostatus(Audio *, void *a, long n, vlong off)
+static int
+anybuf(void *arg)
{
- char buf[300];
+ Ctlr *ctlr = arg;
- snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset %10lud time %19lld\n",
- Bufsize, audio.buffered, audio.totcount, audio.tottime);
- return readstr(off, a, n, buf);
+ return available(&ctlr->ring) || inactive(ctlr);
}
static long
-audiowrite(Audio *, void *vp, long n, vlong)
+audiowrite(Audio *adev, void *vp, long n, vlong)
{
- long m, n0;
- Buf *b;
- char *a;
+ uchar *p, *e;
+ Ctlr *ctlr;
+ Ring *ring;
+ long m;
- a = vp;
- n0 = n;
- qlock(&audio);
+ p = vp;
+ e = p + n;
+ ctlr = adev->ctlr;
+ qlock(ctlr);
if(waserror()){
- qunlock(&audio);
+ qunlock(ctlr);
nexterror();
}
-
- while(n > 0) {
- b = audio.filling;
- if(b == 0) {
- b = getbuf(&audio.empty);
- if(b == 0) {
- if(waitaudio())
- pokeaudio();
+ ring = &ctlr->ring;
+ while(p < e) {
+ if((m = writering(ring, p, e - p)) <= 0){
+ if(!ctlr->active && ring->ri == 0)
+ ctlr->blaster.startdma(ctlr);
+ if(!ctlr->active){
+ setempty(ctlr);
continue;
}
- audio.filling = b;
- audio.curcount = 0;
+ sleep(&ctlr->vous, anybuf, ctlr);
+ continue;
}
-
- m = Bufsize-audio.curcount;
- if(m > n)
- m = n;
- memmove(b->virt+audio.curcount, a, m);
-
- audio.curcount += m;
- n -= m;
- a += m;
- audio.buffered += m;
- if(audio.curcount >= Bufsize) {
- audio.filling = 0;
- swab(b->virt);
- putbuf(&audio.full, b);
- pokeaudio();
- }
+ p += m;
}
poperror();
- qunlock(&audio);
+ qunlock(ctlr);
- return n0 - n;
+ return p - (uchar*)vp;
}
static void
-audioclose(Audio *)
+audioclose(Audio *adev)
{
- qlock(&audio);
+ Ctlr *ctlr;
+
+ ctlr = adev->ctlr;
+ qlock(ctlr);
if(waserror()){
- qunlock(&audio);
+ qunlock(ctlr);
nexterror();
}
- if(1) {
- Buf *b;
-
- /* flush out last partial buffer */
- b = audio.filling;
- if(b) {
- audio.filling = 0;
- memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
- audio.buffered += Bufsize-audio.curcount;
- swab(b->virt);
- putbuf(&audio.full, b);
- }
- if(!audio.active && audio.full.first)
- pokeaudio();
- }
- while(audio.active && waitaudio() == 0)
- ;
- setempty();
- audio.curcount = 0;
+ sleep(&ctlr->vous, inactive, ctlr);
+ setempty(ctlr);
poperror();
- qunlock(&audio);
+ qunlock(ctlr);
}
static int
-ess1688(ISAConf* sbconf)
+ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
{
int i, major, minor;
@@ -774,15 +681,15 @@
/*
* Try for ESS1688.
*/
- sbcmd(0xE7); /* get version */
- major = sbread();
- minor = sbread();
+ sbcmd(blaster, 0xE7); /* get version */
+ major = sbread(blaster);
+ minor = sbread(blaster);
if(major != 0x68 || minor != 0x8B){
- print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n", audio.ctlrno, major, minor);
- return 1;
+ print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n", ctlrno, major, minor);
+ return -1;
}
- ess1688reset();
+ ess1688reset(blaster, ctlrno);
switch(sbconf->irq){
case 2:
@@ -799,10 +706,10 @@
i = 0x50|(3<<2);
break;
default:
- print("#A%d: bad ESS1688 irq %d\n", audio.ctlrno, sbconf->irq);
+ print("#A%d: bad ESS1688 irq %d\n", ctlrno, sbconf->irq);
return 1;
}
- ess1688w(0xB1, i);
+ ess1688w(blaster, 0xB1, i);
switch(sbconf->dma){
case 0:
@@ -815,15 +722,15 @@
i = 0x50|(3<<2);
break;
default:
- print("#A%d: bad ESS1688 dma %lud\n", audio.ctlrno, sbconf->dma);
+ print("#A%d: bad ESS1688 dma %lud\n", ctlrno, sbconf->dma);
return 1;
}
- ess1688w(0xB2, i);
+ ess1688w(blaster, 0xB2, i);
- ess1688reset();
+ ess1688reset(blaster, ctlrno);
- blaster.startdma = ess1688startdma;
- blaster.intr = ess1688intr;
+ blaster->startdma = ess1688startdma;
+ blaster->intr = ess1688intr;
return 0;
}
@@ -831,26 +738,19 @@
static int
audioprobe(Audio *adev)
{
+ static int irq[] = {9,5,7,10};
+
+ Ctlr *ctlr;
+ Blaster *blaster;
ISAConf sbconf;
int i, x;
- static int irq[] = {2,5,7,10};
- static int dma16[] = {0,5,6,7};
- if(audio.probed)
- return -1;
-
sbconf.port = 0x220;
- sbconf.dma = 1;
sbconf.irq = 5;
+ sbconf.dma = 0;
if(isaconfig("audio", adev->ctlrno, &sbconf) == 0)
return -1;
- audio.probed = 1;
- audio.ctlrno = adev->ctlrno;
- if(sbconf.type == nil ||
- (cistrcmp(sbconf.type, "sb16") != 0 &&
- cistrcmp(sbconf.type, "ess1688") != 0))
- return -1;
switch(sbconf.port){
case 0x220:
case 0x240:
@@ -858,125 +758,127 @@
case 0x280:
break;
default:
- print("#A%d: bad port %#lux\n", audio.ctlrno, sbconf.port);
+ print("#A%d: bad port %#lux\n", adev->ctlrno, sbconf.port);
return -1;
}
if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
- print("#A%d: cannot ioalloc range %lux+0x10\n", audio.ctlrno, sbconf.port);
+ print("#A%d: cannot ioalloc range %lux+0x10\n", adev->ctlrno, sbconf.port);
return -1;
}
if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
iofree(sbconf.port);
- print("#A%d: cannot ioalloc range %lux+0x01\n", audio.ctlrno, sbconf.port+0x100);
+ print("#A%d: cannot ioalloc range %lux+0x01\n", adev->ctlrno, sbconf.port+0x100);
return -1;
}
- blaster.reset = sbconf.port + 0x6;
- blaster.read = sbconf.port + 0xa;
- blaster.write = sbconf.port + 0xc;
- blaster.wstatus = sbconf.port + 0xc;
- blaster.rstatus = sbconf.port + 0xe;
- blaster.mixaddr = sbconf.port + 0x4;
- blaster.mixdata = sbconf.port + 0x5;
- blaster.clri8 = sbconf.port + 0xe;
- blaster.clri16 = sbconf.port + 0xf;
- blaster.clri401 = sbconf.port + 0x100;
- blaster.dma = sbconf.dma;
+ ctlr = malloc(sizeof(Ctlr));
+ ctlr->adev = adev;
+ adev->ctlr = ctlr;
- blaster.startdma = sb16startdma;
- blaster.intr = sb16intr;
+ blaster = &ctlr->blaster;
+ blaster->reset = sbconf.port + 0x6;
+ blaster->read = sbconf.port + 0xa;
+ blaster->write = sbconf.port + 0xc;
+ blaster->wstatus = sbconf.port + 0xc;
+ blaster->rstatus = sbconf.port + 0xe;
+ blaster->mixaddr = sbconf.port + 0x4;
+ blaster->mixdata = sbconf.port + 0x5;
+ blaster->clri8 = sbconf.port + 0xe;
+ blaster->clri16 = sbconf.port + 0xf;
+ blaster->clri401 = sbconf.port + 0x100;
+ blaster->dma = sbconf.dma;
- resetlevel();
+ blaster->startdma = sb16startdma;
+ blaster->intr = sb16intr;
- outb(blaster.reset, 1);
- delay(3); /* >3 υs */
- outb(blaster.reset, 0);
+ resetlevel(ctlr);
+
+ outb(blaster->reset, 1);
+ delay(1); /* >3 υs */
+ outb(blaster->reset, 0);
delay(1);
- i = sbread();
+ i = sbread(blaster);
if(i != 0xaa) {
- print("#A%d: no response #%.2x\n", audio.ctlrno, i);
+ print("#A%d: no response #%.2x\n", adev->ctlrno, i);
iofree(sbconf.port);
iofree(sbconf.port+0x100);
+ free(ctlr);
return -1;
}
- sbcmd(0xe1); /* get version */
- audio.major = sbread();
- audio.minor = sbread();
+ sbcmd(blaster, 0xe1); /* get version */
+ ctlr->major = sbread(blaster);
+ ctlr->minor = sbread(blaster);
- if(audio.major != 4) {
- if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
+ if(ctlr->major != 4) {
+ if(ctlr->major != 3 || ctlr->minor != 1 || ess1688(&sbconf, blaster, adev->ctlrno)){
print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
- audio.ctlrno, audio.major, audio.minor);
+ adev->ctlrno, ctlr->major, ctlr->minor);
iofree(sbconf.port);
iofree(sbconf.port+0x100);
return -1;
}
- audio.major = 4;
+ ctlr->major = 4;
}
/*
* initialize the mixer
*/
- mxcmd(0x00, 0); /* Reset mixer */
- mxvolume();
+ mxcmd(blaster, 0x00, 0); /* Reset mixer */
+ mxvolume(ctlr);
- /*
- * Attempt to set IRQ/DMA channels.
- * On old ISA boards, these registers are writable.
- * On Plug-n-Play boards, these are read-only.
- *
- * To accomodate both, we write to the registers,
- * but then use the contents in case the write is
- * disallowed.
- */
+ /* set irq */
for(i=0; i<nelem(irq); i++){
- if(irq[i] == sbconf.irq){
- mxcmd(0x80, 1<<i);
+ if(sbconf.irq == irq[i]){
+ mxcmd(blaster, 0x80, 1<<i);
break;
}
}
- x = mxread(0x80);
- for(i=0; i<nelem(irq); i++)
+ x = mxread(blaster, 0x80);
+ for(i=0; i<nelem(irq); i++){
if(x & (1<<i)){
sbconf.irq = irq[i];
break;
}
+ }
- if(blaster.dma < 4)
- mxcmd(0x81, 1<<blaster.dma);
- else {
- for(i=0; i<nelem(dma16); i++){
- if(dma16[i] == blaster.dma){
- x = mxread(0x81);
- mxcmd(0x81, 0x10<<i | (x & 0xf));
+ for(;;){
+ /* set 16bit dma */
+ if(blaster->dma>=5 && blaster->dma<=7){
+ x = mxread(blaster, 0x81);
+ mxcmd(blaster, 0x81, (1<<blaster->dma) & 0xF0 | (x & 0x0F));
+ }
+ x = mxread(blaster, 0x81);
+ for(i=5; i<=7; i++){
+ if(x & (1<<i)){
+ blaster->dma = i;
break;
}
}
- }
- x = mxread(0x81);
- for(i=0; i<4; i++)
- if(x & (1<<i))
- blaster.dma = i;
- for(i=0; i<nelem(dma16); i++)
- if(x & (0x10<<i)){
- blaster.dma = dma16[i];
- break;
+ if(blaster->dma<5){
+ blaster->dma = 7;
+ continue;
}
+ break;
+ }
- print("#A%d: %s port 0x%04lux irq %d dma %d\n", audio.ctlrno, sbconf.type,
- sbconf.port, sbconf.irq, blaster.dma);
+ print("#A%d: %s port 0x%04lux irq %d dma %d\n", adev->ctlrno, sbconf.type,
+ sbconf.port, sbconf.irq, blaster->dma);
- if(dmainit(blaster.dma, Bufsize))
+ ctlr->ring.nbuf = Blocks*Blocksize;
+ if(dmainit(blaster->dma, ctlr->ring.nbuf)){
+ free(ctlr);
return -1;
- intrenable(sbconf.irq, pcaudiosbintr, 0, BUSUNKNOWN, "sb16");
+ }
+ ctlr->ring.buf = dmabva(blaster->dma);
- sbbufinit();
- setempty();
- mxvolume();
+ intrenable(sbconf.irq, audiointr, adev, BUSUNKNOWN, sbconf.type);
+ setempty(ctlr);
+ mxvolume(ctlr);
+
adev->write = audiowrite;
adev->close = audioclose;
adev->status = audiostatus;
@@ -989,4 +891,5 @@
audiosb16link(void)
{
addaudiocard("sb16", audioprobe);
+ addaudiocard("ess1688", audioprobe);
}
--- a/sys/src/9/pc/devfloppy.c
+++ b/sys/src/9/pc/devfloppy.c
@@ -857,7 +857,7 @@
dmaend(DMAchan);
nexterror();
}
- dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
+ dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread ? DMAREAD : DMAWRITE);
if(dp->len < 0)
error(Eio);
@@ -999,7 +999,7 @@
dmaend(DMAchan);
nexterror();
}
- if(dmasetup(DMAchan, buf, bp-buf, 0) < 0)
+ if(dmasetup(DMAchan, buf, bp-buf, DMAWRITE) < 0)
error(Eio);
/*
--- a/sys/src/9/pc/dma.c
+++ b/sys/src/9/pc/dma.c
@@ -18,7 +18,7 @@
int blen; /* bounce buffer length */
void* va; /* virtual address destination/src */
long len; /* bytes to be transferred */
- int isread;
+ int flags;
};
/*
@@ -81,7 +81,7 @@
if(i8237dma > 2)
i8237dma = 2;
- bva = xspanalloc(64*1024*i8237dma, BY2PG, 64*1024);
+ bva = xspanalloc(64*1024*i8237dma, 0, 64*1024);
if(bva == nil || PADDR(bva)+64*1024*i8237dma > 16*MB){
/*
* This will panic with the current
@@ -137,11 +137,38 @@
xp->bpa = PADDR(xp->bva);
xp->blen = maxtransfer;
xp->len = 0;
- xp->isread = 0;
+ xp->flags = 0;
return 0;
}
+void*
+dmabva(int chan)
+{
+ DMA *dp;
+ DMAxfer *xp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ xp = &dp->x[chan];
+ return xp->bva;
+}
+
+int
+dmacount(int chan)
+{
+ int retval;
+ DMA *dp;
+
+ dp = &dma[(chan>>2)&1];
+ chan = chan & 3;
+ ilock(dp);
+ retval = inb(dp->count[chan]);
+ retval |= inb(dp->count[chan]) << 8;
+ iunlock(dp);
+ return ((retval<<dp->shift)+1) & 0xFFFF;
+}
+
/*
* setup a dma transfer. if the destination is not in kernel
* memory, allocate a page for the transfer.
@@ -153,7 +180,7 @@
* boundaries)
*/
long
-dmasetup(int chan, void *va, long len, int isread)
+dmasetup(int chan, void *va, long len, int flags)
{
DMA *dp;
ulong pa;
@@ -175,11 +202,11 @@
return -1;
if(len > xp->blen)
len = xp->blen;
- if(!isread)
+ if(!(flags & DMAREAD))
memmove(xp->bva, va, len);
xp->va = va;
xp->len = len;
- xp->isread = isread;
+ xp->flags = flags;
pa = xp->bpa;
}
else
@@ -189,7 +216,7 @@
* this setup must be atomic
*/
ilock(dp);
- mode = (isread ? 0x44 : 0x48) | chan;
+ mode = ((flags & DMAREAD) ? 0x44 : 0x48) | ((flags & DMALOOP) ? 0x10 : 0) | chan;
outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
outb(dp->page[chan], pa>>16);
outb(dp->cbp, 0); /* set count & address to their first byte */
@@ -238,7 +265,7 @@
iunlock(dp);
xp = &dp->x[chan];
- if(xp->len == 0 || !xp->isread)
+ if(xp->len == 0 || !(xp->flags & DMAREAD))
return;
/*
@@ -248,17 +275,3 @@
xp->len = 0;
}
-/*
-int
-dmacount(int chan)
-{
- int retval;
- DMA *dp;
-
- dp = &dma[(chan>>2)&1];
- outb(dp->cbp, 0);
- retval = inb(dp->count[chan]);
- retval |= inb(dp->count[chan]) << 8;
- return((retval<<dp->shift)+1);
-}
- */
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -18,10 +18,14 @@
void cpuidprint(void);
void (*cycles)(uvlong*);
void delay(int);
+void* dmabva(int);
int dmacount(int);
int dmadone(int);
void dmaend(int);
int dmainit(int, int);
+#define DMAWRITE 0
+#define DMAREAD 1
+#define DMALOOP 2
long dmasetup(int, void*, long, int);
#define evenaddr(x) /* x86 doesn't care */
void fpclear(void);
@@ -181,5 +185,3 @@
#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define KADDR(a) kaddr(a)
#define PADDR(a) paddr((void*)(a))
-
-#define dcflush(a, b)
--- a/sys/src/9/port/devaudio.c
+++ b/sys/src/9/port/devaudio.c
@@ -18,6 +18,7 @@
Qaudioctl,
Qaudiostatus,
Qvolume,
+
Maxaudioprobes = 8,
};
@@ -48,19 +49,26 @@
int i, ctlrno = 0;
Audio **pp;
Audioprobe *probe;
+
pp = &audiodevs;
*pp = malloc(sizeof(Audio));
- (*pp)->ctlrno = ctlrno++;
- for(i = 0; i < naudioprobes; i++){
+
+ for(i=0; i<naudioprobes; i++){
probe = &audioprobes[i];
- (*pp)->name = probe->name;
- while(!probe->probe(*pp)){
+
+ for(;;){
+ memset(*pp, 0, sizeof(Audio));
+ (*pp)->ctlrno = ctlrno;
+ (*pp)->name = probe->name;
+ if(probe->probe(*pp))
+ break;
+
+ ctlrno++;
pp = &(*pp)->next;
*pp = malloc(sizeof(Audio));
- (*pp)->ctlrno = ctlrno++;
- (*pp)->name = probe->name;
}
}
+
free(*pp);
*pp = nil;
}