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 "io.h" 11 #include "audio.h" 12 13 typedef struct AQueue AQueue; 14 typedef struct Buf Buf; 15 16 enum 17 { 18 Qdir = 0, 19 Qaudio, 20 Qvolume, 21 Qstatus, 22 23 Fmono = 1, 24 Fin = 2, 25 Fout = 4, 26 27 Aclosed = 0, 28 Aread, 29 Awrite, 30 31 Vaudio = 0, 32 Vsynth, 33 Vcd, 34 Vline, 35 Vmic, 36 Vspeaker, 37 Vtreb, 38 Vbass, 39 Vspeed, 40 Nvol, 41 42 Speed = 44100, 43 Ncmd = 50, /* max volume command words */ 44 }; 45 46 Dirtab 47 audiodir[] = 48 { 49 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 50 "audio", {Qaudio}, 0, 0666, 51 "volume", {Qvolume}, 0, 0666, 52 "audiostat",{Qstatus}, 0, 0444, 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 buffered; /* number of bytes en route */ 72 int bufinit; /* boolean if buffers allocated */ 73 int curcount; /* how much data in current buffer */ 74 int active; /* boolean dma running */ 75 int intr; /* boolean an interrupt has happened */ 76 int amode; /* Aclosed/Aread/Awrite for /audio */ 77 int rivol[Nvol]; /* right/left input/output volumes */ 78 int livol[Nvol]; 79 int rovol[Nvol]; 80 int lovol[Nvol]; 81 int major; /* SB16 major version number (sb 4) */ 82 int minor; /* SB16 minor version number */ 83 ulong totcount; /* how many bytes processed since open */ 84 vlong tottime; /* time at which totcount bytes were processed */ 85 86 Buf buf[Nbuf]; /* buffers and queues */ 87 AQueue empty; 88 AQueue full; 89 Buf* current; 90 Buf* filling; 91 } audio; 92 93 static struct 94 { 95 char* name; 96 int flag; 97 int ilval; /* initial values */ 98 int irval; 99 } volumes[] = 100 { 101 [Vaudio] "audio", Fout, 50, 50, 102 [Vsynth] "synth", Fin|Fout, 0, 0, 103 [Vcd] "cd", Fin|Fout, 0, 0, 104 [Vline] "line", Fin|Fout, 0, 0, 105 [Vmic] "mic", Fin|Fout|Fmono, 0, 0, 106 [Vspeaker] "speaker", Fout|Fmono, 0, 0, 107 108 [Vtreb] "treb", Fout, 50, 50, 109 [Vbass] "bass", Fout, 50, 50, 110 111 [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, 112 0 113 }; 114 115 static struct 116 { 117 Lock; 118 int reset; /* io ports to the sound blaster */ 119 int read; 120 int write; 121 int wstatus; 122 int rstatus; 123 int mixaddr; 124 int mixdata; 125 int clri8; 126 int clri16; 127 int clri401; 128 int dma; 129 130 void (*startdma)(void); 131 void (*intr)(void); 132 } blaster; 133 134 static void swab(uchar*); 135 136 static char Emajor[] = "soundblaster not responding/wrong version"; 137 static char Emode[] = "illegal open mode"; 138 static char Evolume[] = "illegal volume specifier"; 139 140 static int 141 sbcmd(int val) 142 { 143 int i, s; 144 145 for(i=1<<16; i!=0; i--) { 146 s = inb(blaster.wstatus); 147 if((s & 0x80) == 0) { 148 outb(blaster.write, val); 149 return 0; 150 } 151 } 152 /* print("#A: sbcmd (0x%.2x) timeout\n", val); /**/ 153 return 1; 154 } 155 156 static int 157 sbread(void) 158 { 159 int i, s; 160 161 for(i=1<<16; i!=0; i--) { 162 s = inb(blaster.rstatus); 163 if((s & 0x80) != 0) { 164 return inb(blaster.read); 165 } 166 } 167 /* print("#A: sbread did not respond\n"); /**/ 168 return -1; 169 } 170 171 static int 172 ess1688w(int reg, int val) 173 { 174 if(sbcmd(reg) || sbcmd(val)) 175 return 1; 176 177 return 0; 178 } 179 180 static int 181 ess1688r(int reg) 182 { 183 if(sbcmd(0xC0) || sbcmd(reg)) 184 return -1; 185 186 return sbread(); 187 } 188 189 static int 190 mxcmd(int addr, int val) 191 { 192 193 outb(blaster.mixaddr, addr); 194 outb(blaster.mixdata, val); 195 return 1; 196 } 197 198 static int 199 mxread(int addr) 200 { 201 int s; 202 203 outb(blaster.mixaddr, addr); 204 s = inb(blaster.mixdata); 205 return s; 206 } 207 208 static void 209 mxcmds(int s, int v) 210 { 211 212 if(v > 100) 213 v = 100; 214 if(v < 0) 215 v = 0; 216 mxcmd(s, (v*255)/100); 217 } 218 219 static void 220 mxcmdt(int s, int v) 221 { 222 223 if(v > 100) 224 v = 100; 225 if(v <= 0) 226 mxcmd(s, 0); 227 else 228 mxcmd(s, 255-100+v); 229 } 230 231 static void 232 mxcmdu(int s, int v) 233 { 234 235 if(v > 100) 236 v = 100; 237 if(v <= 0) 238 v = 0; 239 mxcmd(s, 128-50+v); 240 } 241 242 static void 243 mxvolume(void) 244 { 245 int *left, *right; 246 int source; 247 248 if(audio.amode == Aread){ 249 left = audio.livol; 250 right = audio.rivol; 251 }else{ 252 left = audio.lovol; 253 right = audio.rovol; 254 } 255 256 ilock(&blaster); 257 258 mxcmd(0x30, 255); /* left master */ 259 mxcmd(0x31, 255); /* right master */ 260 mxcmd(0x3f, 0); /* left igain */ 261 mxcmd(0x40, 0); /* right igain */ 262 mxcmd(0x41, 0); /* left ogain */ 263 mxcmd(0x42, 0); /* right ogain */ 264 265 mxcmds(0x32, left[Vaudio]); 266 mxcmds(0x33, right[Vaudio]); 267 268 mxcmds(0x34, left[Vsynth]); 269 mxcmds(0x35, right[Vsynth]); 270 271 mxcmds(0x36, left[Vcd]); 272 mxcmds(0x37, right[Vcd]); 273 274 mxcmds(0x38, left[Vline]); 275 mxcmds(0x39, right[Vline]); 276 277 mxcmds(0x3a, left[Vmic]); 278 mxcmds(0x3b, left[Vspeaker]); 279 280 mxcmdu(0x44, left[Vtreb]); 281 mxcmdu(0x45, right[Vtreb]); 282 283 mxcmdu(0x46, left[Vbass]); 284 mxcmdu(0x47, right[Vbass]); 285 286 source = 0; 287 if(left[Vsynth]) 288 source |= 1<<6; 289 if(right[Vsynth]) 290 source |= 1<<5; 291 if(left[Vaudio]) 292 source |= 1<<4; 293 if(right[Vaudio]) 294 source |= 1<<3; 295 if(left[Vcd]) 296 source |= 1<<2; 297 if(right[Vcd]) 298 source |= 1<<1; 299 if(left[Vmic]) 300 source |= 1<<0; 301 if(audio.amode == Aread) 302 mxcmd(0x3c, 0); /* output switch */ 303 else 304 mxcmd(0x3c, source); 305 mxcmd(0x3d, source); /* input left switch */ 306 mxcmd(0x3e, source); /* input right switch */ 307 iunlock(&blaster); 308 } 309 310 static Buf* 311 getbuf(AQueue *q) 312 { 313 Buf *b; 314 315 ilock(q); 316 b = q->first; 317 if(b) 318 q->first = b->next; 319 iunlock(q); 320 321 return b; 322 } 323 324 static void 325 putbuf(AQueue *q, Buf *b) 326 { 327 328 ilock(q); 329 b->next = 0; 330 if(q->first) 331 q->last->next = b; 332 else 333 q->first = b; 334 q->last = b; 335 iunlock(q); 336 } 337 338 /* 339 * move the dma to the next buffer 340 */ 341 static void 342 contindma(void) 343 { 344 Buf *b; 345 346 if(!audio.active) 347 goto shutdown; 348 349 b = audio.current; 350 if(b){ 351 audio.totcount += Bufsize; 352 audio.tottime = todget(nil); 353 } 354 if(audio.amode == Aread) { 355 if(b){ 356 putbuf(&audio.full, b); 357 audio.buffered += Bufsize; 358 } 359 b = getbuf(&audio.empty); 360 } else { 361 if(b){ 362 putbuf(&audio.empty, b); 363 audio.buffered -= Bufsize; 364 } 365 b = getbuf(&audio.full); 366 } 367 audio.current = b; 368 if(b == 0) 369 goto shutdown; 370 371 if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0) 372 return; 373 print("#A: dmasetup fail\n"); 374 putbuf(&audio.empty, b); 375 376 shutdown: 377 dmaend(blaster.dma); 378 sbcmd(0xd9); /* exit at end of count */ 379 sbcmd(0xd5); /* pause */ 380 audio.curcount = 0; 381 audio.active = 0; 382 } 383 384 /* 385 * cause sb to get an interrupt per buffer. 386 * start first dma 387 */ 388 static void 389 sb16startdma(void) 390 { 391 ulong count; 392 int speed; 393 394 ilock(&blaster); 395 dmaend(blaster.dma); 396 if(audio.amode == Aread) { 397 sbcmd(0x42); /* input sampling rate */ 398 speed = audio.livol[Vspeed]; 399 } else { 400 sbcmd(0x41); /* output sampling rate */ 401 speed = audio.lovol[Vspeed]; 402 } 403 sbcmd(speed>>8); 404 sbcmd(speed); 405 406 count = (Bufsize >> 1) - 1; 407 if(audio.amode == Aread) 408 sbcmd(0xbe); /* A/D, autoinit */ 409 else 410 sbcmd(0xb6); /* D/A, autoinit */ 411 sbcmd(0x30); /* stereo, 16 bit */ 412 sbcmd(count); 413 sbcmd(count>>8); 414 415 audio.active = 1; 416 contindma(); 417 iunlock(&blaster); 418 } 419 420 static int 421 ess1688reset(void) 422 { 423 int i; 424 425 outb(blaster.reset, 3); 426 delay(1); /* >3 υs */ 427 outb(blaster.reset, 0); 428 delay(1); 429 430 i = sbread(); 431 if(i != 0xAA) { 432 print("#A: no response 0x%.2x\n", i); 433 return 1; 434 } 435 436 if(sbcmd(0xC6)){ /* extended mode */ 437 print("#A: barf 3\n"); 438 return 1; 439 } 440 441 return 0; 442 } 443 444 static void 445 ess1688startdma(void) 446 { 447 ulong count; 448 int speed, x; 449 450 ilock(&blaster); 451 dmaend(blaster.dma); 452 453 if(audio.amode == Awrite) 454 ess1688reset(); 455 if(audio.amode == Aread) 456 sbcmd(0xD3); /* speaker off */ 457 458 /* 459 * Set the speed. 460 */ 461 if(audio.amode == Aread) 462 speed = audio.livol[Vspeed]; 463 else 464 speed = audio.lovol[Vspeed]; 465 if(speed < 4000) 466 speed = 4000; 467 else if(speed > 48000) 468 speed = 48000; 469 470 if(speed > 22000) 471 x = 0x80|(256-(795500+speed/2)/speed); 472 else 473 x = 128-(397700+speed/2)/speed; 474 ess1688w(0xA1, x & 0xFF); 475 476 speed = (speed * 9) / 20; 477 x = 256 - 7160000 / (speed * 82); 478 ess1688w(0xA2, x & 0xFF); 479 480 if(audio.amode == Aread) 481 ess1688w(0xB8, 0x0E); /* A/D, autoinit */ 482 else 483 ess1688w(0xB8, 0x04); /* D/A, autoinit */ 484 x = ess1688r(0xA8) & ~0x03; 485 ess1688w(0xA8, x|0x01); /* 2 channels */ 486 ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */ 487 488 if(audio.amode == Awrite) 489 ess1688w(0xB6, 0); 490 ess1688w(0xB7, 0x71); 491 ess1688w(0xB7, 0xBC); 492 493 x = ess1688r(0xB1) & 0x0F; 494 ess1688w(0xB1, x|0x50); 495 x = ess1688r(0xB2) & 0x0F; 496 ess1688w(0xB2, x|0x50); 497 if(audio.amode == Awrite) 498 sbcmd(0xD1); /* speaker on */ 499 500 count = -Bufsize; 501 ess1688w(0xA4, count & 0xFF); 502 ess1688w(0xA5, (count>>8) & 0xFF); 503 x = ess1688r(0xB8); 504 ess1688w(0xB8, x|0x05); 505 506 audio.active = 1; 507 contindma(); 508 iunlock(&blaster); 509 } 510 511 /* 512 * if audio is stopped, 513 * start it up again. 514 */ 515 static void 516 pokeaudio(void) 517 { 518 if(!audio.active) 519 blaster.startdma(); 520 } 521 522 static void 523 sb16intr(void) 524 { 525 int stat, dummy; 526 527 stat = mxread(0x82) & 7; /* get irq status */ 528 if(stat) { 529 dummy = 0; 530 if(stat & 2) { 531 ilock(&blaster); 532 dummy = inb(blaster.clri16); 533 contindma(); 534 iunlock(&blaster); 535 audio.intr = 1; 536 wakeup(&audio.vous); 537 } 538 if(stat & 1) { 539 dummy = inb(blaster.clri8); 540 } 541 if(stat & 4) { 542 dummy = inb(blaster.clri401); 543 } 544 USED(dummy); 545 } 546 } 547 548 static void 549 ess1688intr(void) 550 { 551 int dummy; 552 553 if(audio.active){ 554 ilock(&blaster); 555 contindma(); 556 dummy = inb(blaster.clri8); 557 iunlock(&blaster); 558 audio.intr = 1; 559 wakeup(&audio.vous); 560 USED(dummy); 561 } 562 else 563 print("#A: unexpected ess1688 interrupt\n"); 564 } 565 566 void 567 audiosbintr(void) 568 { 569 /* 570 * Carrera interrupt interface. 571 */ 572 blaster.intr(); 573 } 574 575 static void 576 pcaudiosbintr(Ureg*, void*) 577 { 578 /* 579 * x86 interrupt interface. 580 */ 581 blaster.intr(); 582 } 583 584 void 585 audiodmaintr(void) 586 { 587 /* print("#A: dma interrupt\n"); /**/ 588 } 589 590 static int 591 anybuf(void*) 592 { 593 return audio.intr; 594 } 595 596 /* 597 * wait for some output to get 598 * empty buffers back. 599 */ 600 static void 601 waitaudio(void) 602 { 603 604 audio.intr = 0; 605 pokeaudio(); 606 tsleep(&audio.vous, anybuf, 0, 10000); 607 if(audio.intr == 0) { 608 /* print("#A: audio timeout\n"); /**/ 609 audio.active = 0; 610 pokeaudio(); 611 } 612 } 613 614 static void 615 sbbufinit(void) 616 { 617 int i; 618 uchar *p; 619 620 p = (uchar*)(((ulong)xalloc((Nbuf+1) * Bufsize) + Bufsize-1)&~(Bufsize-1)); 621 for(i=0; i<Nbuf; i++) { 622 dcflush(p, Bufsize); 623 audio.buf[i].virt = UNCACHED(uchar, p); 624 audio.buf[i].phys = (ulong)PADDR(p); 625 p += Bufsize; 626 } 627 } 628 629 static void 630 setempty(void) 631 { 632 int i; 633 634 ilock(&blaster); 635 audio.empty.first = 0; 636 audio.empty.last = 0; 637 audio.full.first = 0; 638 audio.full.last = 0; 639 audio.current = 0; 640 audio.filling = 0; 641 audio.buffered = 0; 642 for(i=0; i<Nbuf; i++) 643 putbuf(&audio.empty, &audio.buf[i]); 644 audio.totcount = 0; 645 audio.tottime = 0LL; 646 iunlock(&blaster); 647 } 648 649 static void 650 resetlevel(void) 651 { 652 int i; 653 654 for(i=0; volumes[i].name; i++) { 655 audio.lovol[i] = volumes[i].ilval; 656 audio.rovol[i] = volumes[i].irval; 657 audio.livol[i] = volumes[i].ilval; 658 audio.rivol[i] = volumes[i].irval; 659 } 660 } 661 662 static int 663 ess1688(ISAConf* sbconf) 664 { 665 int i, major, minor; 666 667 /* 668 * Try for ESS1688. 669 */ 670 sbcmd(0xE7); /* get version */ 671 major = sbread(); 672 minor = sbread(); 673 if(major != 0x68 || minor != 0x8B){ 674 print("#A: model 0x%.2x 0x%.2x; not ESS1688 compatible\n", major, minor); 675 return 1; 676 } 677 678 ess1688reset(); 679 680 switch(sbconf->irq){ 681 case 2: 682 case 9: 683 i = 0x50|(0<<2); 684 break; 685 case 5: 686 i = 0x50|(1<<2); 687 break; 688 case 7: 689 i = 0x50|(2<<2); 690 break; 691 case 10: 692 i = 0x50|(3<<2); 693 break; 694 default: 695 print("#A: bad ESS1688 irq %d\n", sbconf->irq); 696 return 1; 697 } 698 ess1688w(0xB1, i); 699 700 switch(sbconf->dma){ 701 case 0: 702 i = 0x50|(1<<2); 703 break; 704 case 1: 705 i = 0xF0|(2<<2); 706 break; 707 case 3: 708 i = 0x50|(3<<2); 709 break; 710 default: 711 print("#A: bad ESS1688 dma %lud\n", sbconf->dma); 712 return 1; 713 } 714 ess1688w(0xB2, i); 715 716 ess1688reset(); 717 718 blaster.startdma = ess1688startdma; 719 blaster.intr = ess1688intr; 720 721 return 0; 722 } 723 724 static void 725 audioinit(void) 726 { 727 ISAConf sbconf; 728 int i, x; 729 static int irq[] = {2,5,7,10}; 730 731 sbconf.port = 0x220; 732 sbconf.dma = Dma; 733 sbconf.irq = IrqAUDIO; 734 if(isaconfig("audio", 0, &sbconf) == 0) 735 return; 736 if(sbconf.type == nil || 737 (cistrcmp(sbconf.type, "sb16") != 0 && 738 cistrcmp(sbconf.type, "ess1688") != 0)) 739 return; 740 switch(sbconf.port){ 741 case 0x220: 742 case 0x240: 743 case 0x260: 744 case 0x280: 745 break; 746 default: 747 print("#A: bad port 0x%lux\n", sbconf.port); 748 return; 749 } 750 751 if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){ 752 print("#A: cannot ioalloc range %lux+0x10\n", sbconf.port); 753 return; 754 } 755 if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){ 756 iofree(sbconf.port); 757 print("#A: cannot ioalloc range %lux+0x01\n", sbconf.port+0x100); 758 return; 759 } 760 761 switch(sbconf.irq){ 762 case 2: 763 case 5: 764 case 7: 765 case 9: 766 case 10: 767 break; 768 default: 769 print("#A: bad irq %d\n", sbconf.irq); 770 iofree(sbconf.port); 771 iofree(sbconf.port+0x100); 772 return; 773 } 774 775 blaster.reset = sbconf.port + 0x6; 776 blaster.read = sbconf.port + 0xa; 777 blaster.write = sbconf.port + 0xc; 778 blaster.wstatus = sbconf.port + 0xc; 779 blaster.rstatus = sbconf.port + 0xe; 780 blaster.mixaddr = sbconf.port + 0x4; 781 blaster.mixdata = sbconf.port + 0x5; 782 blaster.clri8 = sbconf.port + 0xe; 783 blaster.clri16 = sbconf.port + 0xf; 784 blaster.clri401 = sbconf.port + 0x100; 785 blaster.dma = sbconf.dma; 786 787 blaster.startdma = sb16startdma; 788 blaster.intr = sb16intr; 789 790 audio.amode = Aclosed; 791 resetlevel(); 792 793 outb(blaster.reset, 1); 794 delay(1); /* >3 υs */ 795 outb(blaster.reset, 0); 796 delay(1); 797 798 i = sbread(); 799 if(i != 0xaa) { 800 print("#A: no response #%.2x\n", i); 801 iofree(sbconf.port); 802 iofree(sbconf.port+0x100); 803 return; 804 } 805 806 sbcmd(0xe1); /* get version */ 807 audio.major = sbread(); 808 audio.minor = sbread(); 809 810 if(audio.major != 4) { 811 if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){ 812 print("#A: model 0x%.2x 0x%.2x; not SB 16 compatible\n", 813 audio.major, audio.minor); 814 iofree(sbconf.port); 815 iofree(sbconf.port+0x100); 816 return; 817 } 818 audio.major = 4; 819 } 820 821 /* 822 * initialize the mixer 823 */ 824 mxcmd(0x00, 0); /* Reset mixer */ 825 mxvolume(); 826 827 /* 828 * Attempt to set IRQ/DMA channels. 829 * On old ISA boards, these registers are writable. 830 * On Plug-n-Play boards, these are read-only. 831 * 832 * To accomodate both, we write to the registers, 833 * but then use the contents in case the write is 834 * disallowed. 835 */ 836 mxcmd(0x80, /* irq */ 837 (sbconf.irq==2)? 1: 838 (sbconf.irq==5)? 2: 839 (sbconf.irq==7)? 4: 840 (sbconf.irq==9)? 1: 841 (sbconf.irq==10)? 8: 842 0); 843 844 mxcmd(0x81, 1<<blaster.dma); /* dma */ 845 846 x = mxread(0x81); 847 for(i=5; i<=7; i++) 848 if(x & (1<<i)){ 849 blaster.dma = i; 850 break; 851 } 852 853 x = mxread(0x80); 854 for(i=0; i<=3; i++) 855 if(x & (1<<i)){ 856 sbconf.irq = irq[i]; 857 break; 858 } 859 860 seteisadma(blaster.dma, audiodmaintr); 861 setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0); 862 } 863 864 static Chan* 865 audioattach(char *param) 866 { 867 return devattach('A', param); 868 } 869 870 static Walkqid* 871 audiowalk(Chan *c, Chan *nc, char **name, int nname) 872 { 873 return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); 874 } 875 876 static int 877 audiostat(Chan *c, uchar *db, int n) 878 { 879 audiodir[Qaudio].length = audio.buffered; 880 return devstat(c, db, n, audiodir, nelem(audiodir), devgen); 881 } 882 883 static Chan* 884 audioopen(Chan *c, int omode) 885 { 886 int amode; 887 888 if(audio.major != 4) 889 error(Emajor); 890 891 switch((ulong)c->qid.path) { 892 default: 893 error(Eperm); 894 break; 895 896 case Qstatus: 897 if((omode&7) != OREAD) 898 error(Eperm); 899 case Qvolume: 900 case Qdir: 901 break; 902 903 case Qaudio: 904 amode = Awrite; 905 if((omode&7) == OREAD) 906 amode = Aread; 907 qlock(&audio); 908 if(audio.amode != Aclosed){ 909 qunlock(&audio); 910 error(Einuse); 911 } 912 if(audio.bufinit == 0) { 913 audio.bufinit = 1; 914 sbbufinit(); 915 } 916 audio.amode = amode; 917 setempty(); 918 audio.curcount = 0; 919 qunlock(&audio); 920 mxvolume(); 921 break; 922 } 923 c = devopen(c, omode, audiodir, nelem(audiodir), devgen); 924 c->mode = openmode(omode); 925 c->flag |= COPEN; 926 c->offset = 0; 927 928 return c; 929 } 930 931 static void 932 audioclose(Chan *c) 933 { 934 Buf *b; 935 936 switch((ulong)c->qid.path) { 937 default: 938 error(Eperm); 939 break; 940 941 case Qdir: 942 case Qvolume: 943 case Qstatus: 944 break; 945 946 case Qaudio: 947 if(c->flag & COPEN) { 948 qlock(&audio); 949 if(audio.amode == Awrite) { 950 /* flush out last partial buffer */ 951 b = audio.filling; 952 if(b) { 953 audio.filling = 0; 954 memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount); 955 audio.buffered += Bufsize-audio.curcount; 956 swab(b->virt); 957 putbuf(&audio.full, b); 958 } 959 if(!audio.active && audio.full.first) 960 pokeaudio(); 961 } 962 audio.amode = Aclosed; 963 if(waserror()){ 964 qunlock(&audio); 965 nexterror(); 966 } 967 while(audio.active) 968 waitaudio(); 969 setempty(); 970 poperror(); 971 qunlock(&audio); 972 } 973 break; 974 } 975 } 976 977 static long 978 audioread(Chan *c, void *v, long n, vlong off) 979 { 980 int liv, riv, lov, rov; 981 long m, n0; 982 char buf[300]; 983 Buf *b; 984 int j; 985 ulong offset = off; 986 char *a; 987 988 n0 = n; 989 a = v; 990 switch((ulong)c->qid.path) { 991 default: 992 error(Eperm); 993 break; 994 995 case Qdir: 996 return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); 997 998 case Qaudio: 999 if(audio.amode != Aread) 1000 error(Emode); 1001 qlock(&audio); 1002 if(waserror()){ 1003 qunlock(&audio); 1004 nexterror(); 1005 } 1006 while(n > 0) { 1007 b = audio.filling; 1008 if(b == 0) { 1009 b = getbuf(&audio.full); 1010 if(b == 0) { 1011 waitaudio(); 1012 continue; 1013 } 1014 audio.filling = b; 1015 swab(b->virt); 1016 audio.curcount = 0; 1017 } 1018 m = Bufsize-audio.curcount; 1019 if(m > n) 1020 m = n; 1021 memmove(a, b->virt+audio.curcount, m); 1022 1023 audio.curcount += m; 1024 n -= m; 1025 a += m; 1026 audio.buffered -= m; 1027 if(audio.curcount >= Bufsize) { 1028 audio.filling = 0; 1029 putbuf(&audio.empty, b); 1030 } 1031 } 1032 poperror(); 1033 qunlock(&audio); 1034 break; 1035 1036 case Qstatus: 1037 buf[0] = 0; 1038 snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset %10lud time %19lld\n", 1039 Bufsize, audio.buffered, audio.totcount, audio.tottime); 1040 return readstr(offset, a, n, buf); 1041 1042 case Qvolume: 1043 j = 0; 1044 buf[0] = 0; 1045 for(m=0; volumes[m].name; m++){ 1046 liv = audio.livol[m]; 1047 riv = audio.rivol[m]; 1048 lov = audio.lovol[m]; 1049 rov = audio.rovol[m]; 1050 j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); 1051 if((volumes[m].flag & Fmono) || liv==riv && lov==rov){ 1052 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) 1053 j += snprint(buf+j, sizeof(buf)-j, " %d", liv); 1054 else{ 1055 if(volumes[m].flag & Fin) 1056 j += snprint(buf+j, sizeof(buf)-j, 1057 " in %d", liv); 1058 if(volumes[m].flag & Fout) 1059 j += snprint(buf+j, sizeof(buf)-j, 1060 " out %d", lov); 1061 } 1062 }else{ 1063 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && 1064 liv==lov && riv==rov) 1065 j += snprint(buf+j, sizeof(buf)-j, 1066 " left %d right %d", 1067 liv, riv); 1068 else{ 1069 if(volumes[m].flag & Fin) 1070 j += snprint(buf+j, sizeof(buf)-j, 1071 " in left %d right %d", 1072 liv, riv); 1073 if(volumes[m].flag & Fout) 1074 j += snprint(buf+j, sizeof(buf)-j, 1075 " out left %d right %d", 1076 lov, rov); 1077 } 1078 } 1079 j += snprint(buf+j, sizeof(buf)-j, "\n"); 1080 } 1081 return readstr(offset, a, n, buf); 1082 } 1083 return n0-n; 1084 } 1085 1086 static long 1087 audiowrite(Chan *c, void *vp, long n, vlong) 1088 { 1089 long m, n0; 1090 int i, v, left, right, in, out; 1091 Cmdbuf *cb; 1092 Buf *b; 1093 char *a; 1094 1095 a = vp; 1096 n0 = n; 1097 switch((ulong)c->qid.path) { 1098 default: 1099 error(Eperm); 1100 break; 1101 1102 case Qvolume: 1103 v = Vaudio; 1104 left = 1; 1105 right = 1; 1106 in = 1; 1107 out = 1; 1108 cb = parsecmd(vp, n); 1109 if(waserror()){ 1110 free(cb); 1111 nexterror(); 1112 } 1113 1114 for(i = 0; i < cb->nf; i++){ 1115 /* 1116 * a number is volume 1117 */ 1118 if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') { 1119 m = strtoul(cb->f[i], 0, 10); 1120 if(left && out) 1121 audio.lovol[v] = m; 1122 if(left && in) 1123 audio.livol[v] = m; 1124 if(right && out) 1125 audio.rovol[v] = m; 1126 if(right && in) 1127 audio.rivol[v] = m; 1128 mxvolume(); 1129 goto cont0; 1130 } 1131 1132 for(m=0; volumes[m].name; m++) { 1133 if(strcmp(cb->f[i], volumes[m].name) == 0) { 1134 v = m; 1135 in = 1; 1136 out = 1; 1137 left = 1; 1138 right = 1; 1139 goto cont0; 1140 } 1141 } 1142 1143 if(strcmp(cb->f[i], "reset") == 0) { 1144 resetlevel(); 1145 mxvolume(); 1146 goto cont0; 1147 } 1148 if(strcmp(cb->f[i], "in") == 0) { 1149 in = 1; 1150 out = 0; 1151 goto cont0; 1152 } 1153 if(strcmp(cb->f[i], "out") == 0) { 1154 in = 0; 1155 out = 1; 1156 goto cont0; 1157 } 1158 if(strcmp(cb->f[i], "left") == 0) { 1159 left = 1; 1160 right = 0; 1161 goto cont0; 1162 } 1163 if(strcmp(cb->f[i], "right") == 0) { 1164 left = 0; 1165 right = 1; 1166 goto cont0; 1167 } 1168 error(Evolume); 1169 break; 1170 cont0:; 1171 } 1172 free(cb); 1173 poperror(); 1174 break; 1175 1176 case Qaudio: 1177 if(audio.amode != Awrite) 1178 error(Emode); 1179 qlock(&audio); 1180 if(waserror()){ 1181 qunlock(&audio); 1182 nexterror(); 1183 } 1184 while(n > 0) { 1185 b = audio.filling; 1186 if(b == 0) { 1187 b = getbuf(&audio.empty); 1188 if(b == 0) { 1189 waitaudio(); 1190 continue; 1191 } 1192 audio.filling = b; 1193 audio.curcount = 0; 1194 } 1195 1196 m = Bufsize-audio.curcount; 1197 if(m > n) 1198 m = n; 1199 memmove(b->virt+audio.curcount, a, m); 1200 1201 audio.curcount += m; 1202 n -= m; 1203 a += m; 1204 audio.buffered += m; 1205 if(audio.curcount >= Bufsize) { 1206 audio.filling = 0; 1207 swab(b->virt); 1208 putbuf(&audio.full, b); 1209 pokeaudio(); 1210 } 1211 } 1212 poperror(); 1213 qunlock(&audio); 1214 break; 1215 } 1216 return n0 - n; 1217 } 1218 1219 static void 1220 swab(uchar *a) 1221 { 1222 ulong *p, *ep, b; 1223 1224 if(!SBswab){ 1225 USED(a); 1226 return; 1227 } 1228 p = (ulong*)a; 1229 ep = p + (Bufsize>>2); 1230 while(p < ep) { 1231 b = *p; 1232 b = (b>>24) | (b<<24) | 1233 ((b&0xff0000) >> 8) | 1234 ((b&0x00ff00) << 8); 1235 *p++ = b; 1236 } 1237 } 1238 1239 Dev audiodevtab = { 1240 'A', 1241 "audio", 1242 1243 devreset, 1244 audioinit, 1245 devshutdown, 1246 audioattach, 1247 audiowalk, 1248 audiostat, 1249 audioopen, 1250 devcreate, 1251 audioclose, 1252 audioread, 1253 devbread, 1254 audiowrite, 1255 devbwrite, 1256 devremove, 1257 devwstat, 1258 }; 1259