Annotation of ntddk/src/mmedia/soundlib/wave.c, revision 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.