Annotation of ntddk/src/mmedia/sndblst/driver/hardware.c, revision 1.1.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.