From a45354107bf6d6b5174c23ec4a240b5689bbf06d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 14 Feb 1995 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1995-02-14 --- carrera/audio.h | 2 + carrera/dat.h | 7 ++ carrera/dma.c | 125 +++++++++++++++++++++++++++++++ carrera/fns.h | 3 + carrera/main.c | 15 ++++ pc/audio.h | 26 +------ pc/devata.c | 26 +++---- pc/dma.c | 36 +++++---- port/devaudio.c | 193 +++++++++++++++++++++++++++++++++--------------- 9 files changed, 321 insertions(+), 112 deletions(-) create mode 100644 carrera/dma.c diff --git a/carrera/audio.h b/carrera/audio.h index dd05c6a895daebcfce8d30026c16b5e50cf3cb1b..3b2ad2a054db81e8d44753a90201810c156ff3cb 100644 --- a/carrera/audio.h +++ b/carrera/audio.h @@ -5,6 +5,8 @@ enum Dma = 6, Irq = 7, + SBswab = 1, + DMA2_WRMASK = 0xd4, DMA2_WRMODE = 0xd6, DMA2_CLRBP = 0xd8, diff --git a/carrera/dat.h b/carrera/dat.h index 2b8301825343046ce61feb74f06a2d2e19768559..c79c5ef6824b151209a5c1b626fb1acd6a4570d4 100644 --- a/carrera/dat.h +++ b/carrera/dat.h @@ -1,5 +1,6 @@ typedef struct Conf Conf; typedef struct FPsave FPsave; +typedef struct ISAConf ISAConf; typedef struct KMap KMap; typedef struct Lance Lance; typedef struct Lancemem Lancemem; @@ -150,6 +151,12 @@ struct short exiting; }active; +struct ISAConf { + char type[NAMELEN]; + ulong port; + ulong irq; +}; + extern KMap kpte[]; extern register Mach *m; extern register Proc *up; diff --git a/carrera/dma.c b/carrera/dma.c new file mode 100644 index 0000000000000000000000000000000000000000..8099cb0b53d622daf2f812a601d7f30bb324a2c6 --- /dev/null +++ b/carrera/dma.c @@ -0,0 +1,125 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * headland chip set for the safari. + */ +typedef struct DMAport DMAport; +typedef struct DMA DMA; + +enum +{ + /* + * the byte registers for DMA0 are all one byte apart + */ + Dma0= 0x00, + Dma0status= Dma0+0x8, /* status port */ + Dma0reset= Dma0+0xD, /* reset port */ + + /* + * the byte registers for DMA1 are all two bytes apart (why?) + */ + Dma1= 0xC0, + Dma1status= Dma1+2*0x8, /* status port */ + Dma1reset= Dma1+2*0xD, /* reset port */ +}; + +/* + * the dma controllers. the first half of this structure specifies + * the I/O ports used by the DMA controllers. + */ +struct DMAport +{ + uchar addr[4]; /* current address (4 channels) */ + uchar count[4]; /* current count (4 channels) */ + uchar page[4]; /* page registers (4 channels) */ + uchar cmd; /* command status register */ + uchar req; /* request registers */ + uchar sbm; /* single bit mask register */ + uchar mode; /* mode register */ + uchar cbp; /* clear byte pointer */ + uchar mc; /* master clear */ + uchar cmask; /* clear mask register */ + uchar wam; /* write all mask register bit */ +}; + +struct DMA +{ + DMAport; + int shift; + Lock; +}; + +DMA dma[2] = { + { 0x00, 0x02, 0x04, 0x06, + 0x01, 0x03, 0x05, 0x07, + 0x87, 0x83, 0x81, 0x82, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0 }, + + { 0xc0, 0xc4, 0xc8, 0xcc, + 0xc2, 0xc6, 0xca, 0xce, + 0x8f, 0x8b, 0x89, 0x8a, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 1 }, +}; + +/* + * setup a dma transfer. + * needs to change if the address is over 16meg + * + * we assume BIOS has set up the command register before we + * are booted. + */ +long +dmasetup(int chan, void *va, long len, int isread) +{ + DMA *dp; + ulong pa; + uchar mode; + + dp = &dma[(chan>>2)&1]; + chan = chan & 3; + + pa = PADDR(va); + + /* + * this setup must be atomic + */ + ilock(dp); + mode = (isread ? 0x44 : 0x48) | chan; + EISAOUTB(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */ + EISAOUTB(dp->page[chan], pa>>16); + EISAOUTB(dp->cbp, 0); /* set count & address to their first byte */ + EISAOUTB(dp->addr[chan], pa>>dp->shift); /* set address */ + EISAOUTB(dp->addr[chan], pa>>(8+dp->shift)); + EISAOUTB(dp->count[chan], (len>>dp->shift)-1); /* set count */ + EISAOUTB(dp->count[chan], ((len>>dp->shift)-1)>>8); + EISAOUTB(dp->sbm, chan); /* enable the channel */ + iunlock(dp); + + return len; +} + +/* + * this must be called after a dma has been completed. + */ +void +dmaend(int chan) +{ + DMA *dp; + + dp = &dma[(chan>>2)&1]; + chan = chan & 3; + + /* + * disable the channel + */ + ilock(dp); + EISAOUTB(dp->sbm, 4|chan); + iunlock(dp); +} diff --git a/carrera/fns.h b/carrera/fns.h index 64977bdd7da176c5eb22e5a40e73cc47ecd342c4..4e47ff47f8cd0db7e231779196e7a3cb10c97e97 100644 --- a/carrera/fns.h +++ b/carrera/fns.h @@ -19,6 +19,8 @@ void consoff(void); int consputc(int); void dcflush(void*, ulong); void dcinvalidate(void*, ulong); +void dmaend(int); +long dmasetup(int, void*, long, int); void epcenable(ulong); void epcinit(int, int); void evenaddr(ulong); @@ -42,6 +44,7 @@ void icflush(void *, ulong); void intr(Ureg*); void ioinit(int); int iprint(char*, ...); +int isaconfig(char*, int, ISAConf*); int kbdinit(void); void kbdintr(void); void kfault(Ureg*); diff --git a/carrera/main.c b/carrera/main.c index 83f06c912a8b95bd3bf96f3f6dbb0c5d5a529251..a6e1e61dfa1146410f906c6cadfa66eb43262690 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -479,6 +479,21 @@ buzz(int f, int d) USED(d); } +/* + * dummy routine for interoperability with pc's + */ +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + if(strcmp(class, "audio") == 0 && ctlrno == 0){ + strcpy(isa->type, "sb16"); + isa->port = 0x220; + isa->irq = 7; + return 1; + } + return 0; +} + /* register offsets of ARCS prom jmpbuf JB_PC 0 diff --git a/pc/audio.h b/pc/audio.h index 12979dcfbf5def95826de9fa46e0000d04092932..cc38eb89bad3c68eb33221824e80d4c68d1270c4 100644 --- a/pc/audio.h +++ b/pc/audio.h @@ -3,31 +3,7 @@ enum Bufsize = 16*1024, /* 92 ms each */ Nbuf = 16, /* 1.5 seconds total */ Dma = 6, - Irq = 7, - - DMA2_WRMASK = 0xd4, - DMA2_WRMODE = 0xd6, - DMA2_CLRBP = 0xd8, - - DMA6_ADDRESS = 0xc8, - DMA6_COUNT = 0xca, - DMA6_LPAGE = 0x89, - DMA6_HPAGE = 0x489, - - Dspport = 0x220, - - PORT_RESET = Dspport + 0x6, - PORT_READ = Dspport + 0xA, - PORT_WRITE = Dspport + 0xC, - PORT_WSTATUS = Dspport + 0xC, - PORT_RSTATUS = Dspport + 0xE, - - PORT_MIXER_ADDR = Dspport + 0x4, - PORT_MIXER_DATA = Dspport + 0x5, - - PORT_CLRI8 = Dspport + 0xE, - PORT_CLRI16 = Dspport + 0xF, - PORT_CLRI401 = Dspport + 0x100, + SBswab = 0, }; #define seteisadma(a, b) ; diff --git a/pc/devata.c b/pc/devata.c index 2c9c9a95b9ed8c20bb29435effc009ab273dcabd..6f7127192a859afa1ed638c70867b3ffc4686440 100644 --- a/pc/devata.c +++ b/pc/devata.c @@ -118,7 +118,7 @@ struct Controller { QLock; /* exclusive access to the controller */ - Lock; /* exclusive access to the registers */ + Lock reglock; /* exclusive access to the registers */ int confused; /* needs to be recalibrated (or worse) */ int pbase; /* base port */ @@ -566,7 +566,7 @@ ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) dp->usetime = m->ticks; cmdreadywait(dp); - ilock(cp); + ilock(&cp->reglock); cp->sofar = 0; cp->buf = buf; cp->nsecs = len; @@ -589,7 +589,7 @@ ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); } else stat = 0; - iunlock(cp); + iunlock(&cp->reglock); if(stat & Serr) error(Eio); @@ -646,12 +646,12 @@ atasetbuf(Drive *dp, int on) cmdreadywait(dp); - ilock(cp); + ilock(&cp->reglock); cp->cmd = Csetbuf; outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */ outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); outb(cp->pbase+Pcmd, Csetbuf); - iunlock(cp); + iunlock(&cp->reglock); sleep(&cp->r, cmddone, cp); @@ -727,7 +727,7 @@ ataident(Drive *dp) cmdreadywait(dp); - ilock(cp); + ilock(&cp->reglock); cp->nsecs = 1; cp->sofar = 0; cp->cmd = Cident; @@ -735,7 +735,7 @@ ataident(Drive *dp) cp->buf = buf; outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); outb(cp->pbase+Pcmd, Cident); - iunlock(cp); + iunlock(&cp->reglock); sleep(&cp->r, cmddone, cp); if(cp->status & Serr){ @@ -812,7 +812,7 @@ ataprobe(Drive *dp, int cyl, int sec, int head) cmdreadywait(dp); - ilock(cp); + ilock(&cp->reglock); cp->cmd = Cread; cp->dp = dp; cp->status = 0; @@ -825,7 +825,7 @@ ataprobe(Drive *dp, int cyl, int sec, int head) outb(cp->pbase+Pcyllsb, cyl); outb(cp->pbase+Pcylmsb, cyl>>8); outb(cp->pbase+Pcmd, Cread); - iunlock(cp); + iunlock(&cp->reglock); sleep(&cp->r, cmddone, cp); @@ -1058,7 +1058,7 @@ ataintr(Ureg *ur, void *arg) cp = &atac[0]; dp = cp->dp; - ilock(cp); + ilock(&cp->reglock); loop = 0; while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ @@ -1152,7 +1152,7 @@ ataintr(Ureg *ur, void *arg) break; } - iunlock(cp); + iunlock(&cp->reglock); } void @@ -1172,12 +1172,12 @@ hardclock(void) diff = TK2SEC(m->ticks - dp->usetime); if((dp->state == Sspinning) && (diff >= spindowntime)){ - ilock(cp); + ilock(&cp->reglock); cp->cmd = Cstandby; outb(cp->pbase+Pcount, 0); outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | 0); outb(cp->pbase+Pcmd, cp->cmd); - iunlock(cp); + iunlock(&cp->reglock); dp->state = Sstandby; } } diff --git a/pc/dma.c b/pc/dma.c index 9e29a19e4dfe1efecd0986376fc5d794c8315ba5..9a937b219d2104a5a36ab8924ae0f9570bdf3bbb 100644 --- a/pc/dma.c +++ b/pc/dma.c @@ -56,13 +56,12 @@ struct DMAport uchar mc; /* master clear */ uchar cmask; /* clear mask register */ uchar wam; /* write all mask register bit */ - - Lock; }; struct DMA { DMAport; + int shift; Lock; DMAxfer x[4]; }; @@ -71,11 +70,14 @@ DMA dma[2] = { { 0x00, 0x02, 0x04, 0x06, 0x01, 0x03, 0x05, 0x07, 0x87, 0x83, 0x81, 0x82, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, - { 0xc0, 0xc6, 0xca, 0xce, - 0xc4, 0xc8, 0xcc, 0xcf, - 0x80, 0x8b, 0x89, 0x8a, - 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0 }, + + { 0xc0, 0xc4, 0xc8, 0xcc, + 0xc2, 0xc6, 0xca, 0xce, + 0x8f, 0x8b, 0x89, 0x8a, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 1 }, }; /* @@ -95,6 +97,8 @@ dmainit(void) xp = &dp->x[chan]; xp->pg.pa = (ulong)xspanalloc(BY2PG, BY2PG, 0); xp->pg.va = KZERO|xp->pg.pa; + xp->len = 0; + xp->isread = 0; } } } @@ -143,17 +147,17 @@ dmasetup(int chan, void *va, long len, int isread) /* * this setup must be atomic */ - lock(dp); - outb(dp->cbp, 0); /* set count & address to their first byte */ + ilock(dp); mode = (isread ? 0x44 : 0x48) | chan; outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */ - outb(dp->addr[chan], pa); /* set address */ - outb(dp->addr[chan], pa>>8); outb(dp->page[chan], pa>>16); - outb(dp->count[chan], len-1); /* set count */ - outb(dp->count[chan], (len-1)>>8); + outb(dp->cbp, 0); /* set count & address to their first byte */ + outb(dp->addr[chan], pa>>dp->shift); /* set address */ + outb(dp->addr[chan], pa>>(8+dp->shift)); + outb(dp->count[chan], (len>>dp->shift)-1); /* set count */ + outb(dp->count[chan], ((len>>dp->shift)-1)>>8); outb(dp->sbm, chan); /* enable the channel */ - unlock(dp); + iunlock(dp); return len; } @@ -177,9 +181,9 @@ dmaend(int chan) /* * disable the channel */ - lock(dp); + ilock(dp); outb(dp->sbm, 4|chan); - unlock(dp); + iunlock(dp); xp = &dp->x[chan]; if(xp->len == 0 || !xp->isread) diff --git a/port/devaudio.c b/port/devaudio.c index 478f23c697cc5cc13de67b52048156376d9b8a77..fc7e2d5fb95e271fd2b80cddeb8b80bd02b3c236 100644 --- a/port/devaudio.c +++ b/port/devaudio.c @@ -11,8 +11,6 @@ #include "io.h" #include "audio.h" - -#define nelem(x) (sizeof (x)/sizeof(x[0])) #define NPORT (sizeof audiodir/sizeof(Dirtab)) typedef struct Buf Buf; @@ -26,7 +24,8 @@ enum Fmono = 1, - Aread = 0, + Aclosed = 0, + Aread, Awrite, Speed = 44100, @@ -67,12 +66,13 @@ struct Queue }; 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; /* Aread/Awrite for /audio */ + int amode; /* Aclosed/Aread/Awrite for /audio */ Level left; /* all of left volumes */ Level right; /* all of right volumes */ int mic; /* mono level */ @@ -121,9 +121,24 @@ static struct 0 }; +static struct +{ + 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; +} blaster; + static void swab(uchar*); -static char Emajor[] = "SB16 version too old"; +static char Emajor[] = "SoundBlaster version too old"; static char Emode[] = "illegal open mode"; static char Evolume[] = "illegal volume specifier"; @@ -133,9 +148,9 @@ sbcmd(int val) int i, s; for(i=1<<16; i!=0; i--) { - s = inb(PORT_WSTATUS); + s = inb(blaster.wstatus); if((s & 0x80) == 0) { - outb(PORT_WRITE, val); + outb(blaster.write, val); return 0; } } @@ -149,9 +164,9 @@ sbread(void) int i, s; for(i=1<<16; i!=0; i--) { - s = inb(PORT_RSTATUS); + s = inb(blaster.rstatus); if((s & 0x80) != 0) { - return inb(PORT_READ); + return inb(blaster.read); } } /* print("SB16 sbread did not respond\n"); /**/ @@ -162,8 +177,8 @@ static int mxcmd(int addr, int val) { - outb(PORT_MIXER_ADDR, addr); - outb(PORT_MIXER_DATA, val); + outb(blaster.mixaddr, addr); + outb(blaster.mixdata, val); return 1; } @@ -172,8 +187,8 @@ mxread(int addr) { int s; - outb(PORT_MIXER_ADDR, addr); - s = inb(PORT_MIXER_DATA); + outb(blaster.mixaddr, addr); + s = inb(blaster.mixdata); return s; } @@ -214,9 +229,7 @@ mxcmdu(int s, int v) static void mxvolume(void) { - ulong sp; - - sp = splhi(); + ilock(&blaster); mxcmds(0x30, audio.left.master); mxcmds(0x31, audio.right.master); @@ -249,7 +262,7 @@ mxvolume(void) mxcmd(0x3c, audio.oswitch); mxcmd(0x3d, audio.left.iswitch); mxcmd(0x3e, audio.right.iswitch); - splx(sp); + iunlock(&blaster); } static Buf* @@ -287,7 +300,6 @@ static void contindma(void) { Buf *b; - ulong count, addr; if(!audio.active) goto shutdown; @@ -306,24 +318,11 @@ contindma(void) if(b == 0) goto shutdown; - addr = b->phys; - count = ((Bufsize) >> 1) - 1; - -/* outb(DMA2_WRMASK, 4|(Dma&3)); /* disable dma */ - outb(DMA6_LPAGE, (addr>>16) & 0xfe); - outb(DMA2_CLRBP, 0); /* clear ff */ - outb(DMA6_ADDRESS, addr>>1); - outb(DMA6_ADDRESS, addr>>9); - - outb(DMA2_CLRBP, 0); /* clear ff */ - outb(DMA6_COUNT, count); - outb(DMA6_COUNT, count>>8); - outb(DMA2_WRMASK, (Dma&3)); /* enable dma */ - + dmasetup(Dma, b->virt, Bufsize, audio.amode == Aread); return; shutdown: - outb(DMA2_WRMASK, 4|(Dma&3)); /* disable dma */ + dmaend(Dma); sbcmd(0xd9); /* exit at end of count */ sbcmd(0xd5); /* pause */ audio.curcount = 0; @@ -339,14 +338,12 @@ startdma(void) { ulong count; - outb(DMA2_WRMASK, 4|(Dma&3)); /* disable dma */ - if(audio.amode == Aread) { - outb(DMA2_WRMODE, 0x44 | (Dma&3)); /* set mode */ + ilock(&blaster); + dmaend(Dma); + if(audio.amode == Aread) sbcmd(0x42); /* input sampling rate */ - } else { - outb(DMA2_WRMODE, 0x48 | (Dma&3)); /* set mode */ + else sbcmd(0x41); /* output sampling rate */ - } sbcmd(audio.speed>>8); sbcmd(audio.speed); @@ -361,6 +358,7 @@ startdma(void) audio.active = 1; contindma(); + iunlock(&blaster); } /* @@ -370,12 +368,8 @@ startdma(void) static void pokeaudio(void) { - ulong sp; - - sp = splhi(); if(!audio.active) startdma(); - splx(sp); } void @@ -387,21 +381,31 @@ audiosbintr(void) if(stat) { dummy = 0; if(stat & 2) { - dummy = inb(PORT_CLRI16); + ilock(&blaster); + dummy = inb(blaster.clri16); contindma(); + iunlock(&blaster); audio.intr = 1; wakeup(&audio.vous); } if(stat & 1) { - dummy = inb(PORT_CLRI8); + dummy = inb(blaster.clri8); } if(stat & 4) { - dummy = inb(PORT_CLRI401); + dummy = inb(blaster.clri401); } USED(dummy); } } +void +pcaudiosbintr(Ureg *ureg, void *rock) +{ + USED(ureg, rock); +/* print("sb16 audio interrupt\n"); /**/ + audiosbintr(); +} + void audiodmaintr(void) { @@ -427,7 +431,7 @@ waitaudio(void) pokeaudio(); tsleep(&audio.vous, anybuf, 0, 10*1000); if(audio.intr == 0) { -/* print("audio timeout\n"); /**/ + print("audio timeout\n"); /**/ audio.active = 0; pokeaudio(); } @@ -452,6 +456,7 @@ setempty(void) { int i; + ilock(&blaster); audio.empty.first = 0; audio.empty.last = 0; audio.full.first = 0; @@ -460,6 +465,7 @@ setempty(void) audio.filling = 0; for(i=0; i3 υs */ - outb(PORT_RESET, 0); + outb(blaster.reset, 0); delay(1); i = sbread(); @@ -516,10 +563,10 @@ audioinit(void) * set up irq/dma chans */ mxcmd(0x80, /* irq */ - (Irq==2)? 1: - (Irq==5)? 2: - (Irq==7)? 4: - (Irq==10)? 8: + (sbconf.irq==2)? 1: + (sbconf.irq==5)? 2: + (sbconf.irq==7)? 4: + (sbconf.irq==10)? 8: 0); mxcmd(0x81, 1<flag & COPEN) { + qlock(&audio); + audio.amode = Aclosed; + if(waserror()){ + qunlock(&audio); + nexterror(); + } while(audio.active) waitaudio(); setempty(); + poperror(); + qunlock(&audio); } break; } @@ -640,6 +701,11 @@ audioread(Chan *c, char *a, long n, ulong offset) case Qaudio: if(audio.amode != Aread) error(Emode); + qlock(&audio); + if(waserror()){ + qunlock(&audio); + nexterror(); + } while(n > 0) { b = audio.filling; if(b == 0) { @@ -665,6 +731,8 @@ audioread(Chan *c, char *a, long n, ulong offset) putbuf(&audio.empty, b); } } + poperror(); + qunlock(&audio); break; case Qvolume: @@ -770,6 +838,11 @@ audiowrite(Chan *c, char *a, long n, ulong offset) case Qaudio: if(audio.amode != Awrite) error(Emode); + qlock(&audio); + if(waserror()){ + qunlock(&audio); + nexterror(); + } while(n > 0) { b = audio.filling; if(b == 0) { @@ -796,6 +869,8 @@ audiowrite(Chan *c, char *a, long n, ulong offset) putbuf(&audio.full, b); } } + poperror(); + qunlock(&audio); break; } return n0 - n; @@ -829,6 +904,8 @@ swab(uchar *a) { ulong *p, *ep, b; + if(!SBswab) + return; p = (ulong*)a; ep = p + (Bufsize>>2); while(p < ep) {