5 #include "../port/lib.h"
10 #include "../port/error.h"
11 #include "../port/audioif.h"
13 typedef struct Ring Ring;
14 typedef struct Blaster Blaster;
15 typedef struct Ctlr Ctlr;
34 Blocks = 65536/Blocksize,
49 int reset; /* io ports to the sound blaster */
60 void (*startdma)(Ctlr*);
67 int active; /* boolean dma running */
68 int major; /* SB16 major version number (sb 4) */
69 int minor; /* SB16 minor version number */
70 ulong totcount; /* how many bytes processed since open */
71 vlong tottime; /* time at which totcount bytes were processed */
72 Ring ring; /* dma ring buffer */
84 static Volume voltab[] = {
85 [Vmaster] "master", 0x30, 0xff, Stereo, 0,
86 [Vaudio] "audio", 0x32, 0xff, Stereo, 0,
87 [Vsynth] "synth", 0x34, 0xff, Stereo, 0,
88 [Vcd] "cd", 0x36, 0xff, Stereo, 0,
89 [Vline] "line", 0x38, 0xff, Stereo, 0,
90 [Vmic] "mic", 0x3a, 0xff, Mono, 0,
91 [Vspeaker] "speaker", 0x3b, 0xff, Mono, 0,
92 [Vtreb] "treb", 0x44, 0xff, Stereo, 0,
93 [Vbass] "bass", 0x46, 0xff, Stereo, 0,
94 [Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
95 [Vogain] "outgain", 0x41, 0xff, Stereo, 0,
96 [Vspeed] "speed", 0, 0, Absolute, 0,
100 static char Emajor[] = "soundblaster not responding/wrong version";
112 return r->nbuf - (ri - wi);
120 m = (r->nbuf - 1) - buffered(r);
127 readring(Ring *r, uchar *p, long n)
133 if((m = buffered(r)) <= 0)
138 if(r->ri + m > r->nbuf)
140 memmove(p, r->buf + r->ri, m);
143 r->ri = (r->ri + m) % r->nbuf;
150 writering(Ring *r, uchar *p, long n)
156 if((m = available(r)) <= 0)
161 if(r->wi + m > r->nbuf)
163 memmove(r->buf + r->wi, p, m);
166 r->wi = (r->wi + m) % r->nbuf;
173 sbcmd(Blaster *blaster, int val)
177 for(i=1<<16; i!=0; i--) {
178 s = inb(blaster->wstatus);
179 if((s & 0x80) == 0) {
180 outb(blaster->write, val);
188 sbread(Blaster *blaster)
192 for(i=1<<16; i!=0; i--) {
193 s = inb(blaster->rstatus);
194 if((s & 0x80) != 0) {
195 return inb(blaster->read);
202 ess1688w(Blaster *blaster, int reg, int val)
204 if(sbcmd(blaster, reg) || sbcmd(blaster, val))
210 ess1688r(Blaster *blaster, int reg)
212 if(sbcmd(blaster, 0xC0) || sbcmd(blaster, reg))
214 return sbread(blaster);
218 mxcmd(Blaster *blaster, int addr, int val)
220 outb(blaster->mixaddr, addr);
221 outb(blaster->mixdata, val);
226 mxread(Blaster *blaster, int addr)
230 outb(blaster->mixaddr, addr);
231 s = inb(blaster->mixdata);
236 mxsetvol(Audio *adev, int x, int a[2])
239 Ctlr *ctlr = adev->ctlr;
243 ctlr->lvol[x] = ctlr->rvol[x] = a[0];
248 blaster = &ctlr->blaster;
252 ctlr->rvol[x] = a[1];
253 mxcmd(blaster, vol->reg+1, a[1]);
256 ctlr->lvol[x] = a[0];
257 mxcmd(blaster, vol->reg, a[0]);
265 mxgetvol(Audio *adev, int x, int a[2])
267 Ctlr *ctlr = adev->ctlr;
269 a[0] = ctlr->lvol[x];
270 a[1] = ctlr->rvol[x];
276 contindma(Ctlr *ctlr)
281 blaster = &ctlr->blaster;
283 if(buffered(ring) >= Blocksize){
284 ring->ri = ring->nbuf - dmacount(ctlr->conf.dma);
286 ctlr->totcount += Blocksize;
287 ctlr->tottime = todget(nil);
289 dmaend(ctlr->conf.dma);
290 sbcmd(blaster, 0xd9); /* exit at end of count */
291 sbcmd(blaster, 0xd5); /* pause */
298 * cause sb to get an interrupt per buffer.
302 sb16startdma(Ctlr *ctlr)
309 blaster = &ctlr->blaster;
312 dmaend(ctlr->conf.dma);
314 sbcmd(blaster, 0x42); /* input sampling rate */
316 sbcmd(blaster, 0x41); /* output sampling rate */
317 speed = ctlr->lvol[Vspeed];
318 sbcmd(blaster, speed>>8);
319 sbcmd(blaster, speed);
322 sbcmd(blaster, 0xbe); /* A/D, autoinit */
324 sbcmd(blaster, 0xb6); /* D/A, autoinit */
326 sbcmd(blaster, 0x30); /* stereo, signed 16 bit */
328 count = (Blocksize>>1) - 1;
329 sbcmd(blaster, count);
330 sbcmd(blaster, count>>8);
333 if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
335 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
341 ess1688reset(Blaster *blaster, int ctlrno)
345 outb(blaster->reset, 3);
346 delay(1); /* >3 υs */
347 outb(blaster->reset, 0);
352 print("#A%d: no response %#.2x\n", ctlrno, i);
356 if(sbcmd(blaster, 0xC6)){ /* extended mode */
357 print("#A%d: barf 3\n", ctlrno);
365 ess1688startdma(Ctlr *ctlr)
372 blaster = &ctlr->blaster;
376 dmaend(ctlr->conf.dma);
378 ess1688reset(blaster, ctlr->adev->ctlrno);
383 speed = ctlr->lvol[Vspeed];
386 else if(speed > 48000)
389 x = 0x80|(256-(795500+speed/2)/speed);
391 x = 128-(397700+speed/2)/speed;
392 ess1688w(blaster, 0xA1, x & 0xFF);
394 speed = (speed * 9) / 20;
395 x = 256 - 7160000 / (speed * 82);
396 ess1688w(blaster, 0xA2, x & 0xFF);
399 ess1688w(blaster, 0xB8, 0x0E); /* A/D, autoinit */
401 ess1688w(blaster, 0xB8, 0x04); /* D/A, autoinit */
402 x = ess1688r(blaster, 0xA8) & ~0x03;
403 ess1688w(blaster, 0xA8, x|0x01); /* 2 channels */
404 ess1688w(blaster, 0xB9, 2); /* demand mode, 4 bytes per request */
407 ess1688w(blaster, 0xB6, 0); /* for output */
409 ess1688w(blaster, 0xB7, 0x71);
410 ess1688w(blaster, 0xB7, 0xBC);
412 x = ess1688r(blaster, 0xB1) & 0x0F;
413 ess1688w(blaster, 0xB1, x|0x50);
414 x = ess1688r(blaster, 0xB2) & 0x0F;
415 ess1688w(blaster, 0xB2, x|0x50);
418 sbcmd(blaster, 0xD1); /* speaker on */
421 ess1688w(blaster, 0xA4, count & 0xFF);
422 ess1688w(blaster, 0xA5, (count>>8) & 0xFF);
423 x = ess1688r(blaster, 0xB8);
424 ess1688w(blaster, 0xB8, x|0x05);
427 if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
429 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
440 blaster = &ctlr->blaster;
442 stat = mxread(blaster, 0x82); /* get irq status */
446 inb(blaster->clri16);
450 inb(blaster->clri401);
455 ess1688intr(Ctlr *ctlr)
459 blaster = &ctlr->blaster;
467 audiointr(Ureg *, void *arg)
475 iprint("#A%d: unexpected %s interrupt\n",
476 ctlr->adev->ctlrno, ctlr->adev->name);
479 ctlr->blaster.intr(ctlr);
485 ilock(&ctlr->blaster);
490 iunlock(&ctlr->blaster);
494 audiobuffered(Audio *adev)
496 return buffered(&((Ctlr*)adev->ctlr)->ring);
500 audiostatus(Audio *adev, void *a, long n, vlong)
502 Ctlr *ctlr = adev->ctlr;
504 return snprint((char*)a, n,
505 "bufsize %6d buffered %6ld "
506 "offset %10lud time %19lld\n",
507 Blocksize, buffered(&ctlr->ring),
508 ctlr->totcount, ctlr->tottime);
516 return !ctlr->active;
524 return available(&ctlr->ring) || inactive(ctlr);
528 audiowrite(Audio *adev, void *vp, long n, vlong)
539 if((n = writering(ring, p, e - p)) <= 0){
540 if(!ctlr->active && ring->ri == 0)
541 ctlr->blaster.startdma(ctlr);
545 sleep(&ctlr->vous, anybuf, ctlr);
549 return p - (uchar*)vp;
553 audioclose(Audio *adev)
558 sleep(&ctlr->vous, inactive, ctlr);
563 audiovolread(Audio *adev, void *a, long n, vlong)
565 return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
569 audiovolwrite(Audio *adev, void *a, long n, vlong)
576 blaster = &ctlr->blaster;
578 n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
581 if(ctlr->lvol[Vsynth])
583 if(ctlr->rvol[Vsynth])
585 if(ctlr->lvol[Vaudio])
587 if(ctlr->rvol[Vaudio])
597 mxcmd(blaster, 0x3c, source); /* output switch */
598 mxcmd(blaster, 0x3d, source); /* input left switch */
599 mxcmd(blaster, 0x3e, source); /* input right switch */
606 ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
613 sbcmd(blaster, 0xE7); /* get version */
614 major = sbread(blaster);
615 minor = sbread(blaster);
616 if(major != 0x68 || minor != 0x8B){
617 print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n",
618 ctlrno, major, minor);
622 ess1688reset(blaster, ctlrno);
639 print("#A%d: bad ESS1688 irq %d\n", ctlrno, sbconf->irq);
642 ess1688w(blaster, 0xB1, i);
655 print("#A%d: bad ESS1688 dma %lud\n", ctlrno, sbconf->dma);
658 ess1688w(blaster, 0xB2, i);
660 ess1688reset(blaster, ctlrno);
662 blaster->startdma = ess1688startdma;
663 blaster->intr = ess1688intr;
669 audioprobe(Audio *adev)
671 static int irq[] = {9,5,7,10};
672 static Ctlr *cards = nil;
678 /* make a list of audio isa cards if not already done */
680 for(i=0; i<nelem(irq); i++){
681 ctlr = malloc(sizeof(Ctlr));
682 memset(ctlr, 0, sizeof(Ctlr));
683 ctlr->conf.port = 0x220 + i*0x10;
684 ctlr->conf.irq = irq[i];
686 if(isaconfig("audio", i, &ctlr->conf) == 0){
696 for(ctlr = cards; ctlr; ctlr = ctlr->next){
697 if(ctlr->conf.type && strcmp(adev->name, ctlr->conf.type) == 0){
698 ctlr->conf.type = nil;
705 switch(ctlr->conf.port){
712 print("#A%d: bad port %#lux\n", adev->ctlrno, ctlr->conf.port);
716 if(ioalloc(ctlr->conf.port, 0x10, 0, "audio") < 0){
717 print("#A%d: cannot ioalloc range %lux+0x10\n",
718 adev->ctlrno, ctlr->conf.port);
721 if(ioalloc(ctlr->conf.port+0x100, 1, 0, "audio.mpu401") < 0){
722 iofree(ctlr->conf.port);
723 print("#A%d: cannot ioalloc range %lux+0x01\n",
724 adev->ctlrno, ctlr->conf.port+0x100);
731 blaster = &ctlr->blaster;
732 blaster->reset = ctlr->conf.port + 0x6;
733 blaster->read = ctlr->conf.port + 0xa;
734 blaster->write = ctlr->conf.port + 0xc;
735 blaster->wstatus = ctlr->conf.port + 0xc;
736 blaster->rstatus = ctlr->conf.port + 0xe;
737 blaster->mixaddr = ctlr->conf.port + 0x4;
738 blaster->mixdata = ctlr->conf.port + 0x5;
739 blaster->clri8 = ctlr->conf.port + 0xe;
740 blaster->clri16 = ctlr->conf.port + 0xf;
741 blaster->clri401 = ctlr->conf.port + 0x100;
743 blaster->startdma = sb16startdma;
744 blaster->intr = sb16intr;
746 outb(blaster->reset, 1);
747 delay(1); /* >3 υs */
748 outb(blaster->reset, 0);
753 print("#A%d: no response #%.2x\n", adev->ctlrno, i);
755 iofree(ctlr->conf.port);
756 iofree(ctlr->conf.port+0x100);
760 sbcmd(blaster, 0xe1); /* get version */
761 ctlr->major = sbread(blaster);
762 ctlr->minor = sbread(blaster);
764 if(ctlr->major != 4) {
765 if(ctlr->major != 3 || ctlr->minor != 1 ||
766 ess1688(&ctlr->conf, blaster, adev->ctlrno)){
767 print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
768 adev->ctlrno, ctlr->major, ctlr->minor);
775 * initialize the mixer
777 mxcmd(blaster, 0x00, 0); /* Reset mixer */
779 for(i=0; i<Nvol; i++){
784 mxsetvol(adev, i, a);
788 for(i=0; i<nelem(irq); i++){
789 if(ctlr->conf.irq == irq[i]){
790 mxcmd(blaster, 0x80, 1<<i);
794 x = mxread(blaster, 0x80);
795 for(i=0; i<nelem(irq); i++){
797 ctlr->conf.irq = irq[i];
804 if(ctlr->conf.dma>=5 && ctlr->conf.dma<=7){
805 x = mxread(blaster, 0x81);
806 mxcmd(blaster, 0x81, (1<<ctlr->conf.dma) & 0xF0 | (x & 0x0F));
808 x = mxread(blaster, 0x81);
815 if(ctlr->conf.dma>=5)
820 print("#A%d: %s port 0x%04lux irq %d dma %lud\n", adev->ctlrno, adev->name,
821 ctlr->conf.port, ctlr->conf.irq, ctlr->conf.dma);
823 ctlr->ring.nbuf = Blocks*Blocksize;
824 if(dmainit(ctlr->conf.dma, ctlr->ring.nbuf))
826 ctlr->ring.buf = dmabva(ctlr->conf.dma);
827 print("#A%d: %s dma buffer %p-%p\n", adev->ctlrno, adev->name,
828 ctlr->ring.buf, ctlr->ring.buf+ctlr->ring.nbuf);
832 adev->write = audiowrite;
833 adev->close = audioclose;
834 adev->volread = audiovolread;
835 adev->volwrite = audiovolwrite;
836 adev->status = audiostatus;
837 adev->buffered = audiobuffered;
839 intrenable(ctlr->conf.irq, audiointr, adev, BUSUNKNOWN, adev->name);
847 addaudiocard("sb16", audioprobe);
848 addaudiocard("ess1688", audioprobe);