]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audiosb16.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / audiosb16.c
1 /*
2  *      SB 16 driver
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "../port/error.h"
11 #include "../port/audioif.h"
12
13 typedef struct  Ring    Ring;
14 typedef struct  Blaster Blaster;
15 typedef struct  Ctlr    Ctlr;
16
17 enum
18 {
19         Vmaster,
20         Vaudio,
21         Vsynth,
22         Vcd,
23         Vline,
24         Vmic,
25         Vspeaker,
26         Vtreb,
27         Vbass,
28         Vigain,
29         Vogain,
30         Vspeed,
31         Vdelay,
32         Nvol,
33
34         Blocksize       = 4096,
35         Blocks          = 65536/Blocksize,
36 };
37
38 struct Ring
39 {
40         uchar   *buf;
41         ulong   nbuf;
42
43         ulong   ri;
44         ulong   wi;
45 };
46
47 struct Blaster
48 {
49         Lock;
50         int     reset;          /* io ports to the sound blaster */
51         int     read;
52         int     write;
53         int     wstatus;
54         int     rstatus;
55         int     mixaddr;
56         int     mixdata;
57         int     clri8;
58         int     clri16;
59         int     clri401;
60
61         void    (*startdma)(Ctlr*);
62         void    (*intr)(Ctlr*);
63 };
64
65 struct Ctlr
66 {
67         Rendez  vous;
68         int     active;         /* boolean dma running */
69         int     major;          /* SB16 major version number (sb 4) */
70         int     minor;          /* SB16 minor version number */
71         Ring    ring;           /* dma ring buffer */
72         Blaster blaster;
73
74         int     lvol[Nvol];
75         int     rvol[Nvol];
76
77         /* for probe */
78         Audio   *adev;
79         ISAConf conf;
80         Ctlr *next;
81 };
82
83 static Volume voltab[] = {
84         [Vmaster] "master", 0x30, 0xff, Stereo, 0,
85         [Vaudio] "audio", 0x32, 0xff, Stereo, 0,
86         [Vsynth] "synth", 0x34, 0xff, Stereo, 0,
87         [Vcd] "cd", 0x36, 0xff, Stereo, 0,
88         [Vline] "line", 0x38, 0xff, Stereo, 0,
89         [Vmic] "mic", 0x3a, 0xff, Mono, 0,
90         [Vspeaker] "speaker", 0x3b, 0xff, Mono, 0,
91         [Vtreb] "treb", 0x44, 0xff, Stereo, 0,
92         [Vbass] "bass", 0x46, 0xff, Stereo, 0,
93         [Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
94         [Vogain] "outgain", 0x41, 0xff, Stereo, 0,
95         [Vspeed] "speed", 0, 0, Absolute, 0,
96         [Vdelay] "delay", 0, 0, Absolute, 0,
97         0,
98 };
99
100 static  char    Emajor[]        = "soundblaster not responding/wrong version";
101
102 static long
103 buffered(Ring *r)
104 {
105         ulong ri, wi;
106
107         ri = r->ri;
108         wi = r->wi;
109         if(wi >= ri)
110                 return wi - ri;
111         else
112                 return r->nbuf - (ri - wi);
113 }
114
115 static long
116 available(Ring *r)
117 {
118         long m;
119
120         m = (r->nbuf - 1) - buffered(r);
121         if(m < 0)
122                 m = 0;
123         return m;
124 }
125
126 static long
127 readring(Ring *r, uchar *p, long n)
128 {
129         long n0, m;
130
131         n0 = n;
132         while(n > 0){
133                 if((m = buffered(r)) <= 0)
134                         break;
135                 if(m > n)
136                         m = n;
137                 if(p){
138                         if(r->ri + m > r->nbuf)
139                                 m = r->nbuf - r->ri;
140                         memmove(p, r->buf + r->ri, m);
141                         p += m;
142                 }
143                 r->ri = (r->ri + m) % r->nbuf;
144                 n -= m;
145         }
146         return n0 - n;
147 }
148
149 static long
150 writering(Ring *r, uchar *p, long n)
151 {
152         long n0, m;
153
154         n0 = n;
155         while(n > 0){
156                 if((m = available(r)) <= 0)
157                         break;
158                 if(m > n)
159                         m = n;
160                 if(p){
161                         if(r->wi + m > r->nbuf)
162                                 m = r->nbuf - r->wi;
163                         memmove(r->buf + r->wi, p, m);
164                         p += m;
165                 }
166                 r->wi = (r->wi + m) % r->nbuf;
167                 n -= m;
168         }
169         return n0 - n;
170 }
171
172 static  int
173 sbcmd(Blaster *blaster, int val)
174 {
175         int i, s;
176
177         for(i=1<<16; i!=0; i--) {
178                 s = inb(blaster->wstatus);
179                 if((s & 0x80) == 0) {
180                         outb(blaster->write, val);
181                         return 0;
182                 }
183         }
184         return 1;
185 }
186
187 static  int
188 sbread(Blaster *blaster)
189 {
190         int i, s;
191
192         for(i=1<<16; i!=0; i--) {
193                 s = inb(blaster->rstatus);
194                 if((s & 0x80) != 0) {
195                         return inb(blaster->read);
196                 }
197         }
198         return -1;
199 }
200
201 static int
202 ess1688w(Blaster *blaster, int reg, int val)
203 {
204         if(sbcmd(blaster, reg) || sbcmd(blaster, val))
205                 return 1;
206         return 0;
207 }
208
209 static int
210 ess1688r(Blaster *blaster, int reg)
211 {
212         if(sbcmd(blaster, 0xC0) || sbcmd(blaster, reg))
213                 return -1;
214         return sbread(blaster);
215 }
216
217 static  int
218 mxcmd(Blaster *blaster, int addr, int val)
219 {
220         outb(blaster->mixaddr, addr);
221         outb(blaster->mixdata, val);
222         return 1;
223 }
224
225 static  int
226 mxread(Blaster *blaster, int addr)
227 {
228         int s;
229
230         outb(blaster->mixaddr, addr);
231         s = inb(blaster->mixdata);
232         return s;
233 }
234
235 static int
236 mxsetvol(Audio *adev, int x, int a[2])
237 {
238         Blaster *blaster;
239         Ctlr *ctlr = adev->ctlr;
240         Volume *vol;
241
242         vol = voltab+x;
243         blaster = &ctlr->blaster;
244         ilock(blaster);
245         switch(vol->type){
246         case Absolute:
247                 switch(x){
248                 case Vdelay:
249                         adev->delay = a[0];
250                         break;
251                 case Vspeed:
252                         adev->speed = a[0];
253                         break;
254                 }
255                 ctlr->lvol[x] = ctlr->rvol[x] = a[0];
256                 break;
257         case Stereo:
258                 ctlr->rvol[x] = a[1];
259                 mxcmd(blaster, vol->reg+1, a[1]);
260                 /* no break */
261         case Mono:
262                 ctlr->lvol[x] = a[0];
263                 mxcmd(blaster, vol->reg, a[0]);
264         }
265         iunlock(blaster);
266
267         return 0;
268 }
269
270 static int
271 mxgetvol(Audio *adev, int x, int a[2])
272 {
273         Ctlr *ctlr = adev->ctlr;
274
275         a[0] = ctlr->lvol[x];
276         a[1] = ctlr->rvol[x];
277
278         return 0;
279 }
280
281 static  void
282 contindma(Ctlr *ctlr)
283 {
284         Blaster *blaster;
285         Ring *ring;
286
287         blaster = &ctlr->blaster;
288         ring = &ctlr->ring;
289         if(buffered(ring) >= Blocksize)
290                 ring->ri = ring->nbuf - dmacount(ctlr->conf.dma);
291         else{
292                 dmaend(ctlr->conf.dma);
293                 sbcmd(blaster, 0xd9);   /* exit at end of count */
294                 sbcmd(blaster, 0xd5);   /* pause */
295                 ctlr->active = 0;
296         }
297         wakeup(&ctlr->vous);
298 }
299
300 /*
301  * cause sb to get an interrupt per buffer.
302  * start first dma
303  */
304 static  void
305 sb16startdma(Ctlr *ctlr)
306 {
307         Blaster *blaster;
308         Ring *ring;
309         long count;
310         int speed;
311
312         blaster = &ctlr->blaster;
313         ring = &ctlr->ring;
314         ilock(blaster);
315         dmaend(ctlr->conf.dma);
316         if(0)
317                 sbcmd(blaster, 0x42);   /* input sampling rate */
318         else
319                 sbcmd(blaster, 0x41);   /* output sampling rate */
320         speed = ctlr->adev->speed;
321         sbcmd(blaster, speed>>8);
322         sbcmd(blaster, speed);
323
324         if(0)
325                 sbcmd(blaster, 0xbe);   /* A/D, autoinit */
326         else
327                 sbcmd(blaster, 0xb6);   /* D/A, autoinit */
328
329         sbcmd(blaster, 0x30);   /* stereo, signed 16 bit */
330
331         count = (Blocksize>>1) - 1;
332         sbcmd(blaster, count);
333         sbcmd(blaster, count>>8);
334
335         ctlr->active = 1;
336         if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
337                 ctlr->active = 0;
338                 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
339         }
340         iunlock(blaster);
341 }
342
343 static int
344 ess1688reset(Blaster *blaster, int ctlrno)
345 {
346         int i;
347
348         outb(blaster->reset, 3);
349         delay(1);       /* >3 υs */
350         outb(blaster->reset, 0);
351         delay(1);
352
353         i = sbread(blaster);
354         if(i != 0xAA) {
355                 print("#A%d: no response %#.2x\n", ctlrno, i);
356                 return 1;
357         }
358
359         if(sbcmd(blaster, 0xC6)){       /* extended mode */
360                 print("#A%d: barf 3\n", ctlrno);
361                 return 1;
362         }
363
364         return 0;
365 }
366
367 static  void
368 ess1688startdma(Ctlr *ctlr)
369 {
370         Blaster *blaster;
371         Ring *ring;
372         ulong count;
373         int speed, x;
374
375         blaster = &ctlr->blaster;
376         ring = &ctlr->ring;
377
378         ilock(blaster);
379         dmaend(ctlr->conf.dma);
380
381         ess1688reset(blaster, ctlr->adev->ctlrno);
382
383         /*
384          * Set the speed.
385          */
386         speed = ctlr->adev->speed;
387         if(speed < 4000)
388                 speed = 4000;
389         else if(speed > 48000)
390                 speed = 48000;
391         if(speed > 22000)
392                   x = 0x80|(256-(795500+speed/2)/speed);
393         else
394                   x = 128-(397700+speed/2)/speed;
395         ess1688w(blaster, 0xA1, x & 0xFF);
396
397         speed = (speed * 9) / 20;
398         x = 256 - 7160000 / (speed * 82);
399         ess1688w(blaster, 0xA2, x & 0xFF);
400
401         if(0)
402                 ess1688w(blaster, 0xB8, 0x0E);  /* A/D, autoinit */
403         else
404                 ess1688w(blaster, 0xB8, 0x04);  /* D/A, autoinit */
405         x = ess1688r(blaster, 0xA8) & ~0x03;
406         ess1688w(blaster, 0xA8, x|0x01);        /* 2 channels */
407         ess1688w(blaster, 0xB9, 2);     /* demand mode, 4 bytes per request */
408
409         if(1)
410                 ess1688w(blaster, 0xB6, 0);     /* for output */
411
412         ess1688w(blaster, 0xB7, 0x71);
413         ess1688w(blaster, 0xB7, 0xBC);
414
415         x = ess1688r(blaster, 0xB1) & 0x0F;
416         ess1688w(blaster, 0xB1, x|0x50);
417         x = ess1688r(blaster, 0xB2) & 0x0F;
418         ess1688w(blaster, 0xB2, x|0x50);
419
420         if(1)
421                 sbcmd(blaster, 0xD1);   /* speaker on */
422
423         count = -Blocksize;
424         ess1688w(blaster, 0xA4, count & 0xFF);
425         ess1688w(blaster, 0xA5, (count>>8) & 0xFF);
426         x = ess1688r(blaster, 0xB8);
427         ess1688w(blaster, 0xB8, x|0x05);
428
429         ctlr->active = 1;
430         if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
431                 ctlr->active = 0;
432                 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
433         }
434         iunlock(blaster);
435 }
436
437 static void
438 sb16intr(Ctlr *ctlr)
439 {
440         Blaster *blaster;
441         int stat;
442
443         blaster = &ctlr->blaster;
444         ilock(blaster);
445         stat = mxread(blaster, 0x82);           /* get irq status */
446         if(stat & 3){
447                 contindma(ctlr);
448                 if(stat & 2)
449                         inb(blaster->clri16);
450                 else if(stat & 1)
451                         inb(blaster->clri8);
452         } else if(stat & 4)
453                 inb(blaster->clri401);
454         iunlock(blaster);
455 }
456
457 static void
458 ess1688intr(Ctlr *ctlr)
459 {
460         Blaster *blaster;
461
462         blaster = &ctlr->blaster;
463         ilock(blaster);
464         contindma(ctlr);
465         inb(blaster->clri8);
466         iunlock(blaster);
467 }
468
469 static void
470 audiointr(Ureg *, void *arg)
471 {
472         Audio *adev;
473         Ctlr *ctlr;
474
475         adev = arg;
476         ctlr = adev->ctlr;
477         if(!ctlr->active){
478                 iprint("#A%d: unexpected %s interrupt\n",
479                         ctlr->adev->ctlrno, ctlr->adev->name);
480                 return;
481         }
482         ctlr->blaster.intr(ctlr);
483 }
484
485 static void
486 setempty(Ctlr *ctlr)
487 {
488         ilock(&ctlr->blaster);
489         ctlr->ring.ri = 0;
490         ctlr->ring.wi = 0;
491         iunlock(&ctlr->blaster);
492 }
493
494 static long
495 audiobuffered(Audio *adev)
496 {
497         return buffered(&((Ctlr*)adev->ctlr)->ring);
498 }
499
500 static long
501 audiostatus(Audio *adev, void *a, long n, vlong)
502 {
503         Ctlr *ctlr = adev->ctlr;
504         return snprint((char*)a, n, "bufsize %6d buffered %6ld\n",
505                 Blocksize, buffered(&ctlr->ring));
506 }
507
508 static int
509 inactive(void *arg)
510 {
511         Ctlr *ctlr = arg;
512         return !ctlr->active;
513 }
514
515 static int
516 anybuf(void *arg)
517 {
518         Ctlr *ctlr = arg;
519         return available(&ctlr->ring) || inactive(ctlr);
520 }
521
522 static int
523 ratebuf(void *arg)
524 {
525         Ctlr *ctlr = arg;
526         int delay = ctlr->adev->delay*4;
527         return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || inactive(ctlr);
528 }
529
530 static long
531 audiowrite(Audio *adev, void *vp, long n, vlong)
532 {
533         uchar *p, *e;
534         Ctlr *ctlr;
535         Ring *ring;
536
537         p = vp;
538         e = p + n;
539         ctlr = adev->ctlr;
540         ring = &ctlr->ring;
541         while(p < e) {
542                 if((n = writering(ring, p, e - p)) <= 0){
543                         if(!ctlr->active && ring->ri == 0)
544                                 ctlr->blaster.startdma(ctlr);
545                         if(!ctlr->active)
546                                 setempty(ctlr);
547                         else
548                                 sleep(&ctlr->vous, anybuf, ctlr);
549                 }
550                 p += n;
551         }
552         while(ratebuf(ctlr) == 0)
553                 sleep(&ctlr->vous, ratebuf, ctlr);
554         return p - (uchar*)vp;
555 }
556
557 static void
558 audioclose(Audio *adev, int mode)
559 {
560         Ctlr *ctlr;
561
562         if(mode == OREAD)
563                 return;
564         ctlr = adev->ctlr;
565         sleep(&ctlr->vous, inactive, ctlr);
566         setempty(ctlr);
567 }
568
569 static long
570 audiovolread(Audio *adev, void *a, long n, vlong)
571 {
572         return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
573 }
574
575 static long
576 audiovolwrite(Audio *adev, void *a, long n, vlong)
577 {
578         Blaster *blaster;
579         Ctlr *ctlr;
580         int source;
581
582         ctlr = adev->ctlr;
583         blaster = &ctlr->blaster;
584
585         n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
586
587         source = 0;
588         if(ctlr->lvol[Vsynth])
589                 source |= 1<<6;
590         if(ctlr->rvol[Vsynth])
591                 source |= 1<<5;
592         if(ctlr->lvol[Vaudio])
593                 source |= 1<<4;
594         if(ctlr->rvol[Vaudio])
595                 source |= 1<<3;
596         if(ctlr->lvol[Vcd])
597                 source |= 1<<2;
598         if(ctlr->rvol[Vcd])
599                 source |= 1<<1;
600         if(ctlr->lvol[Vmic])
601                 source |= 1<<0;
602
603         ilock(blaster);
604         mxcmd(blaster, 0x3c, source);   /* output switch */
605         mxcmd(blaster, 0x3d, source);   /* input left switch */
606         mxcmd(blaster, 0x3e, source);   /* input right switch */
607         iunlock(blaster);
608
609         return n;
610 }
611
612 static int
613 ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
614 {
615         int i, major, minor;
616
617         /*
618          * Try for ESS1688.
619          */
620         sbcmd(blaster, 0xE7);                   /* get version */
621         major = sbread(blaster);
622         minor = sbread(blaster);
623         if(major != 0x68 || minor != 0x8B){
624                 print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n",
625                         ctlrno, major, minor);
626                 return -1;
627         }
628
629         ess1688reset(blaster, ctlrno);
630
631         switch(sbconf->irq){
632         case 2:
633         case 9:
634                 i = 0x50|(0<<2);
635                 break;
636         case 5:
637                 i = 0x50|(1<<2);
638                 break;
639         case 7:
640                 i = 0x50|(2<<2);
641                 break;
642         case 10:
643                 i = 0x50|(3<<2);
644                 break;
645         default:
646                 print("#A%d: bad ESS1688 irq %d\n", ctlrno, sbconf->irq);
647                 return 1;
648         }
649         ess1688w(blaster, 0xB1, i);
650
651         switch(sbconf->dma){
652         case 0:
653                 i = 0x50|(1<<2);
654                 break;
655         case 1:
656                 i = 0xF0|(2<<2);
657                 break;
658         case 3:
659                 i = 0x50|(3<<2);
660                 break;
661         default:
662                 print("#A%d: bad ESS1688 dma %lud\n", ctlrno, sbconf->dma);
663                 return 1;
664         }
665         ess1688w(blaster, 0xB2, i);
666
667         ess1688reset(blaster, ctlrno);
668
669         blaster->startdma = ess1688startdma;
670         blaster->intr = ess1688intr;
671
672         return 0;
673 }
674
675 static int
676 audioprobe(Audio *adev)
677 {
678         static int irq[] = {9,5,7,10};
679         static Ctlr *cards = nil;
680
681         Ctlr *ctlr;
682         Blaster *blaster;
683         int i, x;
684
685         /* make a list of audio isa cards if not already done */
686         if(cards == nil){
687                 for(i=0; i<nelem(irq); i++){
688                         ctlr = mallocz(sizeof(Ctlr), 1);
689                         if(ctlr == nil){
690                                 print("sb16: can't allocate memory\n");
691                                 break;
692                         }
693                         ctlr->conf.port = 0x220 + i*0x10;
694                         ctlr->conf.irq = irq[i];
695                         ctlr->conf.dma = 0;
696                         if(isaconfig("audio", i, &ctlr->conf) == 0){
697                                 free(ctlr);
698                                 break;
699                         }
700                         ctlr->next = cards;
701                         cards = ctlr;
702                 }
703         }
704
705         /* pick a card */
706         for(ctlr = cards; ctlr; ctlr = ctlr->next){
707                 if(ctlr->conf.type && strcmp(adev->name, ctlr->conf.type) == 0){
708                         ctlr->conf.type = nil;
709                         goto Found;
710                 }
711         }
712         return -1;
713
714 Found:
715         switch(ctlr->conf.port){
716         case 0x220:
717         case 0x240:
718         case 0x260:
719         case 0x280:
720                 break;
721         default:
722                 print("#A%d: bad port %#lux\n", adev->ctlrno, ctlr->conf.port);
723                 return -1;
724         }
725
726         if(ioalloc(ctlr->conf.port, 0x10, 0, "audio") < 0){
727                 print("#A%d: cannot ioalloc range %lux+0x10\n",
728                         adev->ctlrno, ctlr->conf.port);
729                 return -1;
730         }
731         if(ioalloc(ctlr->conf.port+0x100, 1, 0, "audio.mpu401") < 0){
732                 iofree(ctlr->conf.port);
733                 print("#A%d: cannot ioalloc range %lux+0x01\n",
734                         adev->ctlrno, ctlr->conf.port+0x100);
735                 return -1;
736         }
737
738         ctlr->adev = adev;
739         adev->ctlr = ctlr;
740
741         blaster = &ctlr->blaster;
742         blaster->reset = ctlr->conf.port + 0x6;
743         blaster->read = ctlr->conf.port + 0xa;
744         blaster->write = ctlr->conf.port + 0xc;
745         blaster->wstatus = ctlr->conf.port + 0xc;
746         blaster->rstatus = ctlr->conf.port + 0xe;
747         blaster->mixaddr = ctlr->conf.port + 0x4;
748         blaster->mixdata = ctlr->conf.port + 0x5;
749         blaster->clri8 = ctlr->conf.port + 0xe;
750         blaster->clri16 = ctlr->conf.port + 0xf;
751         blaster->clri401 = ctlr->conf.port + 0x100;
752
753         blaster->startdma = sb16startdma;
754         blaster->intr = sb16intr;
755
756         outb(blaster->reset, 1);
757         delay(1);                       /* >3 υs */
758         outb(blaster->reset, 0);
759         delay(1);
760
761         i = sbread(blaster);
762         if(i != 0xaa) {
763                 print("#A%d: no response #%.2x\n", adev->ctlrno, i);
764 Errout:
765                 iofree(ctlr->conf.port);
766                 iofree(ctlr->conf.port+0x100);
767                 return -1;
768         }
769
770         sbcmd(blaster, 0xe1);                   /* get version */
771         ctlr->major = sbread(blaster);
772         ctlr->minor = sbread(blaster);
773
774         if(ctlr->major != 4) {
775                 if(ctlr->major != 3 || ctlr->minor != 1 ||
776                         ess1688(&ctlr->conf, blaster, adev->ctlrno)){
777                         print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
778                                 adev->ctlrno, ctlr->major, ctlr->minor);
779                         goto Errout;
780                 }
781                 ctlr->major = 4;
782         }
783
784         /*
785          * initialize the mixer
786          */
787         mxcmd(blaster, 0x00, 0);                        /* Reset mixer */
788
789         for(i=0; i<Nvol; i++){
790                 int a[2];
791
792                 a[0] = 0;
793                 a[1] = 0;
794                 mxsetvol(adev, i, a);
795         }
796
797         /* set irq */
798         for(i=0; i<nelem(irq); i++){
799                 if(ctlr->conf.irq == irq[i]){
800                         mxcmd(blaster, 0x80, 1<<i);
801                         break;
802                 }
803         }
804         x = mxread(blaster, 0x80);
805         for(i=0; i<nelem(irq); i++){
806                 if(x & (1<<i)){
807                         ctlr->conf.irq = irq[i];
808                         break;
809                 }
810         }
811
812         for(;;){
813                 /* set 16bit dma */
814                 if(ctlr->conf.dma>=5 && ctlr->conf.dma<=7){
815                         x = mxread(blaster, 0x81);
816                         mxcmd(blaster, 0x81, (1<<ctlr->conf.dma) & 0xF0 | (x & 0x0F));
817                 }
818                 x = mxread(blaster, 0x81);
819                 for(i=5; i<=7; i++){
820                         if(x & (1<<i)){
821                                 ctlr->conf.dma = i;
822                                 break;
823                         }
824                 }
825                 if(ctlr->conf.dma>=5)
826                         break;
827                 ctlr->conf.dma = 7;
828         }
829
830         print("#A%d: %s port 0x%04lux irq %d dma %lud\n", adev->ctlrno, adev->name,
831                 ctlr->conf.port, ctlr->conf.irq, ctlr->conf.dma);
832
833         ctlr->ring.nbuf = Blocks*Blocksize;
834         if(dmainit(ctlr->conf.dma, ctlr->ring.nbuf))
835                 goto Errout;
836         ctlr->ring.buf = dmabva(ctlr->conf.dma);
837         print("#A%d: %s dma buffer %p-%p\n", adev->ctlrno, adev->name,
838                 ctlr->ring.buf, ctlr->ring.buf+ctlr->ring.nbuf);
839
840         setempty(ctlr);
841
842         adev->write = audiowrite;
843         adev->close = audioclose;
844         adev->volread = audiovolread;
845         adev->volwrite = audiovolwrite;
846         adev->status = audiostatus;
847         adev->buffered = audiobuffered;
848
849         intrenable(ctlr->conf.irq, audiointr, adev, BUSUNKNOWN, adev->name);
850
851         return 0;
852 }
853
854 void
855 audiosb16link(void)
856 {
857         addaudiocard("sb16", audioprobe);
858         addaudiocard("ess1688", audioprobe);
859 }