From 12db97fe6b1cd05b962cb2c0dec6f5e099afbcc8 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 8 May 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-05-08 --- bitsy/devuda1341.c | 117 ++++++++++++++++++++++++++++++++++++++++----- port/devsegment.c | 17 +++---- port/segment.c | 19 ++++---- 3 files changed, 125 insertions(+), 28 deletions(-) diff --git a/bitsy/devuda1341.c b/bitsy/devuda1341.c index 5bd1b0815651c937eee0e93f87eac10da61f0867..dce5c2beafd50f2175e38449732c00657d8301d0 100644 --- a/bitsy/devuda1341.c +++ b/bitsy/devuda1341.c @@ -94,6 +94,7 @@ enum Qdir = 0, Qaudio, Qvolume, + Qspeed, Qstatus, Fmono = 1, @@ -120,11 +121,29 @@ enum Ncmd = 50, /* max volume command words */ }; +enum { + Flushbuf = 0xe0000000, +}; + +/* System Clock */ +enum { + SC512FS = 0, + SC384FS = 1, + SC256FS = 2, +}; + +/* Format */ +enum { + LSB16 = 1, + LSB18 = 2, +}; + Dirtab audiodir[] = { - "audio", {Qaudio}, 0, 0666, + "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, + "speed", {Qspeed}, 0, 0666, "audiostat",{Qstatus}, 0, 0444, }; @@ -166,7 +185,6 @@ static struct IOstate o; } audio; -Buf zeroes; int zerodma; /* dma buffer used for sending zero */ static struct @@ -197,6 +215,7 @@ static struct [Nvol] {0} }; +static int rate = Speed; /* Current sample rate */ static void setreg(char *name, int val, int n); /* @@ -404,12 +423,6 @@ bufinit(IOstate *b) memset(b->buf[i].virt, 0xAA, Bufsize); } b->bufinit = 1; - - if (b == &audio.o) { - zeroes.virt = xalloc(Bufsize); - zeroes.phys = PADDR(b->buf[i].virt); - memset(zeroes.virt, 0, Bufsize); - } }; static void @@ -469,6 +482,9 @@ uchar data0e4[2] = {0xc4, 0xe0}; uchar data0e5[2] = {0xc5, 0xe0}; uchar data0e6[2] = {0xc6, 0xe3}; +static void +mxspeed(int _rate); + static void enable(void) { @@ -531,6 +547,61 @@ resetlevel(void) } } +static void +mxspeed(int _rate) +{ + uchar data; + + egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1); + /* set the external clock generator */ + rate = _rate; + switch (rate) { + case 32000: + case 48000: + /* 00 */ + gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o; + break; + default: + rate = 44100; + case 44100: + /* 01 */ + gpioregs->set = GPIO_CLK_SET0_o; + gpioregs->clear = GPIO_CLK_SET1_o; + break; + case 8000: + case 16000: + /* 10 */ + gpioregs->set = GPIO_CLK_SET1_o; + gpioregs->clear = GPIO_CLK_SET0_o; + break; + case 11025: + case 22050: + /* 11 */ + gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o; + break; + } + delay(100); + + switch (rate) { + case 8000: + case 11025: + data = SC512FS; + break; + case 16000: + case 22050: + case 44100: + case 48000: + data = SC256FS; + break; + case 32000: + data = SC384FS; + break; + } + data |= (LSB16 << 4)|0x2; + L3_write(UDA1341_L3Addr | UDA1341_STATUS, &data, 1); +} + + static void mxvolume(void) { int *left, *right; @@ -694,7 +765,7 @@ sendaudio(IOstate *s) { ilock(&s->ilock); if ((audio.amode & Aread) && s->next == s->filling && dmaidle(s->dma)) { // send an empty buffer to provide an input clock - zerodma |= dmastart(s->dma, zeroes.phys, Bufsize) & 0xff; + zerodma |= dmastart(s->dma, Flushbuf, Bufsize) & 0xff; if (zerodma == 0) if (debug) print("emptyfail\n"); iostats.empties++; @@ -863,6 +934,7 @@ audioopen(Chan *c, int mode) if((omode&7) != OREAD) error(Eperm); case Qvolume: + case Qspeed: case Qdir: break; @@ -900,6 +972,7 @@ audioopen(Chan *c, int mode) audio.amode |= Awrite; outenable(); } + mxspeed(Speed); mxvolume(); qunlock(&audio); if (audio.amode & Aread) @@ -928,6 +1001,7 @@ audioclose(Chan *c) case Qdir: case Qvolume: + case Qspeed: case Qstatus: break; @@ -1059,6 +1133,11 @@ audioread(Chan *c, void *v, long n, vlong off) audio.totcount, audio.tottime); return readstr(offset, p, n, buf); + case Qspeed: + buf[0] = '\0'; + snprint(buf, sizeof(buf), "speed %d\n", rate); + return readstr(offset, p, n, buf); + case Qvolume: j = 0; buf[0] = 0; @@ -1119,6 +1198,23 @@ audiowrite(Chan *c, void *vp, long n, vlong) error(Eperm); break; + case Qspeed: + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, p, n); + buf[n] = '\0'; + nf = getfields(buf, field, Ncmd, 1, " \t\n"); + if (nf != 2 && nf != 1) error(Ebadarg); + if (nf == 2) { + if (strcmp(field[0], "speed")) + error(Ebadarg); + i = 1; + } + else + i = 0; + mxspeed((int)strtol(field[i], (char **)nil, 0)); + break; + case Qvolume: v = Vaudio; left = 1; @@ -1214,11 +1310,10 @@ audiowrite(Chan *c, void *vp, long n, vlong) } while(n > 0) { /* wait if dma in progress */ - while (!dmaidle(a->dma) && a->filling == a->current) { + while (!dmaidle(a->dma) && !zerodma && a->filling == a->current) { if (debug > 1) print("#A: sleep\n"); sleep(&a->vous, audioqnotfull, a); } - m = Bufsize - a->filling->nbytes; if(m > n) m = n; diff --git a/port/devsegment.c b/port/devsegment.c index 1b50b077904aed549a122acaca2e3f2552902e8b..455c9e888556d061341b282c979e76d4cfd26d50 100644 --- a/port/devsegment.c +++ b/port/devsegment.c @@ -84,7 +84,8 @@ putgseg(Globalseg *g) { if(decref(g) > 0) return; - putseg(g->s); + if(g->s != nil) + putseg(g->s); if(g->kproc) docmd(g, Cdie); free(g); @@ -290,12 +291,11 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm) if(xfree < 0) error("too many global segments"); g = smalloc(sizeof(Globalseg)); - g->ref = 2; + g->ref = 1; strncpy(g->name, name, sizeof(g->name)); strncpy(g->uid, up->user, sizeof(g->uid)); g->perm = 0660; globalseg[xfree] = g; - c->aux = g; unlock(&globalseglock); poperror(); @@ -353,8 +353,7 @@ segmentwrite(Chan *c, void *a, long n, vlong voff) { Cmdbuf *cb; Globalseg *g; - ulong va; - ulong len; + ulong va, len, top; if(c->qid.path&CHDIR) error(Eperm); @@ -369,9 +368,10 @@ segmentwrite(Chan *c, void *a, long n, vlong voff) if(cb->nf < 3) error(Ebadarg); va = strtoul(cb->f[1], 0, 0); - va = va&~(BY2PG-1); len = strtoul(cb->f[2], 0, 0); - len = ROUND(len, BY2PG)/BY2PG; + top = PGROUND(va + len); + va = va&~(BY2PG-1); + len = (top - va) / BY2PG; if(len == 0) error(Ebadarg); g->s = newseg(SG_SHARED, va, len); @@ -474,10 +474,11 @@ globalsegattach(Proc *p, char *name) s = g->s; if(s == nil) error("global segment not assigned a virtual address"); - if(isoverlap(p, s->base, s->top-s->base) != nil) + if(isoverlap(p, s->base, s->top) != nil) error("overlaps existing segment"); incref(s); unlock(&globalseglock); + poperror(); return s; } diff --git a/port/segment.c b/port/segment.c index 40d2f68caed4a6ba1cffa6706615501567943e40..848012b02f19beb8f2cb3650b31934aeb9022d7b 100644 --- a/port/segment.c +++ b/port/segment.c @@ -541,13 +541,11 @@ out: } Segment* -isoverlap(Proc *p, ulong va, int len) +isoverlap(Proc *p, ulong va, int newtop) { int i; Segment *ns; - ulong newtop; - newtop = va+len; for(i = 0; i < NSEG; i++) { ns = p->seg[i]; if(ns == 0) @@ -609,6 +607,7 @@ ulong segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) { int sno; + ulong top; Segment *s, *os; Physseg *ps; @@ -626,7 +625,7 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) error(Enovmem); /* - * first look for a global segment with the + * first look for a global segment with the * same name */ if(_globalsegattach != nil){ @@ -637,7 +636,6 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) } } - len = PGROUND(len); if(len == 0) error(Ebadarg); @@ -649,9 +647,10 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) * or the address space is exhausted. */ if(va == 0) { + len = PGROUND(len); va = p->seg[SSEG]->base - len; for(;;) { - os = isoverlap(p, va, len); + os = isoverlap(p, va, va+len); if(os == nil) break; va = os->base; @@ -661,8 +660,10 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) } } + top = PGROUND(va + len); va = va&~(BY2PG-1); - if(isoverlap(p, va, len) != nil) + len = top - va; + if(isoverlap(p, va, top) != nil) error(Esoverlap); for(ps = physseg; ps->name; ps++) @@ -701,9 +702,9 @@ long syssegflush(ulong *arg) { Segment *s; - ulong addr, l; + ulong addr, l, ps, pe; Pte *pte; - int chunk, ps, pe, len; + int chunk, len; addr = arg[0]; len = arg[1];