|
|
1.1 ! root 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 "../port/error.h" ! 10: #include "devtab.h" ! 11: #include "io.h" ! 12: #include "audio.h" ! 13: ! 14: #define NPORT (sizeof audiodir/sizeof(Dirtab)) ! 15: ! 16: typedef struct AQueue AQueue; ! 17: typedef struct Buf Buf; ! 18: ! 19: enum ! 20: { ! 21: Qdir = 0, ! 22: Qaudio, ! 23: Qvolume, ! 24: ! 25: Fmono = 1, ! 26: Fin = 2, ! 27: Fout = 4, ! 28: ! 29: Aclosed = 0, ! 30: Aread, ! 31: Awrite, ! 32: ! 33: Vaudio = 0, ! 34: Vsynth, ! 35: Vcd, ! 36: Vline, ! 37: Vmic, ! 38: Vspeaker, ! 39: Vtreb, ! 40: Vbass, ! 41: Vspeed, ! 42: Nvol, ! 43: ! 44: Speed = 44100, ! 45: Ncmd = 50, /* max volume command words */ ! 46: }; ! 47: ! 48: Dirtab ! 49: audiodir[] = ! 50: { ! 51: "audio", {Qaudio}, 0, 0666, ! 52: "volume", {Qvolume}, 0, 0666, ! 53: }; ! 54: ! 55: struct Buf ! 56: { ! 57: uchar* virt; ! 58: ulong phys; ! 59: Buf* next; ! 60: }; ! 61: struct AQueue ! 62: { ! 63: Lock; ! 64: Buf* first; ! 65: Buf* last; ! 66: }; ! 67: static struct ! 68: { ! 69: QLock; ! 70: Rendez vous; ! 71: int bufinit; /* boolean if buffers allocated */ ! 72: int curcount; /* how much data in current buffer */ ! 73: int active; /* boolean dma running */ ! 74: int intr; /* boolean an interrupt has happened */ ! 75: int amode; /* Aclosed/Aread/Awrite for /audio */ ! 76: int rivol[Nvol]; /* right/left input/output volumes */ ! 77: int livol[Nvol]; ! 78: int rovol[Nvol]; ! 79: int lovol[Nvol]; ! 80: int major; /* SB16 major version number (sb 4) */ ! 81: int minor; /* SB16 minor version number */ ! 82: ! 83: Buf buf[Nbuf]; /* buffers and queues */ ! 84: AQueue empty; ! 85: AQueue full; ! 86: Buf* current; ! 87: Buf* filling; ! 88: } audio; ! 89: ! 90: static struct ! 91: { ! 92: char* name; ! 93: int flag; ! 94: int ilval; /* initial values */ ! 95: int irval; ! 96: } volumes[] = ! 97: { ! 98: [Vaudio] "audio", Fout, 50, 50, ! 99: [Vsynth] "synth", Fin|Fout, 0, 0, ! 100: [Vcd] "cd", Fin|Fout, 0, 0, ! 101: [Vline] "line", Fin|Fout, 0, 0, ! 102: [Vmic] "mic", Fin|Fout|Fmono, 0, 0, ! 103: [Vspeaker] "speaker", Fout|Fmono, 0, 0, ! 104: ! 105: [Vtreb] "treb", Fout, 50, 50, ! 106: [Vbass] "bass", Fout, 50, 50, ! 107: ! 108: [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, ! 109: 0 ! 110: }; ! 111: ! 112: static struct ! 113: { ! 114: Lock; ! 115: int reset; /* io ports to the sound blaster */ ! 116: int read; ! 117: int write; ! 118: int wstatus; ! 119: int rstatus; ! 120: int mixaddr; ! 121: int mixdata; ! 122: int clri8; ! 123: int clri16; ! 124: int clri401; ! 125: int dma; ! 126: } blaster; ! 127: ! 128: static void swab(uchar*); ! 129: ! 130: static char Emajor[] = "soundblaster not responding/wrong version"; ! 131: static char Emode[] = "illegal open mode"; ! 132: static char Evolume[] = "illegal volume specifier"; ! 133: ! 134: static int ! 135: sbcmd(int val) ! 136: { ! 137: int i, s; ! 138: ! 139: for(i=1<<16; i!=0; i--) { ! 140: s = inb(blaster.wstatus); ! 141: if((s & 0x80) == 0) { ! 142: outb(blaster.write, val); ! 143: return 0; ! 144: } ! 145: } ! 146: return 1; ! 147: } ! 148: ! 149: static int ! 150: sbread(void) ! 151: { ! 152: int i, s; ! 153: ! 154: for(i=1<<16; i!=0; i--) { ! 155: s = inb(blaster.rstatus); ! 156: if((s & 0x80) != 0) { ! 157: return inb(blaster.read); ! 158: } ! 159: } ! 160: return 0xbb; ! 161: } ! 162: ! 163: static int ! 164: mxcmd(int addr, int val) ! 165: { ! 166: ! 167: outb(blaster.mixaddr, addr); ! 168: outb(blaster.mixdata, val); ! 169: return 1; ! 170: } ! 171: ! 172: static int ! 173: mxread(int addr) ! 174: { ! 175: int s; ! 176: ! 177: outb(blaster.mixaddr, addr); ! 178: s = inb(blaster.mixdata); ! 179: return s; ! 180: } ! 181: ! 182: static void ! 183: mxcmds(int s, int v) ! 184: { ! 185: ! 186: if(v > 100) ! 187: v = 100; ! 188: if(v < 0) ! 189: v = 0; ! 190: mxcmd(s, (v*255)/100); ! 191: } ! 192: ! 193: static void ! 194: mxcmdt(int s, int v) ! 195: { ! 196: ! 197: if(v > 100) ! 198: v = 100; ! 199: if(v <= 0) ! 200: mxcmd(s, 0); ! 201: else ! 202: mxcmd(s, 255-100+v); ! 203: } ! 204: ! 205: static void ! 206: mxcmdu(int s, int v) ! 207: { ! 208: ! 209: if(v > 100) ! 210: v = 100; ! 211: if(v <= 0) ! 212: v = 0; ! 213: mxcmd(s, 128-50+v); ! 214: } ! 215: ! 216: static void ! 217: mxvolume(void) ! 218: { ! 219: int *left, *right; ! 220: int source; ! 221: ! 222: if(audio.amode == Aread){ ! 223: left = audio.livol; ! 224: right = audio.rivol; ! 225: }else{ ! 226: left = audio.lovol; ! 227: right = audio.rovol; ! 228: } ! 229: ! 230: ilock(&blaster); ! 231: ! 232: mxcmd(0x30, 255); /* left master */ ! 233: mxcmd(0x31, 255); /* right master */ ! 234: mxcmd(0x3f, 0); /* left igain */ ! 235: mxcmd(0x40, 0); /* right igain */ ! 236: mxcmd(0x41, 0); /* left ogain */ ! 237: mxcmd(0x42, 0); /* right ogain */ ! 238: ! 239: mxcmds(0x32, left[Vaudio]); ! 240: mxcmds(0x33, right[Vaudio]); ! 241: ! 242: mxcmds(0x34, left[Vsynth]); ! 243: mxcmds(0x35, right[Vsynth]); ! 244: ! 245: mxcmds(0x36, left[Vcd]); ! 246: mxcmds(0x37, right[Vcd]); ! 247: ! 248: mxcmds(0x38, left[Vline]); ! 249: mxcmds(0x39, right[Vline]); ! 250: ! 251: mxcmds(0x3a, left[Vmic]); ! 252: mxcmds(0x3b, left[Vspeaker]); ! 253: ! 254: mxcmdu(0x44, left[Vtreb]); ! 255: mxcmdu(0x45, right[Vtreb]); ! 256: ! 257: mxcmdu(0x46, left[Vbass]); ! 258: mxcmdu(0x47, right[Vbass]); ! 259: ! 260: source = 0; ! 261: if(left[Vsynth]) ! 262: source |= 1<<6; ! 263: if(right[Vsynth]) ! 264: source |= 1<<5; ! 265: if(left[Vaudio]) ! 266: source |= 1<<4; ! 267: if(right[Vaudio]) ! 268: source |= 1<<3; ! 269: if(left[Vcd]) ! 270: source |= 1<<2; ! 271: if(right[Vcd]) ! 272: source |= 1<<1; ! 273: if(left[Vmic]) ! 274: source |= 1<<0; ! 275: if(audio.amode == Aread) ! 276: mxcmd(0x3c, 0); /* output switch */ ! 277: else ! 278: mxcmd(0x3c, source); ! 279: mxcmd(0x3d, source); /* input left switch */ ! 280: mxcmd(0x3e, source); /* input right switch */ ! 281: iunlock(&blaster); ! 282: } ! 283: ! 284: static Buf* ! 285: getbuf(AQueue *q) ! 286: { ! 287: Buf *b; ! 288: ! 289: ilock(q); ! 290: b = q->first; ! 291: if(b) ! 292: q->first = b->next; ! 293: iunlock(q); ! 294: ! 295: return b; ! 296: } ! 297: ! 298: static void ! 299: putbuf(AQueue *q, Buf *b) ! 300: { ! 301: ! 302: ilock(q); ! 303: b->next = 0; ! 304: if(q->first) ! 305: q->last->next = b; ! 306: else ! 307: q->first = b; ! 308: q->last = b; ! 309: iunlock(q); ! 310: } ! 311: ! 312: /* ! 313: * move the dma to the next buffer ! 314: */ ! 315: static void ! 316: contindma(void) ! 317: { ! 318: Buf *b; ! 319: ! 320: if(!audio.active) ! 321: goto shutdown; ! 322: ! 323: b = audio.current; ! 324: if(audio.amode == Aread) { ! 325: if(b) /* shouldnt happen */ ! 326: putbuf(&audio.full, b); ! 327: b = getbuf(&audio.empty); ! 328: } else { ! 329: if(b) /* shouldnt happen */ ! 330: putbuf(&audio.empty, b); ! 331: b = getbuf(&audio.full); ! 332: } ! 333: audio.current = b; ! 334: if(b == 0) ! 335: goto shutdown; ! 336: ! 337: dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread); ! 338: return; ! 339: ! 340: shutdown: ! 341: dmaend(blaster.dma); ! 342: sbcmd(0xd9); /* exit at end of count */ ! 343: sbcmd(0xd5); /* pause */ ! 344: audio.curcount = 0; ! 345: audio.active = 0; ! 346: } ! 347: ! 348: /* ! 349: * cause sb to get an interrupt per buffer. ! 350: * start first dma ! 351: */ ! 352: static void ! 353: startdma(void) ! 354: { ! 355: ulong count; ! 356: int speed; ! 357: ! 358: ilock(&blaster); ! 359: dmaend(blaster.dma); ! 360: if(audio.amode == Aread) { ! 361: sbcmd(0x42); /* input sampling rate */ ! 362: speed = audio.livol[Vspeed]; ! 363: } else { ! 364: sbcmd(0x41); /* output sampling rate */ ! 365: speed = audio.lovol[Vspeed]; ! 366: } ! 367: sbcmd(speed>>8); ! 368: sbcmd(speed); ! 369: ! 370: count = (Bufsize >> 1) - 1; ! 371: if(audio.amode == Aread) ! 372: sbcmd(0xbe); /* A/D, autoinit */ ! 373: else ! 374: sbcmd(0xb6); /* D/A, autoinit */ ! 375: sbcmd(0x30); /* stereo, 16 bit */ ! 376: sbcmd(count); ! 377: sbcmd(count>>8); ! 378: ! 379: audio.active = 1; ! 380: contindma(); ! 381: iunlock(&blaster); ! 382: } ! 383: ! 384: /* ! 385: * if audio is stopped, ! 386: * start it up again. ! 387: */ ! 388: static void ! 389: pokeaudio(void) ! 390: { ! 391: if(!audio.active) ! 392: startdma(); ! 393: } ! 394: ! 395: void ! 396: audiosbintr(void) ! 397: { ! 398: int stat, dummy; ! 399: ! 400: stat = mxread(0x82) & 7; /* get irq status */ ! 401: if(stat) { ! 402: dummy = 0; ! 403: if(stat & 2) { ! 404: ilock(&blaster); ! 405: dummy = inb(blaster.clri16); ! 406: contindma(); ! 407: iunlock(&blaster); ! 408: audio.intr = 1; ! 409: wakeup(&audio.vous); ! 410: } ! 411: if(stat & 1) { ! 412: dummy = inb(blaster.clri8); ! 413: } ! 414: if(stat & 4) { ! 415: dummy = inb(blaster.clri401); ! 416: } ! 417: USED(dummy); ! 418: } ! 419: } ! 420: ! 421: void ! 422: pcaudiosbintr(Ureg *ureg, void *rock) ! 423: { ! 424: USED(ureg, rock); ! 425: audiosbintr(); ! 426: } ! 427: ! 428: void ! 429: audiodmaintr(void) ! 430: { ! 431: } ! 432: ! 433: static int ! 434: anybuf(void *p) ! 435: { ! 436: USED(p); ! 437: return audio.intr; ! 438: } ! 439: ! 440: /* ! 441: * wait for some output to get ! 442: * empty buffers back. ! 443: */ ! 444: static void ! 445: waitaudio(void) ! 446: { ! 447: ! 448: audio.intr = 0; ! 449: pokeaudio(); ! 450: tsleep(&audio.vous, anybuf, 0, 10*1000); ! 451: if(audio.intr == 0) { ! 452: audio.active = 0; ! 453: pokeaudio(); ! 454: } ! 455: } ! 456: ! 457: static void ! 458: sbbufinit(void) ! 459: { ! 460: int i; ! 461: void *p; ! 462: ! 463: for(i=0; i<Nbuf; i++) { ! 464: p = xspanalloc(Bufsize, CACHELINESZ, 64*1024); ! 465: audio.buf[i].virt = UNCACHED(uchar, p); ! 466: audio.buf[i].phys = (ulong)PADDR(p); ! 467: } ! 468: } ! 469: ! 470: static void ! 471: setempty(void) ! 472: { ! 473: int i; ! 474: ! 475: ilock(&blaster); ! 476: audio.empty.first = 0; ! 477: audio.empty.last = 0; ! 478: audio.full.first = 0; ! 479: audio.full.last = 0; ! 480: audio.current = 0; ! 481: audio.filling = 0; ! 482: for(i=0; i<Nbuf; i++) ! 483: putbuf(&audio.empty, &audio.buf[i]); ! 484: iunlock(&blaster); ! 485: } ! 486: ! 487: void ! 488: audioreset(void) ! 489: { ! 490: } ! 491: ! 492: static void ! 493: resetlevel(void) ! 494: { ! 495: int i; ! 496: ! 497: for(i=0; volumes[i].name; i++) { ! 498: audio.lovol[i] = volumes[i].ilval; ! 499: audio.rovol[i] = volumes[i].irval; ! 500: audio.livol[i] = volumes[i].ilval; ! 501: audio.rivol[i] = volumes[i].irval; ! 502: } ! 503: } ! 504: ! 505: void ! 506: audioinit(void) ! 507: { ! 508: ISAConf sbconf; ! 509: int i; ! 510: ! 511: sbconf.port = 0x220; ! 512: sbconf.dma = 5; ! 513: sbconf.irq = 7; ! 514: if(isaconfig("audio", 0, &sbconf) == 0) ! 515: return; ! 516: if(strcmp(sbconf.type, "sb16") != 0) ! 517: return; ! 518: ! 519: switch(sbconf.port){ ! 520: case 0x220: ! 521: case 0x240: ! 522: case 0x260: ! 523: case 0x280: ! 524: break; ! 525: default: ! 526: print("devaudio: bad sb16 port 0x%x\n", sbconf.port); ! 527: return; ! 528: } ! 529: switch(sbconf.irq){ ! 530: case 2: ! 531: case 5: ! 532: case 7: ! 533: case 10: ! 534: break; ! 535: default: ! 536: print("devaudio: bad sb16 irq %d\n", sbconf.irq); ! 537: return; ! 538: } ! 539: ! 540: blaster.dma = sbconf.dma; ! 541: ! 542: blaster.reset = sbconf.port + 0x6; ! 543: blaster.read = sbconf.port + 0xa; ! 544: blaster.write = sbconf.port + 0xc; ! 545: blaster.wstatus = sbconf.port + 0xc; ! 546: blaster.rstatus = sbconf.port + 0xe; ! 547: blaster.mixaddr = sbconf.port + 0x4; ! 548: blaster.mixdata = sbconf.port + 0x5; ! 549: blaster.clri8 = sbconf.port + 0xe; ! 550: blaster.clri16 = sbconf.port + 0xf; ! 551: blaster.clri401 = sbconf.port + 0x100; ! 552: ! 553: seteisadma(blaster.dma, audiodmaintr); ! 554: setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0); ! 555: ! 556: audio.amode = Aclosed; ! 557: resetlevel(); ! 558: ! 559: outb(blaster.reset, 1); ! 560: delay(1); /* >3 υs */ ! 561: outb(blaster.reset, 0); ! 562: delay(1); ! 563: ! 564: i = sbread(); ! 565: if(i != 0xaa) { ! 566: print("sound blaster didnt respond #%.2x\n", i); ! 567: return; ! 568: } ! 569: ! 570: sbcmd(0xe1); /* get version */ ! 571: audio.major = sbread(); ! 572: audio.minor = sbread(); ! 573: ! 574: if(audio.major != 4) { ! 575: print("bad soundblaster model #%.2x #%.2x; not SB 16\n", audio.major, audio.minor); ! 576: return; ! 577: } ! 578: /* ! 579: * initialize the mixer ! 580: */ ! 581: mxcmd(0x00, 0); /* Reset mixer */ ! 582: mxvolume(); ! 583: ! 584: /* ! 585: * set up irq/dma chans ! 586: */ ! 587: mxcmd(0x80, /* irq */ ! 588: (sbconf.irq==2)? 1: ! 589: (sbconf.irq==5)? 2: ! 590: (sbconf.irq==7)? 4: ! 591: (sbconf.irq==10)? 8: ! 592: 0); ! 593: mxcmd(0x81, 1<<blaster.dma); /* dma */ ! 594: } ! 595: ! 596: Chan* ! 597: audioattach(char *param) ! 598: { ! 599: return devattach('A', param); ! 600: } ! 601: ! 602: Chan* ! 603: audioclone(Chan *c, Chan *nc) ! 604: { ! 605: return devclone(c, nc); ! 606: } ! 607: ! 608: int ! 609: audiowalk(Chan *c, char *name) ! 610: { ! 611: return devwalk(c, name, audiodir, NPORT, devgen); ! 612: } ! 613: ! 614: void ! 615: audiostat(Chan *c, char *db) ! 616: { ! 617: devstat(c, db, audiodir, NPORT, devgen); ! 618: } ! 619: ! 620: Chan* ! 621: audioopen(Chan *c, int omode) ! 622: { ! 623: int amode; ! 624: ! 625: if(audio.major != 4) ! 626: error(Emajor); ! 627: ! 628: switch(c->qid.path & ~CHDIR) { ! 629: default: ! 630: error(Eperm); ! 631: break; ! 632: ! 633: case Qvolume: ! 634: case Qdir: ! 635: break; ! 636: ! 637: case Qaudio: ! 638: amode = Awrite; ! 639: if((omode&7) == OREAD) ! 640: amode = Aread; ! 641: qlock(&audio); ! 642: if(audio.amode != Aclosed){ ! 643: qunlock(&audio); ! 644: error(Einuse); ! 645: } ! 646: if(audio.bufinit == 0) { ! 647: audio.bufinit = 1; ! 648: sbbufinit(); ! 649: } ! 650: audio.amode = amode; ! 651: setempty(); ! 652: audio.curcount = 0; ! 653: qunlock(&audio); ! 654: mxvolume(); ! 655: break; ! 656: } ! 657: c = devopen(c, omode, audiodir, NPORT, devgen); ! 658: c->mode = openmode(omode); ! 659: c->flag |= COPEN; ! 660: c->offset = 0; ! 661: ! 662: return c; ! 663: } ! 664: ! 665: void ! 666: audiocreate(Chan *c, char *name, int omode, ulong perm) ! 667: { ! 668: USED(c); ! 669: USED(name); ! 670: USED(omode); ! 671: USED(perm); ! 672: ! 673: error(Eperm); ! 674: } ! 675: ! 676: void ! 677: audioclose(Chan *c) ! 678: { ! 679: ! 680: switch(c->qid.path & ~CHDIR) { ! 681: default: ! 682: error(Eperm); ! 683: break; ! 684: ! 685: case Qdir: ! 686: case Qvolume: ! 687: break; ! 688: ! 689: case Qaudio: ! 690: if(c->flag & COPEN) { ! 691: qlock(&audio); ! 692: audio.amode = Aclosed; ! 693: if(waserror()){ ! 694: qunlock(&audio); ! 695: nexterror(); ! 696: } ! 697: while(audio.active) ! 698: waitaudio(); ! 699: setempty(); ! 700: poperror(); ! 701: qunlock(&audio); ! 702: } ! 703: break; ! 704: } ! 705: } ! 706: ! 707: long ! 708: audioread(Chan *c, char *a, long n, ulong offset) ! 709: { ! 710: int liv, riv, lov, rov; ! 711: long m, n0; ! 712: char buf[300]; ! 713: Buf *b; ! 714: int j; ! 715: ! 716: n0 = n; ! 717: switch(c->qid.path & ~CHDIR) { ! 718: default: ! 719: error(Eperm); ! 720: break; ! 721: ! 722: case Qdir: ! 723: return devdirread(c, a, n, audiodir, NPORT, devgen); ! 724: ! 725: case Qaudio: ! 726: if(audio.amode != Aread) ! 727: error(Emode); ! 728: qlock(&audio); ! 729: if(waserror()){ ! 730: qunlock(&audio); ! 731: nexterror(); ! 732: } ! 733: while(n > 0) { ! 734: b = audio.filling; ! 735: if(b == 0) { ! 736: b = getbuf(&audio.full); ! 737: if(b == 0) { ! 738: waitaudio(); ! 739: continue; ! 740: } ! 741: audio.filling = b; ! 742: swab(b->virt); ! 743: audio.curcount = 0; ! 744: } ! 745: m = Bufsize-audio.curcount; ! 746: if(m > n) ! 747: m = n; ! 748: memmove(a, b->virt+audio.curcount, m); ! 749: ! 750: audio.curcount += m; ! 751: n -= m; ! 752: a += m; ! 753: if(audio.curcount >= Bufsize) { ! 754: audio.filling = 0; ! 755: putbuf(&audio.empty, b); ! 756: } ! 757: } ! 758: poperror(); ! 759: qunlock(&audio); ! 760: break; ! 761: ! 762: case Qvolume: ! 763: j = 0; ! 764: buf[0] = 0; ! 765: for(m=0; volumes[m].name; m++){ ! 766: liv = audio.livol[m]; ! 767: riv = audio.rivol[m]; ! 768: lov = audio.lovol[m]; ! 769: rov = audio.rovol[m]; ! 770: j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); ! 771: if((volumes[m].flag & Fmono) || liv==riv && lov==rov){ ! 772: if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) ! 773: j += snprint(buf+j, sizeof(buf)-j, " %d", liv); ! 774: else{ ! 775: if(volumes[m].flag & Fin) ! 776: j += snprint(buf+j, sizeof(buf)-j, " in %d", liv); ! 777: if(volumes[m].flag & Fout) ! 778: j += snprint(buf+j, sizeof(buf)-j, " out %d", lov); ! 779: } ! 780: }else{ ! 781: if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov) ! 782: j += snprint(buf+j, sizeof(buf)-j, " left %d right %d", ! 783: liv, riv); ! 784: else{ ! 785: if(volumes[m].flag & Fin) ! 786: j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d", ! 787: liv, riv); ! 788: if(volumes[m].flag & Fout) ! 789: j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d", ! 790: lov, rov); ! 791: } ! 792: } ! 793: j += snprint(buf+j, sizeof(buf)-j, "\n"); ! 794: } ! 795: ! 796: return readstr(offset, a, n, buf); ! 797: } ! 798: return n0-n; ! 799: } ! 800: ! 801: long ! 802: audiowrite(Chan *c, char *a, long n, ulong offset) ! 803: { ! 804: long m, n0; ! 805: int i, nf, v, left, right, in, out; ! 806: char buf[255], *field[Ncmd]; ! 807: Buf *b; ! 808: ! 809: USED(offset); ! 810: ! 811: n0 = n; ! 812: switch(c->qid.path & ~CHDIR) { ! 813: default: ! 814: error(Eperm); ! 815: break; ! 816: ! 817: case Qvolume: ! 818: v = Vaudio; ! 819: left = 1; ! 820: right = 1; ! 821: in = 1; ! 822: out = 1; ! 823: if(n > sizeof(buf)-1) ! 824: n = sizeof(buf)-1; ! 825: memmove(buf, a, n); ! 826: buf[n] = '\0'; ! 827: ! 828: nf = getfields(buf, field, Ncmd, " \t\n"); ! 829: for(i = 0; i < nf; i++){ ! 830: /* ! 831: * a number is volume ! 832: */ ! 833: if(field[i][0] >= '0' && field[i][0] <= '9') { ! 834: m = strtoul(field[i], 0, 10); ! 835: if(left && out) ! 836: audio.lovol[v] = m; ! 837: if(left && in) ! 838: audio.livol[v] = m; ! 839: if(right && out) ! 840: audio.rovol[v] = m; ! 841: if(right && in) ! 842: audio.rivol[v] = m; ! 843: mxvolume(); ! 844: goto cont0; ! 845: } ! 846: ! 847: for(m=0; volumes[m].name; m++) { ! 848: if(strcmp(field[i], volumes[m].name) == 0) { ! 849: v = m; ! 850: in = 1; ! 851: out = 1; ! 852: left = 1; ! 853: right = 1; ! 854: goto cont0; ! 855: } ! 856: } ! 857: ! 858: if(strcmp(field[i], "reset") == 0) { ! 859: resetlevel(); ! 860: mxvolume(); ! 861: goto cont0; ! 862: } ! 863: if(strcmp(field[i], "in") == 0) { ! 864: in = 1; ! 865: out = 0; ! 866: goto cont0; ! 867: } ! 868: if(strcmp(field[i], "out") == 0) { ! 869: in = 0; ! 870: out = 1; ! 871: goto cont0; ! 872: } ! 873: if(strcmp(field[i], "left") == 0) { ! 874: left = 1; ! 875: right = 0; ! 876: goto cont0; ! 877: } ! 878: if(strcmp(field[i], "right") == 0) { ! 879: left = 0; ! 880: right = 1; ! 881: goto cont0; ! 882: } ! 883: error(Evolume); ! 884: break; ! 885: cont0:; ! 886: } ! 887: break; ! 888: ! 889: case Qaudio: ! 890: if(audio.amode != Awrite) ! 891: error(Emode); ! 892: qlock(&audio); ! 893: if(waserror()){ ! 894: qunlock(&audio); ! 895: nexterror(); ! 896: } ! 897: while(n > 0) { ! 898: b = audio.filling; ! 899: if(b == 0) { ! 900: b = getbuf(&audio.empty); ! 901: if(b == 0) { ! 902: waitaudio(); ! 903: continue; ! 904: } ! 905: audio.filling = b; ! 906: audio.curcount = 0; ! 907: } ! 908: ! 909: m = Bufsize-audio.curcount; ! 910: if(m > n) ! 911: m = n; ! 912: memmove(b->virt+audio.curcount, a, m); ! 913: ! 914: audio.curcount += m; ! 915: n -= m; ! 916: a += m; ! 917: if(audio.curcount >= Bufsize) { ! 918: audio.filling = 0; ! 919: swab(b->virt); ! 920: putbuf(&audio.full, b); ! 921: } ! 922: } ! 923: poperror(); ! 924: qunlock(&audio); ! 925: break; ! 926: } ! 927: return n0 - n; ! 928: } ! 929: ! 930: void ! 931: audioremove(Chan *c) ! 932: { ! 933: USED(c); ! 934: ! 935: error(Eperm); ! 936: } ! 937: ! 938: void ! 939: audiowstat(Chan *c, char *dp) ! 940: { ! 941: USED(c); ! 942: USED(dp); ! 943: ! 944: error(Eperm); ! 945: } ! 946: ! 947: static void ! 948: swab(uchar *a) ! 949: { ! 950: ulong *p, *ep, b; ! 951: ! 952: if(!SBswab) ! 953: return; ! 954: p = (ulong*)a; ! 955: ep = p + (Bufsize>>2); ! 956: while(p < ep) { ! 957: b = *p; ! 958: b = (b>>24) | (b<<24) | ! 959: ((b&0xff0000) >> 8) | ! 960: ((b&0x00ff00) << 8); ! 961: *p++ = b; ! 962: } ! 963: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.