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;
35 Blocks = 65536/Blocksize,
50 int reset; /* io ports to the sound blaster */
61 void (*startdma)(Ctlr*);
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 */
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,
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 blaster = &ctlr->blaster;
255 ctlr->lvol[x] = ctlr->rvol[x] = a[0];
258 ctlr->rvol[x] = a[1];
259 mxcmd(blaster, vol->reg+1, a[1]);
262 ctlr->lvol[x] = a[0];
263 mxcmd(blaster, vol->reg, a[0]);
271 mxgetvol(Audio *adev, int x, int a[2])
273 Ctlr *ctlr = adev->ctlr;
275 a[0] = ctlr->lvol[x];
276 a[1] = ctlr->rvol[x];
282 contindma(Ctlr *ctlr)
287 blaster = &ctlr->blaster;
289 if(buffered(ring) >= Blocksize)
290 ring->ri = ring->nbuf - dmacount(ctlr->conf.dma);
292 dmaend(ctlr->conf.dma);
293 sbcmd(blaster, 0xd9); /* exit at end of count */
294 sbcmd(blaster, 0xd5); /* pause */
301 * cause sb to get an interrupt per buffer.
305 sb16startdma(Ctlr *ctlr)
312 blaster = &ctlr->blaster;
315 dmaend(ctlr->conf.dma);
317 sbcmd(blaster, 0x42); /* input sampling rate */
319 sbcmd(blaster, 0x41); /* output sampling rate */
320 speed = ctlr->adev->speed;
321 sbcmd(blaster, speed>>8);
322 sbcmd(blaster, speed);
325 sbcmd(blaster, 0xbe); /* A/D, autoinit */
327 sbcmd(blaster, 0xb6); /* D/A, autoinit */
329 sbcmd(blaster, 0x30); /* stereo, signed 16 bit */
331 count = (Blocksize>>1) - 1;
332 sbcmd(blaster, count);
333 sbcmd(blaster, count>>8);
336 if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
338 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
344 ess1688reset(Blaster *blaster, int ctlrno)
348 outb(blaster->reset, 3);
349 delay(1); /* >3 υs */
350 outb(blaster->reset, 0);
355 print("#A%d: no response %#.2x\n", ctlrno, i);
359 if(sbcmd(blaster, 0xC6)){ /* extended mode */
360 print("#A%d: barf 3\n", ctlrno);
368 ess1688startdma(Ctlr *ctlr)
375 blaster = &ctlr->blaster;
379 dmaend(ctlr->conf.dma);
381 ess1688reset(blaster, ctlr->adev->ctlrno);
386 speed = ctlr->adev->speed;
389 else if(speed > 48000)
392 x = 0x80|(256-(795500+speed/2)/speed);
394 x = 128-(397700+speed/2)/speed;
395 ess1688w(blaster, 0xA1, x & 0xFF);
397 speed = (speed * 9) / 20;
398 x = 256 - 7160000 / (speed * 82);
399 ess1688w(blaster, 0xA2, x & 0xFF);
402 ess1688w(blaster, 0xB8, 0x0E); /* A/D, autoinit */
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 */
410 ess1688w(blaster, 0xB6, 0); /* for output */
412 ess1688w(blaster, 0xB7, 0x71);
413 ess1688w(blaster, 0xB7, 0xBC);
415 x = ess1688r(blaster, 0xB1) & 0x0F;
416 ess1688w(blaster, 0xB1, x|0x50);
417 x = ess1688r(blaster, 0xB2) & 0x0F;
418 ess1688w(blaster, 0xB2, x|0x50);
421 sbcmd(blaster, 0xD1); /* speaker on */
424 ess1688w(blaster, 0xA4, count & 0xFF);
425 ess1688w(blaster, 0xA5, (count>>8) & 0xFF);
426 x = ess1688r(blaster, 0xB8);
427 ess1688w(blaster, 0xB8, x|0x05);
430 if(dmasetup(ctlr->conf.dma, ring->buf, ring->nbuf, DMAWRITE|DMALOOP) < 0){
432 print("#A%d: dmasetup fail\n", ctlr->adev->ctlrno);
443 blaster = &ctlr->blaster;
445 stat = mxread(blaster, 0x82); /* get irq status */
449 inb(blaster->clri16);
453 inb(blaster->clri401);
458 ess1688intr(Ctlr *ctlr)
462 blaster = &ctlr->blaster;
470 audiointr(Ureg *, void *arg)
478 iprint("#A%d: unexpected %s interrupt\n",
479 ctlr->adev->ctlrno, ctlr->adev->name);
482 ctlr->blaster.intr(ctlr);
488 ilock(&ctlr->blaster);
491 iunlock(&ctlr->blaster);
495 audiobuffered(Audio *adev)
497 return buffered(&((Ctlr*)adev->ctlr)->ring);
501 audiostatus(Audio *adev, void *a, long n, vlong)
503 Ctlr *ctlr = adev->ctlr;
504 return snprint((char*)a, n, "bufsize %6d buffered %6ld\n",
505 Blocksize, buffered(&ctlr->ring));
512 return !ctlr->active;
519 return available(&ctlr->ring) || inactive(ctlr);
526 int delay = ctlr->adev->delay*4;
527 return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || inactive(ctlr);
531 audiowrite(Audio *adev, void *vp, long n, vlong)
542 if((n = writering(ring, p, e - p)) <= 0){
543 if(!ctlr->active && ring->ri == 0)
544 ctlr->blaster.startdma(ctlr);
548 sleep(&ctlr->vous, anybuf, ctlr);
552 while(ratebuf(ctlr) == 0)
553 sleep(&ctlr->vous, ratebuf, ctlr);
554 return p - (uchar*)vp;
558 audioclose(Audio *adev, int mode)
565 sleep(&ctlr->vous, inactive, ctlr);
570 audiovolread(Audio *adev, void *a, long n, vlong)
572 return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
576 audiovolwrite(Audio *adev, void *a, long n, vlong)
583 blaster = &ctlr->blaster;
585 n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
588 if(ctlr->lvol[Vsynth])
590 if(ctlr->rvol[Vsynth])
592 if(ctlr->lvol[Vaudio])
594 if(ctlr->rvol[Vaudio])
604 mxcmd(blaster, 0x3c, source); /* output switch */
605 mxcmd(blaster, 0x3d, source); /* input left switch */
606 mxcmd(blaster, 0x3e, source); /* input right switch */
613 ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
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);
629 ess1688reset(blaster, ctlrno);
646 print("#A%d: bad ESS1688 irq %d\n", ctlrno, sbconf->irq);
649 ess1688w(blaster, 0xB1, i);
662 print("#A%d: bad ESS1688 dma %lud\n", ctlrno, sbconf->dma);
665 ess1688w(blaster, 0xB2, i);
667 ess1688reset(blaster, ctlrno);
669 blaster->startdma = ess1688startdma;
670 blaster->intr = ess1688intr;
676 audioprobe(Audio *adev)
678 static int irq[] = {9,5,7,10};
679 static Ctlr *cards = nil;
685 /* make a list of audio isa cards if not already done */
687 for(i=0; i<nelem(irq); i++){
688 ctlr = mallocz(sizeof(Ctlr), 1);
690 print("sb16: can't allocate memory\n");
693 ctlr->conf.port = 0x220 + i*0x10;
694 ctlr->conf.irq = irq[i];
696 if(isaconfig("audio", i, &ctlr->conf) == 0){
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;
715 switch(ctlr->conf.port){
722 print("#A%d: bad port %#lux\n", adev->ctlrno, ctlr->conf.port);
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);
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);
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;
753 blaster->startdma = sb16startdma;
754 blaster->intr = sb16intr;
756 outb(blaster->reset, 1);
757 delay(1); /* >3 υs */
758 outb(blaster->reset, 0);
763 print("#A%d: no response #%.2x\n", adev->ctlrno, i);
765 iofree(ctlr->conf.port);
766 iofree(ctlr->conf.port+0x100);
770 sbcmd(blaster, 0xe1); /* get version */
771 ctlr->major = sbread(blaster);
772 ctlr->minor = sbread(blaster);
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);
785 * initialize the mixer
787 mxcmd(blaster, 0x00, 0); /* Reset mixer */
789 for(i=0; i<Nvol; i++){
794 mxsetvol(adev, i, a);
798 for(i=0; i<nelem(irq); i++){
799 if(ctlr->conf.irq == irq[i]){
800 mxcmd(blaster, 0x80, 1<<i);
804 x = mxread(blaster, 0x80);
805 for(i=0; i<nelem(irq); i++){
807 ctlr->conf.irq = irq[i];
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));
818 x = mxread(blaster, 0x81);
825 if(ctlr->conf.dma>=5)
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);
833 ctlr->ring.nbuf = Blocks*Blocksize;
834 if(dmainit(ctlr->conf.dma, ctlr->ring.nbuf))
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);
842 adev->write = audiowrite;
843 adev->close = audioclose;
844 adev->volread = audiovolread;
845 adev->volwrite = audiovolwrite;
846 adev->status = audiostatus;
847 adev->buffered = audiobuffered;
849 intrenable(ctlr->conf.irq, audiointr, adev, BUSUNKNOWN, adev->name);
857 addaudiocard("sb16", audioprobe);
858 addaudiocard("ess1688", audioprobe);