📄 devaudio.c
字号:
void *p; for(i=0; i<Nbuf; i++) { p = xspanalloc(Bufsize, CACHELINESZ, 64*1024); dcflush(p, Bufsize); audio.buf[i].virt = UNCACHED(uchar, p); audio.buf[i].phys = (ulong)PADDR(p); }}static voidsetempty(void){ int i; ilock(&blaster); audio.empty.first = 0; audio.empty.last = 0; audio.full.first = 0; audio.full.last = 0; audio.current = 0; audio.filling = 0; for(i=0; i<Nbuf; i++) putbuf(&audio.empty, &audio.buf[i]); audio.totcount = 0; audio.tottime = 0LL; iunlock(&blaster);}static voidresetlevel(void){ int i; for(i=0; volumes[i].name; i++) { audio.lovol[i] = volumes[i].ilval; audio.rovol[i] = volumes[i].irval; audio.livol[i] = volumes[i].ilval; audio.rivol[i] = volumes[i].irval; }}static intess1688(ISAConf* sbconf){ int i, major, minor; /* * Try for ESS1688. */ sbcmd(0xE7); /* get version */ major = sbread(); minor = sbread(); if(major != 0x68 || minor != 0x8B){ print("#A: model 0x%.2x 0x%.2x; not ESS1688 compatible\n", major, minor); return 1; } ess1688reset(); switch(sbconf->irq){ case 2: case 9: i = 0x50|(0<<2); break; case 5: i = 0x50|(1<<2); break; case 7: i = 0x50|(2<<2); break; case 10: i = 0x50|(3<<2); break; default: print("#A: bad ESS1688 irq %lud\n", sbconf->irq); return 1; } ess1688w(0xB1, i); switch(sbconf->dma){ case 0: i = 0x50|(1<<2); break; case 1: i = 0xF0|(2<<2); break; case 3: i = 0x50|(3<<2); break; default: print("#A: bad ESS1688 dma %lud\n", sbconf->dma); return 1; } ess1688w(0xB2, i); ess1688reset(); blaster.startdma = ess1688startdma; blaster.intr = ess1688intr; return 0;}static voidaudioinit(void){ ISAConf sbconf; int i, x; static int irq[] = {2,5,7,10}; sbconf.port = 0x220; sbconf.dma = Dma; sbconf.irq = IrqAUDIO; if(isaconfig("audio", 0, &sbconf) == 0) return; if(cistrcmp(sbconf.type, "sb16") != 0 && cistrcmp(sbconf.type, "ess1688") != 0) return; switch(sbconf.port){ case 0x220: case 0x240: case 0x260: case 0x280: break; default: print("#A: bad port 0x%lux\n", sbconf.port); return; } switch(sbconf.irq){ case 2: case 5: case 7: case 9: case 10: break; default: print("#A: bad irq %lud\n", sbconf.irq); return; } blaster.reset = sbconf.port + 0x6; blaster.read = sbconf.port + 0xa; blaster.write = sbconf.port + 0xc; blaster.wstatus = sbconf.port + 0xc; blaster.rstatus = sbconf.port + 0xe; blaster.mixaddr = sbconf.port + 0x4; blaster.mixdata = sbconf.port + 0x5; blaster.clri8 = sbconf.port + 0xe; blaster.clri16 = sbconf.port + 0xf; blaster.clri401 = sbconf.port + 0x100; blaster.dma = sbconf.dma; blaster.startdma = sb16startdma; blaster.intr = sb16intr; audio.amode = Aclosed; resetlevel(); outb(blaster.reset, 1); delay(1); /* >3 υs */ outb(blaster.reset, 0); delay(1); i = sbread(); if(i != 0xaa) { print("#A: no response #%.2x\n", i); return; } sbcmd(0xe1); /* get version */ audio.major = sbread(); audio.minor = sbread(); if(audio.major != 4) { if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){ print("#A: model 0x%.2x 0x%.2x; not SB 16 compatible\n", audio.major, audio.minor); return; } audio.major = 4; } /* * initialize the mixer */ mxcmd(0x00, 0); /* Reset mixer */ mxvolume(); /* * Attempt to set IRQ/DMA channels. * On old ISA boards, these registers are writable. * On Plug-n-Play boards, these are read-only. * * To accomodate both, we write to the registers, * but then use the contents in case the write is * disallowed. */ mxcmd(0x80, /* irq */ (sbconf.irq==2)? 1: (sbconf.irq==5)? 2: (sbconf.irq==7)? 4: (sbconf.irq==9)? 1: (sbconf.irq==10)? 8: 0); mxcmd(0x81, 1<<blaster.dma); /* dma */ x = mxread(0x81); for(i=5; i<=7; i++) if(x & (1<<i)){ blaster.dma = i; break; } x = mxread(0x80); for(i=0; i<=3; i++) if(x & (1<<i)){ sbconf.irq = irq[i]; break; } seteisadma(blaster.dma, audiodmaintr); setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);}static Chan*audioattach(char *param){ return devattach('A', param);}static intaudiowalk(Chan *c, char *name){ return devwalk(c, name, audiodir, nelem(audiodir), devgen);}static voidaudiostat(Chan *c, char *db){ devstat(c, db, audiodir, nelem(audiodir), devgen);}static Chan*audioopen(Chan *c, int omode){ int amode; if(audio.major != 4) error(Emajor); switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qstatus: if((omode&7) != OREAD) error(Eperm); case Qvolume: case Qdir: break; case Qaudio: amode = Awrite; if((omode&7) == OREAD) amode = Aread; qlock(&audio); if(audio.amode != Aclosed){ qunlock(&audio); error(Einuse); } if(audio.bufinit == 0) { audio.bufinit = 1; sbbufinit(); } audio.amode = amode; setempty(); audio.curcount = 0; qunlock(&audio); mxvolume(); break; } c = devopen(c, omode, audiodir, nelem(audiodir), devgen); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;}static voidaudioclose(Chan *c){ Buf *b; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qdir: case Qvolume: case Qstatus: break; case Qaudio: if(c->flag & COPEN) { qlock(&audio); if(audio.amode == Awrite) { /* flush out last partial buffer */ b = audio.filling; if(b) { audio.filling = 0; memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount); swab(b->virt); putbuf(&audio.full, b); } if(!audio.active && audio.full.first) pokeaudio(); } audio.amode = Aclosed; if(waserror()){ qunlock(&audio); nexterror(); } while(audio.active) waitaudio(); setempty(); poperror(); qunlock(&audio); } break; }}static longaudioread(Chan *c, void *v, long n, vlong off){ int liv, riv, lov, rov; long m, n0; char buf[300]; Buf *b; int j; ulong offset = off; char *a; n0 = n; a = v; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qdir: return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: if(audio.amode != Aread) error(Emode); qlock(&audio); if(waserror()){ qunlock(&audio); nexterror(); } while(n > 0) { b = audio.filling; if(b == 0) { b = getbuf(&audio.full); if(b == 0) { waitaudio(); continue; } audio.filling = b; swab(b->virt); audio.curcount = 0; } m = Bufsize-audio.curcount; if(m > n) m = n; memmove(a, b->virt+audio.curcount, m); audio.curcount += m; n -= m; a += m; if(audio.curcount >= Bufsize) { audio.filling = 0; putbuf(&audio.empty, b); } } poperror(); qunlock(&audio); break; case Qstatus: buf[0] = 0; snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n", audio.totcount, audio.tottime); return readstr(offset, a, n, buf); case Qvolume: j = 0; buf[0] = 0; for(m=0; volumes[m].name; m++){ liv = audio.livol[m]; riv = audio.rivol[m]; lov = audio.lovol[m]; rov = audio.rovol[m]; j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); if((volumes[m].flag & Fmono) || liv==riv && lov==rov){ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) j += snprint(buf+j, sizeof(buf)-j, " %d", liv); else{ if(volumes[m].flag & Fin) j += snprint(buf+j, sizeof(buf)-j, " in %d", liv); if(volumes[m].flag & Fout) j += snprint(buf+j, sizeof(buf)-j, " out %d", lov); } }else{ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov) j += snprint(buf+j, sizeof(buf)-j, " left %d right %d", liv, riv); else{ if(volumes[m].flag & Fin) j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d", liv, riv); if(volumes[m].flag & Fout) j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d", lov, rov); } } j += snprint(buf+j, sizeof(buf)-j, "\n"); } return readstr(offset, a, n, buf); } return n0-n;}static longaudiowrite(Chan *c, void *vp, long n, vlong){ long m, n0; int i, nf, v, left, right, in, out; char buf[255], *field[Ncmd]; Buf *b; char *a; a = vp; n0 = n; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qvolume: v = Vaudio; left = 1; right = 1; in = 1; out = 1; if(n > sizeof(buf)-1) n = sizeof(buf)-1; memmove(buf, a, n); buf[n] = '\0'; nf = getfields(buf, field, Ncmd, 1, " \t\n"); for(i = 0; i < nf; i++){ /* * a number is volume */ if(field[i][0] >= '0' && field[i][0] <= '9') { m = strtoul(field[i], 0, 10); if(left && out) audio.lovol[v] = m; if(left && in) audio.livol[v] = m; if(right && out) audio.rovol[v] = m; if(right && in) audio.rivol[v] = m; mxvolume(); goto cont0; } for(m=0; volumes[m].name; m++) { if(strcmp(field[i], volumes[m].name) == 0) { v = m; in = 1; out = 1; left = 1; right = 1; goto cont0; } } if(strcmp(field[i], "reset") == 0) { resetlevel(); mxvolume(); goto cont0; } if(strcmp(field[i], "in") == 0) { in = 1; out = 0; goto cont0; } if(strcmp(field[i], "out") == 0) { in = 0; out = 1; goto cont0; } if(strcmp(field[i], "left") == 0) { left = 1; right = 0; goto cont0; } if(strcmp(field[i], "right") == 0) { left = 0; right = 1; goto cont0; } error(Evolume); break; cont0:; } break; case Qaudio: if(audio.amode != Awrite) error(Emode); qlock(&audio); if(waserror()){ qunlock(&audio); nexterror(); } while(n > 0) { b = audio.filling; if(b == 0) { b = getbuf(&audio.empty); if(b == 0) { waitaudio(); continue; } audio.filling = b; audio.curcount = 0; } m = Bufsize-audio.curcount; if(m > n) m = n; memmove(b->virt+audio.curcount, a, m); audio.curcount += m; n -= m; a += m; if(audio.curcount >= Bufsize) { audio.filling = 0; swab(b->virt); putbuf(&audio.full, b); } } poperror(); qunlock(&audio); break; } return n0 - n;}static voidswab(uchar *a){ ulong *p, *ep, b; if(!SBswab){ USED(a); return; } p = (ulong*)a; ep = p + (Bufsize>>2); while(p < ep) { b = *p; b = (b>>24) | (b<<24) | ((b&0xff0000) >> 8) | ((b&0x00ff00) << 8); *p++ = b; }}Dev audiodevtab = { 'A', "audio", devreset, audioinit, audioattach, devclone, audiowalk, audiostat, audioopen, devcreate, audioclose, audioread, devbread, audiowrite, devbwrite, devremove, devwstat,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -