@@ 77,6 77,7 @@ enum {
typedef struct AQueue AQueue;
typedef struct Buf Buf;
+typedef struct IOstate IOstate;
enum
{
@@ 104,8 105,8 @@ enum
Vspeed,
Nvol,
- Bufsize = 16*1024, /* 92 ms each */
- Nbuf = 16, /* 1.5 seconds total */
+ Bufsize = 8*1024, /* 46 ms each */
+ Nbuf = 32, /* 1.5 seconds total */
Speed = 44100,
Ncmd = 50, /* max volume command words */
@@ 121,66 122,34 @@ audiodir[] =
struct Buf
{
+ int active; /* dma running */
uchar* virt;
- ulong phys;
- Buf* next;
+ uint nbytes;
};
-struct AQueue
-{
- Lock;
- Buf* first;
- Buf* last;
-};
-
-static struct
+struct IOstate
{
QLock;
Rendez vous;
- int bufinit; /* boolean if buffers allocated */
- int curcount; /* how much data in current buffer */
- int active; /* boolean dma running */
- int intr; /* boolean an interrupt has happened */
- int amode; /* Aclosed/Aread/Awrite for /audio */
- int rivol[Nvol]; /* right/left input/output volumes */
- int livol[Nvol];
- int rovol[Nvol];
- int lovol[Nvol];
- int major; /* SB16 major version number (sb 4) */
- int minor; /* SB16 minor version number */
- ulong totcount; /* how many bytes processed since open */
- vlong tottime; /* time at which totcount bytes were processed */
-
- Buf buf[Nbuf]; /* buffers and queues */
- AQueue empty;
- AQueue full;
- Buf* current;
- Buf* filling;
-} input, output;
+ int bufinit; /* boolean, if buffers allocated */
+ Buf buf[Nbuf]; /* buffers and queues */
+ Buf *current; /* next candidate for dma */
+ Buf *filling; /* buffer being filled */
+};
static struct
{
QLock;
- Rendez vous;
- int bufinit; /* boolean if buffers allocated */
- int curcount; /* how much data in current buffer */
- int active; /* boolean dma running */
- int intr; /* boolean an interrupt has happened */
- int amode; /* Aclosed/Aread/Awrite for /audio */
- int rivol[Nvol]; /* right/left input/output volumes */
- int livol[Nvol];
- int rovol[Nvol];
- int lovol[Nvol];
- int major; /* SB16 major version number (sb 4) */
- int minor; /* SB16 minor version number */
- ulong totcount; /* how many bytes processed since open */
- vlong tottime; /* time at which totcount bytes were processed */
-
- Buf buf[Nbuf]; /* buffers and queues */
- AQueue empty;
- AQueue full;
- Buf* current;
- Buf* filling;
+ int amode; /* Aclosed/Aread/Awrite for /audio */
+ int intr; /* boolean an interrupt has happened */
+ int rivol[Nvol]; /* right/left input/output volumes */
+ int livol[Nvol];
+ int rovol[Nvol];
+ int lovol[Nvol];
+ ulong totcount; /* how many bytes processed since open */
+ vlong tottime; /* time at which totcount bytes were processed */
+ IOstate i;
+ IOstate o;
} audio;
static struct
@@ 388,32 357,27 @@ static int L3_read(char addr, char * data, int len)
static char Emode[] = "illegal open mode";
static char Evolume[] = "illegal volume specifier";
-static Buf*
-getbuf(AQueue *q)
+static void
+bufinit(IOstate *b)
{
- Buf *b;
-
- ilock(q);
- b = q->first;
- if(b)
- q->first = b->next;
- iunlock(q);
+ int i;
- return b;
-}
+ for (i = 0; i < Nbuf; i++)
+ b->buf[i].virt = xalloc(Bufsize);
+ b->bufinit = 1;
+};
-static void
-putbuf(AQueue *q, Buf *b)
+static void
+setempty(IOstate *b)
{
+ int i;
- ilock(q);
- b->next = 0;
- if(q->first)
- q->last->next = b;
- else
- q->first = b;
- q->last = b;
- iunlock(q);
+ for (i = 0; i < Nbuf; i++) {
+ b->buf[i].nbytes = 0;
+ b->buf[i].active = 0;
+ }
+ b->filling = b->buf;
+ b->current = b->buf;
}
static void
@@ 462,9 426,14 @@ audioinit(void)
}
static void
-audioinit(void)
-{}
-
+sendaudio(IOstat *b) {
+ if (dmastart(b->chan, b->current->virt, b->current->nbytes)) {
+ b->current->active++;
+ b->current++;
+ if (b->current == &b->buf[Nbuf])
+ b->current == &b->buf[0];
+ }
+}
static Chan*
audioattach(char *param)
@@ 487,7 456,6 @@ audiostat(Chan *c, char *db)
static Chan*
audioopen(Chan *c, int omode)
{
- int amode;
switch(c->qid.path & ~CHDIR) {
default:
@@ 502,31 470,30 @@ audioopen(Chan *c, int omode)
break;
case Qaudio:
- if ((omode & 0x7) > 2)
+ omode = (omode & 0x7) + 1;
+ if (omode & ~(Aread | Awrite))
error(Ebadarg);
qlock(&audio);
- omode++;
if(audio.amode & omode){
qunlock(&audio);
error(Einuse);
}
- if (omode & AudioIn) {
+ if (omode & Aread) {
/* read */
- audio.amode |= AudioIn;
- if((audio.bufinit & AudioIn) == 0) {
- audio.bufinit |= AudioIn;
- sbbufinit();
- }
+ audio.amode |= Aread;
+ if(audio.i.bufinit == 0)
+ bufinit(&audio.i);
+ setempty(&audio.i);
}
if (omode & 0x2) {
/* write */
- audio.amode |= 0x2;
+ audio.amode |= Awrite;
+ if(audio.o.bufinit == 0)
+ bufinit(&audio.o);
+ setempty(&audio.o);
}
- audio.amode = amode;
- setempty();
- audio.curcount = 0;
qunlock(&audio);
- mxvolume();
+// mxvolume();
break;
}
c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
@@ 555,17 522,12 @@ audioclose(Chan *c)
case Qaudio:
if(c->flag & COPEN) {
qlock(&audio);
- if(audio.amode == Awrite) {
+ if(audio.amode & Awrite) {
/* flush out last partial buffer */
- b = audio.filling;
- if(b) {
- audio.filling = 0;
- memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
- swab(b->virt);
+ b = audio.o.filling;
+ if(audio.o.buf[b].count) {
putbuf(&audio.full, b);
}
- if(!audio.active && audio.full.first)
- pokeaudio();
}
audio.amode = Aclosed;
if(waserror()){
@@ 697,9 659,10 @@ audiowrite(Chan *c, void *vp, long n, vlong)
int i, nf, v, left, right, in, out;
char buf[255], *field[Ncmd];
Buf *b;
- char *a;
+ char *p;
+ IOstate *a;
- a = vp;
+ p = vp;
n0 = n;
switch(c->qid.path & ~CHDIR) {
default:
@@ 714,7 677,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
out = 1;
if(n > sizeof(buf)-1)
n = sizeof(buf)-1;
- memmove(buf, a, n);
+ memmove(buf, p, n);
buf[n] = '\0';
nf = getfields(buf, field, Ncmd, 1, " \t\n");
@@ 779,41 742,36 @@ audiowrite(Chan *c, void *vp, long n, vlong)
break;
case Qaudio:
- if(audio.amode != Awrite)
+ if((audio.amode & Awrite) == 0)
error(Emode);
- qlock(&audio);
+ a = &audio.o;
+ qlock(a);
if(waserror()){
- qunlock(&audio);
+ qunlock(a);
nexterror();
}
while(n > 0) {
- b = audio.filling;
- if(b == 0) {
- b = getbuf(&audio.empty);
- if(b == 0) {
- waitaudio();
- continue;
- }
- audio.filling = b;
- audio.curcount = 0;
- }
+ /* wait if dma in progress */
+ while (a->filling->active)
+ waitaudio(a);
- m = Bufsize-audio.curcount;
+ m = Bufsize - a->filling->nbytes;
if(m > n)
m = n;
- memmove(b->virt+audio.curcount, a, m);
+ memmove(a->filling->buf + a->filling->nbytes, p, m);
- audio.curcount += m;
+ a->filling->nbytes += m;
n -= m;
- a += m;
- if(audio.curcount >= Bufsize) {
- audio.filling = 0;
- swab(b->virt);
- putbuf(&audio.full, b);
+ p += m;
+ if(a->filling->nbytes >= Bufsize) {
+ sendaudio(a);
+ a->filling++;
+ if (a->filling == &a->buf[Nbuf])
+ a->filling = a->buf;
}
}
poperror();
- qunlock(&audio);
+ qunlock(a);
break;
}
return n0 - n;
@@ 37,10 37,15 @@ enum {
BIU = 7
};
+typedef struct Chan {
+ int inuse;
+ Rendez r;
+ void (*f)(void);
+} Chan;
+
struct {
Lock;
- Rendez r[6];
- int channels;
+ Chan chan[6];
} dma;
struct dmaregs {
@@ 66,9 71,9 @@ dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *
lock(&dma);
for (i = 0; i < NDMA; i++) {
- if (dma.channels & (1 << i))
+ if (dma.chan[i].inuse)
continue;
- dma.channels |= 1 << i;
+ dma.chan[i].inuse++;
unlock(&dma);
dmaregs[i].ddar =
(rd?1:0)<<RW |
@@ 85,9 90,7 @@ dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *
void
dmafree(int i) {
- lock(&dma);
- dma.channels &= ~(1<<i);
- unlock(&dma);
+ dma.chan[i].inuse = 0;
}
static int
@@ 97,13 100,14 @@ dmaready(void *dcsr) {
ulong
dmastart(int chan, void *addr, int count) {
- ulong ab;
+ ulong status;
- while ((ab = dmaready(&dmaregs[chan].dcsr_rd)) == 0) {
- sleep(&dma.r[chan], dmaready, &dmaregs[chan].dcsr_rd);
- }
- cachewb();
- if (ab & (1<<DONEA)) {
+ if (((status = dmaregs[chan].dcsr_rd) & ((1<<DONEA)|(1<<DONEB))) == 0)
+ return 0;
+
+ cachewbregion(addr, count);
+ if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
+ (status & (1<<BIU | 1<<STRTA)) == (1<<STRTA)) {
dmaregs[chan].dcsr_clr |= 1<<DONEA | 1<<STRTA;
dmaregs[chan].dstrtA = addr;
dmaregs[chan].dxcntA = count-1;
@@ 133,7 137,7 @@ dmawait(int chan, ulong op) {
ulong dcsr;
while (((dcsr = dmaregs[chan].dcsr_rd) & (op | 1<<ERROR)) == 0)
- sleep(&dma.r[chan], dmaready, &dmaregs[chan].dcsr_rd);
+ sleep(&dma.chan[chan].r, dmaready, &dmaregs[chan].dcsr_rd);
if (dcsr & 1<<ERROR)
pprint("DMA error, chan %d, status 0x%lux\n", chan, dcsr);
}
@@ 145,9 149,12 @@ static void
dmaintr(Ureg*, void *x)
{
int i;
+ ulong dcsr;
for (i = 0; i < NDMA; i++) {
- if (dmaregs[i].dcsr_rd & (1<<DONEA | 1<<DONEB | 1<<ERROR))
- wakeup(&dma.r[i]);
+ if ((dcsr = dmaregs[i].dcsr_rd) & (1<<DONEA | 1<<DONEB | 1<<ERROR))
+ wakeup(&dma.chan[i].r);
+ if (dma.chan[i].f)
+ (*dma.chan[i].f)(dcsr);
}
}