Annotation of ntddk/src/mmedia/soundlib/wave.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1992  Microsoft Corporation
                      4: 
                      5: Module Name:
                      6: 
                      7:     wave.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This module contains code for wave input and output which is non
                     12:     hardware specific.
                     13: 
                     14: Author:
                     15: 
                     16:     Robin Speed (RobinSp) 1-Nov-1992
                     17: 
                     18: Environment:
                     19: 
                     20:     Kernel mode
                     21: 
                     22: Revision History:
                     23: 
                     24:     03-11-93 EPA
                     25:     Added SoundGetDMABufferSize( IN OUT PWAVE_INFO WaveInfo )
                     26: 
                     27: Notes:
                     28: 
                     29:     This component implements a wave type device with recording and
                     30:     playing.
                     31: 
                     32:        Dispatch routine :
                     33:            Create device               IRP_MJ_CREATE
                     34:            Cleanup and close device    IRP_MJ_CLEANUP and IRP_MJ_CLOSE
                     35:            Read for recording          IRP_MJ_READ
                     36:            Write for playing           IRP_MJ_WRITE
                     37:            IO controls                 IRP_MJ_DEVICE_CONTROL
                     38: 
                     39:     The device state is held mainly in a WAVE_INFO structure except
                     40:     for actual state variable itself (playing, paused) which is in the
                     41:     local device info.
                     42: 
                     43:     The device is assume to use DMA.  The design is always to copy the
                     44:     DMA data into a designated buffer which divided into two halves :
                     45: 
                     46:         The half that is playing
                     47:         The half that is prepared for playing
                     48: 
                     49:     DMA stops either because of a request to stop or because the data
                     50:     runs out.  The latter condition is detected rather lazily by waiting
                     51:     until a half buffer completes and testing if there's anything in the
                     52:     buffer prepared for playing.  This could be improved by setting a
                     53:     timer at the start of the 'last' buffer.  We don't switch our method
                     54:     of playing for the 'last' buffer because the application could
                     55:     supply more data while this buffer is playing.
                     56: 
                     57:     Once DMA is started a 'deferred procedure call' (Dpc) routine
                     58:     is queued for every interrupt (the device specific code outside this
                     59:     component must arrange for this by making SoundWaveDeferred) the
                     60:     Dpc routine for the device object and calling IoRequestDpc from
                     61:     its interrupt service routine ONLY IF the DMABusy flag is set.
                     62: 
                     63:     The DMA buffer size is varied depending on the number of bits
                     64:     per second.
                     65: 
                     66:     Mutual exclusion is on 4 levels :
                     67: 
                     68:        1. At the application request level by the application's exclusion
                     69:        routine which is called back for every request (usually a MUTANT
                     70:        or MUTEX - NOT a spin lock).
                     71: 
                     72:        2. Between routines on the application thread and the Dpc routines
                     73:        for variables owned by this component by a spin lock.
                     74: 
                     75:        3. Between routines below device level and device level by the
                     76:        interrupt object.
                     77: 
                     78:        4. Exclusion implemented for device access (eg synch with ISR or
                     79:        between multiple devices) by the hardware access callback routines.
                     80: 
                     81:        Irp handling :
                     82:        --------------
                     83: 
                     84:        Both wave input and output have an input queue or Irps attached
                     85:        to QueueHead in the WAVE_INFO structure.  Irps on this queue
                     86:        can be cancelled at any time and can only be accessed under
                     87:        the Cancel spin lock.
                     88: 
                     89:        Wave output has an additional queue of non-cancellable Irps
                     90:        attached from ProgressQueue.  These Irps have some or all of
                     91:        their data actually in the DMA buffers.  The head Irp in this
                     92:        second queue has its IoStatus.Information field set to the position
                     93:        where the first data byte in the DMA buffers was copied from.  When
                     94:        a DMA buffer completes Irps are completed for the bytes in the
                     95:        buffer and a new IoStatus.Information field set.
                     96: 
                     97:        If output is paused the ProgressQueue is moved back under QueueHead
                     98:        and the Irps in it become cancellable.  Restarting from Pause
                     99:        takes note of the IoStatus.Information field for the first byte
                    100:        to take from the first buffer (which may not be the same as that
                    101:        when we were paused because in theory that one could have been
                    102:        cancelled).
                    103: 
                    104:        Timer monitoring of devices to make sure they aren't dead
                    105:        ---------------------------------------------------------
                    106: 
                    107:        When DMA starts we start a timer Dpc with a timeout of 3 seconds.
                    108: 
                    109:        Each time an IO completion Dpc runs we set a flag to say we've had
                    110:        a Dpc routine (and hence an interrupt).
                    111: 
                    112:        The timer Dpc routine checks that we've had a interrupt in the last
                    113:        3 seconds and shuts down the device (forever - by setting DeviceBad
                    114:        in the WAVE_INFO) if not.  Otherwise it queues a clone of itself.
                    115: 
                    116:        If we detect the bad state and set DeviceBad we stop the DMA so
                    117:        as to release resources.  Any new request to the driver will
                    118:        receive STATUS_INVALID_DEVICE_REQUEST.
                    119: 
                    120:        Shutting down the timer Dpc is rather complicated :
                    121: 
                    122:            We aim to get to a state where either :
                    123: 
                    124:            A.  The Dpc will not run again (unless re-initiated) and is
                    125:                not running.
                    126: 
                    127:            B.  We can wait for the Dpc routine to set an event.
                    128: 
                    129:            And to know which of A or B we reached.
                    130: 
                    131:            The timer logical thread can be in one of :
                    132: 
                    133:            X.  Really complete
                    134: 
                    135:            Y.  On timer queue
                    136: 
                    137:            Z.  On Dpc queue
                    138: 
                    139:            W1. Dpc routine running before getting spin lock
                    140: 
                    141:            W2. Dpc routine running after releasing spin lock.
                    142:                This is just the tail of the routine which does nothing
                    143:                so regard the timer as 'finished' (state X).
                    144: 
                    145:            W3. Holding spin lock
                    146: 
                    147:            Outside the device spin lock the TimerActive boolean is TRUE
                    148:            in case X and FALSE in other cases (except when we're synchronously
                    149:            starting the thing up when we set it prior to setting the
                    150:            first timer).
                    151: 
                    152: 
                    153:            The method of reaching a known state is :
                    154: 
                    155:               Inside the device spin lock :
                    156: 
                    157:                   If TimerActive is FALSE do nothing
                    158: 
                    159:                   Cancel the timer
                    160: 
                    161:                       If the timer was set we were in state Y and we're done
                    162: 
                    163:                   Otherwise note that we cannot now enter state Y while
                    164:                   we have the spin lock here because we would have to
                    165:                   go through state W3 (because the Dpc routine is the one
                    166:                   which restarts the timer and it has the spin lock while it
                    167:                   does it).
                    168: 
                    169:                   Thus we know we're in state Z or W1 so now we just reset our
                    170:                   event and set TimerActive to be FALSE.
                    171: 
                    172:                   We then release the device spin lock and wait
                    173:                   for the event to be set by the timer Dpc routine.  We
                    174: 
                    175: 
                    176: --*/
                    177: 
                    178: #include <stdlib.h>   // For min, max
                    179: #include <string.h>
                    180: #include <soundlib.h>
                    181: #include <wave.h>
                    182: 
                    183: //
                    184: // Local definitions
                    185: //
                    186: 
                    187: VOID
                    188: SoundStartWaveRecord(
                    189:     IN OUT PLOCAL_DEVICE_INFO pLDI
                    190: );
                    191: 
                    192: VOID
                    193: SoundStopWaveRecord(
                    194:     IN OUT PLOCAL_DEVICE_INFO pLDI
                    195: );
                    196: VOID
                    197: SoundStartDMA(
                    198:     IN    PWAVE_INFO WaveInfo
                    199: );
                    200: IO_ALLOCATION_ACTION
                    201: SoundProgramDMA(
                    202:     IN    PDEVICE_OBJECT pDO,
                    203:     IN    PIRP pIrp,
                    204:     IN    PVOID pMRB,
                    205:     IN    PVOID Context
                    206: );
                    207: VOID
                    208: SoundTerminateDMA(
                    209:     IN    PWAVE_INFO WaveInfo,
                    210:     IN    BOOLEAN Pause
                    211: );
                    212: VOID
                    213: SoundStopDMA(
                    214:     IN    PWAVE_INFO WaveInfo,
                    215:     IN    BOOLEAN Pause
                    216: );
                    217: VOID
                    218: SoundResetOutput(
                    219:     IN OUT PSOUND_BUFFER_QUEUE BufferQueue
                    220: );
                    221: BOOLEAN
                    222: SoundAdjustHalf(
                    223:     PVOID Context
                    224: );
                    225: NTSTATUS
                    226: SoundSetWaveInputState(
                    227:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                    228:     IN     ULONG State
                    229: );
                    230: NTSTATUS
                    231: SoundSetWaveOutputState(
                    232:     PLOCAL_DEVICE_INFO pLDI,
                    233:     ULONG State,
                    234:     PIRP pIrp
                    235: );
                    236: VOID
                    237: SoundGetNextBuffer(
                    238:     PSOUND_BUFFER_QUEUE BufferQueue
                    239: );
                    240: 
                    241: VOID
                    242: SoundCompleteIoBuffer(
                    243:     PSOUND_BUFFER_QUEUE BufferQueue
                    244: );
                    245: VOID
                    246: SoundInitializeBufferQ(
                    247:     PSOUND_BUFFER_QUEUE BufferQueue
                    248: );
                    249: 
                    250: VOID
                    251: SoundInitializeDoubleBuffer(
                    252:     IN OUT PWAVE_INFO WaveInfo
                    253: );
                    254: 
                    255: VOID
                    256: SoundClearDoubleBuffer(
                    257:     IN OUT PWAVE_INFO WaveInfo
                    258: );
                    259: 
                    260: VOID
                    261: SoundLoadDMABuffer(
                    262:     PSOUND_BUFFER_QUEUE BufferQueue,
                    263:     struct SOUND_DMABUF *pDMA,
                    264:     UCHAR pad
                    265: );
                    266: VOID
                    267: SoundTestDeviceDeferred(
                    268:     IN    PKDPC Dpc,
                    269:     IN    PVOID Context,
                    270:     IN    PVOID Param1,
                    271:     IN    PVOID Param2
                    272: );
                    273: VOID
                    274: SoundSynchTimer(
                    275:     IN    PWAVE_INFO WaveInfo
                    276: );
                    277: 
                    278: 
                    279: WAVE_INTERFACE_ROUTINE SoundFillOutputBuffers;
                    280: WAVE_INTERFACE_ROUTINE SoundFillInputBuffers;
                    281: 
                    282: WAVE_INTERFACE_ROUTINE SoundMapDMA;
                    283: WAVE_INTERFACE_ROUTINE SoundFlushDMA;
                    284: 
                    285: //
                    286: // Remove initialization stuff from resident memory
                    287: //
                    288: 
                    289: #ifdef ALLOC_PRAGMA
                    290: #pragma alloc_text(init,SoundGetCommonBuffer)
                    291: #pragma alloc_text(init,SoundTestWaveDevice)
                    292: #endif
                    293: 
                    294: 
                    295: /***************************************************************************
                    296:  *
                    297:  *    Allocate DMA Buffer for auto-init DMA
                    298:  *
                    299:  ***************************************************************************/
                    300: 
                    301: NTSTATUS
                    302: SoundGetCommonBuffer(
                    303:     IN  PDEVICE_DESCRIPTION DeviceDescription,
                    304:     IN  OUT PSOUND_DMA_BUFFER AutoBuffer
                    305: )
                    306: /*++
                    307: 
                    308: Routine Description :
                    309: 
                    310:     Find the adapter object for our adapter
                    311: 
                    312:     Allocate and map a common buffer for use with auto-init DMA
                    313:     devices.  The buffer returned should not cross a 64KB boundary
                    314:     for an Isa device
                    315: 
                    316: Arguments :
                    317: 
                    318:     DeviceDescription - The adapter object description
                    319:     SoundAutoData - the information describing our buffer
                    320: 
                    321: Return Value :
                    322: 
                    323:     NTSTATUS code - STATUS_SUCCESS if OK
                    324: 
                    325: --*/
                    326: {
                    327:     SOUND_DMA_BUFFER SoundAutoData;
                    328:     ULONG NumberOfMapRegisters;
                    329: 
                    330:     SoundAutoData.BufferSize = DeviceDescription->MaximumLength;
                    331: 
                    332:     //
                    333:     // Try to find an adapter
                    334:     //
                    335: 
                    336:     SoundAutoData.AdapterObject[0] = HalGetAdapter(
                    337:                                          DeviceDescription,
                    338:                                          &NumberOfMapRegisters);
                    339:     //
                    340:     // Check we got a good adapter and enough registers
                    341:     //
                    342: 
                    343:     if (SoundAutoData.AdapterObject[0] == NULL) {
                    344:         dprintf1(("Could not find adapter"));
                    345:         return STATUS_DEVICE_CONFIGURATION_ERROR;
                    346:     }
                    347: 
                    348:     if (NumberOfMapRegisters < BYTES_TO_PAGES(SoundAutoData.BufferSize)) {
                    349:         dprintf1(("Could only get %u mapping registers for DMA buffer",
                    350:                   NumberOfMapRegisters));
                    351: 
                    352:         if (NumberOfMapRegisters == 0) {
                    353:             return STATUS_INSUFFICIENT_RESOURCES;
                    354:         }
                    355:         SoundAutoData.BufferSize = NumberOfMapRegisters * PAGE_SIZE;
                    356:     }
                    357: 
                    358:     //
                    359:     // Call the Hal to allocate the right kind of memory.  It may
                    360:     // not be able to get enough - but we never accept less than 4K
                    361:     // and decrease our requirement in 1K chunks.
                    362:     //
                    363: 
                    364:     for (;
                    365:          SoundAutoData.BufferSize >= SOUND_MINIMUM_WAVE_BUFFER_SIZE ;
                    366:          SoundAutoData.BufferSize -= SOUND_MINIMUM_WAVE_BUFFER_SIZE / 4) {
                    367:          SoundAutoData.VirtualAddress =
                    368:             HalAllocateCommonBuffer(SoundAutoData.AdapterObject[0],
                    369:                                     SoundAutoData.BufferSize,
                    370:                                     &SoundAutoData.LogicalAddress,
                    371:                                     FALSE                     // Non-cached
                    372:                                     );
                    373: 
                    374:         if (SoundAutoData.VirtualAddress == NULL) {
                    375:             dprintf1(("Could not allocate DMA buffer size %8X",
                    376:                       SoundAutoData.BufferSize));
                    377:         } else {
                    378:             break;
                    379:         }
                    380:     }
                    381: 
                    382:     if (SoundAutoData.BufferSize < SOUND_MINIMUM_WAVE_BUFFER_SIZE) {
                    383:             return STATUS_INSUFFICIENT_RESOURCES;
                    384:     }
                    385: 
                    386: 
                    387:     SoundAutoData.Mdl = IoAllocateMdl(
                    388:                             SoundAutoData.VirtualAddress,
                    389:                             SoundAutoData.BufferSize,
                    390:                             FALSE,  // not a secondary buffer
                    391:                             FALSE,  // no charge of quota
                    392:                             NULL    // no irp
                    393:                             );
                    394: 
                    395: 
                    396:     if (SoundAutoData.VirtualAddress == NULL) {
                    397:         dprintf1(("Could not allocate DMA buffer size %8X",
                    398:                   SoundAutoData.BufferSize));
                    399: 
                    400:         HalFreeCommonBuffer(
                    401:             SoundAutoData.AdapterObject[0],
                    402:             SoundAutoData.BufferSize,
                    403:             SoundAutoData.LogicalAddress,
                    404:             SoundAutoData.VirtualAddress,
                    405:             FALSE);
                    406: 
                    407:         return STATUS_INSUFFICIENT_RESOURCES;
                    408:     }
                    409: 
                    410:     //
                    411:     // Build an Mdl (ie fill in the physical addresses)
                    412:     //
                    413: 
                    414:     MmBuildMdlForNonPagedPool(SoundAutoData.Mdl);
                    415: 
                    416: 
                    417:     dprintf4(("  DMA Buffer    : %08lXH - physical %08lXH, Length %8lXH",
                    418:              SoundAutoData.VirtualAddress,
                    419:              MmGetPhysicalAddress((PVOID)SoundAutoData.VirtualAddress),
                    420:              SoundAutoData.BufferSize));
                    421: 
                    422:     *AutoBuffer = SoundAutoData;
                    423: 
                    424:     return STATUS_SUCCESS;
                    425: }
                    426: 
                    427: 
                    428: VOID
                    429: SoundFreeCommonBuffer(
                    430:     IN OUT PSOUND_DMA_BUFFER SoundAutoData
                    431: )
                    432: /*++
                    433: 
                    434: Routine Description :
                    435: 
                    436:     Free the data associated with a common buffer
                    437: 
                    438: Arguments :
                    439: 
                    440:     SoundAutoData - The data created when we created the buffer
                    441: 
                    442: Return Value :
                    443: 
                    444:     None
                    445: 
                    446: --*/
                    447: {
                    448:     if (SoundAutoData->Mdl) {
                    449: 
                    450:         IoFreeMdl(SoundAutoData->Mdl);
                    451: 
                    452:         HalFreeCommonBuffer(
                    453:             SoundAutoData->AdapterObject[0],
                    454:             SoundAutoData->BufferSize,
                    455:             SoundAutoData->LogicalAddress,
                    456:             SoundAutoData->VirtualAddress,
                    457:             FALSE);
                    458:     }
                    459: }
                    460: 
                    461: 
                    462: 
                    463: /**************************************************************************
                    464:  *
                    465:  *    Open, close and dispatch routines
                    466:  *
                    467:  **************************************************************************/
                    468: 
                    469: 
                    470: VOID
                    471: SoundStartWaveDevice(
                    472:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                    473:     IN     PIRP pIrp OPTIONAL
                    474: )
                    475: /*++
                    476: 
                    477: Routine Description:
                    478: 
                    479:     Add the input Irp (if any) to the device's input queue.
                    480: 
                    481:     Start the data flow and DMA on the device if necessary (ie
                    482:     if we're in playing or recording state and it's not running
                    483:     already.
                    484: 
                    485: Arguments:
                    486: 
                    487:     pLDI - Local device info
                    488:     pIrp - IO request packet from application
                    489: 
                    490: Return Value:
                    491: 
                    492:     Irp status
                    493: 
                    494: --*/
                    495: {
                    496:     BOOLEAN StartDMA;
                    497:     PWAVE_INFO WaveInfo;
                    498: 
                    499:     WaveInfo = pLDI->DeviceSpecificData;
                    500: 
                    501:     ASSERTMSG("WAVE_INFO structure not correctly initialized",
                    502:               WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
                    503: 
                    504:     DMAEnter(WaveInfo);
                    505: 
                    506:     StartDMA = !WaveInfo->DMABusy;
                    507: 
                    508:     //
                    509:     // Put the request in the queue.  This is valid for any state if
                    510:     // the device is open.
                    511:     //
                    512: 
                    513:     if (pIrp) {
                    514:         SoundAddIrpToCancellableQ(&WaveInfo->BufferQueue.QueueHead, pIrp, FALSE);
                    515: 
                    516:         dprintf3(("irp added"));
                    517:     }
                    518:     DMALeave(WaveInfo);
                    519: 
                    520:     //
                    521:     // NOTE - at this point it is possible for some old output to
                    522:     // complete but not pick up the buffer we've just inserted.
                    523:     // This is OK - we'll notice this just below.  This has
                    524:     // actually happened.
                    525:     //
                    526: 
                    527: 
                    528:     if (pLDI->State == WAVE_DD_PLAYING ||
                    529:         pLDI->State == WAVE_DD_RECORDING) {
                    530: 
                    531:          //
                    532:          // Set the format if necessary
                    533:          //
                    534: 
                    535:         if (StartDMA) {
                    536:             //
                    537:             // We always initialize the buffers for wave recording.
                    538:             // For wave output we may be paused so we usually don't
                    539:             // initialize things.
                    540:             //
                    541:             // Also select DMA Buffer size dependent on number of bytes per
                    542:             // second.
                    543:             //
                    544: 
                    545: 
                    546:             if (WaveInfo->FormatChanged || !WaveInfo->Direction) {
                    547:                 SoundInitializeDoubleBuffer(WaveInfo);
                    548:             }
                    549:         }
                    550: 
                    551: 
                    552:         //
                    553:         // Acquire the spin lock so we are synchronized with the Dpc routine
                    554:         //
                    555: 
                    556:         DMAEnter(WaveInfo);
                    557: 
                    558:         //
                    559:         // Remember whether Dma was running :
                    560:         //
                    561:         //      If it is running now (while we hold the spin lock) then
                    562:         //      the data we've added will keep it going until the data we've
                    563:         //      added runs out - so it's safe to release the spin lock
                    564:         //
                    565:         //      If the Dma is not running now then it needs restarting.  In
                    566:         //      this case nobody but us can restart it (we hold the device
                    567:         //      mutex) so it's safe to release the spin lock
                    568:         //
                    569:         // DMA may have finished when we released the spin lock so re-test it
                    570:         //
                    571: 
                    572:         StartDMA = !WaveInfo->DMABusy;
                    573: 
                    574:         //
                    575:         // If we're not currently running DMA we need to init the buffers
                    576:         //
                    577: 
                    578:         if (WaveInfo->DMABusy) {
                    579: 
                    580:             //
                    581:             // Find out which half we're really in by counting overruns
                    582:             // BUGBUG this is currently a NOOP
                    583:             //
                    584: 
                    585:             KeSynchronizeExecution(
                    586:                 WaveInfo->Interrupt,
                    587:                 SoundAdjustHalf,
                    588:                 (PVOID)WaveInfo);
                    589:         }
                    590: 
                    591: 
                    592:         //
                    593:         // Process as much data as we can
                    594:         //
                    595: 
                    596:         (WaveInfo->Direction ?
                    597:             SoundFillOutputBuffers :
                    598:             SoundFillInputBuffers)
                    599:             (WaveInfo);
                    600: 
                    601: 
                    602: 
                    603:         //
                    604:         // Ok to release the spin lock now
                    605:         //
                    606: 
                    607:         DMALeave(WaveInfo);
                    608: 
                    609: 
                    610:         //
                    611:         // Start the Dma if necessary
                    612:         //
                    613: 
                    614:         if (StartDMA) {
                    615:             //
                    616:             // Set the format
                    617:             //
                    618: 
                    619:             (*WaveInfo->HwSetWaveFormat)(WaveInfo);
                    620: 
                    621:             //
                    622:             // Synchronize with our timer routine if necessary
                    623:             //
                    624: 
                    625:             SoundSynchTimer(WaveInfo);
                    626: 
                    627:             //
                    628:             // Start the DMA
                    629:             //
                    630: 
                    631:             SoundStartDMA(WaveInfo);
                    632:         }
                    633:     } else {
                    634:         ASSERT(!WaveInfo->DMABusy);
                    635:         StartDMA = FALSE;
                    636:     }
                    637: }
                    638: 
                    639: 
                    640: NTSTATUS
                    641: SoundWaveData(
                    642:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                    643:     IN     PIRP pIrp,
                    644:     IN     PIO_STACK_LOCATION pIrpStack
                    645: )
                    646: /*++
                    647: 
                    648: Routine Description:
                    649: 
                    650:     The user has passed in a buffer of wave data to play or of wave data
                    651:     to record into.
                    652: 
                    653:     Call SoundStartWaveDevice to process the request.
                    654: 
                    655: Arguments:
                    656: 
                    657:     pLDI - Local wave device info
                    658:     pIrp - The IO request packet
                    659:     pIrpStack - The current stack location
                    660: 
                    661: Return Value:
                    662: 
                    663:     Irp status
                    664: 
                    665: --*/
                    666: {
                    667:     NTSTATUS Status;
                    668: 
                    669:     //
                    670:     // Check we're the right kind of device
                    671:     //
                    672: 
                    673:     if (pIrpStack->MajorFunction == IRP_MJ_READ &&
                    674:         pLDI->DeviceType != WAVE_IN ||
                    675:         pIrpStack->MajorFunction == IRP_MJ_WRITE &&
                    676:         pLDI->DeviceType != WAVE_OUT) {
                    677:           return STATUS_NOT_SUPPORTED;
                    678:     }
                    679: 
                    680:     //
                    681:     // Mark the Irp pending before starting processing
                    682:     //
                    683: 
                    684:     IoMarkIrpPending(pIrp);
                    685:     pIrp->IoStatus.Status = STATUS_PENDING;
                    686: 
                    687:     //
                    688:     // Mark this request as pending completion.
                    689:     //
                    690: 
                    691:     Status = STATUS_PENDING;
                    692: 
                    693:     if (pLDI->DeviceType == WAVE_IN) {
                    694:         //
                    695:         // Inform debuggers that 0 length buffers are rather strange
                    696:         //
                    697: 
                    698:         if (pIrpStack->Parameters.Read.Length == 0) {
                    699:             dprintf2(("Wave buffer is zero length"));
                    700:         }
                    701: 
                    702:     } else {
                    703:         //
                    704:         // Inform debuggers that 0 length buffers are rather strange
                    705:         //
                    706: 
                    707:         if (pIrpStack->Parameters.Write.Length == 0) {
                    708:             dprintf2(("Wave buffer is zero length"));
                    709:         }
                    710:     }
                    711: 
                    712:     SoundStartWaveDevice(pLDI, pIrp);
                    713: 
                    714: 
                    715:     return Status;
                    716: }
                    717: 
                    718: 
                    719: 
                    720: 
                    721: VOID
                    722: SoundWaveCreate(
                    723:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                    724:     IN     PDEVICE_OBJECT DeviceObject
                    725: )
                    726: /*++
                    727: 
                    728: Routine Description:
                    729: 
                    730:     Create call (for FILE_WRITE_DATA access).  Read access is granted
                    731:     to anyone in SoundWaveDispatch.  SoundWaveDispatch has also
                    732:     verified whether the device can be opened by calling back to
                    733:     the device-specific exlusion routine.
                    734: 
                    735: Arguments:
                    736: 
                    737:     pLDI - our local device into
                    738: 
                    739: Return Value:
                    740: 
                    741:     STATUS_SUCCESS if OK or
                    742:     STATUS_BUSY    if someone else has the device
                    743: 
                    744: 
                    745: --*/
                    746: {
                    747:     NTSTATUS Status;
                    748:     PWAVE_INFO WaveInfo;
                    749: 
                    750:     WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
                    751: 
                    752:     ASSERTMSG("Invalid Wave Info Pointer",
                    753:               WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
                    754: 
                    755: 
                    756:     ASSERT(pLDI->State == 0 &&
                    757:            IsListEmpty(&WaveInfo->BufferQueue.QueueHead));
                    758: 
                    759:     //
                    760:     // Check the device thinks we're open
                    761:     //
                    762: 
                    763:     ASSERT((*pLDI->DeviceInit->ExclusionRoutine)
                    764:                (pLDI, SoundExcludeQueryOpen));
                    765: 
                    766:     //
                    767:     // Initialize format changed flag
                    768:     //
                    769: 
                    770:     WaveInfo->FormatChanged = TRUE;
                    771: 
                    772:     //
                    773:     // Initialize state data and interrupt usage for
                    774:     // the chosen device type.  We set the rates etc to
                    775:     // something anyone can handle.  In reality a device is
                    776:     // never used before the format is set but we must be
                    777:     // unbreakable.
                    778:     //
                    779: 
                    780:     switch (pLDI->DeviceType) {
                    781:     case WAVE_IN:
                    782:         pLDI->State = WAVE_DD_STOPPED;
                    783:         WaveInfo->DeviceObject = DeviceObject;
                    784:         WaveInfo->Direction = FALSE;
                    785: 
                    786: 
                    787:         WaveInfo->SamplesPerSec = WAVE_DEFAULT_RATE;
                    788:         WaveInfo->BitsPerSample = WAVE_DEFAULT_BITS_PER_SAMPLE;
                    789:         WaveInfo->Channels = 1;
                    790: 
                    791:         ASSERT(WaveInfo->BufferQueue.BytesProcessed == 0);
                    792: 
                    793:         dprintf3(("Opened for wave input"));
                    794:         Status = STATUS_SUCCESS;
                    795:         break;
                    796: 
                    797:     case WAVE_OUT:
                    798:         pLDI->State = WAVE_DD_PLAYING;
                    799:         WaveInfo->DeviceObject = DeviceObject;
                    800:         WaveInfo->Direction = TRUE;
                    801: 
                    802:         WaveInfo->SamplesPerSec = WAVE_DEFAULT_RATE;
                    803:         WaveInfo->BitsPerSample = WAVE_DEFAULT_BITS_PER_SAMPLE;
                    804:         WaveInfo->Channels = 1;
                    805: 
                    806:         ASSERT(WaveInfo->BufferQueue.BytesProcessed == 0);
                    807: 
                    808:         dprintf3(("Opened for wave output"));
                    809:         Status = STATUS_SUCCESS;
                    810:         break;
                    811: 
                    812:     default:
                    813:         ASSERT(FALSE);
                    814:         break;
                    815:     }
                    816: 
                    817: }
                    818: 
                    819: 
                    820: 
                    821: NTSTATUS
                    822: SoundWaveCleanup(
                    823:     IN OUT PLOCAL_DEVICE_INFO pLDI
                    824: )
                    825: /*++
                    826: 
                    827: Routine Description:
                    828: 
                    829:     Clean up the requested device (this is effectively CLOSE)
                    830: 
                    831: Arguments:
                    832: 
                    833:     pLDI - pointer to our local device info
                    834: 
                    835: Return Value:
                    836: 
                    837:     STATUS_SUCCESS        if OK otherwise
                    838:     STATUS_INTERNAL_ERROR
                    839: 
                    840: --*/
                    841: {
                    842:     NTSTATUS Status = STATUS_SUCCESS;
                    843:     PWAVE_INFO WaveInfo;
                    844: 
                    845:     WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
                    846: 
                    847:     ASSERTMSG("Invalid Wave Info Pointer",
                    848:               WaveInfo != NULL && WaveInfo->Key == WAVE_INFO_KEY);
                    849: 
                    850:     //
                    851:     // Check this is valid call
                    852:     //
                    853: 
                    854:     ASSERT((*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeQueryOpen));
                    855: 
                    856:     //
                    857:     // Call the device reset function to complete any
                    858:     // pending i/o requests and terminate any current
                    859:     // requests in progress
                    860:     //
                    861: 
                    862:     switch (pLDI->DeviceType) {
                    863:     case WAVE_IN:
                    864: 
                    865:         SoundStopWaveRecord(pLDI);
                    866: 
                    867:         //
                    868:         // Reset position to start and free any pending Irps.
                    869:         //
                    870: 
                    871:         SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
                    872:         WaveInfo->BufferQueue.BytesProcessed = 0;
                    873: 
                    874:         SoundSynchTimer(WaveInfo);
                    875: 
                    876:         break;
                    877: 
                    878:     case WAVE_OUT:
                    879: 
                    880:         //
                    881:         // If anything is in the queue then free it.
                    882:         // beware that the final block of a request may still be
                    883:         // being dma'd when we get this call.  We now kill this as well
                    884:         // because we've changed such that the if the application thinks
                    885:         // all the requests are complete then they are complete.
                    886:         //
                    887: 
                    888:         SoundStopDMA(WaveInfo, FALSE);    // Stop with no pause
                    889: 
                    890:         SoundResetOutput(&WaveInfo->BufferQueue);
                    891: 
                    892:         SoundSynchTimer(WaveInfo);
                    893: 
                    894:         break;
                    895: 
                    896:     default:
                    897:         dprintf1(("Bogus device type for cleanup request"));
                    898:         Status = STATUS_INTERNAL_ERROR;
                    899:         break;
                    900:     }
                    901: 
                    902:     //
                    903:     // return the device to it's idle state
                    904:     //
                    905: 
                    906:     if (NT_SUCCESS(Status)) {
                    907:         pLDI->State = 0;
                    908:         (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeClose);
                    909:         dprintf3(("Device closing"));
                    910:     }
                    911: 
                    912:     return Status;
                    913: }
                    914: 
                    915: 
                    916: NTSTATUS
                    917: SoundIoctlGetWaveState(
                    918:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                    919:     IN    PIRP pIrp,
                    920:     IN    PIO_STACK_LOCATION IrpStack
                    921: )
                    922: /*++
                    923: 
                    924: Routine Description:
                    925: 
                    926:     Get the current state of the device and return it to the caller.
                    927:     This code is COMMON for :
                    928:        Wave out
                    929:        Wave in
                    930: 
                    931: Arguments:
                    932: 
                    933:     pLDI - Pointer to our own device data
                    934:     pIrp - Pointer to the IO Request Packet
                    935:     IrpStack - Pointer to current stack location
                    936: 
                    937: Return Value:
                    938: 
                    939:      Status to put into request packet by caller.
                    940: 
                    941: --*/
                    942: {
                    943:     PULONG pState;
                    944: 
                    945:     if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
                    946:         dprintf1(("Supplied buffer to small for requested data"));
                    947:         return STATUS_BUFFER_TOO_SMALL;
                    948:     }
                    949: 
                    950:     //
                    951:     // say how much we're sending back
                    952:     //
                    953: 
                    954:     pIrp->IoStatus.Information = sizeof(ULONG);
                    955: 
                    956:     //
                    957:     // cast the buffer address to the pointer type we want
                    958:     //
                    959: 
                    960:     pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
                    961: 
                    962:     //
                    963:     // fill in the info -
                    964:     //
                    965: 
                    966: 
                    967:     //
                    968:     // We don't bother to maintain the WAVE_DD_IDLE state internally
                    969:     // for Wave output
                    970:     //
                    971: 
                    972:     if (pLDI->State == WAVE_DD_PLAYING) {
                    973: 
                    974:         ASSERT(pLDI->DeviceType == WAVE_OUT);
                    975: 
                    976:         //
                    977:         // We need to know if it's really playing
                    978:         // and DMABusy can be cleared by the Dpc routine so we need the spin lock
                    979:         //
                    980: 
                    981:         if (!((PWAVE_INFO)pLDI->DeviceSpecificData)->DMABusy) {
                    982:             *pState = WAVE_DD_IDLE;
                    983:         }
                    984: 
                    985:     } else {
                    986:         *pState = pLDI->State;
                    987:     }
                    988: 
                    989: 
                    990:     return STATUS_SUCCESS;
                    991: }
                    992: 
                    993: 
                    994: NTSTATUS SoundIoctlQueryFormat(
                    995:     IN    PLOCAL_DEVICE_INFO pLDI,
                    996:     IN OUT PIRP pIrp,
                    997:     IN    PIO_STACK_LOCATION IrpStack
                    998: )
                    999: /*++
                   1000: 
                   1001: Routine Description:
                   1002: 
                   1003:     Tell the caller whether the wave format specified (input or
                   1004:     output) is supported
                   1005: 
                   1006: Arguments:
                   1007: 
                   1008:     pLDI - pointer to local device info
                   1009:     pIrp - the Irp
                   1010:     IrpStack - the current stack location
                   1011: 
                   1012: Return Value:
                   1013: 
                   1014:     STATUS_SUCCESS - format is supported
                   1015:     STATUS_NOT_SUPPORTED - format not supported
                   1016: 
                   1017: --*/
                   1018: {
                   1019:     PPCMWAVEFORMAT pFormat;
                   1020:     NTSTATUS Status;
                   1021:     PWAVE_INFO WaveInfo;
                   1022:     WaveInfo = pLDI->DeviceSpecificData;
                   1023: 
                   1024:     ASSERT(WaveInfo->Key == WAVE_INFO_KEY);
                   1025: 
                   1026:     //
                   1027:     // check the buffer really is big enough to contain the struct
                   1028:     // we expect before digging into it. If not then assume it's a
                   1029:     // format we don't know how to do.
                   1030:     //
                   1031: 
                   1032:     if (IrpStack->Parameters.DeviceIoControl.InputBufferLength <
                   1033:             sizeof(PCMWAVEFORMAT)) {
                   1034: 
                   1035:         dprintf1(("Format data wrong size"));
                   1036:         return STATUS_NOT_SUPPORTED;
                   1037:     }
                   1038: 
                   1039: 
                   1040:     pFormat = (PPCMWAVEFORMAT)pIrp->AssociatedIrp.SystemBuffer;
                   1041: 
                   1042:     //
                   1043:     // Check if the device can support this format
                   1044:     //
                   1045: 
                   1046:     Status = (*WaveInfo->QueryFormat)(pLDI, pFormat);
                   1047: 
                   1048:     //
                   1049:     // If we're setting the format then copy it to our global info
                   1050:     //
                   1051: 
                   1052:     if (Status == STATUS_SUCCESS &&
                   1053:         IrpStack->Parameters.DeviceIoControl.IoControlCode ==
                   1054:             IOCTL_WAVE_SET_FORMAT) {
                   1055: 
                   1056:         WaveInfo->FormatChanged = TRUE;
                   1057:         WaveInfo->SamplesPerSec = pFormat->wf.nSamplesPerSec;
                   1058:         WaveInfo->BitsPerSample = pFormat->wBitsPerSample;
                   1059:         WaveInfo->Channels = pFormat->wf.nChannels;
                   1060:     }
                   1061: 
                   1062:     return Status;
                   1063: }
                   1064: 
                   1065: 
                   1066: NTSTATUS
                   1067: SoundWaveDispatch(
                   1068:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                   1069:     IN    PIRP pIrp,
                   1070:     IN    PIO_STACK_LOCATION IrpStack
                   1071: )
                   1072: /*++
                   1073: 
                   1074: Routine Description:
                   1075: 
                   1076:     WAVE IOCTL call dispatcher.  This is the entry point for all wave
                   1077:     specific calls.  See dispatch.c.
                   1078: 
                   1079:     This routine should be in the DispatchRoutine entry of the DeviceInit
                   1080:     structure hanging off the local device info - see devices.h.
                   1081: 
                   1082: Arguments:
                   1083: 
                   1084:     pLDI - Pointer to local device data
                   1085:     pIrp - Pointer to IO request packet
                   1086:     IrpStack - Pointer to current stack location
                   1087: 
                   1088: Return Value:
                   1089: 
                   1090:     Return status from dispatched routine
                   1091: 
                   1092: --*/
                   1093: {
                   1094:     NTSTATUS Status;
                   1095: 
                   1096:     Status = STATUS_SUCCESS;
                   1097: 
                   1098:     if (((PWAVE_INFO)pLDI->DeviceSpecificData)->DeviceBad) {
                   1099:         return STATUS_INVALID_DEVICE_REQUEST;
                   1100:     }
                   1101: 
                   1102:     switch (IrpStack->MajorFunction) {
                   1103:     case IRP_MJ_CREATE:
                   1104:         Status = SoundSetShareAccess(pLDI, IrpStack);
                   1105:         if (NT_SUCCESS(Status) && IrpStack->FileObject->WriteAccess) {
                   1106:             SoundWaveCreate(pLDI, IrpStack->DeviceObject);
                   1107:         }
                   1108:         break;
                   1109: 
                   1110:     case IRP_MJ_CLOSE:
                   1111: 
                   1112:         Status = STATUS_SUCCESS;
                   1113: 
                   1114:         break;
                   1115: 
                   1116:     case IRP_MJ_READ:
                   1117:     case IRP_MJ_WRITE:
                   1118: 
                   1119:         if (IrpStack->FileObject->WriteAccess) {
                   1120:             Status = SoundWaveData(pLDI, pIrp, IrpStack);
                   1121:         } else {
                   1122:             Status = STATUS_ACCESS_DENIED;
                   1123:         }
                   1124:         break;
                   1125: 
                   1126: 
                   1127:     case IRP_MJ_DEVICE_CONTROL:
                   1128: 
                   1129:         //
                   1130:         // Check that if someone has the device open for 'write' it's
                   1131:         // marked as in use
                   1132:         //
                   1133: 
                   1134:         ASSERT(!IrpStack->FileObject->WriteAccess ||
                   1135:                 (*pLDI->DeviceInit->ExclusionRoutine)
                   1136:                     (pLDI, SoundExcludeQueryOpen));
                   1137:         //
                   1138:         // Check device access
                   1139:         //
                   1140:         if (!IrpStack->FileObject->WriteAccess) {
                   1141: 
                   1142:             switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   1143:                 case IOCTL_WAVE_GET_VOLUME:
                   1144:                 case IOCTL_WAVE_SET_VOLUME:
                   1145:                 case IOCTL_SOUND_GET_CHANGED_VOLUME:
                   1146: 
                   1147:                     if (pLDI->PreventVolumeSetting) {
                   1148:                         Status = STATUS_ACCESS_DENIED;
                   1149:                     }
                   1150:                     break;
                   1151: 
                   1152: 
                   1153:                 case IOCTL_WAVE_GET_CAPABILITIES:
                   1154:                 case IOCTL_WAVE_QUERY_FORMAT:
                   1155:                     break;
                   1156: 
                   1157:                 default:
                   1158:                     Status = STATUS_ACCESS_DENIED;
                   1159:                     break;
                   1160:             }
                   1161:         }
                   1162: 
                   1163:         if (NT_SUCCESS(Status)) {
                   1164:             //
                   1165:             // Dispatch the IOCTL function
                   1166:             // Note that some IOCTLs only make sense for input or output
                   1167:             // devices and not both.
                   1168:             // Note that APIs which are possibly asynchronous do not
                   1169:             // go through the Irp cleanup at the end here because they
                   1170:             // may get completed before returning here or they are made
                   1171:             // accessible to other requests by being queued.
                   1172:             //
                   1173: 
                   1174:             switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   1175: 
                   1176:             case IOCTL_WAVE_SET_FORMAT:
                   1177:             case IOCTL_WAVE_QUERY_FORMAT:
                   1178:                 Status = SoundIoctlQueryFormat(pLDI, pIrp, IrpStack);
                   1179:                 break;
                   1180: 
                   1181:             case IOCTL_WAVE_GET_CAPABILITIES:
                   1182:                 Status = (*pLDI->DeviceInit->DevCapsRoutine)(pLDI, pIrp, IrpStack);
                   1183:                 break;
                   1184: 
                   1185:             case IOCTL_WAVE_SET_STATE:
                   1186:                 if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
                   1187:                     dprintf1(("Supplied buffer too small for expected data"));
                   1188:                     Status = STATUS_BUFFER_TOO_SMALL;
                   1189:                 } else {
                   1190:                     PULONG pState;
                   1191: 
                   1192:                     //
                   1193:                     // cast the buffer address to the pointer type we want
                   1194:                     //
                   1195: 
                   1196:                     pState = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
                   1197: 
                   1198:                     switch (pLDI->DeviceType) {
                   1199:                     case WAVE_IN:
                   1200:                         Status = SoundSetWaveInputState(pLDI, *pState);
                   1201:                         break;
                   1202: 
                   1203:                     case WAVE_OUT:
                   1204:                         Status = SoundSetWaveOutputState(pLDI, *pState, pIrp);
                   1205:                         break;
                   1206:                     }
                   1207:                 }
                   1208:                 break;
                   1209: 
                   1210:             case IOCTL_WAVE_GET_STATE:
                   1211:                 Status = SoundIoctlGetWaveState(pLDI, pIrp, IrpStack);
                   1212:                 break;
                   1213: 
                   1214:             case IOCTL_WAVE_GET_POSITION:
                   1215:                 Status = SoundIoctlGetPosition(pLDI, pIrp, IrpStack);
                   1216:                 break;
                   1217: 
                   1218:             case IOCTL_WAVE_SET_VOLUME:
                   1219:                 Status = SoundIoctlSetVolume(pLDI, pIrp, IrpStack);
                   1220:                 break;
                   1221: 
                   1222:             case IOCTL_WAVE_GET_VOLUME:
                   1223:                 Status = SoundIoctlGetVolume(pLDI, pIrp, IrpStack);
                   1224:                 break;
                   1225: 
                   1226:             case IOCTL_SOUND_GET_CHANGED_VOLUME:
                   1227:                 Status = SoundIoctlGetChangedVolume(pLDI, pIrp, IrpStack);
                   1228:                 break;
                   1229: 
                   1230:             case IOCTL_WAVE_SET_PITCH:
                   1231:                 Status = STATUS_NOT_SUPPORTED;
                   1232:                 break;
                   1233: 
                   1234:             case IOCTL_WAVE_GET_PITCH:
                   1235:                 // Status = SoundIoctlGetPitch(pLDI, pIrp, IrpStack);
                   1236:                 Status = STATUS_NOT_SUPPORTED;
                   1237:                 break;
                   1238: 
                   1239:             case IOCTL_WAVE_SET_PLAYBACK_RATE:
                   1240:                 Status = STATUS_NOT_SUPPORTED;
                   1241:                 break;
                   1242: 
                   1243:             case IOCTL_WAVE_GET_PLAYBACK_RATE:
                   1244:                 // Status = SoundIoctlGetPlaybackRate(pLDI, pIrp, IrpStack);
                   1245:                 Status = STATUS_NOT_SUPPORTED;
                   1246:                 break;
                   1247: 
                   1248:         #if 0
                   1249:             case IOCTL_WAVE_SET_DEBUG_LEVEL:
                   1250:                 Status = SoundIoctlSetDebugLevel(pLDI, pIrp, IrpStack);
                   1251:                 break;
                   1252:         #endif
                   1253: 
                   1254:             default:
                   1255:                 dprintf2(("Unimplemented IOCTL (%08lXH) requested", IrpStack->Parameters.DeviceIoControl.IoControlCode));
                   1256:                 Status = STATUS_INVALID_DEVICE_REQUEST;
                   1257:                 break;
                   1258:             }
                   1259:             break;
                   1260:         }
                   1261: 
                   1262: 
                   1263:     case IRP_MJ_CLEANUP:
                   1264:         if (IrpStack->FileObject->WriteAccess) {
                   1265:             Status = SoundWaveCleanup(pLDI);
                   1266:             pLDI->PreventVolumeSetting = FALSE;
                   1267:         } else {
                   1268:             Status = STATUS_SUCCESS;
                   1269:         }
                   1270:         break;
                   1271: 
                   1272: 
                   1273:     default:
                   1274:         dprintf2(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction));
                   1275:         Status = STATUS_INVALID_DEVICE_REQUEST;
                   1276:         break;
                   1277:     }
                   1278: 
                   1279:     return Status;
                   1280: }
                   1281: 
                   1282: 
                   1283: 
                   1284: NTSTATUS
                   1285: SoundSetWaveInputState(
                   1286:     IN OUT PLOCAL_DEVICE_INFO pLDI,
                   1287:     IN     ULONG State
                   1288: )
                   1289: /*++
                   1290: 
                   1291: Routine Description:
                   1292: 
                   1293:     Determine which sound recording function to call depending on the
                   1294:     state to be set.
                   1295: 
                   1296: Arguments:
                   1297: 
                   1298:     pLDI - Pointer to local device data
                   1299:     State - the new state to set
                   1300: 
                   1301: Return Value:
                   1302: 
                   1303:     Return status for caller
                   1304: 
                   1305: --*/
                   1306: {
                   1307:     NTSTATUS Status;
                   1308:     PWAVE_INFO WaveInfo;
                   1309: 
                   1310:     WaveInfo = pLDI->DeviceSpecificData;
                   1311: 
                   1312:     switch (State) {
                   1313:     case WAVE_DD_RECORD:
                   1314: 
                   1315:         SoundStartWaveRecord(pLDI);
                   1316:         Status = STATUS_SUCCESS;
                   1317:         dprintf3(("Input started"));
                   1318:         break;
                   1319: 
                   1320:     case WAVE_DD_STOP:
                   1321: 
                   1322:         SoundStopWaveRecord(pLDI);
                   1323:         Status = STATUS_SUCCESS;
                   1324:         dprintf3(("Input stopped"));
                   1325:         break;
                   1326: 
                   1327:     case WAVE_DD_RESET:
                   1328: 
                   1329:         SoundStopWaveRecord(pLDI);
                   1330: 
                   1331:         //
                   1332:         // Reset position to start and free any pending Irps.
                   1333:         //
                   1334: 
                   1335:         SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
                   1336:         WaveInfo->BufferQueue.BytesProcessed = 0;
                   1337: 
                   1338:         Status = STATUS_SUCCESS;
                   1339:         dprintf3(("Input reset"));
                   1340:         break;
                   1341: 
                   1342:     default:
                   1343: 
                   1344:         dprintf1(("Bogus set output state request: %08lXH", State));
                   1345:         Status = STATUS_INVALID_PARAMETER;
                   1346:         break;
                   1347:     }
                   1348: 
                   1349:     return Status;
                   1350: }
                   1351: 
                   1352: 
                   1353: VOID
                   1354: SoundResetOutput(
                   1355:     IN OUT PSOUND_BUFFER_QUEUE BufferQueue
                   1356: )
                   1357: /*++
                   1358: 
                   1359: Routine Description:
                   1360: 
                   1361:     Clear out all the wave output buffers supplied by the application,
                   1362:     cancelling related IO request packets.
                   1363: 
                   1364:     Set the Position to 0.
                   1365: 
                   1366: Arguments:
                   1367: 
                   1368:     WaveInfo - Pointer to structure controlling processing of Irps for
                   1369:        this device
                   1370: 
                   1371: Return Value:
                   1372: 
                   1373:     None
                   1374: 
                   1375: --*/
                   1376: {
                   1377: 
                   1378:     SoundCompleteIoBuffer(BufferQueue);
                   1379: 
                   1380:     //
                   1381:     // Free all our lists of Irps, in the correct order
                   1382:     //
                   1383:     SoundFreeQ(&BufferQueue->ProgressQueue, STATUS_CANCELLED);
                   1384:     SoundFreeQ(&BufferQueue->QueueHead, STATUS_CANCELLED);
                   1385: 
                   1386:     //
                   1387:     // Reset the output position count
                   1388:     //
                   1389: 
                   1390:     BufferQueue->BytesProcessed = 0;
                   1391: }
                   1392: 
                   1393: 
                   1394: NTSTATUS
                   1395: SoundSetWaveOutputState(
                   1396:     PLOCAL_DEVICE_INFO pLDI,
                   1397:     ULONG State,
                   1398:     PIRP pIrp
                   1399: )
                   1400: /*++
                   1401: 
                   1402: Routine Description:
                   1403: 
                   1404:     Set the new sound state.  This is the most complicated part of the
                   1405:     wave stuff because pauses cannot be completed immediately if there
                   1406:     is stuff being DMAd.
                   1407: 
                   1408:     If reset is requested then additionally all the data supplied by
                   1409:     the application is deleted (the Irps are signalled as cancelled)
                   1410:     and the Position is set to 0.  In this case the WAVE_DD_STOPPED
                   1411:     state is set until the reset is complete.
                   1412: 
                   1413: 
                   1414: Arguments:
                   1415: 
                   1416:     pLDI - local device info
                   1417:     State - the new state
                   1418: 
                   1419: 
                   1420: Return Value:
                   1421: 
                   1422: 
                   1423: --*/
                   1424: {
                   1425:     NTSTATUS Status = STATUS_INTERNAL_ERROR;
                   1426:     PWAVE_INFO WaveInfo;
                   1427: 
                   1428:     WaveInfo = pLDI->DeviceSpecificData;
                   1429: 
                   1430:     switch (State) {
                   1431: 
                   1432:     case WAVE_DD_RESET:
                   1433:     case WAVE_DD_STOP:
                   1434: 
                   1435:         SoundStopDMA(WaveInfo, (BOOLEAN)(State == WAVE_DD_STOP));
                   1436: 
                   1437:         if (State == WAVE_DD_RESET) {
                   1438:             SoundResetOutput(&WaveInfo->BufferQueue);
                   1439:             pLDI->State = WAVE_DD_PLAYING;
                   1440:         } else {
                   1441:             //
                   1442:             // Set STOPPED state for now anyway so we don't try to put
                   1443:             // anything more in the buffer
                   1444:             //
                   1445: 
                   1446:             pLDI->State = WAVE_DD_STOPPED;
                   1447: 
                   1448:         }
                   1449: 
                   1450:         Status = STATUS_SUCCESS;
                   1451: 
                   1452: 
                   1453: 
                   1454:         dprintf3(("Output stopped"));
                   1455:         break;
                   1456: 
                   1457: 
                   1458:     case WAVE_DD_PLAY:
                   1459:         //
                   1460:         // Restart playing.  If we're already playing no need to
                   1461:         // restart, otherwise it's safe to restart.
                   1462:         //
                   1463: 
                   1464:         pLDI->State = WAVE_DD_PLAYING;
                   1465:         SoundStartWaveDevice(pLDI, NULL);
                   1466: 
                   1467:         Status = STATUS_SUCCESS;
                   1468:         dprintf3(("Output restarted"));
                   1469:         break;
                   1470: 
                   1471:     default:
                   1472: 
                   1473:         dprintf1(("Bogus set output state request: %08lXH", State));
                   1474:         Status = STATUS_INVALID_PARAMETER;
                   1475:         break;
                   1476:     }
                   1477: 
                   1478:     return Status;
                   1479: }
                   1480: 
                   1481: 
                   1482: 
                   1483: VOID
                   1484: SoundStartWaveRecord(
                   1485:     IN OUT PLOCAL_DEVICE_INFO pLDI
                   1486: )
                   1487: /*++
                   1488: 
                   1489: Routine Description:
                   1490: 
                   1491:     Process the WAVE_DD_RECORD state change
                   1492: 
                   1493:     If recording has already started just return
                   1494:     Otherwise start our DMA.
                   1495: 
                   1496: Arguments:
                   1497: 
                   1498:     pLDI - our local device info
                   1499: 
                   1500: Return Value:
                   1501: 
                   1502:     None
                   1503: 
                   1504: --*/
                   1505: {
                   1506:     PWAVE_INFO WaveInfo;
                   1507: 
                   1508:     WaveInfo = pLDI->DeviceSpecificData;
                   1509: 
                   1510:     ASSERTMSG("Recording on output device !", !WaveInfo->Direction);
                   1511: 
                   1512:     if (pLDI->State == WAVE_DD_RECORDING) {
                   1513:         ASSERT(WaveInfo->DMABusy);
                   1514:         return;
                   1515:     }
                   1516: 
                   1517:     //
                   1518:     // Set state
                   1519:     //
                   1520: 
                   1521:     pLDI->State = WAVE_DD_RECORDING;
                   1522: 
                   1523:     //
                   1524:     // Start the input
                   1525:     //
                   1526: 
                   1527:     SoundStartWaveDevice(pLDI, NULL);
                   1528: 
                   1529: 
                   1530:     //
                   1531:     // Function is complete
                   1532:     //
                   1533: 
                   1534: }
                   1535: 
                   1536: 
                   1537: VOID
                   1538: SoundStopWaveRecord(
                   1539:     IN OUT PLOCAL_DEVICE_INFO pLDI
                   1540: )
                   1541: /*++
                   1542: 
                   1543: Routine Description:
                   1544: 
                   1545:     Stop wave recording.
                   1546: 
                   1547:     If recording is not in progress just return sucess.
                   1548:     Otherwise stop the DMA and return the data we have so far
                   1549:     recorded in the DMA buffer.
                   1550: 
                   1551: Arguments:
                   1552: 
                   1553:     pLDI - pointer to our local device data
                   1554: 
                   1555: Return Value:
                   1556: 
                   1557:     None
                   1558: 
                   1559: --*/
                   1560: {
                   1561:     PWAVE_INFO WaveInfo;
                   1562: 
                   1563:     WaveInfo = pLDI->DeviceSpecificData;
                   1564: 
                   1565:     ASSERTMSG("Recording on output device !", !WaveInfo->Direction);
                   1566: 
                   1567:     if (WaveInfo->DMABusy) {
                   1568: 
                   1569:         ASSERT(pLDI->State == WAVE_DD_RECORDING);
                   1570: 
                   1571:         //
                   1572:         // Stop any more input
                   1573:         //
                   1574: 
                   1575:         SoundStopDMA(WaveInfo, FALSE);
                   1576: 
                   1577:         //
                   1578:         // Pass back any data to the application.  SoundFillInputBuffers
                   1579:         // returns TRUE if it completes any buffers
                   1580:         //
                   1581: 
                   1582:         if (!SoundFillInputBuffers(WaveInfo)) {
                   1583:             SoundGetNextBuffer(&WaveInfo->BufferQueue);
                   1584: 
                   1585:             //
                   1586:             // Send back the first buffer if there is one
                   1587:             //
                   1588: 
                   1589:             if (WaveInfo->BufferQueue.UserBuffer) {
                   1590:                 WaveInfo->BufferQueue.pIrp->IoStatus.Status = STATUS_SUCCESS;
                   1591: 
                   1592:                 SoundCompleteIoBuffer(&WaveInfo->BufferQueue);
                   1593: 
                   1594:                 IoCompleteRequest(WaveInfo->BufferQueue.pIrp, IO_SOUND_INCREMENT);
                   1595:             }
                   1596:         }
                   1597: 
                   1598:         //
                   1599:         // Set state and make sure buffers are clear
                   1600:         //
                   1601: 
                   1602:         pLDI->State = WAVE_DD_STOPPED;
                   1603:     }
                   1604: }
                   1605: 
                   1606: 
                   1607: ULONG
                   1608: SoundGetHalfBufferPosition(
                   1609:     IN    PWAVE_INFO WaveInfo
                   1610: )
                   1611: /*++
                   1612: 
                   1613: Routine Description
                   1614:     Find position in current half buffer by reading the Dma counter
                   1615:     Returns 0 if Dma is not running.
                   1616: 
                   1617:     Requires caller to hold spin lock.
                   1618: 
                   1619: --*/
                   1620: {
                   1621:     ULONG DmaPosition;
                   1622:     ULONG BytesPerSample;
                   1623: 
                   1624: 
                   1625:     //
                   1626:     // Find out where we are in the DMA buffer
                   1627:     //
                   1628: 
                   1629:     DmaPosition = WaveInfo->DoubleBuffer.BufferSize -
                   1630:                        HalReadDmaCounter(WaveInfo->DMABuf.AdapterObject[0]);
                   1631: 
                   1632:     //
                   1633:     // Make sure we don't get in the middle of a sample
                   1634:     //
                   1635:     BytesPerSample = (WaveInfo->BitsPerSample * WaveInfo->Channels) >> 3;
                   1636:     DmaPosition = (DmaPosition / BytesPerSample) * BytesPerSample;
                   1637: 
                   1638:     //
                   1639:     // NextHalf is the half we think is being played or recorded into
                   1640:     // We want the position relative to the beginning of that half so
                   1641:     // if we're playing the upper half we subtract (= add in this
                   1642:     // case) the size of the lower half modulo the buffer size
                   1643:     //
                   1644: 
                   1645:     if (WaveInfo->DoubleBuffer.NextHalf == UpperHalf) {
                   1646:         if (DmaPosition < WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size) {
                   1647:             DmaPosition = 0;
                   1648:         } else {
                   1649:             DmaPosition -= WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size;
                   1650:         }
                   1651:     }
                   1652:     //
                   1653:     // Round down to the current half buffer because if we're overrun
                   1654:     // we're not playing data the user gave us at all.
                   1655:     // In the case of input the number of bytes in the buffer is always
                   1656:     // set to the buffer size.  In the output case the number of bytes
                   1657:     // is the number of bytes actually copied to the buffer.
                   1658:     //
                   1659: 
                   1660:     DmaPosition =
                   1661:           min(DmaPosition,
                   1662:               WaveInfo->DoubleBuffer.Buffer
                   1663:                   [WaveInfo->DoubleBuffer.NextHalf].nBytes);
                   1664: 
                   1665:     return DmaPosition;
                   1666: }
                   1667: 
                   1668: 
                   1669: 
                   1670: NTSTATUS
                   1671: SoundIoctlGetPosition(
                   1672:     IN    PLOCAL_DEVICE_INFO pLDI,
                   1673:     IN    PIRP pIrp,
                   1674:     IN    PIO_STACK_LOCATION IrpStack
                   1675: )
                   1676: /*++
                   1677: 
                   1678: Routine Description:
                   1679: 
                   1680:    IOCTL get wave position.  Read the current position of wave output.
                   1681: 
                   1682: 
                   1683: Arguments:
                   1684: 
                   1685:     pLDI - Local device data
                   1686:     pIrp - IO request packet
                   1687:     IrpStack - current Irp stack location
                   1688: 
                   1689: Return Value:
                   1690: 
                   1691:     Irp status
                   1692: 
                   1693: --*/
                   1694: {
                   1695:     PWAVE_DD_POSITION pPosition;
                   1696:     NTSTATUS status;
                   1697:     PWAVE_INFO WaveInfo;
                   1698: 
                   1699:     status = STATUS_SUCCESS;
                   1700:     WaveInfo = pLDI->DeviceSpecificData;
                   1701: 
                   1702:     if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
                   1703:         sizeof(WAVE_DD_POSITION)) {
                   1704:         dprintf1(("Supplied buffer to small for requested data"));
                   1705:         return STATUS_BUFFER_TOO_SMALL;
                   1706:     }
                   1707: 
                   1708:     //
                   1709:     // say how much we're sending back
                   1710:     //
                   1711: 
                   1712:     pIrp->IoStatus.Information = sizeof(WAVE_DD_POSITION);
                   1713: 
                   1714:     //
                   1715:     // cast the buffer address to the pointer type we want
                   1716:     //
                   1717: 
                   1718:     pPosition = (PWAVE_DD_POSITION)pIrp->AssociatedIrp.SystemBuffer;
                   1719: 
                   1720: 
                   1721:     //
                   1722:     // If DMA is still running we need to check how far it has
                   1723:     // progressed
                   1724:     //
                   1725: 
                   1726:     DMAEnter(WaveInfo);
                   1727: 
                   1728:     pPosition->ByteCount = WaveInfo->BufferQueue.BytesProcessed;
                   1729: 
                   1730:     //
                   1731:     // Don't adjust answer for wave record becase we haven't
                   1732:     // yet copied the data to the application's buffers.  Sound
                   1733:     // recorder in particular would get confused by this and mess
                   1734:     // up its display.
                   1735:     //
                   1736: 
                   1737:     if (WaveInfo->DMABusy && WaveInfo->Direction) {
                   1738:         pPosition->ByteCount += SoundGetHalfBufferPosition(WaveInfo);
                   1739:     }
                   1740: 
                   1741:     DMALeave(WaveInfo);
                   1742: 
                   1743:     //
                   1744:     // Convert to samples
                   1745:     //
                   1746: 
                   1747:     pPosition->SampleCount =
                   1748:         (pPosition->ByteCount << 3) /
                   1749:             (WaveInfo->BitsPerSample * WaveInfo->Channels);
                   1750: 
                   1751:     return status;
                   1752: }
                   1753: 
                   1754: 
                   1755: /**************************************************************************
                   1756:  *
                   1757:  *    Starting and stopping DMA
                   1758:  *
                   1759:  **************************************************************************/
                   1760: 
                   1761: BOOLEAN
                   1762: SoundMapDMA(
                   1763:     IN    PWAVE_INFO WaveInfo
                   1764: )
                   1765: /*++
                   1766: 
                   1767: Routine Description:
                   1768: 
                   1769:     Call IoMapTransfer to start the DMA
                   1770: 
                   1771: Arguments:
                   1772: 
                   1773:     WaveInfo - Wave parameters and state
                   1774: 
                   1775: Return Value:
                   1776: 
                   1777:     None
                   1778: 
                   1779: --*/
                   1780: {
                   1781:     ULONG length;
                   1782: 
                   1783: #if DBG
                   1784:     ULONG LengthRequested;
                   1785: #endif // DBG
                   1786: 
                   1787:     ULONG offset;
                   1788:     int Half;
                   1789: 
                   1790:     Half = 0;
                   1791: 
                   1792:     if (WaveInfo->DMAType == SoundAutoInitDMA) {
                   1793:         length = WaveInfo->DoubleBuffer.BufferSize;
                   1794:         offset = 0;
                   1795:     } else {
                   1796:         length = WaveInfo->DoubleBuffer.BufferSize / 2;
                   1797:         offset = WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? 0 : length;
                   1798:         if (WaveInfo->DMAType == Sound2ChannelDMA) {
                   1799:             Half = WaveInfo->DoubleBuffer.NextHalf;
                   1800:         }
                   1801:     }
                   1802: 
                   1803: #if DBG
                   1804:     LengthRequested = length;
                   1805: #endif // DBG
                   1806: 
                   1807:     dprintf4(("Calling IoMapTransfer"));
                   1808:     IoMapTransfer(WaveInfo->DMABuf.AdapterObject[Half],
                   1809:                   WaveInfo->DMABuf.Mdl,
                   1810:                   WaveInfo->MRB[Half],
                   1811:                   (PUCHAR)MmGetMdlVirtualAddress(WaveInfo->DMABuf.Mdl) +
                   1812:                       offset,
                   1813:                   &length,
                   1814:                   WaveInfo->Direction);
                   1815:                                 // Direction
                   1816: 
                   1817:     ASSERTMSG("Incorrect length mapped by IoMapTransfer",
                   1818:               length == LengthRequested);
                   1819:     //
                   1820:     // Now program the card to begin the transfer.
                   1821:     // Note that this must be synchronized with the isr so
                   1822:     // that we don't start taking interrupts prematurely
                   1823:     //
                   1824: 
                   1825:     dprintf4(("Calling (sync) HwSetupDMA"));
                   1826: 
                   1827:     //
                   1828:     // Prepare the hardware for running DMA
                   1829:     //
                   1830: 
                   1831:     (*WaveInfo->HwSetupDMA)(WaveInfo);
                   1832: 
                   1833:     return TRUE;
                   1834: }
                   1835: 
                   1836: 
                   1837: BOOLEAN
                   1838: SoundFlushDMA(
                   1839:     IN    PWAVE_INFO WaveInfo
                   1840: )
                   1841: /*++
                   1842: 
                   1843: Routine Description:
                   1844: 
                   1845:     Call IoMapTransfer to start the DMA
                   1846: 
                   1847: Arguments:
                   1848: 
                   1849:     WaveInfo - Wave parameters and state
                   1850: 
                   1851: Return Value:
                   1852: 
                   1853:     None
                   1854: 
                   1855: --*/
                   1856: {
                   1857:     ULONG length;
                   1858:     ULONG offset;
                   1859:     int Half;
                   1860: 
                   1861:     Half = 0;
                   1862: 
                   1863:     if (WaveInfo->DMAType == SoundAutoInitDMA) {
                   1864:         length = WaveInfo->DoubleBuffer.BufferSize;
                   1865:         offset = 0;
                   1866:     } else {
                   1867:         length = WaveInfo->DoubleBuffer.BufferSize / 2;
                   1868:         offset = WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? 0 : length;
                   1869:         if (WaveInfo->DMAType == Sound2ChannelDMA) {
                   1870:             Half = WaveInfo->DoubleBuffer.NextHalf;
                   1871:         }
                   1872:     }
                   1873: 
                   1874:     //
                   1875:     // IoFlushAdapterBuffers masks off the DMA amongst other things
                   1876:     //
                   1877: 
                   1878:     IoFlushAdapterBuffers(WaveInfo->DMABuf.AdapterObject[Half],
                   1879:                           WaveInfo->DMABuf.Mdl,
                   1880:                           WaveInfo->MRB[Half],
                   1881:                          (PUCHAR)MmGetMdlVirtualAddress(WaveInfo->DMABuf.Mdl) +
                   1882:                              offset,
                   1883:                           length,
                   1884:                           WaveInfo->Direction);
                   1885:                                     // Direction
                   1886:     return TRUE;
                   1887: }
                   1888: 
                   1889: VOID
                   1890: SoundTestDeviceDeferred(
                   1891:     IN    PKDPC Dpc,
                   1892:     IN    PVOID Context,
                   1893:     IN    PVOID Param1,
                   1894:     IN    PVOID Param2
                   1895: )
                   1896: /*++
                   1897: 
                   1898: Routine Description:
                   1899: 
                   1900:     Tests if our kernel device is still active
                   1901: 
                   1902: Arguments:
                   1903: 
                   1904:     Dpc - Our DPC object
                   1905:     Context - our wave info structure
                   1906:     Param1 - not used - system time
                   1907:     Param2 - not used - system time
                   1908: 
                   1909: Return Value:
                   1910: 
                   1911:     None
                   1912: 
                   1913: --*/
                   1914: {
                   1915:     PWAVE_INFO WaveInfo;
                   1916:     KIRQL OldIrql;
                   1917: 
                   1918: 
                   1919:     WaveInfo = (PWAVE_INFO)Context;
                   1920: 
                   1921:     DMAEnter(WaveInfo);
                   1922: 
                   1923:     if (WaveInfo->DMABusy) {
                   1924: 
                   1925:         if (!WaveInfo->GotWaveDpc) {
                   1926: 
                   1927:             //
                   1928:             // We're broken
                   1929:             //
                   1930: 
                   1931:             dprintf2(("No interrupt from Wave device for 3 seconds! - cancelling IO"));
                   1932:             dprintf2(("Device was wave %s", WaveInfo->Direction ? "output" : "input"));
                   1933: 
                   1934:             if (WaveInfo->FailureCount++ == 30 ) {
                   1935:                 dprintf1(("Device has failed 30 times in a row - mark it as bad"));
                   1936:                 WaveInfo->DeviceBad = TRUE;
                   1937:             }
                   1938: 
                   1939:             //
                   1940:             // But we might be able to start up again!  so clean up our
                   1941:             // state
                   1942:             //
                   1943: 
                   1944:             WaveInfo->TimerActive = FALSE;
                   1945:             WaveInfo->DMABusy = FALSE;
                   1946: 
                   1947:             SoundTerminateDMA(WaveInfo, FALSE);
                   1948: 
                   1949:             //
                   1950:             // Free any outstanding IO - all future requests will be
                   1951:             // denied
                   1952:             //
                   1953: 
                   1954:             if (WaveInfo->Direction) {
                   1955:                 SoundResetOutput(&WaveInfo->BufferQueue);
                   1956:             } else {
                   1957: 
                   1958:                 //
                   1959:                 // We ensure in SoundFillInputBuffers that there are no
                   1960:                 // part-filled buffers for input
                   1961:                 //
                   1962: 
                   1963:                 SoundFreeQ(&WaveInfo->BufferQueue.QueueHead, STATUS_CANCELLED);
                   1964: 
                   1965:                 ((PLOCAL_DEVICE_INFO)
                   1966:                     WaveInfo->DeviceObject->DeviceExtension)->State = WAVE_DD_STOPPED;
                   1967:             }
                   1968: 
                   1969: 
                   1970:         } else {
                   1971:             //
                   1972:             // Start our timer off again
                   1973:             //
                   1974: 
                   1975:             WaveInfo->GotWaveDpc = FALSE;
                   1976: 
                   1977:             KeInitializeDpc(&WaveInfo->TimerDpc,
                   1978:                             SoundTestDeviceDeferred,
                   1979:                             (PVOID)WaveInfo);
                   1980: 
                   1981:             //
                   1982:             // Wait for 3 seconds (in 100 ns units)
                   1983:             //
                   1984: 
                   1985:             KeSetTimer(&WaveInfo->DeviceCheckTimer,
                   1986:                        RtlConvertLongToLargeInteger(-30000000),
                   1987:                        &WaveInfo->TimerDpc);
                   1988:         }
                   1989:     } else {
                   1990: 
                   1991:         //
                   1992:         // Timers dropped off end
                   1993:         //
                   1994: 
                   1995:         WaveInfo->TimerActive = FALSE;
                   1996:     }
                   1997: 
                   1998:     KeSetEvent(&WaveInfo->TimerDpcEvent, 0, FALSE);
                   1999: 
                   2000:     DMALeave(WaveInfo);
                   2001: }
                   2002: 
                   2003: 
                   2004: VOID
                   2005: SoundSynchTimer(
                   2006:     IN    PWAVE_INFO WaveInfo
                   2007: )
                   2008: /*++
                   2009: 
                   2010: Routine Description:
                   2011: 
                   2012:     Kill any timer running 'device alive' timer
                   2013: 
                   2014: Arguments:
                   2015: 
                   2016:     WaveInfo - Wave parameters and state
                   2017: 
                   2018: Return Value:
                   2019: 
                   2020:     None
                   2021: 
                   2022: --*/
                   2023: {
                   2024: 
                   2025:     BOOLEAN Wait;
                   2026: 
                   2027:     Wait = FALSE;
                   2028: 
                   2029:     DMAEnter(WaveInfo);
                   2030: 
                   2031:     //
                   2032:     // 2 cases
                   2033:     //
                   2034:     //   1. TimerActive = FALSE - no timer is set, no Dpc routine is
                   2035:     //      queued or about to be queued
                   2036:     //
                   2037:     //   2. TimerActive = TRUE ...
                   2038:     //
                   2039:     // NB TimerActive is synchronized via this spin lock
                   2040:     //
                   2041: 
                   2042:     if (WaveInfo->TimerActive) {
                   2043: 
                   2044:         //
                   2045:         // 2 cases :
                   2046:         //
                   2047:         //   1. Timer set - in this case killing the timer does it
                   2048:         //
                   2049:         //   2. Timer not set - dpc on queue or running but not
                   2050:         //      yet entered device spin lock.  Just reset the event
                   2051:         //      so we can wait for it.
                   2052:         //
                   2053: 
                   2054:         if (!KeCancelTimer(&WaveInfo->DeviceCheckTimer)) {
                   2055: 
                   2056:             Wait = TRUE;
                   2057:             KeResetEvent(&WaveInfo->TimerDpcEvent);
                   2058:         }
                   2059: 
                   2060:         WaveInfo->TimerActive = FALSE;
                   2061:     }
                   2062: 
                   2063:     DMALeave(WaveInfo);
                   2064: 
                   2065:     if (Wait) {
                   2066:         KeWaitForSingleObject(&WaveInfo->TimerDpcEvent,
                   2067:                               Executive,
                   2068:                               KernelMode,
                   2069:                               FALSE,
                   2070:                               NULL);
                   2071:     }
                   2072: 
                   2073:     ASSERTMSG("Timer synch failed", WaveInfo->TimerActive == FALSE);
                   2074: }
                   2075: 
                   2076: 
                   2077: 
                   2078: VOID
                   2079: SoundStartDMA(
                   2080:     IN    PWAVE_INFO WaveInfo
                   2081: )
                   2082: /*++
                   2083: 
                   2084: Routine Description:
                   2085: 
                   2086:     Set up the DMA by calling IoAllocateAdapterChannel
                   2087: 
                   2088: Arguments:
                   2089: 
                   2090:     WaveInfo - Wave parameters and state
                   2091: 
                   2092: Return Value:
                   2093: 
                   2094:     None
                   2095: 
                   2096: --*/
                   2097: {
                   2098:     KIRQL OldIrql;
                   2099: 
                   2100:     //
                   2101:     // Check that DMA is not already running
                   2102:     //
                   2103: 
                   2104:     //
                   2105:     // Set DMABusy early so that the Hardware routines etc know we're
                   2106:     // getting things going
                   2107:     //
                   2108: 
                   2109:     WaveInfo->DMABusy = TRUE;
                   2110: 
                   2111: 
                   2112:     //
                   2113:     // The following is not necessary because we allocated non-cached
                   2114:     // memory for our common buffer
                   2115:     //
                   2116:     // KeFlushIoBuffers(pGDI->pDMABufferMDL,
                   2117:     //                 pGDI->Usage == SBInterruptUsageWaveIn,
                   2118:     //                 TRUE);
                   2119: 
                   2120:     //
                   2121:     // Be prepared to wait
                   2122:     //
                   2123: 
                   2124:     KeInitializeEvent(&WaveInfo->DmaSetupEvent,
                   2125:                       SynchronizationEvent,
                   2126:                       FALSE);
                   2127: 
                   2128: 
                   2129:     //
                   2130:     // Allocate an adapter channel.  When the system allocates
                   2131:     // the channel, processing will continue in the SoundProgramDMA
                   2132:     // routine below.
                   2133:     //
                   2134: 
                   2135:     dprintf3(("Allocating adapter channel"));
                   2136: 
                   2137:     OldIrql = KeGetCurrentIrql();
                   2138:     if (OldIrql != DISPATCH_LEVEL) {
                   2139:         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
                   2140:     }
                   2141:     IoAllocateAdapterChannel(WaveInfo->DMABuf.AdapterObject[0],
                   2142:                              WaveInfo->DeviceObject,
                   2143:                              BYTES_TO_PAGES(WaveInfo->DMABuf.BufferSize),
                   2144:                              SoundProgramDMA,
                   2145:                              (PVOID)WaveInfo);
                   2146:     if (OldIrql != DISPATCH_LEVEL) {
                   2147:         KeLowerIrql(OldIrql);
                   2148:     }
                   2149: 
                   2150:     //
                   2151:     // Execution will continue in SoundProgramDMA when the
                   2152:     // adapter has been allocated
                   2153:     //
                   2154: 
                   2155:     //
                   2156:     // Wait for it to complete
                   2157:     //
                   2158: 
                   2159:     KeWaitForSingleObject(&WaveInfo->DmaSetupEvent,
                   2160:                           Executive,
                   2161:                           KernelMode,
                   2162:                           FALSE,
                   2163:                           NULL);
                   2164:     //
                   2165:     // Set up our timer to check the device is alive occasionally
                   2166:     // (if we're not just restarting DMA)
                   2167: 
                   2168:     if (OldIrql != DISPATCH_LEVEL) {
                   2169: 
                   2170:         KeInitializeEvent(&WaveInfo->TimerDpcEvent,
                   2171:                           SynchronizationEvent,
                   2172:                           FALSE);
                   2173: 
                   2174:         WaveInfo->TimerActive = TRUE;
                   2175:         WaveInfo->GotWaveDpc = TRUE;  // Get through first time OK
                   2176:         SoundTestDeviceDeferred(NULL, (PVOID)WaveInfo, NULL, NULL);
                   2177: 
                   2178:     }
                   2179: 
                   2180:     //
                   2181:     // Program the DMA controller registers for the transfer
                   2182:     // Set the direction of transfer by whether we're wave in or
                   2183:     // wave out.
                   2184:     //
                   2185: 
                   2186:     SoundMapDMA(WaveInfo);
                   2187: 
                   2188: }
                   2189: 
                   2190: 
                   2191: 
                   2192: IO_ALLOCATION_ACTION
                   2193: SoundProgramDMA(
                   2194:     IN    PDEVICE_OBJECT pDO,
                   2195:     IN    PIRP pIrp,
                   2196:     IN    PVOID pMRB,
                   2197:     IN    PVOID Context
                   2198: )
                   2199: /*++
                   2200: 
                   2201: Routine Description:
                   2202: 
                   2203:     This routine is executed when an adapter channel is allocated
                   2204:     for our DMA needs.  It saves away the MRB (mapping register
                   2205:     base which has been extracted from the adapter object) and
                   2206:     sets the event which SoundStartDMA is waiting on.
                   2207: 
                   2208: Arguments:
                   2209: 
                   2210:     pDO     - Device object
                   2211:     pIrp    - IO request packet
                   2212:     pMRB    - Map register base of registers allocated by adapter
                   2213:     Context - Pointer to our device global data
                   2214: 
                   2215: 
                   2216: Return Value:
                   2217: 
                   2218:     Tell the system what to do with the adapter object
                   2219: 
                   2220: --*/
                   2221: {
                   2222:     PWAVE_INFO WaveInfo;
                   2223: 
                   2224:     WaveInfo =  (PWAVE_INFO) Context;
                   2225: 
                   2226:     ASSERT(WaveInfo->Key == WAVE_INFO_KEY);
                   2227: 
                   2228:     WaveInfo->MRB[0] = pMRB;// Remember our map register base
                   2229: 
                   2230: 
                   2231:     //
                   2232:     // Tell the caller it's time to go!
                   2233:     //
                   2234: 
                   2235:     KeSetEvent(&WaveInfo->DmaSetupEvent, 0, FALSE);
                   2236: 
                   2237:     //
                   2238:     // return a value that says we want to keep the channel
                   2239:     // and map registers.
                   2240:     //
                   2241: 
                   2242:     return KeepObject;
                   2243: }
                   2244: 
                   2245: 
                   2246: VOID
                   2247: SoundAppendList(
                   2248:     PLIST_ENTRY QueueHead,
                   2249:     PLIST_ENTRY ListToAppend
                   2250: )
                   2251: /*++
                   2252: 
                   2253: Routine Description:
                   2254: 
                   2255:     Append a list of Irps to the head of a cancellable list
                   2256:     The list itself is emptied.
                   2257: 
                   2258:     NOTE: Irps involved in these operations could be cancelled and
                   2259:           and freed from the cancellable list while this is going on.
                   2260:           This is OK.
                   2261: 
                   2262: Arguments:
                   2263: 
                   2264:     QueueHead    - The cancellable queue to be appended to
                   2265:     ListToAppend - The list to be appended
                   2266: 
                   2267: Return Value:
                   2268: 
                   2269:     Note
                   2270: 
                   2271: --*/
                   2272: {
                   2273:     while (!IsListEmpty(ListToAppend)) {
                   2274:         PLIST_ENTRY ListEntry;
                   2275:         PIRP Irp;
                   2276: 
                   2277:         //
                   2278:         // Remove Irp from tail of queue and put it at
                   2279:         // head of input queue, making it cancellable
                   2280:         // at the same time
                   2281:         //
                   2282: 
                   2283:         ListEntry = RemoveTailList(ListToAppend);
                   2284: 
                   2285: 
                   2286:         Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
                   2287: 
                   2288:         SoundAddIrpToCancellableQ(QueueHead,
                   2289:                                   Irp,
                   2290:                                   TRUE);
                   2291:     }
                   2292: }
                   2293: 
                   2294: 
                   2295: VOID
                   2296: SoundFreeWaveOutputBuffers(
                   2297:     PLIST_ENTRY Queue,
                   2298:     ULONG BytesProcessed
                   2299: )
                   2300: /*++
                   2301: 
                   2302: Routine Description:
                   2303: 
                   2304:     This routine frees entries from the queue until all the bytes are
                   2305:     used.  If the last entry is not entirely used up then its
                   2306:     IoStatus.Information is bumped by the residual bytes.
                   2307: 
                   2308: 
                   2309: Arguments:
                   2310: 
                   2311: 
                   2312: Return Value:
                   2313: 
                   2314: 
                   2315: --*/
                   2316: {
                   2317:     while (BytesProcessed != 0) {
                   2318:         PIRP Irp;
                   2319:         ULONG BytesInEntry;
                   2320: 
                   2321:         //
                   2322:         // We should NEVER exhaust the queue
                   2323:         //
                   2324: 
                   2325:         ASSERT(!IsListEmpty(Queue));
                   2326: 
                   2327:         Irp = CONTAINING_RECORD(Queue->Flink, IRP, Tail.Overlay.ListEntry);
                   2328: 
                   2329:         //
                   2330:         // The Information field in the Irp records where we have completed
                   2331:         // to up until now
                   2332:         //
                   2333: 
                   2334:         BytesInEntry =
                   2335:             IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length -
                   2336:             Irp->IoStatus.Information;
                   2337: 
                   2338:         if (BytesInEntry > BytesProcessed) {
                   2339:             Irp->IoStatus.Information += BytesProcessed;
                   2340:             BytesProcessed = 0;
                   2341:         } else {
                   2342:             //
                   2343:             // Free this entry
                   2344:             //
                   2345: 
                   2346:             RemoveHeadList(Queue);
                   2347: 
                   2348:             Irp->IoStatus.Information += BytesInEntry;
                   2349: 
                   2350:             ASSERT(Irp->IoStatus.Information ==
                   2351:                    IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length);
                   2352: 
                   2353:             Irp->IoStatus.Status = STATUS_SUCCESS;
                   2354: 
                   2355:             IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
                   2356: 
                   2357:             BytesProcessed -= BytesInEntry;
                   2358:         }
                   2359:     }
                   2360: }
                   2361: 
                   2362: VOID
                   2363: SoundTerminateDMA(
                   2364:     IN    PWAVE_INFO WaveInfo,
                   2365:     IN    BOOLEAN Pause
                   2366: )
                   2367: /*++
                   2368: 
                   2369: Routine Description:
                   2370: 
                   2371:     Stop the DMA at once by passing HALT to the DSP.
                   2372:     Free the adapter channel.
                   2373:     (Opposite of SoundStartDMA).
                   2374: 
                   2375: Arguments:
                   2376: 
                   2377:     WaveInfo - pointer to wave parameters and data
                   2378: 
                   2379: Return Value:
                   2380: 
                   2381:     None
                   2382: 
                   2383: --*/
                   2384: {
                   2385:     ULONG HalfBufferPosition;  // How far we're into current buffer
                   2386:     KIRQL OldIrql;
                   2387:     struct SOUND_DMABUF *DmaBuf;
                   2388: 
                   2389:     DmaBuf = &WaveInfo->DoubleBuffer.Buffer
                   2390:                   [WaveInfo->DoubleBuffer.NextHalf];
                   2391: 
                   2392: 
                   2393:     //
                   2394:     // Quiesce the hardware - do this before getting the buffer position
                   2395:     // so we get an accurate reading.
                   2396:     //
                   2397: 
                   2398:     (*WaveInfo->HwStopDMA)(WaveInfo);
                   2399: 
                   2400:     //
                   2401:     // Adjust our position before we stop the DMA
                   2402:     //
                   2403: 
                   2404:     HalfBufferPosition = SoundGetHalfBufferPosition(WaveInfo);
                   2405:     ASSERT(HalfBufferPosition <= DmaBuf->Size);
                   2406: 
                   2407:     //
                   2408:     // For input work out how many more bytes we have for the user.
                   2409:     //
                   2410: 
                   2411:     if (!WaveInfo->Direction) {
                   2412:          //
                   2413:          // For input the 'nBytes' field means the number of bytes
                   2414:          // already processed from the buffer - Size - nBytes is the
                   2415:          // number of bytes still available
                   2416:          //
                   2417: 
                   2418:          DmaBuf->nBytes =  DmaBuf->Size - HalfBufferPosition;
                   2419: 
                   2420:          //
                   2421:          // Move the bytes we have to where they will be found by
                   2422:          // SoundFillInputBuffers which will update BytesProcessed if
                   2423:          // there are buffers to fill.
                   2424:          //
                   2425: 
                   2426:          RtlMoveMemory(DmaBuf->Buf + DmaBuf->nBytes,  DmaBuf->Buf,
                   2427:                  HalfBufferPosition);
                   2428:     } else {
                   2429: 
                   2430: 
                   2431:          // We could simplify things here by using the hardware pause
                   2432:          // in the device at the expense of introducing an extra state
                   2433:          //
                   2434: 
                   2435:          if (Pause) {
                   2436:              //
                   2437:              // Complete any buffers which may now be complete
                   2438:              //
                   2439: 
                   2440:              SoundFreeWaveOutputBuffers(&WaveInfo->BufferQueue.ProgressQueue,
                   2441:                                         HalfBufferPosition);
                   2442: 
                   2443:              //
                   2444:              // Update the position
                   2445:              //
                   2446: 
                   2447:              WaveInfo->BufferQueue.BytesProcessed += HalfBufferPosition;
                   2448: 
                   2449:              //
                   2450:              // Tidy up partially completed input buffer.  We don't
                   2451:              // need to remember where we are here because we know
                   2452:              // at the other end where the DMA buffers start.
                   2453:              //
                   2454: 
                   2455:              SoundCompleteIoBuffer(&WaveInfo->BufferQueue);
                   2456: 
                   2457:              //
                   2458:              // Roll everything back into the input queue so we can
                   2459:              // support cancel of a paused state properly.
                   2460:              //
                   2461: 
                   2462:              SoundAppendList(&WaveInfo->BufferQueue.QueueHead,
                   2463:                              &WaveInfo->BufferQueue.ProgressQueue);
                   2464: 
                   2465:          }
                   2466: 
                   2467:          WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes = 0;
                   2468:          WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes = 0;
                   2469: 
                   2470:          //
                   2471:          // In either case we must be set up to restart DMA from the
                   2472:          // start of the lower half of the buffer next time
                   2473:          //
                   2474: 
                   2475:          WaveInfo->DoubleBuffer.NextHalf = LowerHalf;
                   2476: 
                   2477:     }
                   2478: 
                   2479:     SoundFlushDMA(WaveInfo);
                   2480: 
                   2481:     //
                   2482:     // Free the adapter channel
                   2483:     //
                   2484: 
                   2485:     {
                   2486:         KIRQL OldIrql;
                   2487:         OldIrql = KeGetCurrentIrql();
                   2488:         if (OldIrql != DISPATCH_LEVEL) {
                   2489:             KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
                   2490:         }
                   2491:         IoFreeAdapterChannel(WaveInfo->DMABuf.AdapterObject[0]);
                   2492:         if (OldIrql != DISPATCH_LEVEL) {
                   2493:             KeLowerIrql(OldIrql);
                   2494:         }
                   2495:     }
                   2496: }
                   2497: 
                   2498: 
                   2499: VOID
                   2500: SoundStopDMA(
                   2501:     IN    PWAVE_INFO WaveInfo,
                   2502:     IN    BOOLEAN Pause
                   2503: )
                   2504: /*++
                   2505: 
                   2506: Routine Description:
                   2507: 
                   2508:     Stop the DMA at once by passing HALT to the DSP.
                   2509:     Free the adapter channel.
                   2510:     (Opposite of SoundStartDMA).
                   2511: 
                   2512: Arguments:
                   2513: 
                   2514:     WaveInfo - pointer to wave parameters and data
                   2515: 
                   2516: Return Value:
                   2517: 
                   2518:     None
                   2519: 
                   2520: --*/
                   2521: {
                   2522:     BOOLEAN DMABusy;
                   2523: 
                   2524:     //
                   2525:     // Acquire the spin lock so we can synchronize with the Dpc
                   2526:     // routine and correctly test DMABusy etc
                   2527:     //
                   2528: 
                   2529:     DMAEnter(WaveInfo);
                   2530: 
                   2531:     DMABusy = WaveInfo->DMABusy;
                   2532: 
                   2533:     if (DMABusy) {
                   2534: 
                   2535:         //
                   2536:         // Note our new state.  We do this inside the spin lock
                   2537:         // so that if any Dpc routine runs now it knows that it
                   2538:         // should act as a NOOP.
                   2539:         //
                   2540:         // The ISR will not do anything once DMABusy is turned off,
                   2541:         // nor will the Dpc routine.
                   2542:         //
                   2543: 
                   2544:         WaveInfo->DMABusy = FALSE;
                   2545:         WaveInfo->Overrun = FALSE;
                   2546: 
                   2547:         //
                   2548:         // At this stage we know :
                   2549:         //    1. We won't get (or act on) any more interrupts
                   2550:         //    2. Nobody can start any more DMA because we hold the
                   2551:         //       common wave input and output mutants
                   2552:         //    3. If a Dpc routine runs it will NOOP because DMABusy is FALSE
                   2553:         //
                   2554: 
                   2555:     }
                   2556: 
                   2557:     //
                   2558:     // Have a stab at stopping our timer
                   2559:     //
                   2560: 
                   2561:     if (KeCancelTimer(&WaveInfo->DeviceCheckTimer)) {
                   2562: 
                   2563:         //
                   2564:         // Update the state - otherwise SoundSynchTimer will
                   2565:         // hang waiting for non-existent timers
                   2566:         //
                   2567: 
                   2568:         WaveInfo->TimerActive = FALSE;
                   2569:     }
                   2570: 
                   2571: 
                   2572:     DMALeave(WaveInfo);
                   2573: 
                   2574: 
                   2575:     if (DMABusy) {
                   2576: 
                   2577:         SoundTerminateDMA(WaveInfo, Pause);
                   2578:     }
                   2579: 
                   2580:     //
                   2581:     // Make sure no more Dpc routines are about to run!
                   2582:     //
                   2583: 
                   2584:     KeResetEvent(&WaveInfo->DpcEvent);
                   2585: 
                   2586:     //
                   2587:     // The Dpc routine clears DpcQueued just before setting this event
                   2588:     // so if it's set then the event will certainly be set.
                   2589:     //
                   2590:     // Note that there's no need to syncrhorinze with the ISR here
                   2591:     // because we NOOPed interrupts when we cleared DMABusy above.
                   2592:     //
                   2593: 
                   2594:     if (WaveInfo->DpcQueued) {
                   2595: 
                   2596:         dprintf2(("Waiting for Dpc routine to finish"));
                   2597:         KeWaitForSingleObject(&WaveInfo->DpcEvent,
                   2598:                               Executive,
                   2599:                               KernelMode,
                   2600:                               FALSE,               // Not alertable
                   2601:                               NULL);
                   2602:     }
                   2603: }
                   2604: 
                   2605: 
                   2606: /***************************************************************************
                   2607:  *
                   2608:  *    Dpc routine and support code
                   2609:  *
                   2610:  ***************************************************************************/
                   2611: 
                   2612: VOID
                   2613: SoundOutDeferred(
                   2614:     PWAVE_INFO WaveInfo
                   2615: )
                   2616: /*++
                   2617: 
                   2618: Routine Description:
                   2619: 
                   2620:     Deferred procedure call routine for wave output interrupts.
                   2621: 
                   2622:     The basic job is just to move to the next buffer which consists of
                   2623: 
                   2624:        -- Completing Irps that made up the buffer just played (in ProgressQueue)
                   2625: 
                   2626:        -- Filling up the next buffer
                   2627: 
                   2628:     However, if the buffer which is about to play is empty we can deduce
                   2629:     that there isn't anything to play - either output was stopped by a
                   2630:     WAVE_DD_STOP or no buffers have arrived (otherwise data would
                   2631:     have already been moved into the buffer which is about to play).
                   2632: 
                   2633:     In this case we
                   2634: 
                   2635:        -- Stop the DMA
                   2636: 
                   2637:        -- Complete any pause packet
                   2638: 
                   2639:        -- Set our new state (WAVE_DD_IDLE if not currently WAVE_DD_STOPPED).
                   2640: 
                   2641: Arguments:
                   2642: 
                   2643:     WaveInfo - Data associated with wave input/output
                   2644: 
                   2645: Return Value:
                   2646: 
                   2647:     TRUE if DMA is to be halted
                   2648: 
                   2649: --*/
                   2650: {
                   2651:     ULONG BytesProcessed;
                   2652: 
                   2653:     ASSERTMSG("SoundOutDeferred called when DMA not busy!",
                   2654:               WaveInfo->DMABusy);
                   2655: 
                   2656:     //
                   2657:     // Flush the DMA unless we're doing autoinit
                   2658:     //
                   2659:     if (WaveInfo->DMAType != SoundAutoInitDMA) {
                   2660:         SoundFlushDMA(WaveInfo);
                   2661:     }
                   2662: 
                   2663:     //
                   2664:     // Get number of bytes just done (note the buffer may not have
                   2665:     // been full) and empty the buffer.
                   2666:     //
                   2667: 
                   2668:     BytesProcessed =
                   2669:         WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes;
                   2670: 
                   2671:     WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes = 0;
                   2672: 
                   2673:     //
                   2674:     // Kill everything on the dead queue
                   2675:     // move the transit queue to the dead queue
                   2676:     // and reinitialize the transit queue ready to receive
                   2677:     // data from the queue of new buffers
                   2678:     //
                   2679: 
                   2680:     SoundFreeWaveOutputBuffers(&WaveInfo->BufferQueue.ProgressQueue,
                   2681:                                BytesProcessed);
                   2682: 
                   2683:     //
                   2684:     // The block we've just done is now empty, ready for reuse
                   2685:     // Update the number of bytes processed, then free it
                   2686:     //
                   2687: 
                   2688:     WaveInfo->BufferQueue.BytesProcessed += BytesProcessed;
                   2689: 
                   2690:     //
                   2691:     // See if we were doing the last block.
                   2692:     //
                   2693: 
                   2694:     if (WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf -
                   2695:                    WaveInfo->DoubleBuffer.NextHalf].nBytes == 0) {
                   2696: 
                   2697:         dprintf4(("end_last"));
                   2698: 
                   2699:         //
                   2700:         // It's possible that a request was queued during the last block
                   2701:         // but that would have caused the LastBlock flag to have been
                   2702:         // cleared if there were any data, unless we're STOPPED.
                   2703:         // If a restart occurred after a stop the silence would
                   2704:         // have been filled out.
                   2705:         //
                   2706:         //
                   2707:         // However, with 0 length buffers possible the dead queue
                   2708:         // can be non-empty even though the next buffer has nothing
                   2709:         // to play in it.
                   2710:         //
                   2711: 
                   2712:         //ASSERT(IsListEmpty(&WaveInfo->BufferQueue.QueueHead) ||
                   2713:         //       ((PLOCAL_DEVICE_INFO)WaveInfo->DeviceObject->
                   2714:         //        DeviceExtension)->State == WAVE_DD_STOPPED);
                   2715: 
                   2716:         if (!IsListEmpty(&WaveInfo->BufferQueue.ProgressQueue)) {
                   2717: 
                   2718:             //
                   2719:             // Note that it should not be possible for there to be
                   2720:             // a half complete buffer lying around.  If we're paused
                   2721:             // that buffer would have been moved back to the
                   2722:             // input queue.
                   2723: 
                   2724:             ASSERTMSG("Unexpected incomplete buffer",
                   2725:                       WaveInfo->BufferQueue.UserBuffer == NULL);
                   2726: 
                   2727:             dprintf1(("Empty buffers being freed at end of playing"));
                   2728:             SoundFreeQ(&WaveInfo->BufferQueue.ProgressQueue, STATUS_SUCCESS);
                   2729:         }
                   2730: 
                   2731:         WaveInfo->DMABusy = FALSE;
                   2732: 
                   2733:         SoundTerminateDMA(WaveInfo, FALSE);  // Stop DMA
                   2734: 
                   2735: 
                   2736:     } else {
                   2737:         WaveInfo->DoubleBuffer.NextHalf =
                   2738:             LowerHalf + UpperHalf - WaveInfo->DoubleBuffer.NextHalf;
                   2739: 
                   2740:         //
                   2741:         // If we're not doing auto-initialize re-start the DMA
                   2742:         //
                   2743: 
                   2744:         if (WaveInfo->DMAType != SoundAutoInitDMA) {
                   2745:             SoundMapDMA(WaveInfo);
                   2746:         }
                   2747: 
                   2748:         //
                   2749:         // That was the end of a normal block.
                   2750:         // Try to load the next half of the dma buffer.
                   2751:         // If this is the tail of the request, the load routine
                   2752:         // will pad it out with silence so we get a full block.
                   2753:         //
                   2754: 
                   2755:         if (((PLOCAL_DEVICE_INFO)WaveInfo->DeviceObject->
                   2756:                DeviceExtension)->State != WAVE_DD_STOPPED) {
                   2757:             SoundLoadDMABuffer(
                   2758:                 &WaveInfo->BufferQueue,
                   2759:                 &WaveInfo->DoubleBuffer.Buffer[
                   2760:                     UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf],
                   2761:                 WaveInfo->DoubleBuffer.Pad);
                   2762:         }
                   2763:         return;
                   2764:     }
                   2765: }
                   2766: 
                   2767: 
                   2768: VOID
                   2769: SoundInDeferred(
                   2770:     IN OUT PWAVE_INFO WaveInfo
                   2771: )
                   2772: /*++
                   2773: 
                   2774: Routine Description:
                   2775: 
                   2776:     Dpc routine for wave input device
                   2777: 
                   2778:     Collect the data from the DMA buffer and pass it to the application's
                   2779:     buffer(s).
                   2780: 
                   2781: Arguments:
                   2782: 
                   2783:     WaveInfo - wave data structure
                   2784: 
                   2785: 
                   2786: Return Value:
                   2787: 
                   2788:     None.
                   2789: 
                   2790: --*/
                   2791: {
                   2792:     //
                   2793:     // Fill in any buffers we can
                   2794:     //
                   2795: 
                   2796: 
                   2797:     dprintf4((WaveInfo->DoubleBuffer.NextHalf == LowerHalf ? "L" : "U"));
                   2798: 
                   2799:     //
                   2800:     // Zero bytes taken out of new buffer
                   2801:     //
                   2802: 
                   2803:     WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes = 0;
                   2804: 
                   2805:     //
                   2806:     // Move on to next buffer
                   2807:     //
                   2808: 
                   2809:     WaveInfo->DoubleBuffer.NextHalf =
                   2810:         UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf;
                   2811: 
                   2812:     //
                   2813:     // If we're not doing auto-initialize re-start the DMA
                   2814:     //
                   2815: 
                   2816:     if (WaveInfo->DMAType != SoundAutoInitDMA) {
                   2817:         SoundMapDMA(WaveInfo);
                   2818:     }
                   2819: 
                   2820:     //
                   2821:     // Request input without posting the last buffer
                   2822:     //
                   2823: 
                   2824:     SoundFillInputBuffers(WaveInfo);
                   2825: 
                   2826: 
                   2827:     return;
                   2828: }
                   2829: 
                   2830: 
                   2831: BOOLEAN
                   2832: SoundSignalDpcEnd(
                   2833:     PVOID Context
                   2834: )
                   2835: {
                   2836:     PWAVE_INFO WaveInfo;
                   2837: 
                   2838:     WaveInfo = (PWAVE_INFO)Context;
                   2839:     WaveInfo->DpcQueued = FALSE;
                   2840: 
                   2841:     return TRUE;
                   2842: }
                   2843: 
                   2844: 
                   2845: BOOLEAN
                   2846: SoundAdjustHalf(
                   2847:     PVOID Context
                   2848: )
                   2849: {
                   2850:     PWAVE_INFO WaveInfo;
                   2851: 
                   2852:     WaveInfo = (PWAVE_INFO)Context;
                   2853: 
                   2854:     //
                   2855:     // Caller MUST have spin lock
                   2856:     //
                   2857: 
                   2858:     ASSERTMSG("Can't adjust half without spin lock", WaveInfo->LockHeld);
                   2859: 
                   2860:     if (FALSE /* WaveInfo->Overrun != 0 */) {
                   2861:         //
                   2862:         // Make sure we look at the half that the latest interrupt
                   2863:         // processed
                   2864:         //
                   2865:         if (WaveInfo->Overrun & 1) {
                   2866:             WaveInfo->DoubleBuffer.NextHalf =
                   2867:                 UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf;
                   2868:         }
                   2869:         //
                   2870:         // If we're adrift then free the buffers
                   2871:         //
                   2872:         WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes =
                   2873:             WaveInfo->Direction ?
                   2874:                 0 :
                   2875:                  WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size;
                   2876:         WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes =
                   2877:             WaveInfo->Direction ?
                   2878:                 0 :
                   2879:                  WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size;
                   2880:     }
                   2881: 
                   2882:     return TRUE;
                   2883: }
                   2884: 
                   2885: 
                   2886: VOID
                   2887: SoundWaveDeferred(
                   2888:     PKDPC pDpc,
                   2889:     PDEVICE_OBJECT pDeviceObject,
                   2890:     PIRP pIrp,
                   2891:     PVOID Context
                   2892: )
                   2893: /*++
                   2894: 
                   2895: Routine Description:
                   2896: 
                   2897:     Deferred procedure call routine for wave output interrupts.
                   2898: 
                   2899:     The job is to call the appropriate wave input or output
                   2900:     Dpc routine under the spin lock if DMA is still busy.
                   2901: 
                   2902:     The Dpc complete event is then signalled in case we're waiting
                   2903:     to synchronize on some thread.
                   2904: 
                   2905: Arguments:
                   2906: 
                   2907:     pDPC - pointer to DPC object
                   2908:     pDeviceObject - pointer to our device object
                   2909:     pIrp - ???
                   2910:     Context - our Dpc context (NULL in our case).
                   2911: 
                   2912: Return Value:
                   2913: 
                   2914:     None
                   2915: 
                   2916: --*/
                   2917: {
                   2918:     PWAVE_INFO WaveInfo;
                   2919:     PLOCAL_DEVICE_INFO pLDI;
                   2920:     BOOLEAN StopDMA;
                   2921: 
                   2922:     pLDI = (PLOCAL_DEVICE_INFO)pDeviceObject->DeviceExtension;
                   2923:     ASSERT(pLDI->Key == LDI_WAVE_IN_KEY ||
                   2924:            pLDI->Key == LDI_WAVE_OUT_KEY);
                   2925: 
                   2926:     WaveInfo = (PWAVE_INFO)pLDI->DeviceSpecificData;
                   2927: 
                   2928:     ASSERTMSG("Invalid Wave Info structure in SoundAutoInitDeferred",
                   2929:               WaveInfo->Key == WAVE_INFO_KEY);
                   2930: 
                   2931:     dprintf4(("("));
                   2932: 
                   2933:     //
                   2934:     // Acquire the spin lock before we mess with the list
                   2935:     //
                   2936: 
                   2937:     DMAEnter(WaveInfo);
                   2938: 
                   2939:     //
                   2940:     // Keep the timer check stuff happy
                   2941:     //
                   2942: 
                   2943:     WaveInfo->GotWaveDpc = TRUE;
                   2944:     WaveInfo->FailureCount = 0;
                   2945: 
                   2946:     //
                   2947:     // The Dpc routine only does something if Dma is active.
                   2948:     // This means that if the device is paused, reset etc
                   2949:     // this routine can be disabled by turning off DMABusy
                   2950:     //
                   2951: 
                   2952:     if (WaveInfo->DMABusy) {
                   2953: 
                   2954:         //
                   2955:         // Find out which half we're really in by counting overruns
                   2956:         //
                   2957: 
                   2958:         KeSynchronizeExecution(
                   2959:             WaveInfo->Interrupt,
                   2960:             SoundAdjustHalf,
                   2961:             (PVOID)WaveInfo);
                   2962: 
                   2963:         (WaveInfo->Direction ? SoundOutDeferred : SoundInDeferred)(WaveInfo);
                   2964:     }
                   2965: 
                   2966:     //
                   2967:     // Release the spin lock
                   2968:     //
                   2969: 
                   2970:     DMALeave(WaveInfo);
                   2971: 
                   2972:     //
                   2973:     // Tell the world we've finished.
                   2974:     //
                   2975: 
                   2976:     KeSynchronizeExecution(
                   2977:         WaveInfo->Interrupt,
                   2978:         SoundSignalDpcEnd,
                   2979:         (PVOID)WaveInfo);
                   2980: 
                   2981:     //
                   2982:     // Tell SoundStopDMA that we're really finished
                   2983:     // (Note this MUST be done after calling SoundSignalDpcEnd)
                   2984:     //
                   2985: 
                   2986:     KeSetEvent(&WaveInfo->DpcEvent, 0, FALSE);
                   2987: 
                   2988:     dprintf4((")"));
                   2989: 
                   2990:     return;
                   2991: }
                   2992: 
                   2993: 
                   2994: /************************************************************************
                   2995:  *
                   2996:  *  Routines to handle filling and emptying of the DMA buffer
                   2997:  *
                   2998:  ************************************************************************/
                   2999: 
                   3000: 
                   3001: VOID
                   3002: SoundLoadDMABuffer(
                   3003:     PSOUND_BUFFER_QUEUE BufferQueue,
                   3004:     struct SOUND_DMABUF *pDMA,
                   3005:     UCHAR pad
                   3006: )
                   3007: /*++
                   3008: 
                   3009: Routine Description:
                   3010: 
                   3011:     Fill the given DMA buffer with as much data as is available.
                   3012: 
                   3013:     This is where the supply of bytes is chopped if we're in a
                   3014:     WAVE_DD_STOPPED state.  The supply then dries up and the Dpc routine
                   3015:     stops the DMA (and posts the pause packet).
                   3016: 
                   3017: 
                   3018: Arguments:
                   3019: 
                   3020:     BufferQueue - our stream of application buffers
                   3021:     pDMA - The buffer and how full it is now
                   3022:     pad - 0x80 for 8-bit sound, 0x00 for 16-bit sound
                   3023: 
                   3024: Return Value:
                   3025: 
                   3026: 
                   3027: --*/
                   3028: {
                   3029:     //
                   3030:     // Loop copying data to the output buffers.  Typically the
                   3031:     // output buffer will be much bigger than the DMA buffer.
                   3032:     //
                   3033: 
                   3034:     while (pDMA->nBytes < pDMA->Size) {
                   3035: 
                   3036:         ULONG BytesToCopy;
                   3037: 
                   3038:         //
                   3039:         // We might have completed the last buffer
                   3040:         // Note that we cope with 0 length buffers here
                   3041:         //
                   3042: 
                   3043:         if (BufferQueue->UserBuffer == NULL) {
                   3044:             SoundGetNextBuffer(BufferQueue);
                   3045:             if (BufferQueue->UserBuffer == NULL) {
                   3046: 
                   3047:                 //
                   3048:                 // There REALLY aren't any buffers
                   3049:                 //
                   3050: 
                   3051:                 break;
                   3052:             } else {
                   3053:                 InsertTailList(
                   3054:                     &BufferQueue->ProgressQueue,
                   3055:                     &BufferQueue->pIrp->Tail.Overlay.ListEntry);
                   3056:             }
                   3057:         }
                   3058: 
                   3059:         //
                   3060:         // Find out how much space we have left in the
                   3061:         // client's buffers
                   3062:         //
                   3063:         // Note that BytesToCopy may be 0 - this is OK
                   3064:         //
                   3065: 
                   3066:         BytesToCopy =
                   3067:             min(BufferQueue->UserBufferSize - BufferQueue->UserBufferPosition,
                   3068:                 pDMA->Size - (ULONG)pDMA->nBytes);
                   3069: 
                   3070:         //
                   3071:         // Copy the data
                   3072:         //
                   3073: 
                   3074:         RtlCopyMemory(pDMA->Buf + pDMA->nBytes,
                   3075:                       BufferQueue->UserBuffer + BufferQueue->UserBufferPosition,
                   3076:                       BytesToCopy);
                   3077: 
                   3078:         //
                   3079:         // Update counters etc.
                   3080:         //
                   3081: 
                   3082:         BufferQueue->UserBufferPosition += BytesToCopy;
                   3083:         pDMA->nBytes += BytesToCopy;
                   3084: 
                   3085:         //
                   3086:         // BufferQueue->BytesProcessed will be updated by the
                   3087:         // Dpc routine
                   3088:         //
                   3089: 
                   3090:         //
                   3091:         // See if we've now filled a buffer
                   3092:         //
                   3093: 
                   3094:         if (BufferQueue->UserBufferPosition == BufferQueue->UserBufferSize) {
                   3095: 
                   3096:             dprintf4((" finished"));
                   3097: 
                   3098:             //
                   3099:             // Complete the buffer
                   3100:             //
                   3101: 
                   3102:             SoundCompleteIoBuffer(BufferQueue);
                   3103:         }
                   3104: 
                   3105:     } // Continue around the loop until the request is satisfied
                   3106: 
                   3107:     //
                   3108:     // if we transferred something, pad out the request with
                   3109:     // silence
                   3110:     //
                   3111:     // BUGBUG do the exponential decay thing here
                   3112: 
                   3113:     if (pDMA->nBytes < pDMA->Size) {
                   3114:         dprintf4((" pad"));
                   3115:         RtlFillMemory(pDMA->Buf + pDMA->nBytes,
                   3116:                       pDMA->Size - pDMA->nBytes,
                   3117:                       pad);
                   3118:     }
                   3119: 
                   3120:     //
                   3121:     // flush the i/o buffers
                   3122:     //
                   3123:     // BUGBUG is this right ?  Actually I386 needs none of this
                   3124:     // KeFlushIoBuffers(BufferQueue->pDMABufferMDL, FALSE); // flush for write
                   3125: 
                   3126: }
                   3127: 
                   3128: 
                   3129: 
                   3130: BOOLEAN
                   3131: SoundFillOutputBuffers(
                   3132:     PWAVE_INFO WaveInfo
                   3133: )
                   3134: /*++
                   3135: 
                   3136: Routine Description:
                   3137: 
                   3138:     This routine is called whenever an event occurs which could
                   3139:     output more wave data :
                   3140: 
                   3141:         A new buffer is supplied
                   3142:         The state is changed from stopped to idle
                   3143: 
                   3144:     If wave data is already playing it may still be possible to move
                   3145:     some data into the half buffer which is not playing.
                   3146: 
                   3147:     If no data is playing then both dma half buffers are primed if
                   3148:     possible.  If no data exists to be played this function is
                   3149:     a NOOP except that some 0 length buffers may be completed.
                   3150: 
                   3151: 
                   3152: Arguments:
                   3153: 
                   3154: 
                   3155: Return Value:
                   3156: 
                   3157: 
                   3158: --*/
                   3159: 
                   3160: {
                   3161:     //
                   3162:     // Try to fill up both buffers
                   3163:     //
                   3164: 
                   3165: 
                   3166:     //
                   3167:     // If DMA is running we may be able to pad out some silence to
                   3168:     // stop DMA from dying later.  If not just initiate everything.
                   3169:     //
                   3170: 
                   3171:     //
                   3172:     // Check we have a consistent state
                   3173:     //
                   3174: 
                   3175: #if 0
                   3176:     if (!WaveInfo->DMABusy &&
                   3177:         WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes == 0) {
                   3178: 
                   3179:         ASSERT(IsListEmpty(&WaveInfo->BufferQueue.ProgressQueue));
                   3180:         ASSERT(WaveInfo->DoubleBuffer.NextHalf == LowerHalf);
                   3181:     }
                   3182: #endif
                   3183: 
                   3184:     //
                   3185:     // First try to stoke up the buffer currently being output (or about
                   3186:     // to be started if DMA is not currently running).
                   3187:     //
                   3188: 
                   3189:     if (WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].nBytes <
                   3190:         WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf].Size) {
                   3191: 
                   3192:         //
                   3193:         // Try to stoke up our buffer.  We may also succeed in
                   3194:         // putting data in an empty buffer
                   3195:         //
                   3196: 
                   3197:         SoundLoadDMABuffer(
                   3198:             &WaveInfo->BufferQueue,
                   3199:             &WaveInfo->DoubleBuffer.Buffer[WaveInfo->DoubleBuffer.NextHalf],
                   3200:             WaveInfo->DoubleBuffer.Pad);
                   3201:     }
                   3202: 
                   3203:     //
                   3204:     // Try to fill the second buffer
                   3205:     //
                   3206: 
                   3207:     if (WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf].nBytes <
                   3208:         WaveInfo->DoubleBuffer.Buffer[UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf].Size
                   3209:         ) {
                   3210: 
                   3211:         SoundLoadDMABuffer(
                   3212:             &WaveInfo->BufferQueue,
                   3213:             &WaveInfo->DoubleBuffer.Buffer[
                   3214:                 UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf],
                   3215:             WaveInfo->DoubleBuffer.Pad);
                   3216:     }
                   3217: 
                   3218:     return TRUE;
                   3219: }
                   3220: 
                   3221: 
                   3222: BOOLEAN
                   3223: SoundFillInputBuffers(
                   3224:     PWAVE_INFO WaveInfo
                   3225: )
                   3226: /*++
                   3227: 
                   3228: Routine Description:
                   3229: 
                   3230:     Send input to client
                   3231: 
                   3232:     Take the data from the last recorded position in the DMA
                   3233:     buffer.  The length of the data is passed in.  Try to
                   3234:     insert it into the caller's buffers.  Note that the client gets
                   3235:     no notification if the data is truncated.
                   3236: 
                   3237: Arguments:
                   3238: 
                   3239:     WaveInfo - current wave (input) state
                   3240: 
                   3241: Return Value:
                   3242: 
                   3243:     TRUE if we completed at least one of the user's Irps
                   3244: 
                   3245: --*/
                   3246: 
                   3247: {
                   3248:     BOOLEAN BufferCompleted;
                   3249:     struct SOUND_DMABUF *pDMA;
                   3250:     PSOUND_BUFFER_QUEUE BufferQueue;
                   3251: 
                   3252:     BufferQueue = &WaveInfo->BufferQueue;
                   3253: 
                   3254:     pDMA = &WaveInfo->DoubleBuffer.Buffer[
                   3255:                     UpperHalf + LowerHalf - WaveInfo->DoubleBuffer.NextHalf];
                   3256: 
                   3257:     BufferCompleted = FALSE;
                   3258: 
                   3259:     //
                   3260:     // While there is data and somewhere to put it
                   3261:     //
                   3262: 
                   3263:     while (pDMA->nBytes < pDMA->Size) {
                   3264: 
                   3265:         ULONG BytesToCopy;
                   3266: 
                   3267:         //
                   3268:         // We might have completed the last buffer
                   3269:         // Note that we cope with 0 length buffers here
                   3270:         //
                   3271: 
                   3272:         if (BufferQueue->UserBuffer == NULL) {
                   3273:             SoundGetNextBuffer(BufferQueue);
                   3274: 
                   3275: 
                   3276:             if (BufferQueue->UserBuffer == NULL) {
                   3277: 
                   3278:                 //
                   3279:                 // There REALLY aren't any buffers
                   3280:                 //
                   3281: 
                   3282:                 break;
                   3283:             }
                   3284:         }
                   3285: 
                   3286:         //
                   3287:         // Find out how much space we have left in the
                   3288:         // client's buffers
                   3289:         // Note that BytesToCopy may be 0 - this is OK
                   3290:         //
                   3291: 
                   3292:         BytesToCopy =
                   3293:             min(BufferQueue->UserBufferSize - BufferQueue->pIrp->IoStatus.Information,
                   3294:                 pDMA->Size - pDMA->nBytes);
                   3295: 
                   3296:         //
                   3297:         // Copy the data
                   3298:         //
                   3299: 
                   3300:         RtlCopyMemory(BufferQueue->UserBuffer +
                   3301:                       BufferQueue->pIrp->IoStatus.Information,
                   3302:                       pDMA->Buf + pDMA->nBytes,
                   3303:                       BytesToCopy);
                   3304: 
                   3305:         //
                   3306:         // Update counters etc.
                   3307:         //
                   3308: 
                   3309:         BufferQueue->pIrp->IoStatus.Information += BytesToCopy;
                   3310:         BufferQueue->BytesProcessed += BytesToCopy;
                   3311:         pDMA->nBytes += BytesToCopy;
                   3312: 
                   3313:         //
                   3314:         // See if we've now filled a buffer
                   3315:         //
                   3316: 
                   3317:         if (BufferQueue->pIrp->IoStatus.Information == BufferQueue->UserBufferSize) {
                   3318: 
                   3319:             SoundCompleteIoBuffer(BufferQueue);
                   3320: 
                   3321:             //
                   3322:             // Mark request as complete
                   3323:             //
                   3324: 
                   3325:             BufferQueue->pIrp->IoStatus.Status = STATUS_SUCCESS;
                   3326:             IoCompleteRequest(BufferQueue->pIrp, IO_SOUND_INCREMENT);
                   3327: 
                   3328:             BufferCompleted = TRUE;
                   3329:         }
                   3330:     }
                   3331: 
                   3332:     //
                   3333:     // If there is a buffer part filled put it back on the queue so that
                   3334:     // it can be cancelled if necessary
                   3335:     //
                   3336: 
                   3337:     if (BufferQueue->UserBuffer != NULL) {
                   3338:         SoundAddIrpToCancellableQ(&BufferQueue->QueueHead,
                   3339:                                   BufferQueue->pIrp,
                   3340:                                   TRUE);
                   3341: 
                   3342:         BufferQueue->UserBuffer = NULL;
                   3343:     }
                   3344: 
                   3345:     return BufferCompleted;
                   3346: }
                   3347: 
                   3348: /************************************************************************
                   3349:  *
                   3350:  *  Routines to handle queues of wave buffers
                   3351:  *
                   3352:  ************************************************************************/
                   3353: 
                   3354: 
                   3355: 
                   3356: VOID
                   3357: SoundGetNextBuffer(
                   3358:     PSOUND_BUFFER_QUEUE BufferQueue
                   3359: )
                   3360: /*++
                   3361: 
                   3362: Routine Description:
                   3363: 
                   3364:   Get the next user's buffer :
                   3365: 
                   3366:     If there is another buffer :
                   3367: 
                   3368:       Remove the first buffer from the head of the list
                   3369:       Discard it if it's cancelled and go to the next
                   3370:       Map the locked user pages so we can refer to them
                   3371:       Update the BufferQueue fields :
                   3372:           UserBuffer        - our pointer to buffer
                   3373:           UserBufferPosition - 0
                   3374:           pIrp               - The request packet for the current buffer
                   3375: 
                   3376: 
                   3377: Arguments:
                   3378: 
                   3379:     BufferQueue - pointer to our local queue info
                   3380: 
                   3381: Return Value:
                   3382: 
                   3383:     None
                   3384: 
                   3385: --*/
                   3386: {
                   3387:     PIO_STACK_LOCATION pIrpStack;
                   3388:     KIRQL OldIrql;
                   3389: 
                   3390:     dprintf4(("New Packet"));
                   3391: 
                   3392:     ASSERT(BufferQueue->UserBuffer == NULL);
                   3393: 
                   3394:     //
                   3395:     // May be no more buffers.  If there are they may be cancelled
                   3396:     // IO requests.
                   3397:     //
                   3398: 
                   3399:     for (;;) {
                   3400: 
                   3401:         //
                   3402:         // pull the next request packet from the front of the list
                   3403:         // This call makes the Irp non cancellable.
                   3404:         //
                   3405: 
                   3406: 
                   3407:         BufferQueue->pIrp =
                   3408:             SoundRemoveFromCancellableQ(&BufferQueue->QueueHead);
                   3409: 
                   3410:         if (BufferQueue->pIrp == NULL) {
                   3411:             break;
                   3412:         }
                   3413: 
                   3414:         pIrpStack = IoGetCurrentIrpStackLocation(BufferQueue->pIrp);
                   3415: 
                   3416:         //
                   3417:         // Get the length of the wave bits
                   3418:         //
                   3419: 
                   3420:         BufferQueue->UserBufferSize =
                   3421:              pIrpStack->MajorFunction == IRP_MJ_WRITE ?
                   3422:                  pIrpStack->Parameters.Write.Length :
                   3423:                  pIrpStack->Parameters.Read.Length;
                   3424: 
                   3425:         //
                   3426:         // Map the buffer pages to kernel mode
                   3427:         // Keep the address of the start so we can unmap them later
                   3428:         // Note the system falls over mapping 0 length buffers !
                   3429:         //
                   3430: 
                   3431:         if (BufferQueue->UserBufferSize != 0) {
                   3432:             BufferQueue->UserBuffer =
                   3433:                 (PUCHAR) MmGetSystemAddressForMdl(BufferQueue->pIrp->MdlAddress);
                   3434:         } else {
                   3435:             BufferQueue->UserBuffer = (PUCHAR)BufferQueue; // Dummy
                   3436:         }
                   3437: 
                   3438:         //
                   3439:         // We now have a buffer - set the position from the
                   3440:         // information field.
                   3441:         //
                   3442: 
                   3443:         BufferQueue->UserBufferPosition =
                   3444:             BufferQueue->pIrp->IoStatus.Information;
                   3445: 
                   3446:         break;
                   3447:     }
                   3448: }
                   3449: 
                   3450: 
                   3451: VOID
                   3452: SoundCompleteIoBuffer(
                   3453:     PSOUND_BUFFER_QUEUE BufferQueue
                   3454: )
                   3455: /*++
                   3456: 
                   3457: Routine Description:
                   3458: 
                   3459:     Complete the processing of a wave buffer
                   3460: 
                   3461:     This involves
                   3462: 
                   3463:     -- Setting the length of data processed in the Irp and
                   3464: 
                   3465:     -- Clearing the UserBuffer field.
                   3466: 
                   3467: Arguments:
                   3468: 
                   3469:     BufferQueue - pointer to our queue data
                   3470: 
                   3471: Return Value:
                   3472: 
                   3473:     None
                   3474: 
                   3475: --*/
                   3476: 
                   3477: {
                   3478:     //
                   3479:     // Note that there is currently no mapped buffer to use
                   3480:     //
                   3481: 
                   3482:     BufferQueue->UserBuffer = NULL;
                   3483: }
                   3484: 
                   3485: 
                   3486: VOID
                   3487: SoundInitializeWaveInfo(
                   3488:     PWAVE_INFO WaveInfo,
                   3489:     UCHAR DMAType,
                   3490:     PSOUND_QUERY_FORMAT_ROUTINE QueryFormat,
                   3491:     PVOID HwContext
                   3492: )
                   3493: /*++
                   3494: 
                   3495: Routine Description:
                   3496: 
                   3497:     Initialize the WAVE_INFO structure
                   3498: 
                   3499: Arguments:
                   3500: 
                   3501:     WaveInfo - The one to initialize
                   3502:     DMAType - type of DMA to do (autoinit, 2 channel etc)
                   3503:     QueryFormat - callback to see if format is supported
                   3504:     Context - hardware specific context stored in WAVE_INFO structure
                   3505: 
                   3506: Return Value:
                   3507: 
                   3508:     None.
                   3509: 
                   3510: --*/
                   3511: {
                   3512:     WaveInfo->Key = WAVE_INFO_KEY;
                   3513:     WaveInfo->DMAType = DMAType;
                   3514:     WaveInfo->QueryFormat = QueryFormat;
                   3515:     WaveInfo->HwContext = HwContext;
                   3516:     SoundInitializeBufferQ(&WaveInfo->BufferQueue);
                   3517: 
                   3518:     KeInitializeSpinLock(&WaveInfo->DeviceSpinLock);
                   3519:     KeInitializeTimer(&WaveInfo->DeviceCheckTimer);
                   3520: 
                   3521:     //
                   3522:     // The event is used for waiting for the Dpc routine to complete -
                   3523:     // it is not reset on completion - hence use of NotificationEvent type.
                   3524:     //
                   3525: 
                   3526:     KeInitializeEvent(&WaveInfo->DpcEvent,
                   3527:                       NotificationEvent,
                   3528:                       TRUE);
                   3529: }
                   3530: 
                   3531: VOID
                   3532: SoundInitializeBufferQ(
                   3533:     PSOUND_BUFFER_QUEUE BufferQueue
                   3534: )
                   3535: /*++
                   3536: 
                   3537: Routine Description:
                   3538: 
                   3539:     Initialize the BufferQ structure
                   3540: 
                   3541: Arguments:
                   3542: 
                   3543:     BufferQueue - The one to initialize
                   3544: 
                   3545: Return Value:
                   3546: 
                   3547:     None.
                   3548: 
                   3549: --*/
                   3550: {
                   3551:     //
                   3552:     // Set up the lists
                   3553:     //
                   3554: 
                   3555:     InitializeListHead(&BufferQueue->QueueHead);
                   3556:     InitializeListHead(&BufferQueue->ProgressQueue);
                   3557: }
                   3558: 
                   3559: 
                   3560: VOID
                   3561: SoundInitializeDoubleBuffer(
                   3562:     IN OUT PWAVE_INFO WaveInfo
                   3563: )
                   3564: /*++
                   3565: 
                   3566: Routine Description:
                   3567: 
                   3568:     Initialize the Double buffer structure
                   3569: 
                   3570: Arguments:
                   3571: 
                   3572:     WaveInfo - pointer to containing structure
                   3573: 
                   3574: Return Value:
                   3575: 
                   3576:     None.
                   3577: 
                   3578: --*/
                   3579: {
                   3580:     ULONG BufferSize;
                   3581:     ULONG HalfBufferSize;
                   3582: 
                   3583:     ASSERTMSG("Setting buffer size while DMA running!", !WaveInfo->DMABusy);
                   3584: 
                   3585:     //
                   3586:     //  go for 8 interrupts per second, and round down to the nearest
                   3587:     //  8 bytes
                   3588:     //
                   3589: 
                   3590:     BufferSize = SoundGetDMABufferSize( WaveInfo );
                   3591: 
                   3592:     HalfBufferSize = BufferSize >> 1;
                   3593: 
                   3594:     WaveInfo->DoubleBuffer.Pad = WaveInfo->BitsPerSample == 8 ? 0x80 : 0;
                   3595:     WaveInfo->DoubleBuffer.BufferSize = BufferSize;
                   3596:     WaveInfo->DoubleBuffer.NextHalf = LowerHalf;
                   3597:     WaveInfo->DoubleBuffer.Buffer[LowerHalf].Size = HalfBufferSize;
                   3598:     WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size = HalfBufferSize;
                   3599:     WaveInfo->DoubleBuffer.Buffer[LowerHalf].nBytes =
                   3600:         WaveInfo->Direction ? 0 : HalfBufferSize;
                   3601:     WaveInfo->DoubleBuffer.Buffer[UpperHalf].nBytes =
                   3602:         WaveInfo->Direction ? 0 : HalfBufferSize;
                   3603:     WaveInfo->DoubleBuffer.Buffer[LowerHalf].Buf =
                   3604:         (PUCHAR)WaveInfo->DMABuf.VirtualAddress;
                   3605:     WaveInfo->DoubleBuffer.Buffer[UpperHalf].Buf =
                   3606:         (PUCHAR)WaveInfo->DMABuf.VirtualAddress + HalfBufferSize;
                   3607: }
                   3608: 
                   3609: 
                   3610: int
                   3611: SoundTestWaveDevice(
                   3612:     IN PDEVICE_OBJECT pDO
                   3613: )
                   3614: /*++
                   3615: 
                   3616: Routine Description:
                   3617: 
                   3618:     Fire up the wave device for a short transfer and return whether it's
                   3619:     working (ie interrupts) or not.
                   3620: 
                   3621:     This routine should not be called except from the DriverEntry routine.
                   3622: 
                   3623:     NOTE - ONLY use this as a last resort - if there's no configuration
                   3624:     information.
                   3625: 
                   3626:     ALSO - before unloading your driver if it fails make sure any termination
                   3627:     of the transfer is complete (eg ExWorker routines etc).
                   3628: 
                   3629:     WARNING - this routine currently only works for auto-init devices - the
                   3630:         test on the DMA position at the end should be corrected for other
                   3631:         forms of DMA.
                   3632: 
                   3633: Arguments:
                   3634: 
                   3635:     pDO - device object of wave device
                   3636: 
                   3637: Return Value:
                   3638: 
                   3639:     0 if success
                   3640:     1 if bad interrupt
                   3641:     2 if bad DMA
                   3642: 
                   3643: --*/
                   3644: {
                   3645:     PWAVE_INFO WaveInfo;
                   3646:     PLOCAL_DEVICE_INFO pLDI;
                   3647:     ULONG DmaBytesLeft;
                   3648: 
                   3649:     pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension;
                   3650: 
                   3651:     WaveInfo = pLDI->DeviceSpecificData;
                   3652: 
                   3653:     //
                   3654:     // To test the wave device we just start a 0 length transfer.  The
                   3655:     // way the code is written this will actually cause a half DMA buffer
                   3656:     // to be sent so we should get an interrupt in less than 1/8 of a second.
                   3657:     // We arrange to wait for 1/4 of a second and see if we got one
                   3658:     //
                   3659: 
                   3660:     if (!(*pLDI->DeviceInit->ExclusionRoutine)(
                   3661:               pLDI, SoundExcludeOpen)) {
                   3662:         return FALSE;    // Something funny going on here
                   3663:     }
                   3664: 
                   3665:     SoundWaveCreate(pLDI, pDO);
                   3666: 
                   3667:     if (!WaveInfo->Direction) {
                   3668:         SoundSetWaveInputState(pLDI, WAVE_DD_RECORDING);
                   3669:     }
                   3670: 
                   3671:     SoundStartWaveDevice(pLDI, NULL);
                   3672: 
                   3673:     SoundDelay(125);   // 125 ms = 1/8 second
                   3674: 
                   3675:     SoundWaveCleanup(pLDI);
                   3676: 
                   3677:     //
                   3678:     // Should be around half a buffer left to go - ie we're in the second
                   3679:     // half buffer
                   3680:     //
                   3681:     DmaBytesLeft = HalReadDmaCounter(WaveInfo->DMABuf.AdapterObject[0]);
                   3682: 
                   3683:     if (!WaveInfo->GotWaveDpc) {
                   3684:         return 1;   // Bad interrupt
                   3685:     }
                   3686:     if (DmaBytesLeft > 0 &&
                   3687:         DmaBytesLeft < WaveInfo->DoubleBuffer.Buffer[UpperHalf].Size) {
                   3688: 
                   3689:         return 0;   // OK
                   3690:     } else {
                   3691:         return 2;   // Bad DMA
                   3692:     }
                   3693: }
                   3694: 
                   3695: /****************************************************************************
                   3696: 
                   3697: Routine Description:
                   3698: 
                   3699:     Get the DMA Buffer size based on the Sample Rate
                   3700: 
                   3701: Arguments:
                   3702: 
                   3703:     WaveInfo - pointer to containing structure
                   3704: 
                   3705: Return Value:
                   3706: 
                   3707:     ULONG   DmaBufferSize
                   3708: 
                   3709: ****************************************************************************/
                   3710: ULONG    SoundGetDMABufferSize( IN OUT PWAVE_INFO WaveInfo )
                   3711: {
                   3712:     /***** Local Variables *****/
                   3713: 
                   3714:     ULONG BytesPerSecond;
                   3715:     ULONG BufferSize;
                   3716: 
                   3717:     /***** Start *****/
                   3718: 
                   3719:     BytesPerSecond = (WaveInfo->Channels *
                   3720:                      WaveInfo->SamplesPerSec *
                   3721:                      WaveInfo->BitsPerSample) >> 3;
                   3722:     //
                   3723:     //  go for 8 interrupts per second, and round down to the nearest
                   3724:     //  8 bytes
                   3725:     //
                   3726:     BufferSize = min((BytesPerSecond >> 2) & ~7,
                   3727:                      WaveInfo->DMABuf.BufferSize);
                   3728: 
                   3729:     dprintf2(("SoundGetDMABufferSize(): DMA Buffer Size calculated = %XH", BufferSize));
                   3730: 
                   3731:     return( BufferSize );
                   3732: 
                   3733: }   // End SoundGetDMABufferSize()
                   3734: 
                   3735: 
                   3736: /************************************ END ***********************************/
                   3737: 

unix.superglobalmegacorp.com

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