|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: hardware.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code for communicating with the DSP ! 12: on the Soundblaster card. ! 13: ! 14: Author: ! 15: ! 16: Nigel Thompson (NigelT) 7-March-1991 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History: ! 23: ! 24: Robin Speed (RobinSp) 29-Jan-1992 ! 25: Add MIDI, support for soundblaster 1, ! 26: ! 27: --*/ ! 28: ! 29: #include "sound.h" ! 30: ! 31: // ! 32: // Remove initialization stuff from resident memory ! 33: // ! 34: ! 35: #ifdef ALLOC_PRAGMA ! 36: #pragma alloc_text(init,HwInitVolume) ! 37: #pragma alloc_text(init,HwInitialize) ! 38: #endif ! 39: ! 40: ! 41: UCHAR ! 42: dspRead( ! 43: IN PSOUND_HARDWARE pHw ! 44: ) ! 45: /*++ ! 46: ! 47: Routine Description: ! 48: ! 49: Read the DSP data port ! 50: Time out occurs after about 1ms ! 51: ! 52: Arguments: ! 53: ! 54: pHw - Pointer to the device extension data. ! 55: pvalue - Pointer to the UCHAR to receive the result ! 56: ! 57: Return Value: ! 58: ! 59: Value read ! 60: ! 61: --*/ ! 62: { ! 63: USHORT uCount; ! 64: UCHAR Value; ! 65: ! 66: ASSERT(pHw->Key == HARDWARE_KEY); ! 67: ! 68: uCount = 100; ! 69: ! 70: Value = 0xFF; // If fail look like port not populated ! 71: ! 72: while (uCount--) { ! 73: int InnerCount; ! 74: ! 75: // ! 76: // Protect all reads and writes with a spin lock ! 77: // ! 78: ! 79: HwEnter(pHw); ! 80: ! 81: // ! 82: // Inner count loop protects against dynamic deadlock with ! 83: // midi. ! 84: // ! 85: ! 86: for (InnerCount = 0; InnerCount < 10; InnerCount++) { ! 87: if (INPORT(pHw, DATA_AVAIL_PORT) & 0x80) { ! 88: Value = INPORT(pHw, DATA_PORT); ! 89: uCount = 0; ! 90: break; ! 91: } ! 92: KeStallExecutionProcessor(1); ! 93: } ! 94: ! 95: HwLeave(pHw); ! 96: } ! 97: // timed out ! 98: ! 99: return Value; ! 100: } ! 101: ! 102: ! 103: ! 104: BOOLEAN ! 105: dspReset( ! 106: PSOUND_HARDWARE pHw ! 107: ) ! 108: /*++ ! 109: ! 110: Routine Description: ! 111: ! 112: Reset the DSP ! 113: ! 114: Arguments: ! 115: ! 116: pHw - pointer to the device extension data ! 117: ! 118: Return Value: ! 119: ! 120: The return value is TRUE if the dsp was reset, FALSE if an error ! 121: occurred. ! 122: ! 123: --*/ ! 124: { ! 125: // ! 126: // When we reset we'll lose the format information so initialize it ! 127: // now. Also the speaker is nominally OFF after reset. ! 128: // ! 129: ! 130: pHw->Format = 0; ! 131: pHw->SpeakerOn = FALSE; ! 132: ! 133: // ! 134: // try for a reset - note that midi output may be running at this ! 135: // point so we need the spin lock while we're trying to reset ! 136: // ! 137: ! 138: HwEnter(pHw); ! 139: ! 140: OUTPORT(pHw, RESET_PORT, 1); ! 141: KeStallExecutionProcessor(3); // wait 3 us ! 142: OUTPORT(pHw, RESET_PORT, 0); ! 143: ! 144: HwLeave(pHw); ! 145: ! 146: // we should get 0xAA at the data port now ! 147: ! 148: if (dspRead(pHw) != 0xAA) { ! 149: ! 150: // ! 151: // timed out or other screw up ! 152: // ! 153: ! 154: // dprintf1(("Failed to reset DSP")); ! 155: return FALSE; ! 156: } ! 157: return TRUE; ! 158: } ! 159: ! 160: ! 161: BOOLEAN ! 162: dspWrite( ! 163: PSOUND_HARDWARE pHw, ! 164: UCHAR value ! 165: ) ! 166: /*++ ! 167: ! 168: Routine Description: ! 169: ! 170: Write a command or data to the DSP ! 171: ! 172: Arguments: ! 173: ! 174: pHw - Pointer to the device extension data ! 175: value - the value to be written ! 176: ! 177: Return Value: ! 178: ! 179: TRUE if written correctly , FALSE otherwise ! 180: ! 181: --*/ ! 182: { ! 183: ULONG uCount; ! 184: ! 185: ASSERT(pHw->Key == HARDWARE_KEY); ! 186: ! 187: uCount = 100; ! 188: ! 189: while (uCount--) { ! 190: int InnerCount; ! 191: ! 192: HwEnter(pHw); ! 193: ! 194: // ! 195: // Inner count loop protects against dynamic deadlock with ! 196: // midi. ! 197: // ! 198: ! 199: for (InnerCount = 0; InnerCount < 10; InnerCount++) { ! 200: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) { ! 201: OUTPORT(pHw, DATA_STATUS_PORT, value); ! 202: break; ! 203: } ! 204: KeStallExecutionProcessor(1); // 1 us ! 205: } ! 206: ! 207: HwLeave(pHw); ! 208: ! 209: if (InnerCount < 10) { ! 210: return TRUE; ! 211: } ! 212: } ! 213: ! 214: dprintf1(("Failed to write %x to dsp", (ULONG)value)); ! 215: ! 216: return FALSE; ! 217: } ! 218: ! 219: BOOLEAN ! 220: dspWriteNoLock( ! 221: PSOUND_HARDWARE pHw, ! 222: UCHAR value ! 223: ) ! 224: /*++ ! 225: ! 226: Routine Description: ! 227: ! 228: Write a command or data to the DSP. The call assumes the ! 229: caller has acquired the spin lock ! 230: ! 231: Arguments: ! 232: ! 233: pHw - Pointer to the device extension data ! 234: value - the value to be written ! 235: ! 236: Return Value: ! 237: ! 238: TRUE if written correctly , FALSE otherwise ! 239: ! 240: --*/ ! 241: { ! 242: int uCount; ! 243: ! 244: ASSERT(pHw->Key == HARDWARE_KEY); ! 245: ! 246: uCount = 1000; ! 247: ! 248: while (uCount--) { ! 249: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) { ! 250: OUTPORT(pHw, DATA_STATUS_PORT, value); ! 251: break; ! 252: } ! 253: KeStallExecutionProcessor(1); // 1 us ! 254: } ! 255: ! 256: if (uCount >= 0) { ! 257: return TRUE; ! 258: } ! 259: ! 260: dprintf1(("Failed to write %x to dsp", (ULONG)value)); ! 261: ! 262: return FALSE; ! 263: } ! 264: ! 265: ! 266: ! 267: USHORT ! 268: dspGetVersion( ! 269: PSOUND_HARDWARE pHw ! 270: ) ! 271: /*++ ! 272: ! 273: Routine Description: ! 274: ! 275: Get the DSP software version ! 276: ! 277: Arguments: ! 278: ! 279: pHw - pointer to the hardware data ! 280: ! 281: Return Value: ! 282: ! 283: The return value contains the major version in the high byte ! 284: and the minor version in the low byte. If an error occurs ! 285: then the return value is zero. ! 286: ! 287: --*/ ! 288: { ! 289: UCHAR major, minor; ! 290: ! 291: // we have a card, try to read the version number ! 292: ! 293: if (dspWrite(pHw, DSP_GET_VERSION)) { ! 294: major = dspRead(pHw); ! 295: minor = dspRead(pHw); ! 296: return (((USHORT)major) << 8) + (USHORT)minor; ! 297: } ! 298: return 0; ! 299: } ! 300: ! 301: ! 302: BOOLEAN ! 303: dspSpeakerOn( ! 304: PSOUND_HARDWARE pHw ! 305: ) ! 306: /*++ ! 307: ! 308: Routine Description: ! 309: ! 310: Turn the speaker on ! 311: ! 312: Arguments: ! 313: ! 314: pHw - pointer to the device extension data ! 315: ! 316: Return Value: ! 317: ! 318: TRUE ! 319: ! 320: --*/ ! 321: { ! 322: int i; ! 323: ! 324: if (!pHw->SpeakerOn) { ! 325: ! 326: // ! 327: // Thunderboard likes a gap ! 328: // ! 329: ! 330: KeStallExecutionProcessor(100); ! 331: ! 332: dspWrite(pHw, DSP_SPEAKER_ON); ! 333: pHw->SpeakerOn = TRUE; ! 334: ! 335: // ! 336: // Now wait until it's OK again (up to 112 ms) ! 337: // ! 338: ! 339: for (i = 0; i < 3; i++) { ! 340: SoundDelay(38); ! 341: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) { ! 342: break; ! 343: } ! 344: } ! 345: ! 346: dprintf4(("Waited %d ms for speaker to go on", i * 38)); ! 347: } ! 348: return TRUE; ! 349: } ! 350: ! 351: ! 352: BOOLEAN ! 353: dspSpeakerOff( ! 354: PSOUND_HARDWARE pHw ! 355: ) ! 356: /*++ ! 357: ! 358: Routine Description: ! 359: ! 360: Turn the speaker on ! 361: ! 362: Arguments: ! 363: ! 364: pHw - pointer to the device extension data ! 365: ! 366: Return Value: ! 367: ! 368: TRUE ! 369: ! 370: --*/ ! 371: { ! 372: int i; ! 373: ! 374: if (pHw->SpeakerOn) { ! 375: dspWrite(pHw, DSP_SPEAKER_OFF); ! 376: pHw->SpeakerOn = FALSE; ! 377: ! 378: // ! 379: // Now wait until it's OK again (up to 225 ms) ! 380: // ! 381: ! 382: for (i = 0; i < 6; i++) { ! 383: SoundDelay(38); ! 384: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) { ! 385: break; ! 386: } ! 387: } ! 388: ! 389: dprintf4(("Waited %d ms for speaker to go off", i * 38)); ! 390: } ! 391: return TRUE; ! 392: } ! 393: ! 394: ! 395: ! 396: BOOLEAN ! 397: dspSetSampleRate( ! 398: PSOUND_HARDWARE pHw, ! 399: ULONG rate ! 400: ) ! 401: /*++ ! 402: ! 403: Routine Description: ! 404: ! 405: Set the current dsp sample rate. ! 406: Note that this routine must only be called when a new transfer ! 407: is being set up or as a new packet is being set up. ! 408: ! 409: Arguments: ! 410: ! 411: pHw - pointer to the device extension data ! 412: rate - the sample rate to set in samples per second ! 413: ! 414: Return Value: ! 415: ! 416: TRUE if success, FALSE otherwise ! 417: ! 418: --*/ ! 419: { ! 420: ULONG TimeFactor; ! 421: ! 422: // ! 423: // the card only does 4kHz up ! 424: // ! 425: ! 426: if (rate < 4000) { ! 427: dprintf1(("Attempt to set bogus DSP rate (%lu)", rate)); ! 428: return FALSE; ! 429: } ! 430: ! 431: // ! 432: // Compute the timing factor as 256 - 1000000 / rate ! 433: // For 4kHz this is 6, for 23kHz it is 212. ! 434: // ! 435: ! 436: TimeFactor = 256 - (1000000 / rate); ! 437: ! 438: if ((UCHAR)TimeFactor != pHw->Format) { ! 439: ! 440: if (!dspWrite(pHw, DSP_SET_SAMPLE_RATE)) { ! 441: return FALSE; ! 442: } ! 443: ! 444: KeStallExecutionProcessor(10); ! 445: dspWrite(pHw, (UCHAR) TimeFactor); ! 446: ! 447: pHw->Format = (UCHAR)TimeFactor; ! 448: ! 449: return TRUE; ! 450: } else { ! 451: // ! 452: // No change ! 453: // ! 454: ! 455: return FALSE; ! 456: } ! 457: } ! 458: ! 459: ! 460: BOOLEAN ! 461: dspStartAutoDMA( ! 462: PSOUND_HARDWARE pHw, ! 463: ULONG Size, ! 464: BOOLEAN Direction ! 465: ) ! 466: /*++ ! 467: ! 468: Routine Description: ! 469: ! 470: This routine begins the output of a new set of dma ! 471: transfers. It sets up the dsp sample rate and ! 472: then programs the dsp to start making dma requests. ! 473: This routine completes the action started by ! 474: sndProgramOutputDMA ! 475: ! 476: Arguments: ! 477: ! 478: pHw - Pointer to global device data ! 479: ! 480: Return Value: ! 481: ! 482: TRUE if operation is sucessful, FALSE otherwise ! 483: ! 484: --*/ ! 485: { ! 486: ULONG SampleRate; ! 487: ! 488: // ! 489: // Program the DSP to start the transfer by sending the ! 490: // block size command followed by the low ! 491: // byte and then the high byte of the block size - 1. ! 492: // Then send the start auto-init command. ! 493: // Note that the block size is half the dma buffer size. ! 494: // ! 495: ! 496: dspWrite(pHw, DSP_SET_BLOCK_SIZE); ! 497: dspWrite(pHw, (UCHAR)((Size/2 - 1) & 0x00FF)); ! 498: dspWrite(pHw, (UCHAR)(((Size/2 - 1) >> 8) & 0x00FF)); ! 499: if (!Direction) { ! 500: dspWrite(pHw, DSP_READ_AUTO); ! 501: } else { ! 502: dspWrite(pHw, DSP_WRITE_AUTO); ! 503: } ! 504: dprintf3(("DMA started")); ! 505: ! 506: // ! 507: // Return the power fail status ! 508: // BUGBUG Power fail status bogus ! 509: // ! 510: ! 511: return TRUE; ! 512: } ! 513: ! 514: ! 515: BOOLEAN ! 516: dspStartNonAutoDMA( ! 517: PSOUND_HARDWARE pHw, ! 518: ULONG Size, ! 519: BOOLEAN Direction ! 520: ) ! 521: /*++ ! 522: ! 523: Routine Description: ! 524: ! 525: This routine begins the output of a new set of dma ! 526: transfers. It sets up the dsp sample rate and ! 527: then programs the dsp to start making dma requests. ! 528: This routine completes the action started by ! 529: sndProgramOutputDMA. ! 530: ! 531: Soundblaster 1 only ! 532: ! 533: Arguments: ! 534: ! 535: pHw - Pointer to global device data ! 536: ! 537: Return Value: ! 538: ! 539: TRUE if operation is sucessful, FALSE otherwise ! 540: ! 541: --*/ ! 542: { ! 543: ULONG SampleRate; ! 544: ! 545: // ! 546: // Program the DSP to start the transfer by sending the ! 547: // Read/Write command followed by the low ! 548: // byte and then the high byte of the block size - 1. ! 549: // Note that the block size is half the dma buffer size. ! 550: // ! 551: ! 552: if (!Direction) { ! 553: dspWrite(pHw, DSP_READ); ! 554: } else { ! 555: dspWrite(pHw, DSP_WRITE); ! 556: } ! 557: dspWrite(pHw, (UCHAR)((Size/2 - 1) & 0x00FF)); ! 558: dspWrite(pHw, (UCHAR)(((Size/2 - 1) >> 8) & 0x00FF)); ! 559: dprintf3(("DMA started")); ! 560: ! 561: // ! 562: // Initialize half we're doing next ! 563: // ! 564: ! 565: pHw->Half = UpperHalf; ! 566: ! 567: // ! 568: // Return the power fail status ! 569: // BUGBUG Power fail status bogus ! 570: // ! 571: ! 572: return TRUE; ! 573: } ! 574: ! 575: VOID ! 576: HwSetVolume( ! 577: IN PLOCAL_DEVICE_INFO pLDI ! 578: ) ! 579: /*++ ! 580: ! 581: Routine Description : ! 582: ! 583: Set the volume for the specified device ! 584: ! 585: Arguments : ! 586: ! 587: pLDI - pointer to device data ! 588: ! 589: Return Value : ! 590: ! 591: None ! 592: ! 593: --*/ ! 594: { ! 595: PSOUND_HARDWARE pHw; ! 596: ULONG PortIndex; ! 597: WAVE_DD_VOLUME Volume; ! 598: PGLOBAL_DEVICE_INFO pGDI; ! 599: ! 600: ! 601: pHw = pLDI->HwContext; ! 602: Volume = pLDI->Volume; ! 603: pGDI = CONTAINING_RECORD(pHw, GLOBAL_DEVICE_INFO, Hw); ! 604: ! 605: #ifdef PAS16 // There's a proper driver now ! 606: if (pGDI->ProAudioSpectrum) { ! 607: UCHAR OutputMixer; ! 608: UCHAR InputNumber; ! 609: ! 610: switch (pLDI->DeviceIndex) { ! 611: #ifdef MICMIX ! 612: case MicDevice: ! 613: InputNumber = IN_MICROPHONE; ! 614: OutputMixer = OUT_PCM; ! 615: break; ! 616: #endif // MICMIX ! 617: ! 618: case LineInDevice: ! 619: InputNumber = IN_EXTERNAL; ! 620: OutputMixer = OUT_AMPLIFIER; //OUT_PCM; ! 621: break; ! 622: ! 623: case WaveOutDevice: ! 624: InputNumber = IN_SNDBLASTER; ! 625: OutputMixer = OUT_AMPLIFIER; ! 626: break; ! 627: } ! 628: ! 629: SetInput(&pGDI->PASInfo, ! 630: InputNumber, ! 631: (USHORT)(Volume.Left >> 16), ! 632: _LEFT, ! 633: MIXCROSSCAPS_NORMAL_STEREO, ! 634: OutputMixer); ! 635: SetInput(&pGDI->PASInfo, ! 636: InputNumber, ! 637: (USHORT)(Volume.Right >> 16), ! 638: _RIGHT, ! 639: MIXCROSSCAPS_NORMAL_STEREO, ! 640: OutputMixer); ! 641: } else ! 642: #endif // PAS16 ! 643: ! 644: { ! 645: ! 646: // ! 647: // Only the 'pro' supports the mixer ! 648: // ! 649: if (!SBPRO(pHw)) { ! 650: return; ! 651: } ! 652: ! 653: // ! 654: // Find which mixer register to set ! 655: // ! 656: ! 657: switch (pLDI->DeviceIndex) { ! 658: #ifdef MICMIX ! 659: case MicDevice: ! 660: Volume.Right = Volume.Left;// Mono for this one ! 661: Volume.Left = 0; ! 662: PortIndex = MIC_MIX_REG; ! 663: break; ! 664: #endif // MICMIX ! 665: ! 666: case WaveOutDevice: ! 667: PortIndex = VOICE_VOL_REG; ! 668: break; ! 669: ! 670: case LineInDevice: ! 671: PortIndex = LINEIN_VOL_REG; ! 672: break; ! 673: } ! 674: ! 675: // ! 676: // Mutual exclusion is guaranteed by holding the device mutex ! 677: // (note that midi output does not have a volume control on the mixer). ! 678: // ! 679: ! 680: // ! 681: // Select voice control reg ! 682: // ! 683: OUTPORT(pHw, MIX_ADDR_PORT, (UCHAR)PortIndex); ! 684: ! 685: KeStallExecutionProcessor(10); ! 686: ! 687: // ! 688: // Set the volume ! 689: // ! 690: OUTPORT(pHw, MIX_DATA_PORT, ! 691: ((Volume.Left >> 24) & 0xF0) | ! 692: (Volume.Right >> 28)); ! 693: ! 694: KeStallExecutionProcessor(10); ! 695: } ! 696: } ! 697: ! 698: VOID ! 699: HwInitVolume( ! 700: IN PGLOBAL_DEVICE_INFO pGDI ! 701: ) ! 702: /*++ ! 703: ! 704: Routine Description : ! 705: ! 706: Initialise volume settings on the hardware. Called at start-up ! 707: to initialise to max volume the mixer line for the midi synthesizer ! 708: (since volume for the synth is controlled by the synth driver itself ! 709: modifying the instrument parameters). ! 710: ! 711: Arguments : ! 712: ! 713: pGDI - pointer to device data ! 714: ! 715: Return Value : ! 716: ! 717: None ! 718: ! 719: --*/ ! 720: { ! 721: PSOUND_HARDWARE pHw; ! 722: ! 723: ! 724: pHw = &pGDI->Hw; ! 725: ! 726: if (!pGDI->ProAudioSpectrum) { ! 727: ! 728: // ! 729: // Only the 'pro' supports the mixer ! 730: // ! 731: if (!SBPRO(pHw)) { ! 732: return; ! 733: } ! 734: ! 735: ! 736: // ! 737: // Select voice control reg ! 738: // ! 739: OUTPORT(pHw, MIX_ADDR_PORT, (UCHAR)SYNTH_VOL_REG); ! 740: ! 741: KeStallExecutionProcessor(10); ! 742: ! 743: // ! 744: // Set the volume to maximum ! 745: // ! 746: OUTPORT(pHw, MIX_DATA_PORT, 0xFF); ! 747: ! 748: KeStallExecutionProcessor(10); ! 749: } ! 750: } ! 751: ! 752: BOOLEAN ! 753: HwSetupDMA( ! 754: IN PWAVE_INFO WaveInfo ! 755: ) ! 756: /*++ ! 757: ! 758: Routine Description : ! 759: ! 760: Start the DMA on the device according to the device parameters ! 761: ! 762: Arguments : ! 763: ! 764: WaveInfo - Wave parameters ! 765: ! 766: Return Value : ! 767: ! 768: None ! 769: ! 770: --*/ ! 771: { ! 772: PSOUND_HARDWARE pHw; ! 773: ! 774: pHw = WaveInfo->HwContext; ! 775: ! 776: // ! 777: // Turn the speaker off for input ! 778: // ! 779: ! 780: if (!WaveInfo->Direction) { ! 781: dspSpeakerOff(pHw); ! 782: } else { ! 783: // ! 784: // This would not normally be necessary but when the DMA ! 785: // gets locked out by the SCSI horrible things happen so ! 786: // we turn on the speaker here. Normally the flag will ! 787: // stop us actually turning it on ! 788: // ! 789: ! 790: dspSpeakerOn(pHw); ! 791: } ! 792: ! 793: // ! 794: // Do different things depending on the type of card ! 795: // Sound blaster 1 cannot use auto-init DMA whereas all ! 796: // the others can ! 797: // ! 798: ! 799: if (SB1(pHw)) { ! 800: dspStartNonAutoDMA(pHw, WaveInfo->DoubleBuffer.BufferSize, ! 801: WaveInfo->Direction); ! 802: } else { ! 803: dspStartAutoDMA(pHw, WaveInfo->DoubleBuffer.BufferSize, ! 804: WaveInfo->Direction); ! 805: } ! 806: ! 807: return TRUE; ! 808: } ! 809: ! 810: BOOLEAN ! 811: HwStopDMA( ! 812: IN PWAVE_INFO WaveInfo ! 813: ) ! 814: /*++ ! 815: ! 816: Routine Description : ! 817: ! 818: Stop the DMA on the device according to the device parameters ! 819: ! 820: Arguments : ! 821: ! 822: WaveInfo - Wave parameters ! 823: ! 824: Return Value : ! 825: ! 826: None ! 827: ! 828: --*/ ! 829: { ! 830: PSOUND_HARDWARE pHw; ! 831: BOOLEAN Rc; ! 832: ! 833: pHw = WaveInfo->HwContext; ! 834: ! 835: Rc = dspWrite(pHw, DSP_HALT_DMA); ! 836: ! 837: if (!Rc) { ! 838: // ! 839: // Resetting then setting the speaker on seems to be the only ! 840: // way to recover! ! 841: // ! 842: ! 843: dspReset(pHw); ! 844: ! 845: // ! 846: // The speaker is off after reset. The next time we play ! 847: // something we'll call dspSpeakerOn which will turn it on. ! 848: // ! 849: } ! 850: ! 851: if (!WaveInfo->Direction) { ! 852: dspSpeakerOn(pHw); ! 853: } ! 854: ! 855: return Rc; ! 856: } ! 857: ! 858: BOOLEAN ! 859: HwSetWaveFormat( ! 860: IN PWAVE_INFO WaveInfo ! 861: ) ! 862: /*++ ! 863: ! 864: Routine Description : ! 865: ! 866: Set device parameters for wave input/output ! 867: ! 868: Arguments : ! 869: ! 870: WaveInfo - Wave parameters ! 871: ! 872: Return Value : ! 873: ! 874: None ! 875: ! 876: --*/ ! 877: { ! 878: PSOUND_HARDWARE pHw; ! 879: UCHAR Format; ! 880: BOOLEAN Different; ! 881: ! 882: Different = FALSE; ! 883: ! 884: pHw = WaveInfo->HwContext; ! 885: ! 886: // ! 887: // For the PRO select stereo if requested ! 888: // ! 889: ! 890: if (SBPRO(pHw)) { ! 891: if ((BOOLEAN)(WaveInfo->Channels > 1) != pHw->Stereo) { ! 892: UCHAR OutputSetting; ! 893: ! 894: Different = TRUE; ! 895: pHw->Stereo = (BOOLEAN)(WaveInfo->Channels > 1); ! 896: ! 897: // ! 898: // Set the output setting register ! 899: // ! 900: ! 901: OUTPORT(pHw, MIX_ADDR_PORT, OUTPUT_SETTING_REG); ! 902: ! 903: KeStallExecutionProcessor(10); ! 904: ! 905: OutputSetting = INPORT(pHw, MIX_DATA_PORT) & ~0x02; ! 906: if (pHw->Stereo) { ! 907: OutputSetting |= 0x02; ! 908: } ! 909: ! 910: OUTPORT(pHw, MIX_DATA_PORT, OutputSetting); ! 911: ! 912: KeStallExecutionProcessor(10); ! 913: } ! 914: } else { ! 915: ASSERT(WaveInfo->Channels == 1); ! 916: } ! 917: ! 918: // ! 919: // Set the actual format ! 920: // ! 921: ! 922: return dspSetSampleRate(pHw, WaveInfo->SamplesPerSec) || Different; ! 923: } ! 924: ! 925: BOOLEAN ! 926: HwStartMidiIn( ! 927: IN PMIDI_INFO MidiInfo ! 928: ) ! 929: /*++ ! 930: ! 931: Routine Description : ! 932: ! 933: Start midi recording ! 934: ! 935: Arguments : ! 936: ! 937: MidiInfo - Midi parameters ! 938: ! 939: Return Value : ! 940: ! 941: None ! 942: ! 943: --*/ ! 944: { ! 945: PSOUND_HARDWARE pHw; ! 946: ! 947: pHw = MidiInfo->HwContext; ! 948: ! 949: // ! 950: // Write start midi input to device ! 951: // ! 952: ! 953: if (SB1(pHw)) { ! 954: return dspWrite(pHw, DSP_MIDI_READ); ! 955: } else { ! 956: return dspWrite(pHw, DSP_MIDI_READ_UART); ! 957: } ! 958: } ! 959: ! 960: BOOLEAN ! 961: HwStopMidiIn( ! 962: IN PMIDI_INFO MidiInfo ! 963: ) ! 964: /*++ ! 965: ! 966: Routine Description : ! 967: ! 968: Stop midi recording ! 969: ! 970: Arguments : ! 971: ! 972: MidiInfo - Midi parameters ! 973: ! 974: Return Value : ! 975: ! 976: None ! 977: ! 978: --*/ ! 979: { ! 980: PSOUND_HARDWARE pHw; ! 981: ! 982: pHw = MidiInfo->HwContext; ! 983: ! 984: if (SB1(pHw)) { ! 985: // ! 986: // Start = stop in this case ! 987: // ! 988: ! 989: HwStartMidiIn(MidiInfo); ! 990: } else { ! 991: // ! 992: // The only way to stop is to reset the DSP ! 993: // Note that this is called only by the app so ! 994: // output cannot be going on at this time (because we ! 995: // have the device mutex). ! 996: // ! 997: ! 998: dspReset(pHw); ! 999: dspSpeakerOn(pHw); ! 1000: } ! 1001: ! 1002: return TRUE; ! 1003: } ! 1004: ! 1005: BOOLEAN ! 1006: HwMidiRead( ! 1007: IN PMIDI_INFO MidiInfo, ! 1008: OUT PUCHAR Byte ! 1009: ) ! 1010: /*++ ! 1011: ! 1012: Routine Description : ! 1013: ! 1014: Read a midi byte from the recording ! 1015: ! 1016: Arguments : ! 1017: ! 1018: MidiInfo - Midi parameters ! 1019: ! 1020: Return Value : ! 1021: ! 1022: None ! 1023: ! 1024: --*/ ! 1025: { ! 1026: PSOUND_HARDWARE pHw; ! 1027: ! 1028: pHw = MidiInfo->HwContext; ! 1029: ! 1030: if (INPORT(pHw, DATA_AVAIL_PORT) & 0x80) { ! 1031: *Byte = INPORT(pHw, DATA_PORT); ! 1032: return TRUE; ! 1033: } else { ! 1034: return FALSE; ! 1035: } ! 1036: ! 1037: } ! 1038: ! 1039: ! 1040: VOID ! 1041: HwMidiOut( ! 1042: ! 1043: IN PMIDI_INFO MidiInfo, ! 1044: IN PUCHAR Bytes, ! 1045: IN int Count ! 1046: ) ! 1047: /*++ ! 1048: ! 1049: Routine Description : ! 1050: ! 1051: Write a midi byte to the output ! 1052: ! 1053: Arguments : ! 1054: ! 1055: MidiInfo - Midi parameters ! 1056: ! 1057: Return Value : ! 1058: ! 1059: None ! 1060: ! 1061: --*/ ! 1062: { ! 1063: PSOUND_HARDWARE pHw; ! 1064: PGLOBAL_DEVICE_INFO pGDI; ! 1065: int i, j; ! 1066: ! 1067: pHw = MidiInfo->HwContext; ! 1068: pGDI = CONTAINING_RECORD(pHw, GLOBAL_DEVICE_INFO, Hw); ! 1069: ! 1070: // ! 1071: // Loop sending data to device. Synchronize with wave and midi input ! 1072: // using the DeviceMutex for everything except the Dpc ! 1073: // routine for which we use the wave output spin lock ! 1074: // ! 1075: ! 1076: while (Count > 0) { ! 1077: // ! 1078: // Synchronize with everything except Dpc routines ! 1079: // (Note we don't use this for the whole of the output ! 1080: // because we don't want wave output to be held off ! 1081: // while we output thousands of Midi bytes, but we ! 1082: // then need to synchronize access to the midi output ! 1083: // which we do with the MidiMutex ! 1084: // ! 1085: ! 1086: KeWaitForSingleObject(&pGDI->DeviceMutex, ! 1087: Executive, ! 1088: KernelMode, ! 1089: FALSE, // Not alertable ! 1090: NULL); ! 1091: ! 1092: for (i = 0; i < 20; i++) { ! 1093: // ! 1094: // If input is active we don't need to specify MIDI write ! 1095: // for version 2 or later (can't be overlapped anyway for ! 1096: // version 1 so the extra test is unnecessary). ! 1097: // ! 1098: ! 1099: if (MidiInfo->fMidiInStarted) { ! 1100: ASSERT(!SB1(pHw)); ! 1101: dspWrite(pHw, Bytes[0]); ! 1102: ! 1103: // ! 1104: // Apparently we have to wait 400 us in this case ! 1105: // ! 1106: ! 1107: KeStallExecutionProcessor(400); ! 1108: } else { ! 1109: UCHAR Byte = Bytes[0]; // Don't take an exception while ! 1110: // we hold the spin lock! ! 1111: ! 1112: // ! 1113: // We don't want to hold on to the spin lock for too ! 1114: // long and since we can only send out 4 bytes per ms ! 1115: // we are rather slow. Hence wait until the device ! 1116: // is ready before entering the spin lock ! 1117: // ! 1118: ! 1119: { ! 1120: int j; ! 1121: for (j = 0; j < 250; j++) { ! 1122: if (INPORT(pHw, DATA_STATUS_PORT) & 0x80) { ! 1123: KeStallExecutionProcessor(1); ! 1124: } else { ! 1125: break; ! 1126: } ! 1127: } ! 1128: } ! 1129: ! 1130: // ! 1131: // Synch with any Dpc routines. This requires that ! 1132: // any write sequences done in a Dpc routine also ! 1133: // hold the spin lock over all the writes. ! 1134: // ! 1135: ! 1136: HwEnter(pHw); ! 1137: dspWriteNoLock(pHw, DSP_MIDI_WRITE); ! 1138: dspWriteNoLock(pHw, Byte); ! 1139: HwLeave(pHw); ! 1140: } ! 1141: ! 1142: // ! 1143: // Move on to next byte ! 1144: // ! 1145: ! 1146: Bytes++; ! 1147: if (--Count == 0) { ! 1148: break; ! 1149: } ! 1150: } ! 1151: KeReleaseMutex(&pGDI->DeviceMutex, FALSE); ! 1152: } ! 1153: ! 1154: } ! 1155: ! 1156: ! 1157: VOID ! 1158: HwInitialize( ! 1159: IN OUT PGLOBAL_DEVICE_INFO pGDI ! 1160: ) ! 1161: /*++ ! 1162: ! 1163: Routine Description : ! 1164: ! 1165: Write hardware routine addresses into global device data ! 1166: ! 1167: Arguments : ! 1168: ! 1169: pGDI - global data ! 1170: ! 1171: Return Value : ! 1172: ! 1173: None ! 1174: ! 1175: --*/ ! 1176: { ! 1177: PWAVE_INFO WaveInfo; ! 1178: PMIDI_INFO MidiInfo; ! 1179: PSOUND_HARDWARE pHw; ! 1180: ! 1181: pHw = &pGDI->Hw; ! 1182: WaveInfo = &pGDI->WaveInfo; ! 1183: MidiInfo = &pGDI->MidiInfo; ! 1184: ! 1185: pHw->Key = HARDWARE_KEY; ! 1186: ! 1187: KeInitializeSpinLock(&pHw->HwSpinLock); ! 1188: ! 1189: ! 1190: // ! 1191: // Install Wave and Midi routine addresses ! 1192: // ! 1193: ! 1194: WaveInfo->HwContext = pHw; ! 1195: WaveInfo->HwSetupDMA = HwSetupDMA; ! 1196: WaveInfo->HwStopDMA = HwStopDMA; ! 1197: WaveInfo->HwSetWaveFormat = HwSetWaveFormat; ! 1198: ! 1199: MidiInfo->HwContext = pHw; ! 1200: MidiInfo->HwStartMidiIn = HwStartMidiIn; ! 1201: MidiInfo->HwStopMidiIn = HwStopMidiIn; ! 1202: MidiInfo->HwMidiRead = HwMidiRead; ! 1203: MidiInfo->HwMidiOut = HwMidiOut; ! 1204: } ! 1205:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.