/* * SB 16 driver */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "io.h"#include "audio.h" typedef struct AQueue AQueue;typedef struct Buf Buf; enum{ Qdir = 0, Qaudio, Qvolume, Fmono = 1, Fin = 2, Fout = 4, Aclosed = 0, Aread, Awrite, Vaudio = 0, Vsynth, Vcd, Vline, Vmic, Vspeaker, Vtreb, Vbass, Vspeed, Nvol, Speed = 44100, Ncmd = 50, /* max volume command words */}; staticDirtab audiodir[] ={ ".", {Qdir, 0, QTDIR}, 0, 0555, "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666,}; struct Buf{ uchar* virt; ulong phys; Buf* next;};struct AQueue{ Lock; Buf* first; Buf* last;};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 */ Buf buf[Nbuf]; /* buffers and queues */ AQueue empty; AQueue full; Buf* current; Buf* filling;} audio; 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, [Vtreb] "treb", Fout, 50, 50,[Vbass] "bass", Fout, 50, 50, [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, 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; int dma;} blaster; static void swab(uchar*); static char Emajor[] = "soundblaster not responding/wrong version";static char Emode[] = "illegal open mode";static char Evolume[] = "illegal volume specifier"; static intsbcmd(int val){ int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.wstatus); if((s & 0x80) == 0) { outb(blaster.write, val); return 0; } }/* print("#A: sbcmd (#%.2x) timeout\n", val); /**/ return 1;} static intsbread(void){ int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.rstatus); if((s & 0x80) != 0) { return inb(blaster.read); } }/* print("#A: sbread did not respond\n"); /**/ return 0xbb;} static intmxcmd(int addr, int val){ outb(blaster.mixaddr, addr); outb(blaster.mixdata, val); return 1;} static intmxread(int addr){ int s; outb(blaster.mixaddr, addr); s = inb(blaster.mixdata); return s;} static voidmxcmds(int s, int v){ if(v > 100) v = 100; if(v < 0) v = 0; mxcmd(s, (v*255)/100);} static voidmxcmdt(int s, int v){ if(v > 100) v = 100; if(v <= 0) mxcmd(s, 0); else mxcmd(s, 255-100+v);} static voidmxcmdu(int s, int v){ if(v > 100) v = 100; if(v <= 0) v = 0; mxcmd(s, 128-50+v);} static voidmxvolume(void){ int *left, *right; int source; if(audio.amode == Aread){ left = audio.livol; right = audio.rivol; }else{ left = audio.lovol; right = audio.rovol; } ilock(&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 */ mxcmds(0x32, left[Vaudio]); mxcmds(0x33, right[Vaudio]); mxcmds(0x34, left[Vsynth]); mxcmds(0x35, right[Vsynth]); mxcmds(0x36, left[Vcd]); mxcmds(0x37, right[Vcd]); mxcmds(0x38, left[Vline]); mxcmds(0x39, right[Vline]); mxcmds(0x3a, left[Vmic]); mxcmds(0x3b, left[Vspeaker]); mxcmdu(0x44, left[Vtreb]); mxcmdu(0x45, right[Vtreb]); mxcmdu(0x46, left[Vbass]); mxcmdu(0x47, right[Vbass]); source = 0; if(left[Vsynth]) source |= 1<<6; if(right[Vsynth]) source |= 1<<5; if(left[Vaudio]) source |= 1<<4; if(right[Vaudio]) source |= 1<<3; if(left[Vcd]) source |= 1<<2; if(right[Vcd]) source |= 1<<1; if(left[Vmic]) source |= 1<<0; if(audio.amode == Aread) mxcmd(0x3c, 0); /* output switch */ else mxcmd(0x3c, source); mxcmd(0x3d, source); /* input left switch */ mxcmd(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 voidputbuf(AQueue *q, Buf *b){ ilock(q); b->next = 0; if(q->first) q->last->next = b; else q->first = b; q->last = b; iunlock(q);} /* * move the dma to the next buffer */static voidcontindma(void){ Buf *b; if(!audio.active) goto shutdown; b = audio.current; if(audio.amode == Aread) { if(b) /* shouldnt happen */ putbuf(&audio.full, b); b = getbuf(&audio.empty); } else { if(b) /* shouldnt happen */ putbuf(&audio.empty, b); b = getbuf(&audio.full); } audio.current = b; if(b == 0) goto shutdown; dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread); return; shutdown: dmaend(blaster.dma); sbcmd(0xd9); /* exit at end of count */ sbcmd(0xd5); /* pause */ audio.curcount = 0; audio.active = 0;} /* * cause sb to get an interrupt per buffer. * start first dma */static voidstartdma(void){ ulong count; int speed; ilock(&blaster); dmaend(blaster.dma); if(audio.amode == Aread) { sbcmd(0x42); /* input sampling rate */ speed = audio.livol[Vspeed]; } else { sbcmd(0x41); /* output sampling rate */ speed = audio.lovol[Vspeed]; } sbcmd(speed>>8); sbcmd(speed); count = (Bufsize >> 1) - 1; if(audio.amode == Aread) sbcmd(0xbe); /* A/D, autoinit */ else sbcmd(0xb6); /* D/A, autoinit */ sbcmd(0x30); /* stereo, 16 bit */ sbcmd(count); sbcmd(count>>8); audio.active = 1; contindma(); iunlock(&blaster);} /* * if audio is stopped, * start it up again. */static voidpokeaudio(void){ if(!audio.active) startdma();} static voidaudiosbintr(void){ int stat, dummy; stat = mxread(0x82) & 7; /* get irq status */ if(stat) { dummy = 0; if(stat & 2) { ilock(&blaster); dummy = inb(blaster.clri16); contindma(); iunlock(&blaster); audio.intr = 1; wakeup(&audio.vous); } if(stat & 1) { dummy = inb(blaster.clri8); } if(stat & 4) { dummy = inb(blaster.clri401); } USED(dummy); }} static voidpcaudiosbintr(Ureg*, void*){/* print("#A: audio interrupt\n"); /**/ audiosbintr();} static voidaudiodmaintr(void){/* print("#A: dma interrupt\n"); /**/} static intanybuf(void*){ return audio.intr;} /* * wait for some output to get * empty buffers back. */static voidwaitaudio(void){ audio.intr = 0; pokeaudio(); tsleep(&audio.vous, anybuf, 0, 10*1000); if(audio.intr == 0) {/* print("#A: audio timeout\n"); /**/ audio.active = 0; pokeaudio(); }} static voidsbbufinit(void){ int i; void *p; for(i=0; i<Nbuf; i++) { p = xspanalloc(Bufsize, CACHELINESZ, 64*1024); dcflush(p, Bufsize); audio.buf[i].virt = UNCACHED(uchar, p); audio.buf[i].phys = (ulong)PADDR(p); }} static voidsetempty(void){ 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; for(i=0; i<Nbuf; i++) putbuf(&audio.empty, &audio.buf[i]); iunlock(&blaster);} static voidresetlevel(void){ int i; 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; }}Lines 1–500 of 947. Load more
/* * SB 16 driver */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "io.h" #include "audio.h" typedef struct AQueue AQueue; typedef struct Buf Buf; enum { Qdir = 0, Qaudio, Qvolume, Fmono = 1, Fin = 2, Fout = 4, Aclosed = 0, Aread, Awrite, Vaudio = 0, Vsynth, Vcd, Vline, Vmic, Vspeaker, Vtreb, Vbass, Vspeed, Nvol, Speed = 44100, Ncmd = 50, /* max volume command words */ }; static Dirtab audiodir[] = { ".", {Qdir, 0, QTDIR}, 0, 0555, "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, }; struct Buf { uchar* virt; ulong phys; Buf* next; }; struct AQueue { Lock; Buf* first; Buf* last; }; 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 */ Buf buf[Nbuf]; /* buffers and queues */ AQueue empty; AQueue full; Buf* current; Buf* filling; } audio; 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, [Vtreb] "treb", Fout, 50, 50, [Vbass] "bass", Fout, 50, 50, [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, 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; int dma; } blaster; static void swab(uchar*); static char Emajor[] = "soundblaster not responding/wrong version"; static char Emode[] = "illegal open mode"; static char Evolume[] = "illegal volume specifier"; static int sbcmd(int val) { int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.wstatus); if((s & 0x80) == 0) { outb(blaster.write, val); return 0; } } /* print("#A: sbcmd (#%.2x) timeout\n", val); /**/ return 1; } static int sbread(void) { int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.rstatus); if((s & 0x80) != 0) { return inb(blaster.read); } } /* print("#A: sbread did not respond\n"); /**/ return 0xbb; } static int mxcmd(int addr, int val) { outb(blaster.mixaddr, addr); outb(blaster.mixdata, val); return 1; } static int mxread(int addr) { int s; outb(blaster.mixaddr, addr); s = inb(blaster.mixdata); return s; } static void mxcmds(int s, int v) { if(v > 100) v = 100; if(v < 0) v = 0; mxcmd(s, (v*255)/100); } static void mxcmdt(int s, int v) { if(v > 100) v = 100; if(v <= 0) mxcmd(s, 0); else mxcmd(s, 255-100+v); } static void mxcmdu(int s, int v) { if(v > 100) v = 100; if(v <= 0) v = 0; mxcmd(s, 128-50+v); } static void mxvolume(void) { int *left, *right; int source; if(audio.amode == Aread){ left = audio.livol; right = audio.rivol; }else{ left = audio.lovol; right = audio.rovol; } ilock(&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 */ mxcmds(0x32, left[Vaudio]); mxcmds(0x33, right[Vaudio]); mxcmds(0x34, left[Vsynth]); mxcmds(0x35, right[Vsynth]); mxcmds(0x36, left[Vcd]); mxcmds(0x37, right[Vcd]); mxcmds(0x38, left[Vline]); mxcmds(0x39, right[Vline]); mxcmds(0x3a, left[Vmic]); mxcmds(0x3b, left[Vspeaker]); mxcmdu(0x44, left[Vtreb]); mxcmdu(0x45, right[Vtreb]); mxcmdu(0x46, left[Vbass]); mxcmdu(0x47, right[Vbass]); source = 0; if(left[Vsynth]) source |= 1<<6; if(right[Vsynth]) source |= 1<<5; if(left[Vaudio]) source |= 1<<4; if(right[Vaudio]) source |= 1<<3; if(left[Vcd]) source |= 1<<2; if(right[Vcd]) source |= 1<<1; if(left[Vmic]) source |= 1<<0; if(audio.amode == Aread) mxcmd(0x3c, 0); /* output switch */ else mxcmd(0x3c, source); mxcmd(0x3d, source); /* input left switch */ mxcmd(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) { ilock(q); b->next = 0; if(q->first) q->last->next = b; else q->first = b; q->last = b; iunlock(q); } /* * move the dma to the next buffer */ static void contindma(void) { Buf *b; if(!audio.active) goto shutdown; b = audio.current; if(audio.amode == Aread) { if(b) /* shouldnt happen */ putbuf(&audio.full, b); b = getbuf(&audio.empty); } else { if(b) /* shouldnt happen */ putbuf(&audio.empty, b); b = getbuf(&audio.full); } audio.current = b; if(b == 0) goto shutdown; dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread); return; shutdown: dmaend(blaster.dma); sbcmd(0xd9); /* exit at end of count */ sbcmd(0xd5); /* pause */ audio.curcount = 0; audio.active = 0; } /* * cause sb to get an interrupt per buffer. * start first dma */ static void startdma(void) { ulong count; int speed; ilock(&blaster); dmaend(blaster.dma); if(audio.amode == Aread) { sbcmd(0x42); /* input sampling rate */ speed = audio.livol[Vspeed]; } else { sbcmd(0x41); /* output sampling rate */ speed = audio.lovol[Vspeed]; } sbcmd(speed>>8); sbcmd(speed); count = (Bufsize >> 1) - 1; if(audio.amode == Aread) sbcmd(0xbe); /* A/D, autoinit */ else sbcmd(0xb6); /* D/A, autoinit */ sbcmd(0x30); /* stereo, 16 bit */ sbcmd(count); sbcmd(count>>8); audio.active = 1; contindma(); iunlock(&blaster); } /* * if audio is stopped, * start it up again. */ static void pokeaudio(void) { if(!audio.active) startdma(); } static void audiosbintr(void) { int stat, dummy; stat = mxread(0x82) & 7; /* get irq status */ if(stat) { dummy = 0; if(stat & 2) { ilock(&blaster); dummy = inb(blaster.clri16); contindma(); iunlock(&blaster); audio.intr = 1; wakeup(&audio.vous); } if(stat & 1) { dummy = inb(blaster.clri8); } if(stat & 4) { dummy = inb(blaster.clri401); } USED(dummy); } } static void pcaudiosbintr(Ureg*, void*) { /* print("#A: audio interrupt\n"); /**/ audiosbintr(); } static void audiodmaintr(void) { /* print("#A: dma interrupt\n"); /**/ } static int anybuf(void*) { return audio.intr; } /* * wait for some output to get * empty buffers back. */ static void waitaudio(void) { audio.intr = 0; pokeaudio(); tsleep(&audio.vous, anybuf, 0, 10*1000); if(audio.intr == 0) { /* print("#A: audio timeout\n"); /**/ audio.active = 0; pokeaudio(); } } static void sbbufinit(void) { int i; void *p; for(i=0; i<Nbuf; i++) { p = xspanalloc(Bufsize, CACHELINESZ, 64*1024); dcflush(p, Bufsize); audio.buf[i].virt = UNCACHED(uchar, p); audio.buf[i].phys = (ulong)PADDR(p); } } static void setempty(void) { 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; for(i=0; i<Nbuf; i++) putbuf(&audio.empty, &audio.buf[i]); iunlock(&blaster); } static void resetlevel(void) { int i; 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; } }