]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/audiosb16.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / audiosb16.c
index ac80cbda044051542141b471a84de11bf46e98cc..a38483aed93bdf4a9b6451adca96a8bd6c0236b3 100644 (file)
@@ -8,6 +8,7 @@
 #include "fns.h"
 #include "io.h"
 #include "../port/error.h"
+#include "../port/audioif.h"
 
 typedef struct Ring    Ring;
 typedef struct Blaster Blaster;
@@ -15,11 +16,8 @@ typedef struct       Ctlr    Ctlr;
 
 enum
 {
-       Fmono           = 1,
-       Fin             = 2,
-       Fout            = 4,
-
-       Vaudio          = 0,
+       Vmaster,
+       Vaudio,
        Vsynth,
        Vcd,
        Vline,
@@ -27,12 +25,12 @@ enum
        Vspeaker,
        Vtreb,
        Vbass,
+       Vigain,
+       Vogain,
        Vspeed,
+       Vdelay,
        Nvol,
 
-       Speed           = 44100,
-       Ncmd            = 50,           /* max volume command words */
-
        Blocksize       = 4096,
        Blocks          = 65536/Blocksize,
 };
@@ -59,7 +57,6 @@ struct Blaster
        int     clri8;
        int     clri16;
        int     clri401;
-       int     dma;
 
        void    (*startdma)(Ctlr*);
        void    (*intr)(Ctlr*);
@@ -67,47 +64,40 @@ struct Blaster
 
 struct Ctlr
 {
-       QLock;
        Rendez  vous;
        int     active;         /* boolean dma running */
-       int     rivol[Nvol];    /* right/left input/output volumes */
-       int     livol[Nvol];
-       int     rovol[Nvol];
-       int     lovol[Nvol];
        int     major;          /* SB16 major version number (sb 4) */
        int     minor;          /* SB16 minor version number */
-       ulong   totcount;       /* how many bytes processed since open */
-       vlong   tottime;        /* time at which totcount bytes were processed */
        Ring    ring;           /* dma ring buffer */
        Blaster blaster;
+
+       int     lvol[Nvol];
+       int     rvol[Nvol];
+
+       /* for probe */
        Audio   *adev;
+       ISAConf conf;
+       Ctlr *next;
 };
 
-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 Volume voltab[] = {
+       [Vmaster] "master", 0x30, 0xff, Stereo, 0,
+       [Vaudio] "audio", 0x32, 0xff, Stereo, 0,
+       [Vsynth] "synth", 0x34, 0xff, Stereo, 0,
+       [Vcd] "cd", 0x36, 0xff, Stereo, 0,
+       [Vline] "line", 0x38, 0xff, Stereo, 0,
+       [Vmic] "mic", 0x3a, 0xff, Mono, 0,
+       [Vspeaker] "speaker", 0x3b, 0xff, Mono, 0,
+       [Vtreb] "treb", 0x44, 0xff, Stereo, 0,
+       [Vbass] "bass", 0x46, 0xff, Stereo, 0,
+       [Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
+       [Vogain] "outgain", 0x41, 0xff, Stereo, 0,
+       [Vspeed] "speed", 0, 0, Absolute, 0,
+       [Vdelay] "delay", 0, 0, Absolute, 0,
+       0,
 };
 
 static char    Emajor[]        = "soundblaster not responding/wrong version";
-static char    Emode[]         = "illegal open mode";
-static char    Evolume[]       = "illegal volume specifier";
-
 
 static long
 buffered(Ring *r)
@@ -242,109 +232,50 @@ mxread(Blaster *blaster, int addr)
        return s;
 }
 
-static void
-mxcmds(Blaster *blaster, int s, int v)
-{
-
-       if(v > 100)
-               v = 100;
-       if(v < 0)
-               v = 0;
-       mxcmd(blaster, s, (v*255)/100);
-}
-
-static void
-mxcmdt(Blaster *blaster, int s, int v)
-{
-
-       if(v > 100)
-               v = 100;
-       if(v <= 0)
-               mxcmd(blaster, s, 0);
-       else
-               mxcmd(blaster, s, 255-100+v);
-}
-
-static void
-mxcmdu(Blaster *blaster, int s, int v)
-{
-
-       if(v > 100)
-               v = 100;
-       if(v <= 0)
-               v = 0;
-       mxcmd(blaster, s, 128-50+v);
-}
-
-static void
-mxvolume(Ctlr *ctlr)
+static int
+mxsetvol(Audio *adev, int x, int a[2])
 {
        Blaster *blaster;
-       int *left, *right;
-       int source;
-
-       if(0){
-               left = ctlr->livol;
-               right = ctlr->rivol;
-       }else{
-               left = ctlr->lovol;
-               right = ctlr->rovol;
-       }
+       Ctlr *ctlr = adev->ctlr;
+       Volume *vol;
 
+       vol = voltab+x;
        blaster = &ctlr->blaster;
-
        ilock(blaster);
+       switch(vol->type){
+       case Absolute:
+               switch(x){
+               case Vdelay:
+                       adev->delay = a[0];
+                       break;
+               case Vspeed:
+                       adev->speed = a[0];
+                       break;
+               }
+               ctlr->lvol[x] = ctlr->rvol[x] = a[0];
+               break;
+       case Stereo:
+               ctlr->rvol[x] = a[1];
+               mxcmd(blaster, vol->reg+1, a[1]);
+               /* no break */
+       case Mono:
+               ctlr->lvol[x] = a[0];
+               mxcmd(blaster, vol->reg, a[0]);
+       }
+       iunlock(blaster);
 
-       mxcmd(blaster, 0x30, 255);              /* left master */
-       mxcmd(blaster, 0x31, 255);              /* right master */
-       mxcmd(blaster, 0x3f, 0);                /* left igain */
-       mxcmd(blaster, 0x40, 0);                /* right igain */
-       mxcmd(blaster, 0x41, 0);                /* left ogain */
-       mxcmd(blaster, 0x42, 0);                /* right ogain */
-
-       mxcmds(blaster, 0x32, left[Vaudio]);
-       mxcmds(blaster, 0x33, right[Vaudio]);
-
-       mxcmds(blaster, 0x34, left[Vsynth]);
-       mxcmds(blaster, 0x35, right[Vsynth]);
-
-       mxcmds(blaster, 0x36, left[Vcd]);
-       mxcmds(blaster, 0x37, right[Vcd]);
-
-       mxcmds(blaster, 0x38, left[Vline]);
-       mxcmds(blaster, 0x39, right[Vline]);
-
-       mxcmds(blaster, 0x3a, left[Vmic]);
-       mxcmds(blaster, 0x3b, left[Vspeaker]);
+       return 0;
+}
 
-       mxcmdu(blaster, 0x44, left[Vtreb]);
-       mxcmdu(blaster, 0x45, right[Vtreb]);
+static int
+mxgetvol(Audio *adev, int x, int a[2])
+{
+       Ctlr *ctlr = adev->ctlr;
 
-       mxcmdu(blaster, 0x46, left[Vbass]);
-       mxcmdu(blaster, 0x47, right[Vbass]);
+       a[0] = ctlr->lvol[x];
+       a[1] = ctlr->rvol[x];
 
-       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(0)
-               mxcmd(blaster, 0x3c, 0);                /* output switch */
-       else
-               mxcmd(blaster, 0x3c, source);
-       mxcmd(blaster, 0x3d, source);           /* input left switch */
-       mxcmd(blaster, 0x3e, source);           /* input right switch */
-       iunlock(blaster);
+       return 0;
 }
 
 static void
@@ -355,13 +286,10 @@ contindma(Ctlr *ctlr)
 
        blaster = &ctlr->blaster;
        ring = &ctlr->ring;
-       if(buffered(ring) >= Blocksize){
-               ring->ri = ring->nbuf - dmacount(blaster->dma);
-
-               ctlr->totcount += Blocksize;
-               ctlr->tottime = todget(nil);
-       }else{
-               dmaend(blaster->dma);
+       if(buffered(ring) >= Blocksize)
+               ring->ri = ring->nbuf - dmacount(ctlr->conf.dma);
+       else{
+               dmaend(ctlr->conf.dma);
                sbcmd(blaster, 0xd9);   /* exit at end of count */
                sbcmd(blaster, 0xd5);   /* pause */
                ctlr->active = 0;
@@ -384,30 +312,28 @@ sb16startdma(Ctlr *ctlr)
        blaster = &ctlr->blaster;
        ring = &ctlr->ring;
        ilock(blaster);
-       dmaend(blaster->dma);
-       if(0) {
-               sbcmd(blaster, 0x42);                   /* input sampling rate */
-               speed = ctlr->livol[Vspeed];
-       } else {
-               sbcmd(blaster, 0x41);                   /* output sampling rate */
-               speed = ctlr->lovol[Vspeed];
-       }
+       dmaend(ctlr->conf.dma);
+       if(0)
+               sbcmd(blaster, 0x42);   /* input sampling rate */
+       else
+               sbcmd(blaster, 0x41);   /* output sampling rate */
+       speed = ctlr->adev->speed;
        sbcmd(blaster, speed>>8);
        sbcmd(blaster, speed);
 
        if(0)
-               sbcmd(blaster, 0xbe);                   /* A/D, autoinit */
+               sbcmd(blaster, 0xbe);   /* A/D, autoinit */
        else
-               sbcmd(blaster, 0xb6);                   /* D/A, autoinit */
+               sbcmd(blaster, 0xb6);   /* D/A, autoinit */
 
-       sbcmd(blaster, 0x30);                           /* stereo, signed 16 bit */
+       sbcmd(blaster, 0x30);   /* stereo, signed 16 bit */
 
        count = (Blocksize>>1) - 1;
        sbcmd(blaster, count);
        sbcmd(blaster, count>>8);
 
        ctlr->active = 1;
-       if(dmasetup(blaster->dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
+       if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
                ctlr->active = 0;
                print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
        }
@@ -420,7 +346,7 @@ ess1688reset(Blaster *blaster, int ctlrno)
        int i;
 
        outb(blaster->reset, 3);
-       delay(1);                       /* >3 υs */
+       delay(1);       /* >3 υs */
        outb(blaster->reset, 0);
        delay(1);
 
@@ -430,7 +356,7 @@ ess1688reset(Blaster *blaster, int ctlrno)
                return 1;
        }
 
-       if(sbcmd(blaster, 0xC6)){               /* extended mode */
+       if(sbcmd(blaster, 0xC6)){       /* extended mode */
                print("#A%d: barf 3\n", ctlrno);
                return 1;
        }
@@ -450,22 +376,18 @@ ess1688startdma(Ctlr *ctlr)
        ring = &ctlr->ring;
 
        ilock(blaster);
-       dmaend(blaster->dma);
+       dmaend(ctlr->conf.dma);
 
        ess1688reset(blaster, ctlr->adev->ctlrno);
 
        /*
         * Set the speed.
         */
-       if(0)
-               speed = ctlr->livol[Vspeed];
-       else
-               speed = ctlr->lovol[Vspeed];
+       speed = ctlr->adev->speed;
        if(speed < 4000)
                speed = 4000;
        else if(speed > 48000)
                speed = 48000;
-
        if(speed > 22000)
                  x = 0x80|(256-(795500+speed/2)/speed);
        else
@@ -477,15 +399,15 @@ ess1688startdma(Ctlr *ctlr)
        ess1688w(blaster, 0xA2, x & 0xFF);
 
        if(0)
-               ess1688w(blaster, 0xB8, 0x0E);          /* A/D, autoinit */
+               ess1688w(blaster, 0xB8, 0x0E);  /* A/D, autoinit */
        else
-               ess1688w(blaster, 0xB8, 0x04);          /* D/A, autoinit */
+               ess1688w(blaster, 0xB8, 0x04);  /* D/A, autoinit */
        x = ess1688r(blaster, 0xA8) & ~0x03;
-       ess1688w(blaster, 0xA8, x|0x01);                        /* 2 channels */
-       ess1688w(blaster, 0xB9, 2);                     /* demand mode, 4 bytes per request */
+       ess1688w(blaster, 0xA8, x|0x01);        /* 2 channels */
+       ess1688w(blaster, 0xB9, 2);     /* demand mode, 4 bytes per request */
 
        if(1)
-               ess1688w(blaster, 0xB6, 0);             /* for output */
+               ess1688w(blaster, 0xB6, 0);     /* for output */
 
        ess1688w(blaster, 0xB7, 0x71);
        ess1688w(blaster, 0xB7, 0xBC);
@@ -496,7 +418,7 @@ ess1688startdma(Ctlr *ctlr)
        ess1688w(blaster, 0xB2, x|0x50);
 
        if(1)
-               sbcmd(blaster, 0xD1);                   /* speaker on */
+               sbcmd(blaster, 0xD1);   /* speaker on */
 
        count = -Blocksize;
        ess1688w(blaster, 0xA4, count & 0xFF);
@@ -505,7 +427,7 @@ ess1688startdma(Ctlr *ctlr)
        ess1688w(blaster, 0xB8, x|0x05);
 
        ctlr->active = 1;
-       if(dmasetup(blaster->dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
+       if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
                ctlr->active = 0;
                print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
        }
@@ -566,24 +488,9 @@ setempty(Ctlr *ctlr)
        ilock(&ctlr->blaster);
        ctlr->ring.ri = 0;
        ctlr->ring.wi = 0;
-       ctlr->totcount = 0;
-       ctlr->tottime = 0LL;
        iunlock(&ctlr->blaster);
 }
 
-static void
-resetlevel(Ctlr *ctlr)
-{
-       int i;
-
-       for(i=0; volumes[i].name; i++) {
-               ctlr->lovol[i] = volumes[i].ilval;
-               ctlr->rovol[i] = volumes[i].irval;
-               ctlr->livol[i] = volumes[i].ilval;
-               ctlr->rivol[i] = volumes[i].irval;
-       }
-}
-
 static long
 audiobuffered(Audio *adev)
 {
@@ -591,24 +498,17 @@ audiobuffered(Audio *adev)
 }
 
 static long
-audiostatus(Audio *adev, void *a, long n, vlong off)
+audiostatus(Audio *adev, void *a, long n, vlong)
 {
-       char buf[300];
-       Ctlr *ctlr;
-
-       ctlr = adev->ctlr;
-       snprint(buf, sizeof(buf), 
-               "buffered %.4lx/%.4lx  offset %10lud time %19lld\n",
-               buffered(&ctlr->ring), available(&ctlr->ring),
-               ctlr->totcount, ctlr->tottime);
-       return readstr(off, a, n, buf);
+       Ctlr *ctlr = adev->ctlr;
+       return snprint((char*)a, n, "bufsize %6d buffered %6ld\n",
+               Blocksize, buffered(&ctlr->ring));
 }
 
 static int
 inactive(void *arg)
 {
        Ctlr *ctlr = arg;
-
        return !ctlr->active;
 }
 
@@ -616,61 +516,97 @@ static int
 anybuf(void *arg)
 {
        Ctlr *ctlr = arg;
-
        return available(&ctlr->ring) || inactive(ctlr);
 }
 
+static int
+ratebuf(void *arg)
+{
+       Ctlr *ctlr = arg;
+       int delay = ctlr->adev->delay*4;
+       return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || inactive(ctlr);
+}
+
 static long
 audiowrite(Audio *adev, void *vp, long n, vlong)
 {
        uchar *p, *e;
        Ctlr *ctlr;
        Ring *ring;
-       long m;
 
        p = vp;
        e = p + n;
        ctlr = adev->ctlr;
-       qlock(ctlr);
-       if(waserror()){
-               qunlock(ctlr);
-               nexterror();
-       }
        ring = &ctlr->ring;
        while(p < e) {
-               if((m = writering(ring, p, e - p)) <= 0){
+               if((n = writering(ring, p, e - p)) <= 0){
                        if(!ctlr->active && ring->ri == 0)
                                ctlr->blaster.startdma(ctlr);
-                       if(!ctlr->active){
+                       if(!ctlr->active)
                                setempty(ctlr);
-                               continue;
-                       }
-                       sleep(&ctlr->vous, anybuf, ctlr);
-                       continue;
+                       else
+                               sleep(&ctlr->vous, anybuf, ctlr);
                }
-               p += m;
+               p += n;
        }
-       poperror();
-       qunlock(ctlr);
-
+       while(ratebuf(ctlr) == 0)
+               sleep(&ctlr->vous, ratebuf, ctlr);
        return p - (uchar*)vp;
 }
 
 static void
-audioclose(Audio *adev)
+audioclose(Audio *adev, int mode)
 {
        Ctlr *ctlr;
 
+       if(mode == OREAD)
+               return;
        ctlr = adev->ctlr;
-       qlock(ctlr);
-       if(waserror()){
-               qunlock(ctlr);
-               nexterror();
-       }
        sleep(&ctlr->vous, inactive, ctlr);
        setempty(ctlr);
-       poperror();
-       qunlock(ctlr);
+}
+
+static long
+audiovolread(Audio *adev, void *a, long n, vlong)
+{
+       return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
+}
+
+static long
+audiovolwrite(Audio *adev, void *a, long n, vlong)
+{
+       Blaster *blaster;
+       Ctlr *ctlr;
+       int source;
+
+       ctlr = adev->ctlr;
+       blaster = &ctlr->blaster;
+
+       n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
+
+       source = 0;
+       if(ctlr->lvol[Vsynth])
+               source |= 1<<6;
+       if(ctlr->rvol[Vsynth])
+               source |= 1<<5;
+       if(ctlr->lvol[Vaudio])
+               source |= 1<<4;
+       if(ctlr->rvol[Vaudio])
+               source |= 1<<3;
+       if(ctlr->lvol[Vcd])
+               source |= 1<<2;
+       if(ctlr->rvol[Vcd])
+               source |= 1<<1;
+       if(ctlr->lvol[Vmic])
+               source |= 1<<0;
+
+       ilock(blaster);
+       mxcmd(blaster, 0x3c, source);   /* output switch */
+       mxcmd(blaster, 0x3d, source);   /* input left switch */
+       mxcmd(blaster, 0x3e, source);   /* input right switch */
+       iunlock(blaster);
+
+       return n;
 }
 
 static int
@@ -685,7 +621,8 @@ ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
        major = sbread(blaster);
        minor = sbread(blaster);
        if(major != 0x68 || minor != 0x8B){
-               print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n", ctlrno, major, minor);
+               print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n",
+                       ctlrno, major, minor);
                return -1;
        }
 
@@ -739,61 +676,83 @@ static int
 audioprobe(Audio *adev)
 {
        static int irq[] = {9,5,7,10};
+       static Ctlr *cards = nil;
 
        Ctlr *ctlr;
        Blaster *blaster;
-       ISAConf sbconf;
        int i, x;
 
-       sbconf.port = 0x220;
-       sbconf.irq = 5;
-       sbconf.dma = 0;
-       if(isaconfig("audio", adev->ctlrno, &sbconf) == 0)
-               return -1;
+       /* make a list of audio isa cards if not already done */
+       if(cards == nil){
+               for(i=0; i<nelem(irq); i++){
+                       ctlr = mallocz(sizeof(Ctlr), 1);
+                       if(ctlr == nil){
+                               print("sb16: can't allocate memory\n");
+                               break;
+                       }
+                       ctlr->conf.port = 0x220 + i*0x10;
+                       ctlr->conf.irq = irq[i];
+                       ctlr->conf.dma = 0;
+                       if(isaconfig("audio", i, &ctlr->conf) == 0){
+                               free(ctlr);
+                               break;
+                       }
+                       ctlr->next = cards;
+                       cards = ctlr;
+               }
+       }
+
+       /* pick a card */
+       for(ctlr = cards; ctlr; ctlr = ctlr->next){
+               if(ctlr->conf.type && strcmp(adev->name, ctlr->conf.type) == 0){
+                       ctlr->conf.type = nil;
+                       goto Found;
+               }
+       }
+       return -1;
 
-       switch(sbconf.port){
+Found:
+       switch(ctlr->conf.port){
        case 0x220:
        case 0x240:
        case 0x260:
        case 0x280:
                break;
        default:
-               print("#A%d: bad port %#lux\n", adev->ctlrno, sbconf.port);
+               print("#A%d: bad port %#lux\n", adev->ctlrno, ctlr->conf.port);
                return -1;
        }
 
-       if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
-               print("#A%d: cannot ioalloc range %lux+0x10\n", adev->ctlrno, sbconf.port);
+       if(ioalloc(ctlr->conf.port, 0x10, 0, "audio") < 0){
+               print("#A%d: cannot ioalloc range %lux+0x10\n",
+                       adev->ctlrno, ctlr->conf.port);
                return -1;
        }
-       if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
-               iofree(sbconf.port);
-               print("#A%d: cannot ioalloc range %lux+0x01\n", adev->ctlrno, sbconf.port+0x100);
+       if(ioalloc(ctlr->conf.port+0x100, 1, 0, "audio.mpu401") < 0){
+               iofree(ctlr->conf.port);
+               print("#A%d: cannot ioalloc range %lux+0x01\n",
+                       adev->ctlrno, ctlr->conf.port+0x100);
                return -1;
        }
 
-       ctlr = malloc(sizeof(Ctlr));
        ctlr->adev = adev;
        adev->ctlr = ctlr;
 
        blaster = &ctlr->blaster;
-       blaster->reset = sbconf.port + 0x6;
-       blaster->read = sbconf.port + 0xa;
-       blaster->write = sbconf.port + 0xc;
-       blaster->wstatus = sbconf.port + 0xc;
-       blaster->rstatus = sbconf.port + 0xe;
-       blaster->mixaddr = sbconf.port + 0x4;
-       blaster->mixdata = sbconf.port + 0x5;
-       blaster->clri8 = sbconf.port + 0xe;
-       blaster->clri16 = sbconf.port + 0xf;
-       blaster->clri401 = sbconf.port + 0x100;
-       blaster->dma = sbconf.dma;
+       blaster->reset = ctlr->conf.port + 0x6;
+       blaster->read = ctlr->conf.port + 0xa;
+       blaster->write = ctlr->conf.port + 0xc;
+       blaster->wstatus = ctlr->conf.port + 0xc;
+       blaster->rstatus = ctlr->conf.port + 0xe;
+       blaster->mixaddr = ctlr->conf.port + 0x4;
+       blaster->mixdata = ctlr->conf.port + 0x5;
+       blaster->clri8 = ctlr->conf.port + 0xe;
+       blaster->clri16 = ctlr->conf.port + 0xf;
+       blaster->clri401 = ctlr->conf.port + 0x100;
 
        blaster->startdma = sb16startdma;
        blaster->intr = sb16intr;
 
-       resetlevel(ctlr);
-
        outb(blaster->reset, 1);
        delay(1);                       /* >3 υs */
        outb(blaster->reset, 0);
@@ -802,9 +761,9 @@ audioprobe(Audio *adev)
        i = sbread(blaster);
        if(i != 0xaa) {
                print("#A%d: no response #%.2x\n", adev->ctlrno, i);
-               iofree(sbconf.port);
-               iofree(sbconf.port+0x100);
-               free(ctlr);
+Errout:
+               iofree(ctlr->conf.port);
+               iofree(ctlr->conf.port+0x100);
                return -1;
        }
 
@@ -813,12 +772,11 @@ audioprobe(Audio *adev)
        ctlr->minor = sbread(blaster);
 
        if(ctlr->major != 4) {
-               if(ctlr->major != 3 || ctlr->minor != 1 || ess1688(&sbconf, blaster, adev->ctlrno)){
+               if(ctlr->major != 3 || ctlr->minor != 1 ||
+                       ess1688(&ctlr->conf, blaster, adev->ctlrno)){
                        print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
                                adev->ctlrno, ctlr->major, ctlr->minor);
-                       iofree(sbconf.port);
-                       iofree(sbconf.port+0x100);
-                       return -1;
+                       goto Errout;
                }
                ctlr->major = 4;
        }
@@ -827,11 +785,18 @@ audioprobe(Audio *adev)
         * initialize the mixer
         */
        mxcmd(blaster, 0x00, 0);                        /* Reset mixer */
-       mxvolume(ctlr);
+
+       for(i=0; i<Nvol; i++){
+               int a[2];
+
+               a[0] = 0;
+               a[1] = 0;
+               mxsetvol(adev, i, a);
+       }
 
        /* set irq */
        for(i=0; i<nelem(irq); i++){
-               if(sbconf.irq == irq[i]){
+               if(ctlr->conf.irq == irq[i]){
                        mxcmd(blaster, 0x80, 1<<i);
                        break;
                }
@@ -839,51 +804,50 @@ audioprobe(Audio *adev)
        x = mxread(blaster, 0x80);
        for(i=0; i<nelem(irq); i++){
                if(x & (1<<i)){
-                       sbconf.irq = irq[i];
+                       ctlr->conf.irq = irq[i];
                        break;
                }
        }
 
        for(;;){
                /* set 16bit dma */
-               if(blaster->dma>=5 && blaster->dma<=7){
+               if(ctlr->conf.dma>=5 && ctlr->conf.dma<=7){
                        x = mxread(blaster, 0x81);
-                       mxcmd(blaster, 0x81, (1<<blaster->dma) & 0xF0 | (x & 0x0F));
+                       mxcmd(blaster, 0x81, (1<<ctlr->conf.dma) & 0xF0 | (x & 0x0F));
                }
                x = mxread(blaster, 0x81);
                for(i=5; i<=7; i++){
                        if(x & (1<<i)){
-                               blaster->dma = i;
+                               ctlr->conf.dma = i;
                                break;
                        }
                }
-               if(blaster->dma<5){
-                       blaster->dma = 7;
-                       continue;
-               }
-               break;
+               if(ctlr->conf.dma>=5)
+                       break;
+               ctlr->conf.dma = 7;
        }
 
-       print("#A%d: %s port 0x%04lux irq %d dma %d\n", adev->ctlrno, sbconf.type,
-               sbconf.port, sbconf.irq, blaster->dma);
+       print("#A%d: %s port 0x%04lux irq %d dma %lud\n", adev->ctlrno, adev->name,
+               ctlr->conf.port, ctlr->conf.irq, ctlr->conf.dma);
 
        ctlr->ring.nbuf = Blocks*Blocksize;
-       if(dmainit(blaster->dma, ctlr->ring.nbuf)){
-               free(ctlr);
-               return -1;
-       }
-       ctlr->ring.buf = dmabva(blaster->dma);
-
-       intrenable(sbconf.irq, audiointr, adev, BUSUNKNOWN, sbconf.type);
+       if(dmainit(ctlr->conf.dma, ctlr->ring.nbuf))
+               goto Errout;
+       ctlr->ring.buf = dmabva(ctlr->conf.dma);
+       print("#A%d: %s dma buffer %p-%p\n", adev->ctlrno, adev->name,
+               ctlr->ring.buf, ctlr->ring.buf+ctlr->ring.nbuf);
 
        setempty(ctlr);
-       mxvolume(ctlr);
 
        adev->write = audiowrite;
        adev->close = audioclose;
+       adev->volread = audiovolread;
+       adev->volwrite = audiovolwrite;
        adev->status = audiostatus;
        adev->buffered = audiobuffered;
 
+       intrenable(ctlr->conf.irq, audiointr, adev, BUSUNKNOWN, adev->name);
+
        return 0;
 }