17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * SB 16 driver
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
97dd7cddfSDavid du Colombier #include "../port/error.h"
107dd7cddfSDavid du Colombier #include "io.h"
117dd7cddfSDavid du Colombier #include "audio.h"
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier typedef struct AQueue AQueue;
147dd7cddfSDavid du Colombier typedef struct Buf Buf;
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier enum
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier Qdir = 0,
197dd7cddfSDavid du Colombier Qaudio,
207dd7cddfSDavid du Colombier Qvolume,
217dd7cddfSDavid du Colombier Qstatus,
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier Fmono = 1,
247dd7cddfSDavid du Colombier Fin = 2,
257dd7cddfSDavid du Colombier Fout = 4,
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier Aclosed = 0,
287dd7cddfSDavid du Colombier Aread,
297dd7cddfSDavid du Colombier Awrite,
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier Vaudio = 0,
327dd7cddfSDavid du Colombier Vsynth,
337dd7cddfSDavid du Colombier Vcd,
347dd7cddfSDavid du Colombier Vline,
357dd7cddfSDavid du Colombier Vmic,
367dd7cddfSDavid du Colombier Vspeaker,
377dd7cddfSDavid du Colombier Vtreb,
387dd7cddfSDavid du Colombier Vbass,
397dd7cddfSDavid du Colombier Vspeed,
407dd7cddfSDavid du Colombier Nvol,
417dd7cddfSDavid du Colombier
427dd7cddfSDavid du Colombier Speed = 44100,
437dd7cddfSDavid du Colombier Ncmd = 50, /* max volume command words */
447dd7cddfSDavid du Colombier };
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier Dirtab
477dd7cddfSDavid du Colombier audiodir[] =
487dd7cddfSDavid du Colombier {
499a747e4fSDavid du Colombier ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
507dd7cddfSDavid du Colombier "audio", {Qaudio}, 0, 0666,
517dd7cddfSDavid du Colombier "volume", {Qvolume}, 0, 0666,
527dd7cddfSDavid du Colombier "audiostat",{Qstatus}, 0, 0444,
537dd7cddfSDavid du Colombier };
547dd7cddfSDavid du Colombier
557dd7cddfSDavid du Colombier struct Buf
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier uchar* virt;
587dd7cddfSDavid du Colombier ulong phys;
597dd7cddfSDavid du Colombier Buf* next;
607dd7cddfSDavid du Colombier };
617dd7cddfSDavid du Colombier struct AQueue
627dd7cddfSDavid du Colombier {
637dd7cddfSDavid du Colombier Lock;
647dd7cddfSDavid du Colombier Buf* first;
657dd7cddfSDavid du Colombier Buf* last;
667dd7cddfSDavid du Colombier };
677dd7cddfSDavid du Colombier static struct
687dd7cddfSDavid du Colombier {
697dd7cddfSDavid du Colombier QLock;
707dd7cddfSDavid du Colombier Rendez vous;
719a747e4fSDavid du Colombier int buffered; /* number of bytes en route */
727dd7cddfSDavid du Colombier int bufinit; /* boolean if buffers allocated */
737dd7cddfSDavid du Colombier int curcount; /* how much data in current buffer */
747dd7cddfSDavid du Colombier int active; /* boolean dma running */
757dd7cddfSDavid du Colombier int intr; /* boolean an interrupt has happened */
767dd7cddfSDavid du Colombier int amode; /* Aclosed/Aread/Awrite for /audio */
777dd7cddfSDavid du Colombier int rivol[Nvol]; /* right/left input/output volumes */
787dd7cddfSDavid du Colombier int livol[Nvol];
797dd7cddfSDavid du Colombier int rovol[Nvol];
807dd7cddfSDavid du Colombier int lovol[Nvol];
817dd7cddfSDavid du Colombier int major; /* SB16 major version number (sb 4) */
827dd7cddfSDavid du Colombier int minor; /* SB16 minor version number */
837dd7cddfSDavid du Colombier ulong totcount; /* how many bytes processed since open */
847dd7cddfSDavid du Colombier vlong tottime; /* time at which totcount bytes were processed */
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier Buf buf[Nbuf]; /* buffers and queues */
877dd7cddfSDavid du Colombier AQueue empty;
887dd7cddfSDavid du Colombier AQueue full;
897dd7cddfSDavid du Colombier Buf* current;
907dd7cddfSDavid du Colombier Buf* filling;
917dd7cddfSDavid du Colombier } audio;
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier static struct
947dd7cddfSDavid du Colombier {
957dd7cddfSDavid du Colombier char* name;
967dd7cddfSDavid du Colombier int flag;
977dd7cddfSDavid du Colombier int ilval; /* initial values */
987dd7cddfSDavid du Colombier int irval;
997dd7cddfSDavid du Colombier } volumes[] =
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier [Vaudio] "audio", Fout, 50, 50,
1027dd7cddfSDavid du Colombier [Vsynth] "synth", Fin|Fout, 0, 0,
1037dd7cddfSDavid du Colombier [Vcd] "cd", Fin|Fout, 0, 0,
1047dd7cddfSDavid du Colombier [Vline] "line", Fin|Fout, 0, 0,
1057dd7cddfSDavid du Colombier [Vmic] "mic", Fin|Fout|Fmono, 0, 0,
1067dd7cddfSDavid du Colombier [Vspeaker] "speaker", Fout|Fmono, 0, 0,
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier [Vtreb] "treb", Fout, 50, 50,
1097dd7cddfSDavid du Colombier [Vbass] "bass", Fout, 50, 50,
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed,
1127dd7cddfSDavid du Colombier 0
1137dd7cddfSDavid du Colombier };
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier static struct
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier Lock;
1187dd7cddfSDavid du Colombier int reset; /* io ports to the sound blaster */
1197dd7cddfSDavid du Colombier int read;
1207dd7cddfSDavid du Colombier int write;
1217dd7cddfSDavid du Colombier int wstatus;
1227dd7cddfSDavid du Colombier int rstatus;
1237dd7cddfSDavid du Colombier int mixaddr;
1247dd7cddfSDavid du Colombier int mixdata;
1257dd7cddfSDavid du Colombier int clri8;
1267dd7cddfSDavid du Colombier int clri16;
1277dd7cddfSDavid du Colombier int clri401;
1287dd7cddfSDavid du Colombier int dma;
1297dd7cddfSDavid du Colombier
1307dd7cddfSDavid du Colombier void (*startdma)(void);
1317dd7cddfSDavid du Colombier void (*intr)(void);
1327dd7cddfSDavid du Colombier } blaster;
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier static void swab(uchar*);
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier static char Emajor[] = "soundblaster not responding/wrong version";
1377dd7cddfSDavid du Colombier static char Emode[] = "illegal open mode";
1387dd7cddfSDavid du Colombier static char Evolume[] = "illegal volume specifier";
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier static int
sbcmd(int val)1417dd7cddfSDavid du Colombier sbcmd(int val)
1427dd7cddfSDavid du Colombier {
1437dd7cddfSDavid du Colombier int i, s;
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier for(i=1<<16; i!=0; i--) {
1467dd7cddfSDavid du Colombier s = inb(blaster.wstatus);
1477dd7cddfSDavid du Colombier if((s & 0x80) == 0) {
1487dd7cddfSDavid du Colombier outb(blaster.write, val);
1497dd7cddfSDavid du Colombier return 0;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier }
152*567483c8SDavid du Colombier /* print("#A: sbcmd (%#.2x) timeout\n", val); /**/
1537dd7cddfSDavid du Colombier return 1;
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier
1567dd7cddfSDavid du Colombier static int
sbread(void)1577dd7cddfSDavid du Colombier sbread(void)
1587dd7cddfSDavid du Colombier {
1597dd7cddfSDavid du Colombier int i, s;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier for(i=1<<16; i!=0; i--) {
1627dd7cddfSDavid du Colombier s = inb(blaster.rstatus);
1637dd7cddfSDavid du Colombier if((s & 0x80) != 0) {
1647dd7cddfSDavid du Colombier return inb(blaster.read);
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier /* print("#A: sbread did not respond\n"); /**/
1687dd7cddfSDavid du Colombier return -1;
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier static int
ess1688w(int reg,int val)1727dd7cddfSDavid du Colombier ess1688w(int reg, int val)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier if(sbcmd(reg) || sbcmd(val))
1757dd7cddfSDavid du Colombier return 1;
1767dd7cddfSDavid du Colombier
1777dd7cddfSDavid du Colombier return 0;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier static int
ess1688r(int reg)1817dd7cddfSDavid du Colombier ess1688r(int reg)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier if(sbcmd(0xC0) || sbcmd(reg))
1847dd7cddfSDavid du Colombier return -1;
1857dd7cddfSDavid du Colombier
1867dd7cddfSDavid du Colombier return sbread();
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier static int
mxcmd(int addr,int val)1907dd7cddfSDavid du Colombier mxcmd(int addr, int val)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier outb(blaster.mixaddr, addr);
1947dd7cddfSDavid du Colombier outb(blaster.mixdata, val);
1957dd7cddfSDavid du Colombier return 1;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier static int
mxread(int addr)1997dd7cddfSDavid du Colombier mxread(int addr)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier int s;
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier outb(blaster.mixaddr, addr);
2047dd7cddfSDavid du Colombier s = inb(blaster.mixdata);
2057dd7cddfSDavid du Colombier return s;
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier static void
mxcmds(int s,int v)2097dd7cddfSDavid du Colombier mxcmds(int s, int v)
2107dd7cddfSDavid du Colombier {
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier if(v > 100)
2137dd7cddfSDavid du Colombier v = 100;
2147dd7cddfSDavid du Colombier if(v < 0)
2157dd7cddfSDavid du Colombier v = 0;
2167dd7cddfSDavid du Colombier mxcmd(s, (v*255)/100);
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier static void
mxcmdt(int s,int v)2207dd7cddfSDavid du Colombier mxcmdt(int s, int v)
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier
2237dd7cddfSDavid du Colombier if(v > 100)
2247dd7cddfSDavid du Colombier v = 100;
2257dd7cddfSDavid du Colombier if(v <= 0)
2267dd7cddfSDavid du Colombier mxcmd(s, 0);
2277dd7cddfSDavid du Colombier else
2287dd7cddfSDavid du Colombier mxcmd(s, 255-100+v);
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier static void
mxcmdu(int s,int v)2327dd7cddfSDavid du Colombier mxcmdu(int s, int v)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier if(v > 100)
2367dd7cddfSDavid du Colombier v = 100;
2377dd7cddfSDavid du Colombier if(v <= 0)
2387dd7cddfSDavid du Colombier v = 0;
2397dd7cddfSDavid du Colombier mxcmd(s, 128-50+v);
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier
2427dd7cddfSDavid du Colombier static void
mxvolume(void)2437dd7cddfSDavid du Colombier mxvolume(void)
2447dd7cddfSDavid du Colombier {
2457dd7cddfSDavid du Colombier int *left, *right;
2467dd7cddfSDavid du Colombier int source;
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier if(audio.amode == Aread){
2497dd7cddfSDavid du Colombier left = audio.livol;
2507dd7cddfSDavid du Colombier right = audio.rivol;
2517dd7cddfSDavid du Colombier }else{
2527dd7cddfSDavid du Colombier left = audio.lovol;
2537dd7cddfSDavid du Colombier right = audio.rovol;
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier
2567dd7cddfSDavid du Colombier ilock(&blaster);
2577dd7cddfSDavid du Colombier
2587dd7cddfSDavid du Colombier mxcmd(0x30, 255); /* left master */
2597dd7cddfSDavid du Colombier mxcmd(0x31, 255); /* right master */
2607dd7cddfSDavid du Colombier mxcmd(0x3f, 0); /* left igain */
2617dd7cddfSDavid du Colombier mxcmd(0x40, 0); /* right igain */
2627dd7cddfSDavid du Colombier mxcmd(0x41, 0); /* left ogain */
2637dd7cddfSDavid du Colombier mxcmd(0x42, 0); /* right ogain */
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier mxcmds(0x32, left[Vaudio]);
2667dd7cddfSDavid du Colombier mxcmds(0x33, right[Vaudio]);
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier mxcmds(0x34, left[Vsynth]);
2697dd7cddfSDavid du Colombier mxcmds(0x35, right[Vsynth]);
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier mxcmds(0x36, left[Vcd]);
2727dd7cddfSDavid du Colombier mxcmds(0x37, right[Vcd]);
2737dd7cddfSDavid du Colombier
2747dd7cddfSDavid du Colombier mxcmds(0x38, left[Vline]);
2757dd7cddfSDavid du Colombier mxcmds(0x39, right[Vline]);
2767dd7cddfSDavid du Colombier
2777dd7cddfSDavid du Colombier mxcmds(0x3a, left[Vmic]);
2787dd7cddfSDavid du Colombier mxcmds(0x3b, left[Vspeaker]);
2797dd7cddfSDavid du Colombier
2807dd7cddfSDavid du Colombier mxcmdu(0x44, left[Vtreb]);
2817dd7cddfSDavid du Colombier mxcmdu(0x45, right[Vtreb]);
2827dd7cddfSDavid du Colombier
2837dd7cddfSDavid du Colombier mxcmdu(0x46, left[Vbass]);
2847dd7cddfSDavid du Colombier mxcmdu(0x47, right[Vbass]);
2857dd7cddfSDavid du Colombier
2867dd7cddfSDavid du Colombier source = 0;
2877dd7cddfSDavid du Colombier if(left[Vsynth])
2887dd7cddfSDavid du Colombier source |= 1<<6;
2897dd7cddfSDavid du Colombier if(right[Vsynth])
2907dd7cddfSDavid du Colombier source |= 1<<5;
2917dd7cddfSDavid du Colombier if(left[Vaudio])
2927dd7cddfSDavid du Colombier source |= 1<<4;
2937dd7cddfSDavid du Colombier if(right[Vaudio])
2947dd7cddfSDavid du Colombier source |= 1<<3;
2957dd7cddfSDavid du Colombier if(left[Vcd])
2967dd7cddfSDavid du Colombier source |= 1<<2;
2977dd7cddfSDavid du Colombier if(right[Vcd])
2987dd7cddfSDavid du Colombier source |= 1<<1;
2997dd7cddfSDavid du Colombier if(left[Vmic])
3007dd7cddfSDavid du Colombier source |= 1<<0;
3017dd7cddfSDavid du Colombier if(audio.amode == Aread)
3027dd7cddfSDavid du Colombier mxcmd(0x3c, 0); /* output switch */
3037dd7cddfSDavid du Colombier else
3047dd7cddfSDavid du Colombier mxcmd(0x3c, source);
3057dd7cddfSDavid du Colombier mxcmd(0x3d, source); /* input left switch */
3067dd7cddfSDavid du Colombier mxcmd(0x3e, source); /* input right switch */
3077dd7cddfSDavid du Colombier iunlock(&blaster);
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier static Buf*
getbuf(AQueue * q)3117dd7cddfSDavid du Colombier getbuf(AQueue *q)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier Buf *b;
3147dd7cddfSDavid du Colombier
3157dd7cddfSDavid du Colombier ilock(q);
3167dd7cddfSDavid du Colombier b = q->first;
3177dd7cddfSDavid du Colombier if(b)
3187dd7cddfSDavid du Colombier q->first = b->next;
3197dd7cddfSDavid du Colombier iunlock(q);
3207dd7cddfSDavid du Colombier
3217dd7cddfSDavid du Colombier return b;
3227dd7cddfSDavid du Colombier }
3237dd7cddfSDavid du Colombier
3247dd7cddfSDavid du Colombier static void
putbuf(AQueue * q,Buf * b)3257dd7cddfSDavid du Colombier putbuf(AQueue *q, Buf *b)
3267dd7cddfSDavid du Colombier {
3277dd7cddfSDavid du Colombier
3287dd7cddfSDavid du Colombier ilock(q);
3297dd7cddfSDavid du Colombier b->next = 0;
3307dd7cddfSDavid du Colombier if(q->first)
3317dd7cddfSDavid du Colombier q->last->next = b;
3327dd7cddfSDavid du Colombier else
3337dd7cddfSDavid du Colombier q->first = b;
3347dd7cddfSDavid du Colombier q->last = b;
3357dd7cddfSDavid du Colombier iunlock(q);
3367dd7cddfSDavid du Colombier }
3377dd7cddfSDavid du Colombier
3387dd7cddfSDavid du Colombier /*
3397dd7cddfSDavid du Colombier * move the dma to the next buffer
3407dd7cddfSDavid du Colombier */
3417dd7cddfSDavid du Colombier static void
contindma(void)3427dd7cddfSDavid du Colombier contindma(void)
3437dd7cddfSDavid du Colombier {
3447dd7cddfSDavid du Colombier Buf *b;
3457dd7cddfSDavid du Colombier
3467dd7cddfSDavid du Colombier if(!audio.active)
3477dd7cddfSDavid du Colombier goto shutdown;
3487dd7cddfSDavid du Colombier
3497dd7cddfSDavid du Colombier b = audio.current;
3509a747e4fSDavid du Colombier if(b){
3519a747e4fSDavid du Colombier audio.totcount += Bufsize;
3529a747e4fSDavid du Colombier audio.tottime = todget(nil);
3539a747e4fSDavid du Colombier }
3547dd7cddfSDavid du Colombier if(audio.amode == Aread) {
3559a747e4fSDavid du Colombier if(b){
3567dd7cddfSDavid du Colombier putbuf(&audio.full, b);
3579a747e4fSDavid du Colombier audio.buffered += Bufsize;
3589a747e4fSDavid du Colombier }
3597dd7cddfSDavid du Colombier b = getbuf(&audio.empty);
3607dd7cddfSDavid du Colombier } else {
3619a747e4fSDavid du Colombier if(b){
3627dd7cddfSDavid du Colombier putbuf(&audio.empty, b);
3639a747e4fSDavid du Colombier audio.buffered -= Bufsize;
3649a747e4fSDavid du Colombier }
3657dd7cddfSDavid du Colombier b = getbuf(&audio.full);
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier audio.current = b;
3687dd7cddfSDavid du Colombier if(b == 0)
3697dd7cddfSDavid du Colombier goto shutdown;
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0)
3727dd7cddfSDavid du Colombier return;
3737dd7cddfSDavid du Colombier print("#A: dmasetup fail\n");
3747dd7cddfSDavid du Colombier putbuf(&audio.empty, b);
3757dd7cddfSDavid du Colombier
3767dd7cddfSDavid du Colombier shutdown:
3777dd7cddfSDavid du Colombier dmaend(blaster.dma);
3787dd7cddfSDavid du Colombier sbcmd(0xd9); /* exit at end of count */
3797dd7cddfSDavid du Colombier sbcmd(0xd5); /* pause */
3807dd7cddfSDavid du Colombier audio.curcount = 0;
3817dd7cddfSDavid du Colombier audio.active = 0;
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier
3847dd7cddfSDavid du Colombier /*
3857dd7cddfSDavid du Colombier * cause sb to get an interrupt per buffer.
3867dd7cddfSDavid du Colombier * start first dma
3877dd7cddfSDavid du Colombier */
3887dd7cddfSDavid du Colombier static void
sb16startdma(void)3897dd7cddfSDavid du Colombier sb16startdma(void)
3907dd7cddfSDavid du Colombier {
3917dd7cddfSDavid du Colombier ulong count;
3927dd7cddfSDavid du Colombier int speed;
3937dd7cddfSDavid du Colombier
3947dd7cddfSDavid du Colombier ilock(&blaster);
3957dd7cddfSDavid du Colombier dmaend(blaster.dma);
3967dd7cddfSDavid du Colombier if(audio.amode == Aread) {
3977dd7cddfSDavid du Colombier sbcmd(0x42); /* input sampling rate */
3987dd7cddfSDavid du Colombier speed = audio.livol[Vspeed];
3997dd7cddfSDavid du Colombier } else {
4007dd7cddfSDavid du Colombier sbcmd(0x41); /* output sampling rate */
4017dd7cddfSDavid du Colombier speed = audio.lovol[Vspeed];
4027dd7cddfSDavid du Colombier }
4037dd7cddfSDavid du Colombier sbcmd(speed>>8);
4047dd7cddfSDavid du Colombier sbcmd(speed);
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier count = (Bufsize >> 1) - 1;
4077dd7cddfSDavid du Colombier if(audio.amode == Aread)
4087dd7cddfSDavid du Colombier sbcmd(0xbe); /* A/D, autoinit */
4097dd7cddfSDavid du Colombier else
4107dd7cddfSDavid du Colombier sbcmd(0xb6); /* D/A, autoinit */
4117dd7cddfSDavid du Colombier sbcmd(0x30); /* stereo, 16 bit */
4127dd7cddfSDavid du Colombier sbcmd(count);
4137dd7cddfSDavid du Colombier sbcmd(count>>8);
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier audio.active = 1;
4167dd7cddfSDavid du Colombier contindma();
4177dd7cddfSDavid du Colombier iunlock(&blaster);
4187dd7cddfSDavid du Colombier }
4197dd7cddfSDavid du Colombier
4207dd7cddfSDavid du Colombier static int
ess1688reset(void)4217dd7cddfSDavid du Colombier ess1688reset(void)
4227dd7cddfSDavid du Colombier {
4237dd7cddfSDavid du Colombier int i;
4247dd7cddfSDavid du Colombier
4257dd7cddfSDavid du Colombier outb(blaster.reset, 3);
4267dd7cddfSDavid du Colombier delay(1); /* >3 υs */
4277dd7cddfSDavid du Colombier outb(blaster.reset, 0);
4287dd7cddfSDavid du Colombier delay(1);
4297dd7cddfSDavid du Colombier
4307dd7cddfSDavid du Colombier i = sbread();
4317dd7cddfSDavid du Colombier if(i != 0xAA) {
432*567483c8SDavid du Colombier print("#A: no response %#.2x\n", i);
4337dd7cddfSDavid du Colombier return 1;
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier if(sbcmd(0xC6)){ /* extended mode */
4377dd7cddfSDavid du Colombier print("#A: barf 3\n");
4387dd7cddfSDavid du Colombier return 1;
4397dd7cddfSDavid du Colombier }
4407dd7cddfSDavid du Colombier
4417dd7cddfSDavid du Colombier return 0;
4427dd7cddfSDavid du Colombier }
4437dd7cddfSDavid du Colombier
4447dd7cddfSDavid du Colombier static void
ess1688startdma(void)4457dd7cddfSDavid du Colombier ess1688startdma(void)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier ulong count;
4487dd7cddfSDavid du Colombier int speed, x;
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier ilock(&blaster);
4517dd7cddfSDavid du Colombier dmaend(blaster.dma);
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier if(audio.amode == Awrite)
4547dd7cddfSDavid du Colombier ess1688reset();
4557dd7cddfSDavid du Colombier if(audio.amode == Aread)
4567dd7cddfSDavid du Colombier sbcmd(0xD3); /* speaker off */
4577dd7cddfSDavid du Colombier
4587dd7cddfSDavid du Colombier /*
4597dd7cddfSDavid du Colombier * Set the speed.
4607dd7cddfSDavid du Colombier */
4617dd7cddfSDavid du Colombier if(audio.amode == Aread)
4627dd7cddfSDavid du Colombier speed = audio.livol[Vspeed];
4637dd7cddfSDavid du Colombier else
4647dd7cddfSDavid du Colombier speed = audio.lovol[Vspeed];
4657dd7cddfSDavid du Colombier if(speed < 4000)
4667dd7cddfSDavid du Colombier speed = 4000;
4677dd7cddfSDavid du Colombier else if(speed > 48000)
4687dd7cddfSDavid du Colombier speed = 48000;
4697dd7cddfSDavid du Colombier
4707dd7cddfSDavid du Colombier if(speed > 22000)
4717dd7cddfSDavid du Colombier x = 0x80|(256-(795500+speed/2)/speed);
4727dd7cddfSDavid du Colombier else
4737dd7cddfSDavid du Colombier x = 128-(397700+speed/2)/speed;
4747dd7cddfSDavid du Colombier ess1688w(0xA1, x & 0xFF);
4757dd7cddfSDavid du Colombier
4767dd7cddfSDavid du Colombier speed = (speed * 9) / 20;
4777dd7cddfSDavid du Colombier x = 256 - 7160000 / (speed * 82);
4787dd7cddfSDavid du Colombier ess1688w(0xA2, x & 0xFF);
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier if(audio.amode == Aread)
4817dd7cddfSDavid du Colombier ess1688w(0xB8, 0x0E); /* A/D, autoinit */
4827dd7cddfSDavid du Colombier else
4837dd7cddfSDavid du Colombier ess1688w(0xB8, 0x04); /* D/A, autoinit */
4847dd7cddfSDavid du Colombier x = ess1688r(0xA8) & ~0x03;
4857dd7cddfSDavid du Colombier ess1688w(0xA8, x|0x01); /* 2 channels */
4867dd7cddfSDavid du Colombier ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier if(audio.amode == Awrite)
4897dd7cddfSDavid du Colombier ess1688w(0xB6, 0);
4907dd7cddfSDavid du Colombier ess1688w(0xB7, 0x71);
4917dd7cddfSDavid du Colombier ess1688w(0xB7, 0xBC);
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier x = ess1688r(0xB1) & 0x0F;
4947dd7cddfSDavid du Colombier ess1688w(0xB1, x|0x50);
4957dd7cddfSDavid du Colombier x = ess1688r(0xB2) & 0x0F;
4967dd7cddfSDavid du Colombier ess1688w(0xB2, x|0x50);
4977dd7cddfSDavid du Colombier if(audio.amode == Awrite)
4987dd7cddfSDavid du Colombier sbcmd(0xD1); /* speaker on */
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier count = -Bufsize;
5017dd7cddfSDavid du Colombier ess1688w(0xA4, count & 0xFF);
5027dd7cddfSDavid du Colombier ess1688w(0xA5, (count>>8) & 0xFF);
5037dd7cddfSDavid du Colombier x = ess1688r(0xB8);
5047dd7cddfSDavid du Colombier ess1688w(0xB8, x|0x05);
5057dd7cddfSDavid du Colombier
5067dd7cddfSDavid du Colombier audio.active = 1;
5077dd7cddfSDavid du Colombier contindma();
5087dd7cddfSDavid du Colombier iunlock(&blaster);
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier /*
5127dd7cddfSDavid du Colombier * if audio is stopped,
5137dd7cddfSDavid du Colombier * start it up again.
5147dd7cddfSDavid du Colombier */
5157dd7cddfSDavid du Colombier static void
pokeaudio(void)5167dd7cddfSDavid du Colombier pokeaudio(void)
5177dd7cddfSDavid du Colombier {
5187dd7cddfSDavid du Colombier if(!audio.active)
5197dd7cddfSDavid du Colombier blaster.startdma();
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier
5227dd7cddfSDavid du Colombier static void
sb16intr(void)5237dd7cddfSDavid du Colombier sb16intr(void)
5247dd7cddfSDavid du Colombier {
5257dd7cddfSDavid du Colombier int stat, dummy;
5267dd7cddfSDavid du Colombier
5277dd7cddfSDavid du Colombier stat = mxread(0x82) & 7; /* get irq status */
5287dd7cddfSDavid du Colombier if(stat) {
5297dd7cddfSDavid du Colombier dummy = 0;
5307dd7cddfSDavid du Colombier if(stat & 2) {
5317dd7cddfSDavid du Colombier ilock(&blaster);
5327dd7cddfSDavid du Colombier dummy = inb(blaster.clri16);
5337dd7cddfSDavid du Colombier contindma();
5347dd7cddfSDavid du Colombier iunlock(&blaster);
5357dd7cddfSDavid du Colombier audio.intr = 1;
5367dd7cddfSDavid du Colombier wakeup(&audio.vous);
5377dd7cddfSDavid du Colombier }
5387dd7cddfSDavid du Colombier if(stat & 1) {
5397dd7cddfSDavid du Colombier dummy = inb(blaster.clri8);
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier if(stat & 4) {
5427dd7cddfSDavid du Colombier dummy = inb(blaster.clri401);
5437dd7cddfSDavid du Colombier }
5447dd7cddfSDavid du Colombier USED(dummy);
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier }
5477dd7cddfSDavid du Colombier
5487dd7cddfSDavid du Colombier static void
ess1688intr(void)5497dd7cddfSDavid du Colombier ess1688intr(void)
5507dd7cddfSDavid du Colombier {
5517dd7cddfSDavid du Colombier int dummy;
5527dd7cddfSDavid du Colombier
5537dd7cddfSDavid du Colombier if(audio.active){
5547dd7cddfSDavid du Colombier ilock(&blaster);
5557dd7cddfSDavid du Colombier contindma();
5567dd7cddfSDavid du Colombier dummy = inb(blaster.clri8);
5577dd7cddfSDavid du Colombier iunlock(&blaster);
5587dd7cddfSDavid du Colombier audio.intr = 1;
5597dd7cddfSDavid du Colombier wakeup(&audio.vous);
5607dd7cddfSDavid du Colombier USED(dummy);
5617dd7cddfSDavid du Colombier }
5627dd7cddfSDavid du Colombier else
5637dd7cddfSDavid du Colombier print("#A: unexpected ess1688 interrupt\n");
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier
5667dd7cddfSDavid du Colombier void
audiosbintr(void)5677dd7cddfSDavid du Colombier audiosbintr(void)
5687dd7cddfSDavid du Colombier {
5697dd7cddfSDavid du Colombier /*
5707dd7cddfSDavid du Colombier * Carrera interrupt interface.
5717dd7cddfSDavid du Colombier */
5727dd7cddfSDavid du Colombier blaster.intr();
5737dd7cddfSDavid du Colombier }
5747dd7cddfSDavid du Colombier
5757dd7cddfSDavid du Colombier static void
pcaudiosbintr(Ureg *,void *)5767dd7cddfSDavid du Colombier pcaudiosbintr(Ureg*, void*)
5777dd7cddfSDavid du Colombier {
5787dd7cddfSDavid du Colombier /*
5797dd7cddfSDavid du Colombier * x86 interrupt interface.
5807dd7cddfSDavid du Colombier */
5817dd7cddfSDavid du Colombier blaster.intr();
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier
5847dd7cddfSDavid du Colombier void
audiodmaintr(void)5857dd7cddfSDavid du Colombier audiodmaintr(void)
5867dd7cddfSDavid du Colombier {
5877dd7cddfSDavid du Colombier /* print("#A: dma interrupt\n"); /**/
5887dd7cddfSDavid du Colombier }
5897dd7cddfSDavid du Colombier
5907dd7cddfSDavid du Colombier static int
anybuf(void *)5917dd7cddfSDavid du Colombier anybuf(void*)
5927dd7cddfSDavid du Colombier {
5937dd7cddfSDavid du Colombier return audio.intr;
5947dd7cddfSDavid du Colombier }
5957dd7cddfSDavid du Colombier
5967dd7cddfSDavid du Colombier /*
5977dd7cddfSDavid du Colombier * wait for some output to get
5987dd7cddfSDavid du Colombier * empty buffers back.
5997dd7cddfSDavid du Colombier */
6007dd7cddfSDavid du Colombier static void
waitaudio(void)6017dd7cddfSDavid du Colombier waitaudio(void)
6027dd7cddfSDavid du Colombier {
6037dd7cddfSDavid du Colombier
6047dd7cddfSDavid du Colombier audio.intr = 0;
6057dd7cddfSDavid du Colombier pokeaudio();
606e288d156SDavid du Colombier tsleep(&audio.vous, anybuf, 0, 10000);
6077dd7cddfSDavid du Colombier if(audio.intr == 0) {
6087dd7cddfSDavid du Colombier /* print("#A: audio timeout\n"); /**/
6097dd7cddfSDavid du Colombier audio.active = 0;
6107dd7cddfSDavid du Colombier pokeaudio();
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier }
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier static void
sbbufinit(void)6157dd7cddfSDavid du Colombier sbbufinit(void)
6167dd7cddfSDavid du Colombier {
6177dd7cddfSDavid du Colombier int i;
6189a747e4fSDavid du Colombier uchar *p;
6197dd7cddfSDavid du Colombier
6209c63691cSDavid du Colombier p = (uchar*)(((ulong)xalloc((Nbuf+1) * Bufsize) + Bufsize-1) &
6219c63691cSDavid du Colombier ~(Bufsize-1));
6229c63691cSDavid du Colombier if (p == nil)
6239c63691cSDavid du Colombier panic("sbbufinit: no memory");
6247dd7cddfSDavid du Colombier for(i=0; i<Nbuf; i++) {
6257dd7cddfSDavid du Colombier dcflush(p, Bufsize);
6267dd7cddfSDavid du Colombier audio.buf[i].virt = UNCACHED(uchar, p);
6277dd7cddfSDavid du Colombier audio.buf[i].phys = (ulong)PADDR(p);
6289a747e4fSDavid du Colombier p += Bufsize;
6297dd7cddfSDavid du Colombier }
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier static void
setempty(void)6337dd7cddfSDavid du Colombier setempty(void)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier int i;
6367dd7cddfSDavid du Colombier
6377dd7cddfSDavid du Colombier ilock(&blaster);
6387dd7cddfSDavid du Colombier audio.empty.first = 0;
6397dd7cddfSDavid du Colombier audio.empty.last = 0;
6407dd7cddfSDavid du Colombier audio.full.first = 0;
6417dd7cddfSDavid du Colombier audio.full.last = 0;
6427dd7cddfSDavid du Colombier audio.current = 0;
6437dd7cddfSDavid du Colombier audio.filling = 0;
6449a747e4fSDavid du Colombier audio.buffered = 0;
6457dd7cddfSDavid du Colombier for(i=0; i<Nbuf; i++)
6467dd7cddfSDavid du Colombier putbuf(&audio.empty, &audio.buf[i]);
6477dd7cddfSDavid du Colombier audio.totcount = 0;
6487dd7cddfSDavid du Colombier audio.tottime = 0LL;
6497dd7cddfSDavid du Colombier iunlock(&blaster);
6507dd7cddfSDavid du Colombier }
6517dd7cddfSDavid du Colombier
6527dd7cddfSDavid du Colombier static void
resetlevel(void)6537dd7cddfSDavid du Colombier resetlevel(void)
6547dd7cddfSDavid du Colombier {
6557dd7cddfSDavid du Colombier int i;
6567dd7cddfSDavid du Colombier
6577dd7cddfSDavid du Colombier for(i=0; volumes[i].name; i++) {
6587dd7cddfSDavid du Colombier audio.lovol[i] = volumes[i].ilval;
6597dd7cddfSDavid du Colombier audio.rovol[i] = volumes[i].irval;
6607dd7cddfSDavid du Colombier audio.livol[i] = volumes[i].ilval;
6617dd7cddfSDavid du Colombier audio.rivol[i] = volumes[i].irval;
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier }
6647dd7cddfSDavid du Colombier
6657dd7cddfSDavid du Colombier static int
ess1688(ISAConf * sbconf)6667dd7cddfSDavid du Colombier ess1688(ISAConf* sbconf)
6677dd7cddfSDavid du Colombier {
6687dd7cddfSDavid du Colombier int i, major, minor;
6697dd7cddfSDavid du Colombier
6707dd7cddfSDavid du Colombier /*
6717dd7cddfSDavid du Colombier * Try for ESS1688.
6727dd7cddfSDavid du Colombier */
6737dd7cddfSDavid du Colombier sbcmd(0xE7); /* get version */
6747dd7cddfSDavid du Colombier major = sbread();
6757dd7cddfSDavid du Colombier minor = sbread();
6767dd7cddfSDavid du Colombier if(major != 0x68 || minor != 0x8B){
677*567483c8SDavid du Colombier print("#A: model %#.2x %#.2x; not ESS1688 compatible\n", major, minor);
6787dd7cddfSDavid du Colombier return 1;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier
6817dd7cddfSDavid du Colombier ess1688reset();
6827dd7cddfSDavid du Colombier
6837dd7cddfSDavid du Colombier switch(sbconf->irq){
6847dd7cddfSDavid du Colombier case 2:
6857dd7cddfSDavid du Colombier case 9:
6867dd7cddfSDavid du Colombier i = 0x50|(0<<2);
6877dd7cddfSDavid du Colombier break;
6887dd7cddfSDavid du Colombier case 5:
6897dd7cddfSDavid du Colombier i = 0x50|(1<<2);
6907dd7cddfSDavid du Colombier break;
6917dd7cddfSDavid du Colombier case 7:
6927dd7cddfSDavid du Colombier i = 0x50|(2<<2);
6937dd7cddfSDavid du Colombier break;
6947dd7cddfSDavid du Colombier case 10:
6957dd7cddfSDavid du Colombier i = 0x50|(3<<2);
6967dd7cddfSDavid du Colombier break;
6977dd7cddfSDavid du Colombier default:
698fb7f0c93SDavid du Colombier print("#A: bad ESS1688 irq %d\n", sbconf->irq);
6997dd7cddfSDavid du Colombier return 1;
7007dd7cddfSDavid du Colombier }
7017dd7cddfSDavid du Colombier ess1688w(0xB1, i);
7027dd7cddfSDavid du Colombier
7037dd7cddfSDavid du Colombier switch(sbconf->dma){
7047dd7cddfSDavid du Colombier case 0:
7057dd7cddfSDavid du Colombier i = 0x50|(1<<2);
7067dd7cddfSDavid du Colombier break;
7077dd7cddfSDavid du Colombier case 1:
7087dd7cddfSDavid du Colombier i = 0xF0|(2<<2);
7097dd7cddfSDavid du Colombier break;
7107dd7cddfSDavid du Colombier case 3:
7117dd7cddfSDavid du Colombier i = 0x50|(3<<2);
7127dd7cddfSDavid du Colombier break;
7137dd7cddfSDavid du Colombier default:
7147dd7cddfSDavid du Colombier print("#A: bad ESS1688 dma %lud\n", sbconf->dma);
7157dd7cddfSDavid du Colombier return 1;
7167dd7cddfSDavid du Colombier }
7177dd7cddfSDavid du Colombier ess1688w(0xB2, i);
7187dd7cddfSDavid du Colombier
7197dd7cddfSDavid du Colombier ess1688reset();
7207dd7cddfSDavid du Colombier
7217dd7cddfSDavid du Colombier blaster.startdma = ess1688startdma;
7227dd7cddfSDavid du Colombier blaster.intr = ess1688intr;
7237dd7cddfSDavid du Colombier
7247dd7cddfSDavid du Colombier return 0;
7257dd7cddfSDavid du Colombier }
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier static void
audioinit(void)7287dd7cddfSDavid du Colombier audioinit(void)
7297dd7cddfSDavid du Colombier {
7307dd7cddfSDavid du Colombier ISAConf sbconf;
7317dd7cddfSDavid du Colombier int i, x;
7327dd7cddfSDavid du Colombier static int irq[] = {2,5,7,10};
7337dd7cddfSDavid du Colombier
7347dd7cddfSDavid du Colombier sbconf.port = 0x220;
7357dd7cddfSDavid du Colombier sbconf.dma = Dma;
7367dd7cddfSDavid du Colombier sbconf.irq = IrqAUDIO;
7377dd7cddfSDavid du Colombier if(isaconfig("audio", 0, &sbconf) == 0)
7387dd7cddfSDavid du Colombier return;
7393ff48bf5SDavid du Colombier if(sbconf.type == nil ||
7403ff48bf5SDavid du Colombier (cistrcmp(sbconf.type, "sb16") != 0 &&
7413ff48bf5SDavid du Colombier cistrcmp(sbconf.type, "ess1688") != 0))
7427dd7cddfSDavid du Colombier return;
7437dd7cddfSDavid du Colombier switch(sbconf.port){
7447dd7cddfSDavid du Colombier case 0x220:
7457dd7cddfSDavid du Colombier case 0x240:
7467dd7cddfSDavid du Colombier case 0x260:
7477dd7cddfSDavid du Colombier case 0x280:
7487dd7cddfSDavid du Colombier break;
7497dd7cddfSDavid du Colombier default:
750*567483c8SDavid du Colombier print("#A: bad port %#lux\n", sbconf.port);
7517dd7cddfSDavid du Colombier return;
7527dd7cddfSDavid du Colombier }
7539a747e4fSDavid du Colombier
7549a747e4fSDavid du Colombier if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
7559a747e4fSDavid du Colombier print("#A: cannot ioalloc range %lux+0x10\n", sbconf.port);
7569a747e4fSDavid du Colombier return;
7579a747e4fSDavid du Colombier }
7589a747e4fSDavid du Colombier if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
7599a747e4fSDavid du Colombier iofree(sbconf.port);
7609a747e4fSDavid du Colombier print("#A: cannot ioalloc range %lux+0x01\n", sbconf.port+0x100);
7619a747e4fSDavid du Colombier return;
7629a747e4fSDavid du Colombier }
7639a747e4fSDavid du Colombier
7647dd7cddfSDavid du Colombier switch(sbconf.irq){
7657dd7cddfSDavid du Colombier case 2:
7667dd7cddfSDavid du Colombier case 5:
7677dd7cddfSDavid du Colombier case 7:
7687dd7cddfSDavid du Colombier case 9:
7697dd7cddfSDavid du Colombier case 10:
7707dd7cddfSDavid du Colombier break;
7717dd7cddfSDavid du Colombier default:
772fb7f0c93SDavid du Colombier print("#A: bad irq %d\n", sbconf.irq);
7739a747e4fSDavid du Colombier iofree(sbconf.port);
7749a747e4fSDavid du Colombier iofree(sbconf.port+0x100);
7757dd7cddfSDavid du Colombier return;
7767dd7cddfSDavid du Colombier }
7777dd7cddfSDavid du Colombier
7787dd7cddfSDavid du Colombier blaster.reset = sbconf.port + 0x6;
7797dd7cddfSDavid du Colombier blaster.read = sbconf.port + 0xa;
7807dd7cddfSDavid du Colombier blaster.write = sbconf.port + 0xc;
7817dd7cddfSDavid du Colombier blaster.wstatus = sbconf.port + 0xc;
7827dd7cddfSDavid du Colombier blaster.rstatus = sbconf.port + 0xe;
7837dd7cddfSDavid du Colombier blaster.mixaddr = sbconf.port + 0x4;
7847dd7cddfSDavid du Colombier blaster.mixdata = sbconf.port + 0x5;
7857dd7cddfSDavid du Colombier blaster.clri8 = sbconf.port + 0xe;
7867dd7cddfSDavid du Colombier blaster.clri16 = sbconf.port + 0xf;
7877dd7cddfSDavid du Colombier blaster.clri401 = sbconf.port + 0x100;
7887dd7cddfSDavid du Colombier blaster.dma = sbconf.dma;
7897dd7cddfSDavid du Colombier
7907dd7cddfSDavid du Colombier blaster.startdma = sb16startdma;
7917dd7cddfSDavid du Colombier blaster.intr = sb16intr;
7927dd7cddfSDavid du Colombier
7937dd7cddfSDavid du Colombier audio.amode = Aclosed;
7947dd7cddfSDavid du Colombier resetlevel();
7957dd7cddfSDavid du Colombier
7967dd7cddfSDavid du Colombier outb(blaster.reset, 1);
7977dd7cddfSDavid du Colombier delay(1); /* >3 υs */
7987dd7cddfSDavid du Colombier outb(blaster.reset, 0);
7997dd7cddfSDavid du Colombier delay(1);
8007dd7cddfSDavid du Colombier
8017dd7cddfSDavid du Colombier i = sbread();
8027dd7cddfSDavid du Colombier if(i != 0xaa) {
8037dd7cddfSDavid du Colombier print("#A: no response #%.2x\n", i);
8049a747e4fSDavid du Colombier iofree(sbconf.port);
8059a747e4fSDavid du Colombier iofree(sbconf.port+0x100);
8067dd7cddfSDavid du Colombier return;
8077dd7cddfSDavid du Colombier }
8087dd7cddfSDavid du Colombier
8097dd7cddfSDavid du Colombier sbcmd(0xe1); /* get version */
8107dd7cddfSDavid du Colombier audio.major = sbread();
8117dd7cddfSDavid du Colombier audio.minor = sbread();
8127dd7cddfSDavid du Colombier
8137dd7cddfSDavid du Colombier if(audio.major != 4) {
8147dd7cddfSDavid du Colombier if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
815*567483c8SDavid du Colombier print("#A: model %#.2x %#.2x; not SB 16 compatible\n",
8167dd7cddfSDavid du Colombier audio.major, audio.minor);
8179a747e4fSDavid du Colombier iofree(sbconf.port);
8189a747e4fSDavid du Colombier iofree(sbconf.port+0x100);
8197dd7cddfSDavid du Colombier return;
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier audio.major = 4;
8227dd7cddfSDavid du Colombier }
8237dd7cddfSDavid du Colombier
8247dd7cddfSDavid du Colombier /*
8257dd7cddfSDavid du Colombier * initialize the mixer
8267dd7cddfSDavid du Colombier */
8277dd7cddfSDavid du Colombier mxcmd(0x00, 0); /* Reset mixer */
8287dd7cddfSDavid du Colombier mxvolume();
8297dd7cddfSDavid du Colombier
8307dd7cddfSDavid du Colombier /*
8317dd7cddfSDavid du Colombier * Attempt to set IRQ/DMA channels.
8327dd7cddfSDavid du Colombier * On old ISA boards, these registers are writable.
8337dd7cddfSDavid du Colombier * On Plug-n-Play boards, these are read-only.
8347dd7cddfSDavid du Colombier *
8357dd7cddfSDavid du Colombier * To accomodate both, we write to the registers,
8367dd7cddfSDavid du Colombier * but then use the contents in case the write is
8377dd7cddfSDavid du Colombier * disallowed.
8387dd7cddfSDavid du Colombier */
8397dd7cddfSDavid du Colombier mxcmd(0x80, /* irq */
8407dd7cddfSDavid du Colombier (sbconf.irq==2)? 1:
8417dd7cddfSDavid du Colombier (sbconf.irq==5)? 2:
8427dd7cddfSDavid du Colombier (sbconf.irq==7)? 4:
8437dd7cddfSDavid du Colombier (sbconf.irq==9)? 1:
8447dd7cddfSDavid du Colombier (sbconf.irq==10)? 8:
8457dd7cddfSDavid du Colombier 0);
8469a747e4fSDavid du Colombier
8477dd7cddfSDavid du Colombier mxcmd(0x81, 1<<blaster.dma); /* dma */
8487dd7cddfSDavid du Colombier
8497dd7cddfSDavid du Colombier x = mxread(0x81);
8507dd7cddfSDavid du Colombier for(i=5; i<=7; i++)
8517dd7cddfSDavid du Colombier if(x & (1<<i)){
8527dd7cddfSDavid du Colombier blaster.dma = i;
8537dd7cddfSDavid du Colombier break;
8547dd7cddfSDavid du Colombier }
8557dd7cddfSDavid du Colombier
8567dd7cddfSDavid du Colombier x = mxread(0x80);
8577dd7cddfSDavid du Colombier for(i=0; i<=3; i++)
8587dd7cddfSDavid du Colombier if(x & (1<<i)){
8597dd7cddfSDavid du Colombier sbconf.irq = irq[i];
8607dd7cddfSDavid du Colombier break;
8617dd7cddfSDavid du Colombier }
8627dd7cddfSDavid du Colombier
8637dd7cddfSDavid du Colombier seteisadma(blaster.dma, audiodmaintr);
8647dd7cddfSDavid du Colombier setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
8657dd7cddfSDavid du Colombier }
8667dd7cddfSDavid du Colombier
8677dd7cddfSDavid du Colombier static Chan*
audioattach(char * param)8687dd7cddfSDavid du Colombier audioattach(char *param)
8697dd7cddfSDavid du Colombier {
8707dd7cddfSDavid du Colombier return devattach('A', param);
8717dd7cddfSDavid du Colombier }
8727dd7cddfSDavid du Colombier
8739a747e4fSDavid du Colombier static Walkqid*
audiowalk(Chan * c,Chan * nc,char ** name,int nname)8749a747e4fSDavid du Colombier audiowalk(Chan *c, Chan *nc, char **name, int nname)
8757dd7cddfSDavid du Colombier {
8769a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
8777dd7cddfSDavid du Colombier }
8787dd7cddfSDavid du Colombier
8799a747e4fSDavid du Colombier static int
audiostat(Chan * c,uchar * db,int n)8809a747e4fSDavid du Colombier audiostat(Chan *c, uchar *db, int n)
8817dd7cddfSDavid du Colombier {
8829a747e4fSDavid du Colombier audiodir[Qaudio].length = audio.buffered;
8839a747e4fSDavid du Colombier return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
8847dd7cddfSDavid du Colombier }
8857dd7cddfSDavid du Colombier
8867dd7cddfSDavid du Colombier static Chan*
audioopen(Chan * c,int omode)8877dd7cddfSDavid du Colombier audioopen(Chan *c, int omode)
8887dd7cddfSDavid du Colombier {
8897dd7cddfSDavid du Colombier int amode;
8907dd7cddfSDavid du Colombier
8917dd7cddfSDavid du Colombier if(audio.major != 4)
8927dd7cddfSDavid du Colombier error(Emajor);
8937dd7cddfSDavid du Colombier
8949a747e4fSDavid du Colombier switch((ulong)c->qid.path) {
8957dd7cddfSDavid du Colombier default:
8967dd7cddfSDavid du Colombier error(Eperm);
8977dd7cddfSDavid du Colombier break;
8987dd7cddfSDavid du Colombier
8997dd7cddfSDavid du Colombier case Qstatus:
9007dd7cddfSDavid du Colombier if((omode&7) != OREAD)
9017dd7cddfSDavid du Colombier error(Eperm);
9027dd7cddfSDavid du Colombier case Qvolume:
9037dd7cddfSDavid du Colombier case Qdir:
9047dd7cddfSDavid du Colombier break;
9057dd7cddfSDavid du Colombier
9067dd7cddfSDavid du Colombier case Qaudio:
9077dd7cddfSDavid du Colombier amode = Awrite;
9087dd7cddfSDavid du Colombier if((omode&7) == OREAD)
9097dd7cddfSDavid du Colombier amode = Aread;
9107dd7cddfSDavid du Colombier qlock(&audio);
9117dd7cddfSDavid du Colombier if(audio.amode != Aclosed){
9127dd7cddfSDavid du Colombier qunlock(&audio);
9137dd7cddfSDavid du Colombier error(Einuse);
9147dd7cddfSDavid du Colombier }
9157dd7cddfSDavid du Colombier if(audio.bufinit == 0) {
9167dd7cddfSDavid du Colombier audio.bufinit = 1;
9177dd7cddfSDavid du Colombier sbbufinit();
9187dd7cddfSDavid du Colombier }
9197dd7cddfSDavid du Colombier audio.amode = amode;
9207dd7cddfSDavid du Colombier setempty();
9217dd7cddfSDavid du Colombier audio.curcount = 0;
9227dd7cddfSDavid du Colombier qunlock(&audio);
9237dd7cddfSDavid du Colombier mxvolume();
9247dd7cddfSDavid du Colombier break;
9257dd7cddfSDavid du Colombier }
9267dd7cddfSDavid du Colombier c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
9277dd7cddfSDavid du Colombier c->mode = openmode(omode);
9287dd7cddfSDavid du Colombier c->flag |= COPEN;
9297dd7cddfSDavid du Colombier c->offset = 0;
9307dd7cddfSDavid du Colombier
9317dd7cddfSDavid du Colombier return c;
9327dd7cddfSDavid du Colombier }
9337dd7cddfSDavid du Colombier
9347dd7cddfSDavid du Colombier static void
audioclose(Chan * c)9357dd7cddfSDavid du Colombier audioclose(Chan *c)
9367dd7cddfSDavid du Colombier {
9377dd7cddfSDavid du Colombier Buf *b;
9387dd7cddfSDavid du Colombier
9399a747e4fSDavid du Colombier switch((ulong)c->qid.path) {
9407dd7cddfSDavid du Colombier default:
9417dd7cddfSDavid du Colombier error(Eperm);
9427dd7cddfSDavid du Colombier break;
9437dd7cddfSDavid du Colombier
9447dd7cddfSDavid du Colombier case Qdir:
9457dd7cddfSDavid du Colombier case Qvolume:
9467dd7cddfSDavid du Colombier case Qstatus:
9477dd7cddfSDavid du Colombier break;
9487dd7cddfSDavid du Colombier
9497dd7cddfSDavid du Colombier case Qaudio:
9507dd7cddfSDavid du Colombier if(c->flag & COPEN) {
9517dd7cddfSDavid du Colombier qlock(&audio);
9527dd7cddfSDavid du Colombier if(audio.amode == Awrite) {
9537dd7cddfSDavid du Colombier /* flush out last partial buffer */
9547dd7cddfSDavid du Colombier b = audio.filling;
9557dd7cddfSDavid du Colombier if(b) {
9567dd7cddfSDavid du Colombier audio.filling = 0;
9577dd7cddfSDavid du Colombier memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
9589a747e4fSDavid du Colombier audio.buffered += Bufsize-audio.curcount;
9597dd7cddfSDavid du Colombier swab(b->virt);
9607dd7cddfSDavid du Colombier putbuf(&audio.full, b);
9617dd7cddfSDavid du Colombier }
9627dd7cddfSDavid du Colombier if(!audio.active && audio.full.first)
9637dd7cddfSDavid du Colombier pokeaudio();
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier audio.amode = Aclosed;
9667dd7cddfSDavid du Colombier if(waserror()){
9677dd7cddfSDavid du Colombier qunlock(&audio);
9687dd7cddfSDavid du Colombier nexterror();
9697dd7cddfSDavid du Colombier }
9707dd7cddfSDavid du Colombier while(audio.active)
9717dd7cddfSDavid du Colombier waitaudio();
9727dd7cddfSDavid du Colombier setempty();
9737dd7cddfSDavid du Colombier poperror();
9747dd7cddfSDavid du Colombier qunlock(&audio);
9757dd7cddfSDavid du Colombier }
9767dd7cddfSDavid du Colombier break;
9777dd7cddfSDavid du Colombier }
9787dd7cddfSDavid du Colombier }
9797dd7cddfSDavid du Colombier
9807dd7cddfSDavid du Colombier static long
audioread(Chan * c,void * v,long n,vlong off)9817dd7cddfSDavid du Colombier audioread(Chan *c, void *v, long n, vlong off)
9827dd7cddfSDavid du Colombier {
9837dd7cddfSDavid du Colombier int liv, riv, lov, rov;
9847dd7cddfSDavid du Colombier long m, n0;
9857dd7cddfSDavid du Colombier char buf[300];
9867dd7cddfSDavid du Colombier Buf *b;
9877dd7cddfSDavid du Colombier int j;
9887dd7cddfSDavid du Colombier ulong offset = off;
9897dd7cddfSDavid du Colombier char *a;
9907dd7cddfSDavid du Colombier
9917dd7cddfSDavid du Colombier n0 = n;
9927dd7cddfSDavid du Colombier a = v;
9939a747e4fSDavid du Colombier switch((ulong)c->qid.path) {
9947dd7cddfSDavid du Colombier default:
9957dd7cddfSDavid du Colombier error(Eperm);
9967dd7cddfSDavid du Colombier break;
9977dd7cddfSDavid du Colombier
9987dd7cddfSDavid du Colombier case Qdir:
9997dd7cddfSDavid du Colombier return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
10007dd7cddfSDavid du Colombier
10017dd7cddfSDavid du Colombier case Qaudio:
10027dd7cddfSDavid du Colombier if(audio.amode != Aread)
10037dd7cddfSDavid du Colombier error(Emode);
10047dd7cddfSDavid du Colombier qlock(&audio);
10057dd7cddfSDavid du Colombier if(waserror()){
10067dd7cddfSDavid du Colombier qunlock(&audio);
10077dd7cddfSDavid du Colombier nexterror();
10087dd7cddfSDavid du Colombier }
10097dd7cddfSDavid du Colombier while(n > 0) {
10107dd7cddfSDavid du Colombier b = audio.filling;
10117dd7cddfSDavid du Colombier if(b == 0) {
10127dd7cddfSDavid du Colombier b = getbuf(&audio.full);
10137dd7cddfSDavid du Colombier if(b == 0) {
10147dd7cddfSDavid du Colombier waitaudio();
10157dd7cddfSDavid du Colombier continue;
10167dd7cddfSDavid du Colombier }
10177dd7cddfSDavid du Colombier audio.filling = b;
10187dd7cddfSDavid du Colombier swab(b->virt);
10197dd7cddfSDavid du Colombier audio.curcount = 0;
10207dd7cddfSDavid du Colombier }
10217dd7cddfSDavid du Colombier m = Bufsize-audio.curcount;
10227dd7cddfSDavid du Colombier if(m > n)
10237dd7cddfSDavid du Colombier m = n;
10247dd7cddfSDavid du Colombier memmove(a, b->virt+audio.curcount, m);
10257dd7cddfSDavid du Colombier
10267dd7cddfSDavid du Colombier audio.curcount += m;
10277dd7cddfSDavid du Colombier n -= m;
10287dd7cddfSDavid du Colombier a += m;
10299a747e4fSDavid du Colombier audio.buffered -= m;
10307dd7cddfSDavid du Colombier if(audio.curcount >= Bufsize) {
10317dd7cddfSDavid du Colombier audio.filling = 0;
10327dd7cddfSDavid du Colombier putbuf(&audio.empty, b);
10337dd7cddfSDavid du Colombier }
10347dd7cddfSDavid du Colombier }
10357dd7cddfSDavid du Colombier poperror();
10367dd7cddfSDavid du Colombier qunlock(&audio);
10377dd7cddfSDavid du Colombier break;
10387dd7cddfSDavid du Colombier
10397dd7cddfSDavid du Colombier case Qstatus:
10407dd7cddfSDavid du Colombier buf[0] = 0;
10419a747e4fSDavid du Colombier snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset %10lud time %19lld\n",
10429a747e4fSDavid du Colombier Bufsize, audio.buffered, audio.totcount, audio.tottime);
10437dd7cddfSDavid du Colombier return readstr(offset, a, n, buf);
10447dd7cddfSDavid du Colombier
10457dd7cddfSDavid du Colombier case Qvolume:
10467dd7cddfSDavid du Colombier j = 0;
10477dd7cddfSDavid du Colombier buf[0] = 0;
10487dd7cddfSDavid du Colombier for(m=0; volumes[m].name; m++){
10497dd7cddfSDavid du Colombier liv = audio.livol[m];
10507dd7cddfSDavid du Colombier riv = audio.rivol[m];
10517dd7cddfSDavid du Colombier lov = audio.lovol[m];
10527dd7cddfSDavid du Colombier rov = audio.rovol[m];
10537dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
10547dd7cddfSDavid du Colombier if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
10557dd7cddfSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
10567dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
10577dd7cddfSDavid du Colombier else{
10587dd7cddfSDavid du Colombier if(volumes[m].flag & Fin)
10597dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
10607dd7cddfSDavid du Colombier " in %d", liv);
10617dd7cddfSDavid du Colombier if(volumes[m].flag & Fout)
10627dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
10637dd7cddfSDavid du Colombier " out %d", lov);
10647dd7cddfSDavid du Colombier }
10657dd7cddfSDavid du Colombier }else{
10667dd7cddfSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
10677dd7cddfSDavid du Colombier liv==lov && riv==rov)
10687dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
10697dd7cddfSDavid du Colombier " left %d right %d",
10707dd7cddfSDavid du Colombier liv, riv);
10717dd7cddfSDavid du Colombier else{
10727dd7cddfSDavid du Colombier if(volumes[m].flag & Fin)
10737dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
10747dd7cddfSDavid du Colombier " in left %d right %d",
10757dd7cddfSDavid du Colombier liv, riv);
10767dd7cddfSDavid du Colombier if(volumes[m].flag & Fout)
10777dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j,
10787dd7cddfSDavid du Colombier " out left %d right %d",
10797dd7cddfSDavid du Colombier lov, rov);
10807dd7cddfSDavid du Colombier }
10817dd7cddfSDavid du Colombier }
10827dd7cddfSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "\n");
10837dd7cddfSDavid du Colombier }
10847dd7cddfSDavid du Colombier return readstr(offset, a, n, buf);
10857dd7cddfSDavid du Colombier }
10867dd7cddfSDavid du Colombier return n0-n;
10877dd7cddfSDavid du Colombier }
10887dd7cddfSDavid du Colombier
10897dd7cddfSDavid du Colombier static long
audiowrite(Chan * c,void * vp,long n,vlong)10907dd7cddfSDavid du Colombier audiowrite(Chan *c, void *vp, long n, vlong)
10917dd7cddfSDavid du Colombier {
10927dd7cddfSDavid du Colombier long m, n0;
10939a747e4fSDavid du Colombier int i, v, left, right, in, out;
10949a747e4fSDavid du Colombier Cmdbuf *cb;
10957dd7cddfSDavid du Colombier Buf *b;
10967dd7cddfSDavid du Colombier char *a;
10977dd7cddfSDavid du Colombier
10987dd7cddfSDavid du Colombier a = vp;
10997dd7cddfSDavid du Colombier n0 = n;
11009a747e4fSDavid du Colombier switch((ulong)c->qid.path) {
11017dd7cddfSDavid du Colombier default:
11027dd7cddfSDavid du Colombier error(Eperm);
11037dd7cddfSDavid du Colombier break;
11047dd7cddfSDavid du Colombier
11057dd7cddfSDavid du Colombier case Qvolume:
11067dd7cddfSDavid du Colombier v = Vaudio;
11077dd7cddfSDavid du Colombier left = 1;
11087dd7cddfSDavid du Colombier right = 1;
11097dd7cddfSDavid du Colombier in = 1;
11107dd7cddfSDavid du Colombier out = 1;
11119a747e4fSDavid du Colombier cb = parsecmd(vp, n);
11129a747e4fSDavid du Colombier if(waserror()){
11139a747e4fSDavid du Colombier free(cb);
11149a747e4fSDavid du Colombier nexterror();
11159a747e4fSDavid du Colombier }
11167dd7cddfSDavid du Colombier
11179a747e4fSDavid du Colombier for(i = 0; i < cb->nf; i++){
11187dd7cddfSDavid du Colombier /*
11197dd7cddfSDavid du Colombier * a number is volume
11207dd7cddfSDavid du Colombier */
11219a747e4fSDavid du Colombier if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
11229a747e4fSDavid du Colombier m = strtoul(cb->f[i], 0, 10);
11237dd7cddfSDavid du Colombier if(left && out)
11247dd7cddfSDavid du Colombier audio.lovol[v] = m;
11257dd7cddfSDavid du Colombier if(left && in)
11267dd7cddfSDavid du Colombier audio.livol[v] = m;
11277dd7cddfSDavid du Colombier if(right && out)
11287dd7cddfSDavid du Colombier audio.rovol[v] = m;
11297dd7cddfSDavid du Colombier if(right && in)
11307dd7cddfSDavid du Colombier audio.rivol[v] = m;
11317dd7cddfSDavid du Colombier mxvolume();
11327dd7cddfSDavid du Colombier goto cont0;
11337dd7cddfSDavid du Colombier }
11347dd7cddfSDavid du Colombier
11357dd7cddfSDavid du Colombier for(m=0; volumes[m].name; m++) {
11369a747e4fSDavid du Colombier if(strcmp(cb->f[i], volumes[m].name) == 0) {
11377dd7cddfSDavid du Colombier v = m;
11387dd7cddfSDavid du Colombier in = 1;
11397dd7cddfSDavid du Colombier out = 1;
11407dd7cddfSDavid du Colombier left = 1;
11417dd7cddfSDavid du Colombier right = 1;
11427dd7cddfSDavid du Colombier goto cont0;
11437dd7cddfSDavid du Colombier }
11447dd7cddfSDavid du Colombier }
11457dd7cddfSDavid du Colombier
11469a747e4fSDavid du Colombier if(strcmp(cb->f[i], "reset") == 0) {
11477dd7cddfSDavid du Colombier resetlevel();
11487dd7cddfSDavid du Colombier mxvolume();
11497dd7cddfSDavid du Colombier goto cont0;
11507dd7cddfSDavid du Colombier }
11519a747e4fSDavid du Colombier if(strcmp(cb->f[i], "in") == 0) {
11527dd7cddfSDavid du Colombier in = 1;
11537dd7cddfSDavid du Colombier out = 0;
11547dd7cddfSDavid du Colombier goto cont0;
11557dd7cddfSDavid du Colombier }
11569a747e4fSDavid du Colombier if(strcmp(cb->f[i], "out") == 0) {
11577dd7cddfSDavid du Colombier in = 0;
11587dd7cddfSDavid du Colombier out = 1;
11597dd7cddfSDavid du Colombier goto cont0;
11607dd7cddfSDavid du Colombier }
11619a747e4fSDavid du Colombier if(strcmp(cb->f[i], "left") == 0) {
11627dd7cddfSDavid du Colombier left = 1;
11637dd7cddfSDavid du Colombier right = 0;
11647dd7cddfSDavid du Colombier goto cont0;
11657dd7cddfSDavid du Colombier }
11669a747e4fSDavid du Colombier if(strcmp(cb->f[i], "right") == 0) {
11677dd7cddfSDavid du Colombier left = 0;
11687dd7cddfSDavid du Colombier right = 1;
11697dd7cddfSDavid du Colombier goto cont0;
11707dd7cddfSDavid du Colombier }
11717dd7cddfSDavid du Colombier error(Evolume);
11727dd7cddfSDavid du Colombier break;
11737dd7cddfSDavid du Colombier cont0:;
11747dd7cddfSDavid du Colombier }
11759a747e4fSDavid du Colombier free(cb);
11769a747e4fSDavid du Colombier poperror();
11777dd7cddfSDavid du Colombier break;
11787dd7cddfSDavid du Colombier
11797dd7cddfSDavid du Colombier case Qaudio:
11807dd7cddfSDavid du Colombier if(audio.amode != Awrite)
11817dd7cddfSDavid du Colombier error(Emode);
11827dd7cddfSDavid du Colombier qlock(&audio);
11837dd7cddfSDavid du Colombier if(waserror()){
11847dd7cddfSDavid du Colombier qunlock(&audio);
11857dd7cddfSDavid du Colombier nexterror();
11867dd7cddfSDavid du Colombier }
11877dd7cddfSDavid du Colombier while(n > 0) {
11887dd7cddfSDavid du Colombier b = audio.filling;
11897dd7cddfSDavid du Colombier if(b == 0) {
11907dd7cddfSDavid du Colombier b = getbuf(&audio.empty);
11917dd7cddfSDavid du Colombier if(b == 0) {
11927dd7cddfSDavid du Colombier waitaudio();
11937dd7cddfSDavid du Colombier continue;
11947dd7cddfSDavid du Colombier }
11957dd7cddfSDavid du Colombier audio.filling = b;
11967dd7cddfSDavid du Colombier audio.curcount = 0;
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier
11997dd7cddfSDavid du Colombier m = Bufsize-audio.curcount;
12007dd7cddfSDavid du Colombier if(m > n)
12017dd7cddfSDavid du Colombier m = n;
12027dd7cddfSDavid du Colombier memmove(b->virt+audio.curcount, a, m);
12037dd7cddfSDavid du Colombier
12047dd7cddfSDavid du Colombier audio.curcount += m;
12057dd7cddfSDavid du Colombier n -= m;
12067dd7cddfSDavid du Colombier a += m;
12079a747e4fSDavid du Colombier audio.buffered += m;
12087dd7cddfSDavid du Colombier if(audio.curcount >= Bufsize) {
12097dd7cddfSDavid du Colombier audio.filling = 0;
12107dd7cddfSDavid du Colombier swab(b->virt);
12117dd7cddfSDavid du Colombier putbuf(&audio.full, b);
121225910e17SDavid du Colombier pokeaudio();
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier }
12157dd7cddfSDavid du Colombier poperror();
12167dd7cddfSDavid du Colombier qunlock(&audio);
12177dd7cddfSDavid du Colombier break;
12187dd7cddfSDavid du Colombier }
12197dd7cddfSDavid du Colombier return n0 - n;
12207dd7cddfSDavid du Colombier }
12217dd7cddfSDavid du Colombier
12227dd7cddfSDavid du Colombier static void
swab(uchar * a)12237dd7cddfSDavid du Colombier swab(uchar *a)
12247dd7cddfSDavid du Colombier {
12257dd7cddfSDavid du Colombier ulong *p, *ep, b;
12267dd7cddfSDavid du Colombier
12277dd7cddfSDavid du Colombier if(!SBswab){
12287dd7cddfSDavid du Colombier USED(a);
12297dd7cddfSDavid du Colombier return;
12307dd7cddfSDavid du Colombier }
12317dd7cddfSDavid du Colombier p = (ulong*)a;
12327dd7cddfSDavid du Colombier ep = p + (Bufsize>>2);
12337dd7cddfSDavid du Colombier while(p < ep) {
12347dd7cddfSDavid du Colombier b = *p;
12357dd7cddfSDavid du Colombier b = (b>>24) | (b<<24) |
12367dd7cddfSDavid du Colombier ((b&0xff0000) >> 8) |
12377dd7cddfSDavid du Colombier ((b&0x00ff00) << 8);
12387dd7cddfSDavid du Colombier *p++ = b;
12397dd7cddfSDavid du Colombier }
12407dd7cddfSDavid du Colombier }
12417dd7cddfSDavid du Colombier
12427dd7cddfSDavid du Colombier Dev audiodevtab = {
12437dd7cddfSDavid du Colombier 'A',
12447dd7cddfSDavid du Colombier "audio",
12457dd7cddfSDavid du Colombier
12467dd7cddfSDavid du Colombier devreset,
12477dd7cddfSDavid du Colombier audioinit,
12489a747e4fSDavid du Colombier devshutdown,
12497dd7cddfSDavid du Colombier audioattach,
12507dd7cddfSDavid du Colombier audiowalk,
12517dd7cddfSDavid du Colombier audiostat,
12527dd7cddfSDavid du Colombier audioopen,
12537dd7cddfSDavid du Colombier devcreate,
12547dd7cddfSDavid du Colombier audioclose,
12557dd7cddfSDavid du Colombier audioread,
12567dd7cddfSDavid du Colombier devbread,
12577dd7cddfSDavid du Colombier audiowrite,
12587dd7cddfSDavid du Colombier devbwrite,
12597dd7cddfSDavid du Colombier devremove,
12607dd7cddfSDavid du Colombier devwstat,
12617dd7cddfSDavid du Colombier };
1262