Annotation of ntddk/src/mmedia/sndblst/driver/hardware.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.