changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/pc/audiosb16.c

changeset 4350: 1f9d7811d546
parent: 1f2dc6ed72ec
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
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 }