]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audiosb16.c
audiohda: first attempt on audio recording support for intel hda audio, distinguish...
[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         sleep(&ctlr->vous, ratebuf, ctlr);
553         return p - (uchar*)vp;
554 }
555
556 static void
557 audioclose(Audio *adev, int mode)
558 {
559         Ctlr *ctlr;
560
561         if(mode == OREAD)
562                 return;
563         ctlr = adev->ctlr;
564         sleep(&ctlr->vous, inactive, ctlr);
565         setempty(ctlr);
566 }
567
568 static long
569 audiovolread(Audio *adev, void *a, long n, vlong)
570 {
571         return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
572 }
573
574 static long
575 audiovolwrite(Audio *adev, void *a, long n, vlong)
576 {
577         Blaster *blaster;
578         Ctlr *ctlr;
579         int source;
580
581         ctlr = adev->ctlr;
582         blaster = &ctlr->blaster;
583
584         n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
585
586         source = 0;
587         if(ctlr->lvol[Vsynth])
588                 source |= 1<<6;
589         if(ctlr->rvol[Vsynth])
590                 source |= 1<<5;
591         if(ctlr->lvol[Vaudio])
592                 source |= 1<<4;
593         if(ctlr->rvol[Vaudio])
594                 source |= 1<<3;
595         if(ctlr->lvol[Vcd])
596                 source |= 1<<2;
597         if(ctlr->rvol[Vcd])
598                 source |= 1<<1;
599         if(ctlr->lvol[Vmic])
600                 source |= 1<<0;
601
602         ilock(blaster);
603         mxcmd(blaster, 0x3c, source);   /* output switch */
604         mxcmd(blaster, 0x3d, source);   /* input left switch */
605         mxcmd(blaster, 0x3e, source);   /* input right switch */
606         iunlock(blaster);
607
608         return n;
609 }
610
611 static int
612 ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
613 {
614         int i, major, minor;
615
616         /*
617          * Try for ESS1688.
618          */
619         sbcmd(blaster, 0xE7);                   /* get version */
620         major = sbread(blaster);
621         minor = sbread(blaster);
622         if(major != 0x68 || minor != 0x8B){
623                 print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n",
624                         ctlrno, major, minor);
625                 return -1;
626         }
627
628         ess1688reset(blaster, ctlrno);
629
630         switch(sbconf->irq){
631         case 2:
632         case 9:
633                 i = 0x50|(0<<2);
634                 break;
635         case 5:
636                 i = 0x50|(1<<2);
637                 break;
638         case 7:
639                 i = 0x50|(2<<2);
640                 break;
641         case 10:
642                 i = 0x50|(3<<2);
643                 break;
644         default:
645                 print("#A%d: bad ESS1688 irq %d\n", ctlrno, sbconf->irq);
646                 return 1;
647         }
648         ess1688w(blaster, 0xB1, i);
649
650         switch(sbconf->dma){
651         case 0:
652                 i = 0x50|(1<<2);
653                 break;
654         case 1:
655                 i = 0xF0|(2<<2);
656                 break;
657         case 3:
658                 i = 0x50|(3<<2);
659                 break;
660         default:
661                 print("#A%d: bad ESS1688 dma %lud\n", ctlrno, sbconf->dma);
662                 return 1;
663         }
664         ess1688w(blaster, 0xB2, i);
665
666         ess1688reset(blaster, ctlrno);
667
668         blaster->startdma = ess1688startdma;
669         blaster->intr = ess1688intr;
670
671         return 0;
672 }
673
674 static int
675 audioprobe(Audio *adev)
676 {
677         static int irq[] = {9,5,7,10};
678         static Ctlr *cards = nil;
679
680         Ctlr *ctlr;
681         Blaster *blaster;
682         int i, x;
683
684         /* make a list of audio isa cards if not already done */
685         if(cards == nil){
686                 for(i=0; i<nelem(irq); i++){
687                         ctlr = mallocz(sizeof(Ctlr), 1);
688                         if(ctlr == nil){
689                                 print("sb16: can't allocate memory\n");
690                                 break;
691                         }
692                         ctlr->conf.port = 0x220 + i*0x10;
693                         ctlr->conf.irq = irq[i];
694                         ctlr->conf.dma = 0;
695                         if(isaconfig("audio", i, &ctlr->conf) == 0){
696                                 free(ctlr);
697                                 break;
698                         }
699                         ctlr->next = cards;
700                         cards = ctlr;
701                 }
702         }
703
704         /* pick a card */
705         for(ctlr = cards; ctlr; ctlr = ctlr->next){
706                 if(ctlr->conf.type && strcmp(adev->name, ctlr->conf.type) == 0){
707                         ctlr->conf.type = nil;
708                         goto Found;
709                 }
710         }
711         return -1;
712
713 Found:
714         switch(ctlr->conf.port){
715         case 0x220:
716         case 0x240:
717         case 0x260:
718         case 0x280:
719                 break;
720         default:
721                 print("#A%d: bad port %#lux\n", adev->ctlrno, ctlr->conf.port);
722                 return -1;
723         }
724
725         if(ioalloc(ctlr->conf.port, 0x10, 0, "audio") < 0){
726                 print("#A%d: cannot ioalloc range %lux+0x10\n",
727                         adev->ctlrno, ctlr->conf.port);
728                 return -1;
729         }
730         if(ioalloc(ctlr->conf.port+0x100, 1, 0, "audio.mpu401") < 0){
731                 iofree(ctlr->conf.port);
732                 print("#A%d: cannot ioalloc range %lux+0x01\n",
733                         adev->ctlrno, ctlr->conf.port+0x100);
734                 return -1;
735         }
736
737         ctlr->adev = adev;
738         adev->ctlr = ctlr;
739
740         blaster = &ctlr->blaster;
741         blaster->reset = ctlr->conf.port + 0x6;
742         blaster->read = ctlr->conf.port + 0xa;
743         blaster->write = ctlr->conf.port + 0xc;
744         blaster->wstatus = ctlr->conf.port + 0xc;
745         blaster->rstatus = ctlr->conf.port + 0xe;
746         blaster->mixaddr = ctlr->conf.port + 0x4;
747         blaster->mixdata = ctlr->conf.port + 0x5;
748         blaster->clri8 = ctlr->conf.port + 0xe;
749         blaster->clri16 = ctlr->conf.port + 0xf;
750         blaster->clri401 = ctlr->conf.port + 0x100;
751
752         blaster->startdma = sb16startdma;
753         blaster->intr = sb16intr;
754
755         outb(blaster->reset, 1);
756         delay(1);                       /* >3 υs */
757         outb(blaster->reset, 0);
758         delay(1);
759
760         i = sbread(blaster);
761         if(i != 0xaa) {
762                 print("#A%d: no response #%.2x\n", adev->ctlrno, i);
763 Errout:
764                 iofree(ctlr->conf.port);
765                 iofree(ctlr->conf.port+0x100);
766                 return -1;
767         }
768
769         sbcmd(blaster, 0xe1);                   /* get version */
770         ctlr->major = sbread(blaster);
771         ctlr->minor = sbread(blaster);
772
773         if(ctlr->major != 4) {
774                 if(ctlr->major != 3 || ctlr->minor != 1 ||
775                         ess1688(&ctlr->conf, blaster, adev->ctlrno)){
776                         print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
777                                 adev->ctlrno, ctlr->major, ctlr->minor);
778                         goto Errout;
779                 }
780                 ctlr->major = 4;
781         }
782
783         /*
784          * initialize the mixer
785          */
786         mxcmd(blaster, 0x00, 0);                        /* Reset mixer */
787
788         for(i=0; i<Nvol; i++){
789                 int a[2];
790
791                 a[0] = 0;
792                 a[1] = 0;
793                 mxsetvol(adev, i, a);
794         }
795
796         /* set irq */
797         for(i=0; i<nelem(irq); i++){
798                 if(ctlr->conf.irq == irq[i]){
799                         mxcmd(blaster, 0x80, 1<<i);
800                         break;
801                 }
802         }
803         x = mxread(blaster, 0x80);
804         for(i=0; i<nelem(irq); i++){
805                 if(x & (1<<i)){
806                         ctlr->conf.irq = irq[i];
807                         break;
808                 }
809         }
810
811         for(;;){
812                 /* set 16bit dma */
813                 if(ctlr->conf.dma>=5 && ctlr->conf.dma<=7){
814                         x = mxread(blaster, 0x81);
815                         mxcmd(blaster, 0x81, (1<<ctlr->conf.dma) & 0xF0 | (x & 0x0F));
816                 }
817                 x = mxread(blaster, 0x81);
818                 for(i=5; i<=7; i++){
819                         if(x & (1<<i)){
820                                 ctlr->conf.dma = i;
821                                 break;
822                         }
823                 }
824                 if(ctlr->conf.dma>=5)
825                         break;
826                 ctlr->conf.dma = 7;
827         }
828
829         print("#A%d: %s port 0x%04lux irq %d dma %lud\n", adev->ctlrno, adev->name,
830                 ctlr->conf.port, ctlr->conf.irq, ctlr->conf.dma);
831
832         ctlr->ring.nbuf = Blocks*Blocksize;
833         if(dmainit(ctlr->conf.dma, ctlr->ring.nbuf))
834                 goto Errout;
835         ctlr->ring.buf = dmabva(ctlr->conf.dma);
836         print("#A%d: %s dma buffer %p-%p\n", adev->ctlrno, adev->name,
837                 ctlr->ring.buf, ctlr->ring.buf+ctlr->ring.nbuf);
838
839         setempty(ctlr);
840
841         adev->write = audiowrite;
842         adev->close = audioclose;
843         adev->volread = audiovolread;
844         adev->volwrite = audiovolwrite;
845         adev->status = audiostatus;
846         adev->buffered = audiobuffered;
847
848         intrenable(ctlr->conf.irq, audiointr, adev, BUSUNKNOWN, adev->name);
849
850         return 0;
851 }
852
853 void
854 audiosb16link(void)
855 {
856         addaudiocard("sb16", audioprobe);
857         addaudiocard("ess1688", audioprobe);
858 }